blob: b05408dadeabaa34d3316c09c90220182af24e0a [file] [log] [blame]
Cullen Jennings235513a2005-09-21 22:51:36 +00001/*
2 * stats.c
3 *
4 * statistical tests for randomness (FIPS 140-2, Section 4.9)
5 *
6 * David A. McGrew
7 * Cisco Systems, Inc.
8 */
9
Teerapap Changwichukarn6cffe242014-09-24 11:24:07 +080010#ifdef HAVE_CONFIG_H
11 #include <config.h>
12#endif
13
Cullen Jennings235513a2005-09-21 22:51:36 +000014#include "stat.h"
15
jfigus02d6f032014-11-21 10:56:42 -050016srtp_debug_module_t mod_stat = {
Cullen Jennings235513a2005-09-21 22:51:36 +000017 0, /* debugging is off by default */
David McGrewfec49dd2005-09-23 19:34:11 +000018 (char *)"stat test" /* printable module name */
Cullen Jennings235513a2005-09-21 22:51:36 +000019};
20
21/*
22 * each test assumes that 20,000 bits (2500 octets) of data is
23 * provided as input
24 */
25
26#define STAT_TEST_DATA_LEN 2500
27
jfigus857009c2014-11-05 11:17:43 -050028srtp_err_status_t
Marcus Sundberg410faaa2005-09-29 12:36:43 +000029stat_test_monobit(uint8_t *data) {
30 uint8_t *data_end = data + STAT_TEST_DATA_LEN;
Cullen Jennings235513a2005-09-21 22:51:36 +000031 uint16_t ones_count;
32
33 ones_count = 0;
34 while (data < data_end) {
35 ones_count += octet_get_weight(*data);
36 data++;
37 }
38
39 debug_print(mod_stat, "bit count: %d", ones_count);
40
41 if ((ones_count < 9725) || (ones_count > 10275))
jfigus857009c2014-11-05 11:17:43 -050042 return srtp_err_status_algo_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +000043
jfigus857009c2014-11-05 11:17:43 -050044 return srtp_err_status_ok;
Cullen Jennings235513a2005-09-21 22:51:36 +000045}
46
jfigus857009c2014-11-05 11:17:43 -050047srtp_err_status_t
Marcus Sundberg410faaa2005-09-29 12:36:43 +000048stat_test_poker(uint8_t *data) {
Cullen Jennings235513a2005-09-21 22:51:36 +000049 int i;
Marcus Sundberg410faaa2005-09-29 12:36:43 +000050 uint8_t *data_end = data + STAT_TEST_DATA_LEN;
Cullen Jennings235513a2005-09-21 22:51:36 +000051 double poker;
52 uint16_t f[16] = {
53 0, 0, 0, 0, 0, 0, 0, 0,
54 0, 0, 0, 0, 0, 0, 0, 0
55 };
56
57 while (data < data_end) {
58 f[*data & 0x0f]++; /* increment freq. count for low nibble */
59 f[(*data) >> 4]++; /* increment freq. count for high nibble */
60 data++;
61 }
62
63 poker = 0.0;
64 for (i=0; i < 16; i++)
65 poker += (double) f[i] * f[i];
66
67 poker *= (16.0 / 5000.0);
68 poker -= 5000.0;
69
70 debug_print(mod_stat, "poker test: %f\n", poker);
71
72 if ((poker < 2.16) || (poker > 46.17))
jfigus857009c2014-11-05 11:17:43 -050073 return srtp_err_status_algo_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +000074
jfigus857009c2014-11-05 11:17:43 -050075 return srtp_err_status_ok;
Cullen Jennings235513a2005-09-21 22:51:36 +000076}
77
78
79/*
80 * runs[i] holds the number of runs of size (i-1)
81 */
82
jfigus857009c2014-11-05 11:17:43 -050083srtp_err_status_t
Marcus Sundberg410faaa2005-09-29 12:36:43 +000084stat_test_runs(uint8_t *data) {
85 uint8_t *data_end = data + STAT_TEST_DATA_LEN;
Cullen Jennings235513a2005-09-21 22:51:36 +000086 uint16_t runs[6] = { 0, 0, 0, 0, 0, 0 };
87 uint16_t gaps[6] = { 0, 0, 0, 0, 0, 0 };
88 uint16_t lo_value[6] = { 2315, 1114, 527, 240, 103, 103 };
89 uint16_t hi_value[6] = { 2685, 1386, 723, 384, 209, 209 };
David McGrewc7805762006-07-11 23:37:10 +000090 int state = 0;
Cullen Jennings235513a2005-09-21 22:51:36 +000091 uint16_t mask;
92 int i;
93
94 /*
95 * the state variable holds the number of bits in the
96 * current run (or gap, if negative)
97 */
98
99 while (data < data_end) {
100
101 /* loop over the bits of this byte */
102 for (mask = 1; mask < 256; mask <<= 1) {
103 if (*data & mask) {
104
105 /* next bit is a one */
106 if (state > 0) {
107
108 /* prefix is a run, so increment the run-count */
109 state++;
110
111 /* check for long runs */
112 if (state > 25) {
113 debug_print(mod_stat, ">25 runs: %d", state);
jfigus857009c2014-11-05 11:17:43 -0500114 return srtp_err_status_algo_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +0000115 }
116
117 } else if (state < 0) {
118
119 /* prefix is a gap */
120 if (state < -25) {
121 debug_print(mod_stat, ">25 gaps: %d", state);
jfigus857009c2014-11-05 11:17:43 -0500122 return srtp_err_status_algo_fail; /* long-runs test failed */
Cullen Jennings235513a2005-09-21 22:51:36 +0000123 }
124 if (state < -6) {
125 state = -6; /* group together gaps > 5 */
126 }
127 gaps[-1-state]++; /* increment gap count */
128 state = 1; /* set state at one set bit */
129 } else {
130
131 /* state is zero; this happens only at initialization */
132 state = 1;
133 }
134 } else {
135
136 /* next bit is a zero */
137 if (state > 0) {
138
139 /* prefix is a run */
140 if (state > 25) {
141 debug_print(mod_stat, ">25 runs (2): %d", state);
jfigus857009c2014-11-05 11:17:43 -0500142 return srtp_err_status_algo_fail; /* long-runs test failed */
Cullen Jennings235513a2005-09-21 22:51:36 +0000143 }
144 if (state > 6) {
145 state = 6; /* group together runs > 5 */
146 }
147 runs[state-1]++; /* increment run count */
148 state = -1; /* set state at one zero bit */
149 } else if (state < 0) {
150
151 /* prefix is a gap, so increment gap-count (decrement state) */
152 state--;
153
154 /* check for long gaps */
155 if (state < -25) {
156 debug_print(mod_stat, ">25 gaps (2): %d", state);
jfigus857009c2014-11-05 11:17:43 -0500157 return srtp_err_status_algo_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +0000158 }
159
160 } else {
161
162 /* state is zero; this happens only at initialization */
163 state = -1;
164 }
165 }
166 }
167
168 /* move along to next octet */
169 data++;
170 }
171
172 if (mod_stat.on) {
173 debug_print(mod_stat, "runs test", NULL);
174 for (i=0; i < 6; i++)
175 debug_print(mod_stat, " runs[]: %d", runs[i]);
176 for (i=0; i < 6; i++)
177 debug_print(mod_stat, " gaps[]: %d", gaps[i]);
178 }
179
180 /* check run and gap counts against the fixed limits */
181 for (i=0; i < 6; i++)
182 if ( (runs[i] < lo_value[i] ) || (runs[i] > hi_value[i])
183 || (gaps[i] < lo_value[i] ) || (gaps[i] > hi_value[i]))
jfigus857009c2014-11-05 11:17:43 -0500184 return srtp_err_status_algo_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +0000185
186
jfigus857009c2014-11-05 11:17:43 -0500187 return srtp_err_status_ok;
Cullen Jennings235513a2005-09-21 22:51:36 +0000188}
189
190
191/*
192 * the function stat_test_rand_source applys the FIPS-140-2 statistical
193 * tests to the random source defined by rs
194 *
195 */
196
197#define RAND_SRC_BUF_OCTETS 50 /* this value MUST divide 2500! */
198
jfigus857009c2014-11-05 11:17:43 -0500199srtp_err_status_t
Cullen Jennings235513a2005-09-21 22:51:36 +0000200stat_test_rand_source(rand_source_func_t get_rand_bytes) {
201 int i;
202 double poker;
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000203 uint8_t *data, *data_end;
Cullen Jennings235513a2005-09-21 22:51:36 +0000204 uint16_t f[16] = {
205 0, 0, 0, 0, 0, 0, 0, 0,
206 0, 0, 0, 0, 0, 0, 0, 0
207 };
Marcus Sundberg410faaa2005-09-29 12:36:43 +0000208 uint8_t buffer[RAND_SRC_BUF_OCTETS];
jfigus857009c2014-11-05 11:17:43 -0500209 srtp_err_status_t status;
Cullen Jennings235513a2005-09-21 22:51:36 +0000210 int ones_count = 0;
211 uint16_t runs[6] = { 0, 0, 0, 0, 0, 0 };
212 uint16_t gaps[6] = { 0, 0, 0, 0, 0, 0 };
213 uint16_t lo_value[6] = { 2315, 1114, 527, 240, 103, 103 };
214 uint16_t hi_value[6] = { 2685, 1386, 723, 384, 209, 209 };
Derek MacDonald17127da2006-07-12 22:22:08 +0000215 int state = 0;
Cullen Jennings235513a2005-09-21 22:51:36 +0000216 uint16_t mask;
217
218 /* counters for monobit, poker, and runs tests are initialized above */
219
220 /* main loop: fill buffer, update counters for stat tests */
221 for (i=0; i < 2500; i+=RAND_SRC_BUF_OCTETS) {
222
223 /* fill data buffer */
224 status = get_rand_bytes(buffer, RAND_SRC_BUF_OCTETS);
225 if (status) {
226 debug_print(mod_stat, "couldn't get rand bytes: %d",status);
227 return status;
228 }
229
230#if 0
231 debug_print(mod_stat, "%s",
232 octet_string_hex_string(buffer, RAND_SRC_BUF_OCTETS));
233#endif
234
235 data = buffer;
236 data_end = data + RAND_SRC_BUF_OCTETS;
237 while (data < data_end) {
238
239 /* update monobit test counter */
240 ones_count += octet_get_weight(*data);
241
242 /* update poker test counters */
243 f[*data & 0x0f]++; /* increment freq. count for low nibble */
244 f[(*data) >> 4]++; /* increment freq. count for high nibble */
245
246 /* update runs test counters */
247 /* loop over the bits of this byte */
248 for (mask = 1; mask < 256; mask <<= 1) {
249 if (*data & mask) {
250
251 /* next bit is a one */
252 if (state > 0) {
253
254 /* prefix is a run, so increment the run-count */
255 state++;
256
257 /* check for long runs */
258 if (state > 25) {
259 debug_print(mod_stat, ">25 runs (3): %d", state);
jfigus857009c2014-11-05 11:17:43 -0500260 return srtp_err_status_algo_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +0000261 }
262
263 } else if (state < 0) {
264
265 /* prefix is a gap */
266 if (state < -25) {
267 debug_print(mod_stat, ">25 gaps (3): %d", state);
jfigus857009c2014-11-05 11:17:43 -0500268 return srtp_err_status_algo_fail; /* long-runs test failed */
Cullen Jennings235513a2005-09-21 22:51:36 +0000269 }
270 if (state < -6) {
271 state = -6; /* group together gaps > 5 */
272 }
273 gaps[-1-state]++; /* increment gap count */
274 state = 1; /* set state at one set bit */
275 } else {
276
277 /* state is zero; this happens only at initialization */
278 state = 1;
279 }
280 } else {
281
282 /* next bit is a zero */
283 if (state > 0) {
284
285 /* prefix is a run */
286 if (state > 25) {
287 debug_print(mod_stat, ">25 runs (4): %d", state);
jfigus857009c2014-11-05 11:17:43 -0500288 return srtp_err_status_algo_fail; /* long-runs test failed */
Cullen Jennings235513a2005-09-21 22:51:36 +0000289 }
290 if (state > 6) {
291 state = 6; /* group together runs > 5 */
292 }
293 runs[state-1]++; /* increment run count */
294 state = -1; /* set state at one zero bit */
295 } else if (state < 0) {
296
297 /* prefix is a gap, so increment gap-count (decrement state) */
298 state--;
299
300 /* check for long gaps */
301 if (state < -25) {
302 debug_print(mod_stat, ">25 gaps (4): %d", state);
jfigus857009c2014-11-05 11:17:43 -0500303 return srtp_err_status_algo_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +0000304 }
305
306 } else {
307
308 /* state is zero; this happens only at initialization */
309 state = -1;
310 }
311 }
312 }
313
314 /* advance data pointer */
315 data++;
316 }
317 }
318
319 /* check to see if test data is within bounds */
320
321 /* check monobit test data */
322
323 debug_print(mod_stat, "stat: bit count: %d", ones_count);
324
325 if ((ones_count < 9725) || (ones_count > 10275)) {
326 debug_print(mod_stat, "stat: failed monobit test %d", ones_count);
jfigus857009c2014-11-05 11:17:43 -0500327 return srtp_err_status_algo_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +0000328 }
329
330 /* check poker test data */
331 poker = 0.0;
332 for (i=0; i < 16; i++)
333 poker += (double) f[i] * f[i];
334
335 poker *= (16.0 / 5000.0);
336 poker -= 5000.0;
337
338 debug_print(mod_stat, "stat: poker test: %f", poker);
339
340 if ((poker < 2.16) || (poker > 46.17)) {
David McGrewfec49dd2005-09-23 19:34:11 +0000341 debug_print(mod_stat, "stat: failed poker test", NULL);
jfigus857009c2014-11-05 11:17:43 -0500342 return srtp_err_status_algo_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +0000343 }
344
345 /* check run and gap counts against the fixed limits */
346 for (i=0; i < 6; i++)
347 if ((runs[i] < lo_value[i] ) || (runs[i] > hi_value[i])
348 || (gaps[i] < lo_value[i] ) || (gaps[i] > hi_value[i])) {
349 debug_print(mod_stat, "stat: failed run/gap test", NULL);
jfigus857009c2014-11-05 11:17:43 -0500350 return srtp_err_status_algo_fail;
Cullen Jennings235513a2005-09-21 22:51:36 +0000351 }
352
353 debug_print(mod_stat, "passed random stat test", NULL);
jfigus857009c2014-11-05 11:17:43 -0500354 return srtp_err_status_ok;
Cullen Jennings235513a2005-09-21 22:51:36 +0000355}
David McGrewb0ad0702006-03-17 20:51:24 +0000356
jfigus857009c2014-11-05 11:17:43 -0500357srtp_err_status_t
David McGrewb0ad0702006-03-17 20:51:24 +0000358stat_test_rand_source_with_repetition(rand_source_func_t source, unsigned num_trials) {
David McGrewc4fc00b2006-06-08 18:51:27 +0000359 unsigned int i;
jfigus857009c2014-11-05 11:17:43 -0500360 srtp_err_status_t err = srtp_err_status_algo_fail;
David McGrewb0ad0702006-03-17 20:51:24 +0000361
362 for (i=0; i < num_trials; i++) {
363 err = stat_test_rand_source(source);
jfigus857009c2014-11-05 11:17:43 -0500364 if (err == srtp_err_status_ok) {
365 return srtp_err_status_ok;
David McGrewb0ad0702006-03-17 20:51:24 +0000366 }
367 debug_print(mod_stat, "failed stat test (try number %d)\n", i);
368 }
369
370 return err;
371}