RandomNumberGenerator vs RNGCryptoServiceProvider

2019-02-12 06:40发布

问题:

According to MSDN documentation for RandomNumberGenerator:

Application code does not directly use this class. This abstract class is provided as the base class for all cryptographic random number generators.

For an implementation of a cryptographic random number generator, use the derived class RNGCryptoServiceProvider.

However, I have seen the following code used on a few occassions in different code bases:

byte[] bytes = new byte[...];
RandomNumberGenerator rng = RandomNumberGenerator.Create();
rng.GetBytes(bytes);

Most notably with StackExchange (which I assume includes SO) and also with BCrypt.Net.

Therefore, I am a little confused - what type of RandomNumberGenerator is the above code returning? Also is it a bit of a flaw that some code bases are using RandomNumberGenerator rather than RNGCryptoServiceProvider?

I assume RandomNumberGenerator.Create() is doing under the hood which I am completely missing here, but technically (as it's an abstract class) shouldn't the above code throw an error?

回答1:

The RandomNumberGenerator.Create() method calls RandomNumberGenerator.Create("System.Security.Cryptography.RandomNumberGenerator"), which will eventually create an instance of RNGCryptoServiceProvider.

(It does some lookups in a pair of dictionaries, so it's likely that you can change the becaviour of that call by registering a default random generator somewhere.)

The actual type of the object returned is not known at compile time, it's only known that it will inherit the RandomNumberGenerator class, so you can use a RandomNumberGenerator reference variable for it.

This way of creating different types of instances depending on the input is used in a couple of places in the framework, for example by the WebRequest.Create method.


Someone at Micrsoft has "fixed" the current documentation (framework 4.5) for the Create() method. It now says:

"When overridden in a derived class, creates an instance of the default implementation of a cryptographic random number generator that can be used to generate random data."

The documentation for framework 4.0 says:

"Creates an instance of the default implementation of a cryptographic random number generator that can be used to generate random data."

This is the correct description of what the method does. I will put in a request to put that description back in the newer documentation.



回答2:

The documentation for RandomNumberGenerator is basically messed up. As another example, there's documentation like this:

When overridden in a derived class, creates an instance of the specified implementation of a cryptographic random number generator.

... for a static method. Static methods can't be overridden. Whoever wrote the documentation clearly wasn't thinking straight.

I suspect the original intention was something like:

Application code does not directly instantiate this class. This abstract class is provided as the base class for all cryptographic random number generators.

I think the code you've posted (using the static Create method) is entirely reasonable. It's the same sort of pattern as is used for XmlReader.Create etc - the static method chooses the most appropriate implementation.



回答3:

RandomNumberGenerator.Create is a static factory method. Surely it will return an instances of a derived class. And that one is not abstract so all of this is legal.

Abstract classes are made to be used everywhere instead of using a more concrete class. They are meant to be a versioning-friendly interface.