RNG tests based on FIPS 140-1
[strongswan.git] / src / charon / plugins / unit_tester / tests / test_rng.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <daemon.h>
17 #include <library.h>
18 #include <utils/mutex.h>
19
20 #include <unistd.h>
21 #include <sched.h>
22 #include <pthread.h>
23
24 static bool test_monobit(chunk_t data)
25 {
26 int i, j, bits = 0;
27
28 for (i = 0; i < data.len; i++)
29 {
30 for (j = 0; j < 8; j++)
31 {
32 if (data.ptr[i] & (1<<j))
33 {
34 bits++;
35 }
36 }
37 }
38 DBG1(DBG_CFG, " Monobit: %d/%d bits set", bits, data.len * 8);
39 if (bits > 9654 && bits < 10346)
40 {
41 return TRUE;
42 }
43 return FALSE;
44 }
45
46 static bool test_poker(chunk_t data)
47 {
48 int i, counter[16];
49 double sum = 0.0;
50
51 memset(counter, 0, sizeof(counter));
52
53 for (i = 0; i < data.len; i++)
54 {
55 counter[data.ptr[i] & 0x0F]++;
56 counter[(data.ptr[i] & 0xF0) >> 4]++;
57 }
58
59 for (i = 0; i < countof(counter); i++)
60 {
61 sum += (counter[i] * counter[i]) / 5000.0 * 16.0;
62 }
63 sum -= 5000.0;
64 DBG1(DBG_CFG, " Poker: %f", sum);
65 if (sum > 1.03 && sum < 57.4)
66 {
67 return TRUE;
68 }
69 return FALSE;
70 }
71
72 static bool test_runs(chunk_t data)
73 {
74 int i, j, zero_runs[7], one_runs[7], zero = 0, one = 0, longrun = 0;
75 bool ok = TRUE;
76
77 memset(one_runs, 0, sizeof(zero_runs));
78 memset(zero_runs, 0, sizeof(one_runs));
79
80 for (i = 0; i < data.len; i++)
81 {
82 for (j = 0; j < 8; j++)
83 {
84 if (data.ptr[i] & (1<<j))
85 {
86 if (one)
87 {
88 if (++one >= 34)
89 {
90 longrun++;
91 break;
92 }
93 }
94 else
95 {
96 zero_runs[min(6, zero)]++;
97 zero = 0;
98 one = 1;
99 }
100 }
101 else
102 {
103 if (zero)
104 {
105 if (++zero >= 34)
106 {
107 longrun++;
108 break;
109 }
110 }
111 else
112 {
113 one_runs[min(6, one)]++;
114 one = 0;
115 zero = 1;
116 }
117 }
118 }
119 }
120
121 DBG1(DBG_CFG, " Runs: zero: %d/%d/%d/%d/%d/%d, one: %d/%d/%d/%d/%d/%d, "
122 "longruns: %d",
123 zero_runs[1], zero_runs[2], zero_runs[3],
124 zero_runs[4], zero_runs[5], zero_runs[6],
125 one_runs[1], one_runs[2], one_runs[3],
126 one_runs[4], one_runs[5], one_runs[6],
127 longrun);
128
129 if (longrun)
130 {
131 return FALSE;
132 }
133
134 for (i = 1; i < countof(zero_runs); i++)
135 {
136 switch (i)
137 {
138 case 1:
139 ok &= zero_runs[i] > 2267 && zero_runs[i] < 2733;
140 ok &= one_runs[i] > 2267 && one_runs[i] < 2733;
141 break;
142 case 2:
143 ok &= zero_runs[i] > 1079 && zero_runs[i] < 1421;
144 ok &= one_runs[i] > 1079 && one_runs[i] < 1421;
145 break;
146 case 3:
147 ok &= zero_runs[i] > 502 && zero_runs[i] < 748;
148 ok &= one_runs[i] > 502 && one_runs[i] < 748;
149 break;
150 case 4:
151 ok &= zero_runs[i] > 223 && zero_runs[i] < 402;
152 ok &= one_runs[i] > 223 && one_runs[i] < 402;
153 break;
154 case 5:
155 ok &= zero_runs[i] > 90 && zero_runs[i] < 223;
156 ok &= one_runs[i] > 90 && one_runs[i] < 223;
157 break;
158 case 6:
159 ok &= zero_runs[i] > 90 && zero_runs[i] < 223;
160 ok &= one_runs[i] > 90 && one_runs[i] < 223;
161 break;
162 }
163 if (!ok)
164 {
165 return FALSE;
166 }
167 }
168 return TRUE;
169 }
170
171 static bool test_rng_quality(rng_quality_t quality)
172 {
173 rng_t *rng;
174 chunk_t chunk;
175
176 rng = lib->crypto->create_rng(lib->crypto, quality);
177 if (!rng)
178 {
179 return FALSE;
180 }
181 DBG1(DBG_CFG, "%N", rng_quality_names, quality);
182 rng->allocate_bytes(rng, 2500, &chunk);
183
184 if (!test_monobit(chunk))
185 {
186 return FALSE;
187 }
188 if (!test_poker(chunk))
189 {
190 return FALSE;
191 }
192 if (!test_runs(chunk))
193 {
194 return FALSE;
195 }
196
197 free(chunk.ptr);
198 rng->destroy(rng);
199 return TRUE;
200 }
201
202 /**
203 * run a test using given values
204 */
205 bool test_rng()
206 {
207 if (!test_rng_quality(RNG_WEAK))
208 {
209 return FALSE;
210 }
211 if (!test_rng_quality(RNG_STRONG))
212 {
213 return FALSE;
214 }
215 if (!test_rng_quality(RNG_REAL))
216 {
217 return FALSE;
218 }
219 return TRUE;
220 }
221