123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- using System;
- using System.Threading;
- using Org.BouncyCastle.Crypto;
- using Org.BouncyCastle.Crypto.Digests;
- using Org.BouncyCastle.Crypto.Prng;
- using Org.BouncyCastle.Utilities;
- namespace Org.BouncyCastle.Security
- {
- public class SecureRandom
- : Random
- {
- private static long counter = Times.NanoTime();
- #if NETCF_1_0 || PORTABLE
- private static object counterLock = new object();
- private static long NextCounterValue()
- {
- lock (counterLock)
- {
- return ++counter;
- }
- }
- private static readonly SecureRandom[] master = { null };
- private static SecureRandom Master
- {
- get
- {
- lock (master)
- {
- if (master[0] == null)
- {
- SecureRandom sr = master[0] = GetInstance("SHA256PRNG", false);
- // Even though Ticks has at most 8 or 14 bits of entropy, there's no harm in adding it.
- sr.SetSeed(DateTime.Now.Ticks);
- // 32 will be enough when ThreadedSeedGenerator is fixed. Until then, ThreadedSeedGenerator returns low
- // entropy, and this is not sufficient to be secure. http://www.bouncycastle.org/csharpdevmailarchive/msg00814.html
- sr.SetSeed(new ThreadedSeedGenerator().GenerateSeed(32, true));
- }
- return master[0];
- }
- }
- }
- #else
- private static long NextCounterValue()
- {
- return Interlocked.Increment(ref counter);
- }
- private static readonly SecureRandom master = new SecureRandom(new CryptoApiRandomGenerator());
- private static SecureRandom Master
- {
- get { return master; }
- }
- #endif
- private static DigestRandomGenerator CreatePrng(string digestName, bool autoSeed)
- {
- IDigest digest = DigestUtilities.GetDigest(digestName);
- if (digest == null)
- return null;
- DigestRandomGenerator prng = new DigestRandomGenerator(digest);
- if (autoSeed)
- {
- prng.AddSeedMaterial(NextCounterValue());
- prng.AddSeedMaterial(GetNextBytes(Master, digest.GetDigestSize()));
- }
- return prng;
- }
- public static byte[] GetNextBytes(SecureRandom secureRandom, int length)
- {
- byte[] result = new byte[length];
- secureRandom.NextBytes(result);
- return result;
- }
- /// <summary>
- /// Create and auto-seed an instance based on the given algorithm.
- /// </summary>
- /// <remarks>Equivalent to GetInstance(algorithm, true)</remarks>
- /// <param name="algorithm">e.g. "SHA256PRNG"</param>
- public static SecureRandom GetInstance(string algorithm)
- {
- return GetInstance(algorithm, true);
- }
- /// <summary>
- /// Create an instance based on the given algorithm, with optional auto-seeding
- /// </summary>
- /// <param name="algorithm">e.g. "SHA256PRNG"</param>
- /// <param name="autoSeed">If true, the instance will be auto-seeded.</param>
- public static SecureRandom GetInstance(string algorithm, bool autoSeed)
- {
- string upper = Org.BouncyCastle.Utilities.Platform.ToUpperInvariant(algorithm);
- if (Org.BouncyCastle.Utilities.Platform.EndsWith(upper, "PRNG"))
- {
- string digestName = upper.Substring(0, upper.Length - "PRNG".Length);
- DigestRandomGenerator prng = CreatePrng(digestName, autoSeed);
- if (prng != null)
- {
- return new SecureRandom(prng);
- }
- }
- 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);
- }
- protected readonly IRandomGenerator generator;
- public SecureRandom()
- : this(CreatePrng("SHA256", true))
- {
- }
- /// <remarks>
- /// To replicate existing predictable output, replace with GetInstance("SHA1PRNG", false), followed by SetSeed(seed)
- /// </remarks>
- [Obsolete("Use GetInstance/SetSeed instead")]
- public SecureRandom(byte[] seed)
- : this(CreatePrng("SHA1", false))
- {
- SetSeed(seed);
- }
- /// <summary>Use the specified instance of IRandomGenerator as random source.</summary>
- /// <remarks>
- /// This constructor performs no seeding of either the <c>IRandomGenerator</c> or the
- /// constructed <c>SecureRandom</c>. It is the responsibility of the client to provide
- /// proper seed material as necessary/appropriate for the given <c>IRandomGenerator</c>
- /// implementation.
- /// </remarks>
- /// <param name="generator">The source to generate all random bytes from.</param>
- 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() & int.MaxValue;
- }
- public override int Next(int maxValue)
- {
- if (maxValue < 2)
- {
- if (maxValue < 0)
- throw new ArgumentOutOfRangeException("maxValue", "cannot be negative");
- return 0;
- }
- int bits;
- // Test whether maxValue is a power of 2
- if ((maxValue & (maxValue - 1)) == 0)
- {
- bits = NextInt() & int.MaxValue;
- return (int)(((long)bits * maxValue) >> 31);
- }
- int result;
- do
- {
- bits = NextInt() & int.MaxValue;
- result = bits % maxValue;
- }
- while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow
- return result;
- }
- 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 diff = maxValue - minValue;
- if (diff > 0)
- return minValue + Next(diff);
- for (;;)
- {
- int i = NextInt();
- if (i >= minValue && i < maxValue)
- return i;
- }
- }
- public override void NextBytes(byte[] buf)
- {
- generator.NextBytes(buf);
- }
- public virtual void NextBytes(byte[] buf, int off, int len)
- {
- generator.NextBytes(buf, off, len);
- }
- private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0);
- public override double NextDouble()
- {
- return Convert.ToDouble((ulong) NextLong()) / DoubleScale;
- }
- public virtual int NextInt()
- {
- byte[] bytes = new byte[4];
- NextBytes(bytes);
- uint result = bytes[0];
- result <<= 8;
- result |= bytes[1];
- result <<= 8;
- result |= bytes[2];
- result <<= 8;
- result |= bytes[3];
- return (int)result;
- }
- public virtual long NextLong()
- {
- return ((long)(uint) NextInt() << 32) | (long)(uint) NextInt();
- }
- }
- }
- #endif
|