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