I'm using this code to generate random strings with given length
public string RandomString(int length)
{
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
StringBuilder res = new StringBuilder();
Random rnd = new Random();
while (0 < length--)
{
res.Append(valid[rnd.Next(valid.Length)]);
}
return res.ToString();
}
However, I read that RNGCryptoServiceProvider
is more secure than Random
class. How can I implement RNGCryptoServiceProvider
to this function. It should use valid
string just like this function.
You need to generate random
byte
s usingRNGCryptoServiceProvider
and append only the valid ones to the returnedstring
:You could also use modulo in order to not skip the invalid
byte
values but that the chances for each character won't be even.see https://bitbucket.org/merarischroeder/number-range-with-no-bias/
I'm sure I have answered this one before with a secure implementation, no bias, and good performance. If so, please comment.
Looking at Tamir's answer, I thought it would be better to use the modulus operation, but trim off the incomplete remainder of byte values. I'm also writing this answer now (possibly again), because I need to reference this solution to a peer.
Approach 1
if (buffer[i] >= exclusiveLimit)
Code for Approach 1
Approach 2
Results:
I personally like to use this:
There shouldn't be any part that needs additional description, but to clarify, this function returns a random string with a random length between 32 and 64 chars and doesn't use
%
(mod) therefore should keep uniformity a little better.I use this to create a random salt at program installation and later save it to a file. Therefore security of generated string is not of special concern while the program is running as it is going to get written to an unencrypted file later on anyway.
However, for more serious situations, this shouldn't be used as it is and should be converted to use
SecureString
class if you are going to keep this value in memory. Read more here:https://docs.microsoft.com/en-us/dotnet/api/system.security.securestring?redirectedfrom=MSDN&view=netframework-4.7.2
However, even this only applies to NetFramework, for NetCore you need to find another way to secure the value in the memory. Read more here:
https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md
My implementation that fixes the issue with 5,9541963103868752088061235991756 bits
Since RNGRandomNumberGenerator only returns byte arrays, you have to do it like this:
Note however that this has a flaw, 62 valid characters is equal to 5,9541963103868752088061235991756 bits (log(62) / log(2)), so it won't divide evenly on a 32 bit number (uint).
What consequences does this have? As a result, the random output won't be uniform. Characters which are lower in valid will occur more likely (just by a small fraction, but still it happens).
To be more precise, the first 4 characters of the valid array are 0,00000144354999199840239435286 % more likely to occur.
To avoid this, you should use array lengths which divide evenly like 64 (Consider using Convert.ToBase64String on the output instead, since you can cleanly match 64 bits to 6 bytes.