Question

I must be having some sort of google-block today, because I can't find an answer to what should be a common issue. I'm coding my password reset section on my site and I want to e-mail the user a URL containing a suffix of 128 characters of entropy that will be used to confirm the generation of a new password. I've looked around and using the Random function isn't recommended as it's not random enough, so I'm looking at using the RNGCryptoServiceProvider to generate the key. However I don't seem to be able to use this to generate a suitable 128 char string.

I've started off trying

byte[] linkBytes = new byte[128];
        System.Security.Cryptography.RNGCryptoServiceProvider rngCrypto = new System.Security.Cryptography.RNGCryptoServiceProvider();
        rngCrypto.GetBytes(linkBytes);
        string text128 = Convert.ToBase64String(linkBytes);
        string text128Enc = Uri.EscapeDataString(text128);

I can use the Uri escaping to encode any URL unfreindly characters and then decode them at the destination, but this generates 172 characters not 128 and I have to be a bit careful (as far as I am aware) or the string lenght due to limits on the URL length in IIS.

What am I doing wrong or is there another way I can generate 128 characters using RNGCrypto? I've seen some code that uses the modulus of 62 of each byte result on a string containing a-zA-Z0-9 (like this)

.....
foreach (byte b in data)
{
    result.Append(chars[b%(chars.Length - 1)]);
}
.....

but obviously unless the limit of the range of the numbers in the bytes was a multiple of 62, this would then skew the distribution of characters, so that method doesn't seem ideal.

Thanks MH

Was it helpful?

Solution

Simply generate 96 random bytes. Then Base64 encode that to obtain a string of 128 characters.

byte[] linkBytes = new byte[96];
var rngCrypto = new System.Security.Cryptography.RNGCryptoServiceProvider();
rngCrypto.GetBytes(linkBytes);
var text128 = Convert.ToBase64String(linkBytes);
var text128Enc = Uri.EscapeDataString(text128);

The base 64 encoding uses 4 bytes to encode every 3 bytes of original data. If you do the math, (128 / 4) * 3 = 96 you get the number of bytes needed to produce a 128-character base64 encoded string.

Note
You mentioned that you need to generate 128 characters of entropy. And I just wanted to point out that usually, the requirements are expressed in number of bits of entropy. If you really meant 128 characters you would have to also be specific about which characters are to be included in your set.

Otherwise, you may want to specify that you need 128 bytes of entropy (or 1024 bits). If that is the case, then the sample code above will not be adequate and there is no way to Base64 encode 128 bytes (1024 bits) of entropy with only 128 readable characters.

OTHER TIPS

In this case it doesn't matter. As long as the value is long enough, the entropy of Random will be more than sufficient. Even if you just use a string of 10 random numbers, that's a one in 10,000,000,000 chance that a malicious user could guess the number. By changing that to 10 random letters (a-z) that becomes one in 141,167,095,653,376. Not really a likely case.

The entropy of Random is only an issue when you're directly using it as a key in a cryptographic appliance, which a "reset password" link is certainly not.

You cannot fit 128 bytes of entropy into 128 URL-safe characters, since a byte can hold more values than a URL-safe character.

You need to either use less entropy for a shorter URL, or use a longer URL that can store the full 128 bytes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top