One of the apps I have been working on recently required that I present the user with a truly random sequence of values. The concept of being random is actually a bit more complicated than one would assume, in fact the idea of randomness is based in mathematics (which I will not get into here).
The following code represents a cryptographically sound random name generator. It takes advantage of the System.Security.Cryptography namespace which provides secure encoding and decoding of data, as well as hashing, and random number generation. Additionally I copped some code from Michael Giagnocavo, who helps resolve the problem of converting the bytes produce by the service into a Base32 string. Please see my notes in line.
public sealed class RandomValue
{
//This value determines how long the random number will be (every 5 bytes produces 8 characters)
//... the bigger the better
private const int FOLDERNAME_BYTES = 20;
private RandomValue() { }
public static string GenerateValues()
{
//This provider fills an array with a cryptographically strong sequence of random byte values.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buffer = new byte[FOLDERNAME_BYTES];
rng.GetBytes(buffer);
//Convert the byte value into a string using "Base32"
return Base32.ToBase32String(buffer);
}
}
public sealed class Base32
{
// the valid chars for the encoding ...
// the order and the values can be changed e.g. 0,1,O,I ...
// but it still needs to be 32 characters.
// Standard base32 encoding uses A-Z and six digits 2-7
// (see http://en.wikipedia.org/wiki/Base32).
private static string ValidChars = "QAZ2WSX3" + "EDC4RFV5" + "TGB6YHN7" + "UJM8K9LP";
///
/// Converts an array of bytes to a Base32-k string.
///
public static string ToBase32String(byte[] bytes)
{
StringBuilder sb = new StringBuilder(); // holds the base32 chars
byte index;
int hi = 5;
int currentByte = 0;
while (currentByte < bytes.Length)
{
// do we need to use the next byte?
if (hi > 8)
{
// get the last piece from the current byte, shift it to the right
// and increment the byte counter
index = (byte)(bytes[currentByte++] >> (hi - 5));
if (currentByte != bytes.Length)
{
// if we are not at the end, get the first piece from
// the next byte, clear it and shift it to the left
index = (byte)(((byte)(bytes[currentByte] << (16 - hi)) >> 3) | index);
}
hi -= 3;
}
else if (hi == 8)
{
index = (byte)(bytes[currentByte++] >> 3);
hi -= 3;
}
else
{
// simply get the stuff from the current byte
index = (byte)((byte)(bytes[currentByte] << (8 - hi)) >> 3);
hi += 5;
}
sb.Append(ValidChars[index]);
}
return sb.ToString();
}
}
Comments are closed.