RandomNumberGeneratorTest.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. //
  2. // RandomNumberGeneratorTest.cs - NUnit Test Cases for RNG
  3. //
  4. // Author:
  5. // Sebastien Pouliot ([email protected])
  6. //
  7. // (C) 2002 Motus Technologies Inc. (http://www.motus.com)
  8. //
  9. using NUnit.Framework;
  10. using System;
  11. using System.IO;
  12. using System.Security.Cryptography;
  13. using System.Text;
  14. namespace MonoTests.System.Security.Cryptography {
  15. // References:
  16. // a. NIST FIPS PUB 140-2: Security requirements for Cryptographic Modules
  17. // http://csrc.nist.gov/publications/fips/fips140-2/fips1402.pdf
  18. // b. NIST SP 800-22: A Statistical Test Suite for Random and Pseudorandom Number Generators for Cryptographic Applications
  19. // not implemented
  20. // http://csrc.nist.gov/publications/nistpubs/800-22/sp-800-22-051501.pdf
  21. // c. IETF RFC1750: Randomness Recommendations for Security
  22. // not implemented
  23. // http://www.ietf.org/rfc/rfc1750.txt
  24. public class RandomNumberGeneratorTest : TestCase {
  25. public RandomNumberGeneratorTest () : base ("System.Security.Cryptography.RandomNumberGenerator testsuite") {}
  26. public RandomNumberGeneratorTest (string name) : base (name) {}
  27. protected RandomNumberGenerator rng;
  28. protected override void SetUp ()
  29. {
  30. rng = RandomNumberGenerator.Create();
  31. }
  32. protected override void TearDown () {}
  33. public static ITest Suite {
  34. get {
  35. return new TestSuite (typeof (RandomNumberGeneratorTest));
  36. }
  37. }
  38. public void AssertEquals (string msg, byte[] array1, byte[] array2)
  39. {
  40. AllTests.AssertEquals (msg, array1, array2);
  41. }
  42. // count the number of 1
  43. protected void Monobit (string rngName, byte[] sample)
  44. {
  45. int x = 0;
  46. for (int i=0; i < sample.Length; i++) {
  47. byte b = sample[i];
  48. for (int j = 0; j < 8; j++) {
  49. if ((b & 0x01) == 0x01)
  50. x++;
  51. // next bit
  52. b >>= 1;
  53. }
  54. }
  55. Assert (rngName + " Monobit x=" + x, ((9725 < x) && (x < 10275)));
  56. }
  57. // 16 patterns (nibbles)
  58. protected void Poker (string rngName, byte[] sample)
  59. {
  60. int[] pattern = new int[16];
  61. for (int i = 0; i < sample.Length; i++) {
  62. byte b = sample[i];
  63. int n = (b & 0x0F);
  64. pattern[n]++;
  65. b >>= 4;
  66. n = b;
  67. pattern[n]++;
  68. }
  69. double result = 0;
  70. for (int i = 0; i < 16; i++)
  71. result += (pattern[i] * pattern[i]);
  72. result = ((16 * result) / 5000) - 5000;
  73. Assert (rngName + " Poker: " + result, ((result > 2.16) && (result < 46.17)));
  74. }
  75. // runs of 1 (or 0)
  76. protected void Runs (string rngName, byte[] sample)
  77. {
  78. int[] runs = new int[6];
  79. int x = 0;
  80. bool one = false;
  81. bool zero = false;
  82. for (int i = sample.Length - 1; i >= 0 ; i--) {
  83. byte b = sample[i];
  84. for (int j = 0; j < 8; j++) {
  85. if ((b & 0x01) == 0x01) {
  86. if (!one) {
  87. one = true;
  88. zero = false;
  89. int p = Math.Min (x, 6) - 1;
  90. if (p >= 0)
  91. runs[p]++;
  92. x = 0;
  93. }
  94. }
  95. else {
  96. if (!zero) {
  97. one = false;
  98. zero = true;
  99. /*int p = Math.Min (x, 6) - 1;
  100. if (p >= 0)
  101. runs[p]++;*/
  102. x = 0;
  103. }
  104. }
  105. x++;
  106. // next bit
  107. b >>= 1;
  108. }
  109. }
  110. Assert (rngName + " Runs length=1: " + runs[0], ((runs[0] >= 2343) && (runs[0] <= 2657)));
  111. Assert (rngName + " Runs length=2: " + runs[1], ((runs[1] >= 1135) && (runs[1] <= 1365)));
  112. Assert (rngName + " Runs length=3: " + runs[2], ((runs[2] >= 542) && (runs[2] <= 708)));
  113. Assert (rngName + " Runs length=4: " + runs[3], ((runs[3] >= 251) && (runs[3] <= 373)));
  114. Assert (rngName + " Runs length=5: " + runs[4], ((runs[4] >= 111) && (runs[4] <= 201)));
  115. Assert (rngName + " Runs length=6+ " + runs[5], ((runs[5] >= 111) && (runs[5] <= 201)));
  116. }
  117. // no long runs of 26 or more (0 or 1)
  118. protected void LongRuns (string rngName, byte[] sample)
  119. {
  120. int longestRun = 0;
  121. int currentRun = 0;
  122. bool one = false;
  123. bool zero = false;
  124. for (int i = sample.Length - 1; i >= 0 ; i--) {
  125. byte b = sample[i];
  126. for (int j = 0; j < 8; j++) {
  127. if ((b & 0x01) == 0x01) {
  128. if (!one) {
  129. one = true;
  130. zero = false;
  131. longestRun = Math.Max (longestRun, currentRun);
  132. currentRun = 0;
  133. }
  134. currentRun++;
  135. }
  136. else {
  137. if (!zero) {
  138. one = false;
  139. zero = true;
  140. longestRun = Math.Max (longestRun, currentRun);
  141. currentRun = 0;
  142. }
  143. currentRun++;
  144. }
  145. // next bit
  146. b >>= 1;
  147. }
  148. }
  149. Assert (rngName + " Long Runs max = " + longestRun, (longestRun < 26));
  150. }
  151. // all tests should be done on the same random sample
  152. public void TestFIPS140()
  153. {
  154. string name = rng.ToString();
  155. // 20,000 bits
  156. byte[] sample = new byte[2500];
  157. rng.GetBytes (sample);
  158. Monobit (name, sample);
  159. Poker (name, sample);
  160. Runs (name, sample);
  161. LongRuns (name, sample);
  162. }
  163. }
  164. }