SecureRandom.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Threading;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Prng;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  9. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Security
  10. {
  11. public class SecureRandom
  12. : Random
  13. {
  14. private static long counter = Times.NanoTime();
  15. #if NETCF_1_0 || PORTABLE || NETFX_CORE
  16. private static object counterLock = new object();
  17. private static long NextCounterValue()
  18. {
  19. lock (counterLock)
  20. {
  21. return ++counter;
  22. }
  23. }
  24. private static readonly SecureRandom[] master = { null };
  25. private static SecureRandom Master
  26. {
  27. get
  28. {
  29. lock (master)
  30. {
  31. if (master[0] == null)
  32. {
  33. SecureRandom sr = master[0] = GetInstance("SHA256PRNG", false);
  34. // Even though Ticks has at most 8 or 14 bits of entropy, there's no harm in adding it.
  35. sr.SetSeed(DateTime.Now.Ticks);
  36. // 32 will be enough when ThreadedSeedGenerator is fixed. Until then, ThreadedSeedGenerator returns low
  37. // entropy, and this is not sufficient to be secure. http://www.bouncycastle.org/csharpdevmailarchive/msg00814.html
  38. sr.SetSeed(new ThreadedSeedGenerator().GenerateSeed(32, true));
  39. }
  40. return master[0];
  41. }
  42. }
  43. }
  44. #else
  45. private static long NextCounterValue()
  46. {
  47. return Interlocked.Increment(ref counter);
  48. }
  49. private static readonly SecureRandom master = new SecureRandom(new CryptoApiRandomGenerator());
  50. private static SecureRandom Master
  51. {
  52. get { return master; }
  53. }
  54. #endif
  55. private static DigestRandomGenerator CreatePrng(string digestName, bool autoSeed)
  56. {
  57. IDigest digest = DigestUtilities.GetDigest(digestName);
  58. if (digest == null)
  59. return null;
  60. DigestRandomGenerator prng = new DigestRandomGenerator(digest);
  61. if (autoSeed)
  62. {
  63. prng.AddSeedMaterial(NextCounterValue());
  64. prng.AddSeedMaterial(GetNextBytes(Master, digest.GetDigestSize()));
  65. }
  66. return prng;
  67. }
  68. public static byte[] GetNextBytes(SecureRandom secureRandom, int length)
  69. {
  70. byte[] result = new byte[length];
  71. secureRandom.NextBytes(result);
  72. return result;
  73. }
  74. /// <summary>
  75. /// Create and auto-seed an instance based on the given algorithm.
  76. /// </summary>
  77. /// <remarks>Equivalent to GetInstance(algorithm, true)</remarks>
  78. /// <param name="algorithm">e.g. "SHA256PRNG"</param>
  79. public static SecureRandom GetInstance(string algorithm)
  80. {
  81. return GetInstance(algorithm, true);
  82. }
  83. /// <summary>
  84. /// Create an instance based on the given algorithm, with optional auto-seeding
  85. /// </summary>
  86. /// <param name="algorithm">e.g. "SHA256PRNG"</param>
  87. /// <param name="autoSeed">If true, the instance will be auto-seeded.</param>
  88. public static SecureRandom GetInstance(string algorithm, bool autoSeed)
  89. {
  90. string upper = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.ToUpperInvariant(algorithm);
  91. if (BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.EndsWith(upper, "PRNG"))
  92. {
  93. string digestName = upper.Substring(0, upper.Length - "PRNG".Length);
  94. DigestRandomGenerator prng = CreatePrng(digestName, autoSeed);
  95. if (prng != null)
  96. {
  97. return new SecureRandom(prng);
  98. }
  99. }
  100. throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm");
  101. }
  102. [Obsolete("Call GenerateSeed() on a SecureRandom instance instead")]
  103. public static byte[] GetSeed(int length)
  104. {
  105. return GetNextBytes(Master, length);
  106. }
  107. protected readonly IRandomGenerator generator;
  108. public SecureRandom()
  109. : this(CreatePrng("SHA256", true))
  110. {
  111. }
  112. /// <remarks>
  113. /// To replicate existing predictable output, replace with GetInstance("SHA1PRNG", false), followed by SetSeed(seed)
  114. /// </remarks>
  115. [Obsolete("Use GetInstance/SetSeed instead")]
  116. public SecureRandom(byte[] seed)
  117. : this(CreatePrng("SHA1", false))
  118. {
  119. SetSeed(seed);
  120. }
  121. /// <summary>Use the specified instance of IRandomGenerator as random source.</summary>
  122. /// <remarks>
  123. /// This constructor performs no seeding of either the <c>IRandomGenerator</c> or the
  124. /// constructed <c>SecureRandom</c>. It is the responsibility of the client to provide
  125. /// proper seed material as necessary/appropriate for the given <c>IRandomGenerator</c>
  126. /// implementation.
  127. /// </remarks>
  128. /// <param name="generator">The source to generate all random bytes from.</param>
  129. public SecureRandom(IRandomGenerator generator)
  130. : base(0)
  131. {
  132. this.generator = generator;
  133. }
  134. public virtual byte[] GenerateSeed(int length)
  135. {
  136. return GetNextBytes(Master, length);
  137. }
  138. public virtual void SetSeed(byte[] seed)
  139. {
  140. generator.AddSeedMaterial(seed);
  141. }
  142. public virtual void SetSeed(long seed)
  143. {
  144. generator.AddSeedMaterial(seed);
  145. }
  146. public override int Next()
  147. {
  148. return NextInt() & int.MaxValue;
  149. }
  150. public override int Next(int maxValue)
  151. {
  152. if (maxValue < 2)
  153. {
  154. if (maxValue < 0)
  155. throw new ArgumentOutOfRangeException("maxValue", "cannot be negative");
  156. return 0;
  157. }
  158. int bits;
  159. // Test whether maxValue is a power of 2
  160. if ((maxValue & (maxValue - 1)) == 0)
  161. {
  162. bits = NextInt() & int.MaxValue;
  163. return (int)(((long)bits * maxValue) >> 31);
  164. }
  165. int result;
  166. do
  167. {
  168. bits = NextInt() & int.MaxValue;
  169. result = bits % maxValue;
  170. }
  171. while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow
  172. return result;
  173. }
  174. public override int Next(int minValue, int maxValue)
  175. {
  176. if (maxValue <= minValue)
  177. {
  178. if (maxValue == minValue)
  179. return minValue;
  180. throw new ArgumentException("maxValue cannot be less than minValue");
  181. }
  182. int diff = maxValue - minValue;
  183. if (diff > 0)
  184. return minValue + Next(diff);
  185. for (;;)
  186. {
  187. int i = NextInt();
  188. if (i >= minValue && i < maxValue)
  189. return i;
  190. }
  191. }
  192. public override void NextBytes(byte[] buf)
  193. {
  194. generator.NextBytes(buf);
  195. }
  196. public virtual void NextBytes(byte[] buf, int off, int len)
  197. {
  198. generator.NextBytes(buf, off, len);
  199. }
  200. private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0);
  201. public override double NextDouble()
  202. {
  203. return Convert.ToDouble((ulong) NextLong()) / DoubleScale;
  204. }
  205. public virtual int NextInt()
  206. {
  207. byte[] bytes = new byte[4];
  208. NextBytes(bytes);
  209. uint result = bytes[0];
  210. result <<= 8;
  211. result |= bytes[1];
  212. result <<= 8;
  213. result |= bytes[2];
  214. result <<= 8;
  215. result |= bytes[3];
  216. return (int)result;
  217. }
  218. public virtual long NextLong()
  219. {
  220. return ((long)(uint) NextInt() << 32) | (long)(uint) NextInt();
  221. }
  222. }
  223. }
  224. #pragma warning restore
  225. #endif