<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.0" />

SecureRandom

public class SecureRandom : Random
using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Prng; using Org.BouncyCastle.Crypto.Utilities; using System; using System.Threading; namespace Org.BouncyCastle.Security { public class SecureRandom : Random { private static long counter = DateTime.UtcNow.Ticks; private static readonly SecureRandom MasterRandom = new SecureRandom(new CryptoApiRandomGenerator()); internal static readonly SecureRandom ArbitraryRandom = new SecureRandom(new VmpcRandomGenerator(), 16); protected readonly IRandomGenerator generator; private static readonly double DoubleScale = 1 / Convert.ToDouble(9007199254740992); private static long NextCounterValue() { return Interlocked.Increment(ref counter); } private static DigestRandomGenerator CreatePrng(string digestName, bool autoSeed) { IDigest digest = DigestUtilities.GetDigest(digestName); if (digest == null) return null; DigestRandomGenerator result = new DigestRandomGenerator(digest); if (autoSeed) AutoSeed(result, 2 * digest.GetDigestSize()); return result; } public static byte[] GetNextBytes(SecureRandom secureRandom, int length) { byte[] array = new byte[length]; secureRandom.NextBytes(array); return array; } public static SecureRandom GetInstance(string algorithm) { return GetInstance(algorithm, true); } public static SecureRandom GetInstance(string algorithm, bool autoSeed) { if (algorithm == null) throw new ArgumentNullException("algorithm"); if (algorithm.EndsWith("PRNG", StringComparison.OrdinalIgnoreCase)) { DigestRandomGenerator digestRandomGenerator = CreatePrng(algorithm.Substring(0, algorithm.Length - "PRNG".Length), autoSeed); if (digestRandomGenerator != null) return new SecureRandom(digestRandomGenerator); } throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm"); } public SecureRandom() : this(CreatePrng("SHA256", true)) { } public SecureRandom(IRandomGenerator generator) : base(0) { this.generator = generator; } public SecureRandom(IRandomGenerator generator, int autoSeedLengthInBytes) : base(0) { AutoSeed(generator, autoSeedLengthInBytes); this.generator = generator; } public virtual byte[] GenerateSeed(int length) { return GetNextBytes(MasterRandom, length); } public virtual void SetSeed(byte[] seed) { generator.AddSeedMaterial(seed); } public virtual void SetSeed(long seed) { generator.AddSeedMaterial(seed); } public override int Next() { return NextInt() & 2147483647; } public override int Next(int maxValue) { if (maxValue < 2) { if (maxValue < 0) throw new ArgumentOutOfRangeException("maxValue", "cannot be negative"); return 0; } int num; if ((maxValue & (maxValue - 1)) == 0) { num = (NextInt() & 2147483647); return (int)((long)num * (long)maxValue >> 31); } int num2; do { num = (NextInt() & 2147483647); num2 = num % maxValue; } while (num - num2 + (maxValue - 1) < 0); return num2; } public override int Next(int minValue, int maxValue) { if (maxValue <= minValue) { if (maxValue == minValue) return minValue; throw new ArgumentException("maxValue cannot be less than minValue"); } int num = maxValue - minValue; if (num > 0) return minValue + Next(num); int num2; do { num2 = NextInt(); } while (num2 < minValue || num2 >= maxValue); return num2; } public override void NextBytes(byte[] buf) { generator.NextBytes(buf); } public virtual void NextBytes(byte[] buf, int off, int len) { generator.NextBytes(buf, off, len); } public override double NextDouble() { return Convert.ToDouble((ulong)NextLong() >> 11) * DoubleScale; } public virtual int NextInt() { byte[] array = new byte[4]; NextBytes(array); return (int)Pack.BE_To_UInt32(array); } public virtual long NextLong() { byte[] array = new byte[8]; NextBytes(array); return (long)Pack.BE_To_UInt64(array); } private static void AutoSeed(IRandomGenerator generator, int seedLength) { generator.AddSeedMaterial(NextCounterValue()); byte[] array = new byte[seedLength]; MasterRandom.NextBytes(array); generator.AddSeedMaterial(array); } } }