1 // 2 // RandomNumberGeneratorTest.cs - NUnit Test Cases for RNG 3 // 4 // Author: 5 // Sebastien Pouliot <sebastien@ximian.com> 6 // 7 // (C) 2002 Motus Technologies Inc. (http://www.motus.com) 8 // Copyright (C) 2006 Novell, Inc (http://www.novell.com) 9 // 10 11 using NUnit.Framework; 12 using System; 13 using System.IO; 14 using System.Security.Cryptography; 15 using System.Text; 16 17 namespace MonoTests.System.Security.Cryptography { 18 19 // References: 20 // a. NIST FIPS PUB 140-2: Security requirements for Cryptographic Modules 21 // http://csrc.nist.gov/publications/fips/fips140-2/fips1402.pdf 22 // b. NIST SP 800-22: A Statistical Test Suite for Random and Pseudorandom Number Generators for Cryptographic Applications 23 // not implemented 24 // http://csrc.nist.gov/publications/nistpubs/800-22/sp-800-22-051501.pdf 25 // c. IETF RFC1750: Randomness Recommendations for Security 26 // not implemented 27 // http://www.ietf.org/rfc/rfc1750.txt 28 29 [TestFixture] 30 public class RandomNumberGeneratorTest { 31 32 private string name; 33 private byte[] sample; 34 35 [TestFixtureSetUp] SetUp()36 public void SetUp () 37 { 38 // all tests should be done on the same random sample 39 RandomNumberGenerator rng = RandomNumberGenerator.Create (); 40 name = rng.ToString (); 41 // 20,000 bits 42 sample = new byte[2500]; 43 rng.GetBytes (sample); 44 } 45 46 // count the number of 1 47 [Test] Monobit()48 public void Monobit () 49 { 50 int x = 0; 51 for (int i=0; i < sample.Length; i++) { 52 byte b = sample[i]; 53 for (int j = 0; j < 8; j++) { 54 if ((b & 0x01) == 0x01) 55 x++; 56 // next bit 57 b >>= 1; 58 } 59 } 60 Assert.IsTrue ((9725 < x), String.Format ("{0} Monobit x={1} > 9725", name, x)); 61 Assert.IsTrue ((x < 10275), String.Format ("{0} Monobit x={1} < 10275", name, x)); 62 } 63 64 // 16 patterns (nibbles) 65 [Test] Poker()66 public void Poker () 67 { 68 int[] pattern = new int[16]; 69 for (int i = 0; i < sample.Length; i++) { 70 byte b = sample[i]; 71 int n = (b & 0x0F); 72 pattern[n]++; 73 b >>= 4; 74 n = b; 75 pattern[n]++; 76 } 77 double result = 0; 78 for (int i = 0; i < 16; i++) 79 result += (pattern[i] * pattern[i]); 80 result = ((16 * result) / 5000) - 5000; 81 82 Assert.IsTrue (((result > 2.16) && (result < 46.17)), name + " Poker: " + result); 83 } 84 85 // runs of 1 (or 0) 86 [Test] Runs()87 public void Runs () 88 { 89 int[,] runs = new int[6,2]; 90 int x = 0; 91 bool one = false; 92 bool zero = false; 93 for (int i = sample.Length - 1; i >= 0 ; i--) { 94 byte b = sample[i]; 95 for (int j = 0; j < 8; j++) { 96 if ((b & 0x01) == 0x01) { 97 if (!one) { 98 one = true; 99 zero = false; 100 int p = Math.Min (x, 6) - 1; 101 if (p >= 0) 102 runs[p,0]++; 103 x = 0; 104 } 105 } 106 else { 107 if (!zero) { 108 one = false; 109 zero = true; 110 int p = Math.Min (x, 6) - 1; 111 if (p >= 0) 112 runs[p,1]++; 113 x = 0; 114 } 115 } 116 x++; 117 // next bit 118 b >>= 1; 119 } 120 } 121 // don't forget the ast run 122 if (x > 0) { 123 int p = Math.Min (x, 6) - 1; 124 if (p >= 0) 125 runs [p, zero ? 0 : 1]++; 126 } 127 // Updated ranges as per FIPS140-2 Change Notice #1 128 // check for runs of zeros 129 Assert.IsTrue (((runs[0,0] >= 2315) && (runs[0,0] <= 2685)), name + " 0-Runs length=1: " + runs[0,0]); 130 Assert.IsTrue (((runs[1,0] >= 1114) && (runs[1,0] <= 1386)), name + " 0-Runs length=2: " + runs[1,0]); 131 Assert.IsTrue (((runs[2,0] >= 527) && (runs[2,0] <= 723)), name + " 0-Runs length=3: " + runs[2,0]); 132 Assert.IsTrue (((runs[3,0] >= 240) && (runs[3,0] <= 384)), name + " 0-Runs length=4: " + runs[3,0]); 133 Assert.IsTrue (((runs[4,0] >= 103) && (runs[4,0] <= 209)), name + " 0-Runs length=5: " + runs[4,0]); 134 Assert.IsTrue (((runs[5,0] >= 103) && (runs[5,0] <= 209)), name + " 0-Runs length=6+ " + runs[5,0]); 135 // check for runs of ones 136 Assert.IsTrue (((runs[0,1] >= 2315) && (runs[0,1] <= 2685)), name + " 1-Runs length=1: " + runs[0,1]); 137 Assert.IsTrue (((runs[1,1] >= 1114) && (runs[1,1] <= 1386)), name + " 1-Runs length=2: " + runs[1,1]); 138 Assert.IsTrue (((runs[2,1] >= 527) && (runs[2,1] <= 723)), name + " 1-Runs length=3: " + runs[2,1]); 139 Assert.IsTrue (((runs[3,1] >= 240) && (runs[3,1] <= 384)), name + " 1-Runs length=4: " + runs[3,1]); 140 Assert.IsTrue (((runs[4,1] >= 103) && (runs[4,1] <= 209)), name + " 1-Runs length=5: " + runs[4,1]); 141 Assert.IsTrue (((runs[5,1] >= 103) && (runs[5,1] <= 209)), name + " 1-Runs length=6+ " + runs[5,1]); 142 } 143 144 // no long runs of 26 or more (0 or 1) 145 [Test] LongRuns()146 public void LongRuns () 147 { 148 int longestRun = 0; 149 int currentRun = 0; 150 bool one = false; 151 bool zero = false; 152 for (int i = sample.Length - 1; i >= 0 ; i--) { 153 byte b = sample[i]; 154 for (int j = 0; j < 8; j++) { 155 if ((b & 0x01) == 0x01) { 156 if (!one) { 157 one = true; 158 zero = false; 159 longestRun = Math.Max (longestRun, currentRun); 160 currentRun = 0; 161 } 162 currentRun++; 163 } 164 else { 165 if (!zero) { 166 one = false; 167 zero = true; 168 longestRun = Math.Max (longestRun, currentRun); 169 currentRun = 0; 170 } 171 currentRun++; 172 } 173 // next bit 174 b >>= 1; 175 } 176 } 177 Assert.IsTrue ((longestRun < 26), name + " Long Runs max = " + longestRun); 178 } 179 } 180 181 } 182