using System; using System.Threading; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Prng; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Security; public class SecureRandom : Random { private static long counter = Times.NanoTime(); private static readonly SecureRandom master = new SecureRandom(new CryptoApiRandomGenerator()); protected readonly IRandomGenerator generator; private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0); private static SecureRandom Master => master; 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 digestRandomGenerator = new DigestRandomGenerator(digest); if (autoSeed) { digestRandomGenerator.AddSeedMaterial(NextCounterValue()); digestRandomGenerator.AddSeedMaterial(GetNextBytes(Master, digest.GetDigestSize())); } return digestRandomGenerator; } 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, autoSeed: true); } public static SecureRandom GetInstance(string algorithm, bool autoSeed) { string text = Platform.ToUpperInvariant(algorithm); if (Platform.EndsWith(text, "PRNG")) { string digestName = text.Substring(0, text.Length - "PRNG".Length); DigestRandomGenerator digestRandomGenerator = CreatePrng(digestName, autoSeed); if (digestRandomGenerator != null) { return new SecureRandom(digestRandomGenerator); } } throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm"); } [Obsolete("Call GenerateSeed() on a SecureRandom instance instead")] public static byte[] GetSeed(int length) { return GetNextBytes(Master, length); } public SecureRandom() : this(CreatePrng("SHA256", autoSeed: true)) { } [Obsolete("Use GetInstance/SetSeed instead")] public SecureRandom(byte[] seed) : this(CreatePrng("SHA1", autoSeed: false)) { SetSeed(seed); } public SecureRandom(IRandomGenerator generator) : base(0) { this.generator = generator; } public virtual byte[] GenerateSeed(int length) { return GetNextBytes(Master, 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() & 0x7FFFFFFF; } 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() & 0x7FFFFFFF; return (int)((long)num * (long)maxValue >> 31); } int num2; do { num = NextInt() & 0x7FFFFFFF; 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()) / DoubleScale; } public virtual int NextInt() { byte[] array = new byte[4]; NextBytes(array); uint num = array[0]; num <<= 8; num |= array[1]; num <<= 8; num |= array[2]; num <<= 8; return (int)(num | array[3]); } public virtual long NextLong() { return (long)(((ulong)(uint)NextInt() << 32) | (uint)NextInt()); } }