RandomNumberGenerator vs RNGCryptoServiceProvider

11,375

Solution 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 behaviour 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.

Solution 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.

Solution 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.

Share:
11,375
James
Author by

James

Updated on June 06, 2022

Comments

  • James
    James almost 2 years

    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?

  • James
    James over 11 years
    "the static method chooses the most appropriate implementation" - it's a bit frustrating that there is no documentation indicating the criteria for what version is the most appropriate though.
  • James
    James over 11 years
    "Surely it will return an instance of a derived class" - I would imagine it is, however, it's not clear from the documentation what version it is returning.
  • usr
    usr over 11 years
    The actual type returned can vary. You can override it in the web.config (don't have the reference at hand, but both my memory and Reflector say this is the case). There are no guarantees about the return type. Does the concrete type matter for you?
  • James
    James over 11 years
    "does the concrete type matter for you" - For what I am using it for probably not as all I need is for it to generate a secure random number. However, I was curious as to why the documentation was quoting stuff like "Application code does not directly use this class" when it's clearly not the case. From the answers posted it does appear that it's a bug in the documentation.
  • James
    James over 11 years
    "which will eventually create an instance of RNGCryptoServiceProvider" - What is the criteria for this though? Why not AesCryptoServiceProvider/SHA512/DAS etc. specifically? Is it just the same approach with RNGCryptoServiceProvider that RandomNumberGenerator has i.e. does that internally decide on which algorithm it will use under the hood?
  • usr
    usr over 11 years
    I agree. It is a documentation flaw.
  • James
    James over 11 years
    Just to clarify your point, the documentation does state "You cannot create an instance of an abstract class. Application code will create a new instance of a derived class.". However, my question was guided more towards what type of derived class it would create.
  • Guffa
    Guffa over 11 years
    @James: Well, basically it is because that's the only random number generator that is implemented by default (see the inheritance hierarchy msdn.microsoft.com/en-us/library/42ks8fz1). AesCryptuServiceProvider is an encryption algorithm, not a random number generator. The random number generator isn't specific for different encryption algorithms. The only reason to make it possible to register a different generator, is that someone might find that the current implementation doesn't produce good enough random numbers.
  • James
    James over 11 years
    D'oh, that was my mistake, assuming all CryptoServiceProvider's were RNG's! So realistically there is only one implementation of an RNG part of the framework and it's RNGCryptoServiceProvider, therefore, it doesn't matter which one I use?
  • Guffa
    Guffa over 11 years
    @James: With what's currently known, the default RNG is the best option. the RNGCryptoServiceProvider may be replaced by a different implementation in future frameworks, and then the Create() method will return that instead. If the RNGCryptoServiceProvider is found to be too weak, you might want to create a specific provider instead, but there is nothing that you can do about that now, so using the Create() method is the most future proof solution.
  • variable
    variable over 2 years
    Is RandomNumberGenerator.Create() thread-safe?
  • variable
    variable over 2 years
    Is RandomNumberGenerator.Create() thread-safe?
  • usr
    usr over 2 years
    @variable Yes. In .NET, static methods generally are thread-safe, and so in this particular case. It would be very hard for different application components and libraries to synchronize access to static methods. They kind of must be thread-safe.
  • David G
    David G about 2 years
    As of .NET Core 6, RNGCryptoServiceProvider is marked as obsolete (so shouldn't be explicitly instantiated). RandomNumberGenerator.Create() appears to be the 'official' way to get an RNG, with the object being returned displayed as a System.Security.Cryptography.RandomNumberGeneratorImplementa‌​tion.