1

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

1
  • 172 characters is not too long. Commented Nov 7, 2011 at 17:33

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

6 Comments

I was wondering about hitting the maths, but I read something that mentioned, but didn't detail, that the extra data came from somewhere, so I thought I'd be diluting the randomness with predictable characters if I used that. It seems that they were talking out of their donkey, then - I wondered where the extra stuff was coming from and didn't they they were quite right
I want 128 characters, maybe my phraseology wasn't quite right.
@MadHalfling - Then my answer should suffice. 96 bytes, when bases 64 encoded should produce 128 characters (based on the rule that for every three bytes of input, 4 bytes of output are generated and 1 character is used to represent 1 byte of output). You should run the code and check it out. You may also want to investigate the padding. There is a chance the Bse64 encoder in .NET adds 4 characters of padding when the modulus of the final count is 0 in which case you will want to use 92 Bytes of input.
Any tips on making these characters more URL-friendly - as I mentioned below, testing this show that even encoded / characters screw up the routing. If it's not one thing, it's another....
The nice thing about Base64 encoding is that if you control both the encoder and the decoder you can use any arbitrary set of characters you want. For instance, after you Base64 encode your buffer, simply replace the / characters with some other character that's not already used. For instance, and exclamation sign !. Then, when you receive the activation link simply to the reverse operation before passing it on to the decoder.
|
0

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.

Comments

0

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.

1 Comment

it was 128 characters that I could then encode to something URL safe - so with 128 chars and my URL prefix I'm very unlikely to hit the 256 char (IIRC) URL length limit if I then encode the 128 characters. However, testing this doesn't work with / characters in the string, even if these are encoded ther still seem to screw up the route (it's an MVC project). This gets me back to where I was earlier, if I have a characters set a-zA-Z0-9 how can I use strong crypto data to select these?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.