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