The method below is returning a string of random characters using RNGCryptoServiceProvider
. The return string result
is built by picking characters from the string chars
by applying % chars.length
on the byte values (0-255) in the array of bytes returned by GetBytes()
. This means that some characters may be favoured over others, depending on the length of chars
.
How can the method be re-written so that all the characters in chars
have an equal chance of being picked?
/// <summary>
/// Returns a string of cryptographically sound random characters
/// </summary>
/// <param name="type">Accepted parameter variables are HEX (0-F), hex (0-f),
/// DEC/dec/NUM/num (0-9), ALPHA (A-Z), alpha (a-z), ALPHANUM (A-Z and 0-9),
/// alphanum (a-z and 0-9) and FULL/full (A-Z, a-z and 0-9)</param>
/// <param name="length">The length of the output string</param>
/// <returns>String of cryptographically sound random characters</returns>
private static string Serial(string type, int length)
{
if (length < 1) return "";
string chars;
switch (type)
{
case "HEX":
chars = "0123456789ABCDEF";
break;
case "hex":
chars = "0123456789abcdef";
break;
case "DEC":
case "dec":
case "NUM":
case "num":
chars = "0123456789";
break;
case "ALPHA":
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
break;
case "alpha":
chars = "abcdefghijklmnopqrstuvwxyz";
break;
case "ALPHANUM":
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
break;
case "alphanum":
chars = "abcdefghijklmnopqrstuvwxyz0123456789";
break;
case "FULL":
case "full":
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
break;
default:
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
break;
}
byte[] data = new byte[length];
using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
{
crypto.GetBytes(data);
}
StringBuilder result = new StringBuilder(length);
foreach (byte b in data)
{
result.Append(chars[b % chars.Length]);
}
return result.ToString();
}