Random Number Generation
RandomNumberGenerator in CryptoHives.Foundation.Security.Cryptography.Rng fills buffers with
cryptographically strong random bytes. It generates nothing itself: every byte comes from the
platform generator behind System.Security.Cryptography.RandomNumberGenerator.Create().
Namespace: CryptoHives.Foundation.Security.Cryptography.Rng · API reference
Why it exists
The in-box static RandomNumberGenerator.Fill(Span<byte>) arrived with .NET Standard 2.1, so code
that fills a span cannot call it on .NET Framework 4.6.2/4.7.2 or .NET Standard 2.0, which this
package also targets. This type offers the same call on every target framework, and the library
uses it wherever it draws randomness of its own:
- keys and IVs from
SymmetricCipher.GenerateKey()/GenerateIV() - the salt and IV of an encrypted PKCS#8 export
- the random bytes of ISO 10126 padding
- below .NET 8, the randomness of ML-KEM key generation and encapsulation, and of ML-DSA and SLH-DSA key generation and hedged signing
Usage
using CryptoHives.Foundation.Security.Cryptography.Rng;
byte[] nonce = new byte[12];
RandomNumberGenerator.Fill(nonce);
Span<byte> key = stackalloc byte[32];
RandomNumberGenerator.Fill(key);
The static Fill overloads share one generator for the whole process, need no instance, and are
safe to call from several threads at once. Prefer them. Create() returns an instance with
GetBytes(byte[]), GetBytes(byte[], int, int) and GetBytes(Span<byte>), for code that is
written against an instance; dispose it when done. After Dispose its GetBytes overloads throw
ObjectDisposedException; the static Fill is unaffected.
Members
| Member | Notes |
|---|---|
static void Fill(Span<byte> data) |
Same name and shape as the in-box static |
static void Fill(byte[] data) |
Not in the in-box type; throws ArgumentNullException for null |
static RandomNumberGenerator Create() |
|
void GetBytes(byte[] data) / GetBytes(byte[] data, int offset, int count) |
Forward to the platform generator |
void GetBytes(Span<byte> data) |
Before .NET 6, staged through a rented ArrayPool<byte> array that is cleared before it goes back |
void Dispose() |
Afterwards the GetBytes overloads throw ObjectDisposedException; safe to call twice |
The in-box convenience members are not here: GetBytes(int), GetInt32, GetNonZeroBytes,
GetItems, GetString, GetHexString and Shuffle. To get a fresh array, allocate it and call
Fill:
byte[] salt = new byte[16];
RandomNumberGenerator.Fill(salt);
Using it next to the in-box type
It wraps System.Security.Cryptography.RandomNumberGenerator rather than deriving from it, so an
instance cannot be passed to an API that expects the in-box type. Where an API wants one, pass the
in-box generator itself.
Because the names match, a file that imports both namespaces gets CS0104 on
RandomNumberGenerator. Alias one side:
using CryptoHives.Foundation.Security.Cryptography.Rng;
using Bcl = System.Security.Cryptography;
RandomNumberGenerator.Fill(nonce); // this package
using var platform = Bcl.RandomNumberGenerator.Create();
On .NET Standard 2.1 and later, System.Security.Cryptography.RandomNumberGenerator.Fill(Span<byte>)
draws from the same platform generator, so code that only targets those frameworks gains nothing by
switching.