Home | History | Annotate | Line # | Download | only in libkern
rngtest.c revision 1.2.28.1
      1  1.2.28.1  skrll /*	$NetBSD: rngtest.c,v 1.2.28.1 2016/04/22 15:44:16 skrll Exp $ */
      2       1.1    tls 
      3       1.1    tls /*-
      4       1.1    tls  * Copyright (c) 2011 The NetBSD Foundation, Inc.
      5       1.1    tls  * All rights reserved.
      6       1.1    tls  *
      7       1.1    tls  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1    tls  * by Thor Lancelot Simon.
      9       1.1    tls  *
     10       1.1    tls  * Redistribution and use in source and binary forms, with or without
     11       1.1    tls  * modification, are permitted provided that the following conditions
     12       1.1    tls  * are met:
     13       1.1    tls  * 1. Redistributions of source code must retain the above copyright
     14       1.1    tls  *    notice, this list of conditions and the following disclaimer.
     15       1.1    tls  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1    tls  *    notice, this list of conditions and the following disclaimer in the
     17       1.1    tls  *    documentation and/or other materials provided with the distribution.
     18       1.1    tls  *
     19       1.1    tls  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1    tls  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1    tls  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1    tls  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1    tls  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1    tls  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1    tls  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1    tls  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1    tls  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1    tls  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1    tls  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1    tls  */
     31       1.1    tls 
     32       1.1    tls /* fips140.c	1.5 (Qualcomm) 02/09/02 */
     33       1.1    tls /*
     34       1.1    tls This software is free for commercial and non-commercial use
     35       1.1    tls subject to the following conditions.
     36       1.1    tls 
     37       1.1    tls Copyright remains vested in QUALCOMM Incorporated, and Copyright
     38       1.1    tls notices in the code are not to be removed.  If this package is used in
     39       1.1    tls a product, QUALCOMM should be given attribution as the author this
     40       1.1    tls software.  This can be in the form of a textual message at program
     41       1.1    tls startup or in documentation (online or textual) provided with the
     42       1.1    tls package.
     43       1.1    tls 
     44       1.1    tls Redistribution and use in source and binary forms, with or without
     45       1.1    tls modification, are permitted provided that the following conditions are
     46       1.1    tls met:
     47       1.1    tls 
     48       1.1    tls 1. Redistributions of source code must retain the copyright notice,
     49       1.1    tls    this list of conditions and the following disclaimer.
     50       1.1    tls 
     51       1.1    tls 2. Redistributions in binary form must reproduce the above copyright
     52       1.1    tls    notice, this list of conditions and the following disclaimer in the
     53       1.1    tls    documentation and/or other materials provided with the
     54       1.1    tls    distribution.
     55       1.1    tls 
     56       1.1    tls 3. All advertising materials mentioning features or use of this
     57       1.1    tls    software must display the following acknowledgement:  This product
     58       1.1    tls    includes software developed by QUALCOMM Incorporated.
     59       1.1    tls 
     60       1.1    tls THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
     61       1.1    tls WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     62       1.1    tls MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     63       1.1    tls IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     64       1.1    tls INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     65       1.1    tls (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     66       1.1    tls SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     67       1.1    tls HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     68       1.1    tls STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     69       1.1    tls IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     70       1.1    tls POSSIBILITY OF SUCH DAMAGE.
     71       1.1    tls 
     72       1.1    tls The license and distribution terms for any publically available version
     73       1.1    tls or derivative of this code cannot be changed, that is, this code cannot
     74       1.1    tls simply be copied and put under another distribution license including
     75       1.1    tls the GNU Public License.
     76       1.1    tls */
     77       1.1    tls 
     78       1.1    tls /* Run FIPS 140 statistical tests on a file */
     79       1.1    tls 
     80       1.1    tls /* written by Greg Rose, Copyright C 2000 QUALCOMM Incorporated */
     81       1.1    tls 
     82       1.1    tls /*
     83       1.1    tls  * Modified for in-kernel use (API adjustments, conversion from
     84       1.1    tls  * floating to fixed-point chi-sq computation) by Thor Lancelot
     85       1.1    tls  * Simon.
     86       1.1    tls  *
     87       1.1    tls  * A comment on appropriate use of this test and the infamous FIPS 140
     88       1.1    tls  * "continuous output test" (COT):  Both tests are very appropriate for
     89       1.1    tls  * software interfaces to hardware implementations, and will quickly tell
     90       1.1    tls  * you if any number of very bad things have happened to your RNG: perhaps
     91       1.1    tls  * it has come disconnected from the rest of the system, somehow, and you
     92       1.1    tls  * are getting only unconditioned bus noise (read: clock edges from the
     93       1.1    tls  * loudest thing in your system).  Perhaps it has ceased to latch a shift
     94       1.1    tls  * register and is feeding you the same data over and over again.  Perhaps
     95       1.1    tls  * it is not really random at all but was sold to you as such.  Perhaps it
     96       1.1    tls  * is not actually *there* (Intel chipset RNG anyone?) but claims to be,
     97       1.1    tls  * and is feeding you 01010101 on every register read.
     98       1.1    tls  *
     99       1.1    tls  * However, when applied to software RNGs, the situation is quite different.
    100       1.1    tls  * Most software RNGs use a modern hash function or cipher as an output
    101       1.1    tls  * stage.  The resulting bitstream assuredly *should* pass both the
    102       1.1    tls  * "continuous output" (no two consecutive samples identical) and
    103       1.1    tls  * statistical tests: if it does not, the cryptographic primitive or its
    104       1.1    tls  * implementation is terribly broken.
    105       1.1    tls  *
    106       1.1    tls  * There is still value to this test: it will tell you if you inadvertently
    107       1.1    tls  * terribly break your implementation of the software RNG.  Which is a thing
    108       1.1    tls  * that has in fact happened from time to time, even to the careful (or
    109       1.1    tls  * paranoid).  But it will not tell you if there is a problem with the
    110       1.1    tls  * _input_ to that final cryptographic primitive -- the bits that are hashed
    111       1.1    tls  * or the key to the cipher -- and if an adversary can find one, you're
    112       1.1    tls  * still toast.
    113       1.1    tls  *
    114       1.1    tls  * The situation is -- sadly -- similar with hardware RNGs that are
    115       1.1    tls  * certified to one of the standards such as X9.31 or SP800-90.  In these
    116       1.1    tls  * cases the hardware vendor has hidden the actual random bitstream behind
    117       1.1    tls  * a hardware cipher/hash implementation that should, indeed, produce good
    118       1.1    tls  * quality random numbers that pass will pass this test -- whether the
    119       1.1    tls  * underlying bitstream is trustworthy or not.
    120       1.1    tls  *
    121       1.1    tls  * However, this test (and the COT) will still probably tell you if the
    122       1.1    tls  * thing fell off the bus, etc.  Which is a thing that has in fact
    123       1.1    tls  * happened from time to time, even to the fully certified...
    124       1.1    tls  *
    125       1.1    tls  * This module does not (yet?) implement the Continuous Output Test.  When
    126       1.1    tls  * I call that test "infamous", it's because it obviously reduces the
    127       1.1    tls  * backtracking resistance of any implementation that includes it -- the
    128       1.1    tls  * implementation has to store the entire previous RNG output in order to
    129       1.1    tls  * perform the required comparison; not just periodically but all the time
    130       1.1    tls  * when operating at all.  Nonetheless, it has obvious value for
    131       1.1    tls  * hardware implementations where it will quickly and surely detect a
    132       1.1    tls  * severe failure; but as of this writing several of the latest comments
    133       1.1    tls  * on SP800-90 recommend removing any requirement for the COT and my
    134       1.1    tls  * personal tendency is to agree.  It's easy to add if you really need it.
    135       1.1    tls  *
    136       1.1    tls  */
    137       1.1    tls 
    138       1.1    tls #include <sys/types.h>
    139       1.1    tls #include <sys/systm.h>
    140       1.1    tls #include <sys/rngtest.h>
    141       1.1    tls 
    142       1.1    tls #include <lib/libkern/libkern.h>
    143       1.1    tls 
    144       1.1    tls #include <sys/cdefs.h>
    145  1.2.28.1  skrll __KERNEL_RCSID(0, "$NetBSD: rngtest.c,v 1.2.28.1 2016/04/22 15:44:16 skrll Exp $");
    146       1.1    tls 
    147       1.1    tls #ifndef _KERNEL
    148       1.1    tls static inline int
    149       1.2  joerg printf(const char * __restrict format, ...)
    150       1.1    tls {
    151       1.1    tls 	return 0;	/* XXX no standard way to do output in libkern? */
    152       1.1    tls }
    153       1.1    tls #endif
    154       1.1    tls 
    155       1.1    tls int bitnum = 0;
    156       1.1    tls 
    157       1.1    tls const int minrun[7] = {0, 2315, 1114, 527, 240, 103, 103};
    158       1.1    tls const int maxrun[7] = {0, 2685, 1386, 723, 384, 209, 209};
    159       1.1    tls #define LONGRUN	26
    160       1.1    tls #define MINONES 9725
    161       1.1    tls #define MAXONES 10275
    162       1.1    tls #define MINPOKE 2.16
    163       1.1    tls #define MAXPOKE 46.17
    164       1.1    tls #define PRECISION 100000
    165       1.1    tls 
    166       1.1    tls const int longrun = LONGRUN;
    167       1.1    tls const int minones = MINONES;
    168       1.1    tls const int maxones = MAXONES;
    169       1.1    tls const long long minpoke = (MINPOKE * PRECISION);
    170       1.1    tls const long long maxpoke = (MAXPOKE * PRECISION);
    171       1.1    tls 
    172       1.1    tls /* Population count of 1's in a byte */
    173       1.1    tls const unsigned char Popcount[] = {
    174       1.1    tls 	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
    175       1.1    tls 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    176       1.1    tls 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    177       1.1    tls 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    178       1.1    tls 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    179       1.1    tls 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    180       1.1    tls 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    181       1.1    tls 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    182       1.1    tls 	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
    183       1.1    tls 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    184       1.1    tls 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    185       1.1    tls 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    186       1.1    tls 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
    187       1.1    tls 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    188       1.1    tls 	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
    189       1.1    tls 	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
    190       1.1    tls };
    191       1.1    tls 
    192       1.1    tls /* end of run */
    193       1.1    tls static void
    194       1.1    tls endrun(rngtest_t *const rc, const int last, int run)
    195       1.1    tls {
    196       1.1    tls 	if (run >= longrun) {
    197       1.1    tls 		printf("Kernel RNG \"%s\" long run test FAILURE: "
    198       1.1    tls 		       "Run of %d %ds found\n", rc->rt_name, run, last);
    199       1.1    tls 		++rc->rt_nerrs;
    200       1.1    tls 	}
    201       1.1    tls 	if (run > 6)
    202       1.1    tls 		run = 6;
    203       1.1    tls 	++rc->rt_runs[last][run];
    204       1.1    tls }
    205       1.1    tls 
    206       1.1    tls int
    207       1.1    tls rngtest(rngtest_t *const rc)
    208       1.1    tls {
    209       1.1    tls 	int i;
    210       1.1    tls 	uint8_t *p;
    211       1.1    tls 	int c;
    212       1.1    tls 	long long X;
    213       1.1    tls 	int last;
    214       1.1    tls 	int run;
    215       1.1    tls 
    216       1.1    tls 	/* Enforce sanity for most members of the context */
    217       1.1    tls 	memset(rc->rt_poker, 0, sizeof(rc->rt_poker));
    218       1.1    tls 	memset(rc->rt_runs, 0, sizeof(rc->rt_runs));
    219       1.1    tls 	rc->rt_nerrs = 0;
    220       1.1    tls 	rc->rt_name[sizeof(rc->rt_name) - 1] = '\0';
    221       1.1    tls 
    222       1.1    tls 	/* monobit test */
    223       1.1    tls 	for (p = rc->rt_b, c = 0; p < &rc->rt_b[sizeof rc->rt_b]; ++p)
    224       1.1    tls 		c += Popcount[*p];
    225       1.1    tls 	if (c <= minones || maxones <= c) {
    226       1.1    tls 		printf("Kernel RNG \"%s\" monobit test FAILURE: %d ones\n",
    227       1.1    tls 		       rc->rt_name, c);
    228       1.1    tls 		++rc->rt_nerrs;
    229       1.1    tls 	}
    230       1.1    tls 	/* poker test */
    231       1.1    tls 	for (p = rc->rt_b; p < &rc->rt_b[sizeof rc->rt_b]; ++p) {
    232       1.1    tls 		++rc->rt_poker[*p & 0xF];
    233       1.1    tls 		++rc->rt_poker[(*p >> 4) & 0xF];
    234       1.1    tls 	}
    235       1.1    tls 	for (X = i = 0; i < 16; ++i) {
    236       1.1    tls 		X += rc->rt_poker[i] * rc->rt_poker[i];
    237       1.1    tls 	}
    238       1.1    tls 	X *= PRECISION;
    239       1.1    tls 	X = 16 * X / 5000 - 5000 * PRECISION;
    240       1.1    tls 	if (X <= minpoke || maxpoke <= X) {
    241       1.1    tls 		printf("Kernel RNG \"%s\" poker test failure: "
    242       1.1    tls 		       "parameter X = %lld.%lld\n", rc->rt_name,
    243       1.1    tls 		       (X / PRECISION), (X % PRECISION));
    244       1.1    tls 		++rc->rt_nerrs;
    245       1.1    tls 	}
    246       1.1    tls 	/* runs test */
    247       1.1    tls 	last = (rc->rt_b[0] >> 7) & 1;
    248       1.1    tls 	run = 0;
    249       1.1    tls 	for (p = rc->rt_b; p < &rc->rt_b[sizeof rc->rt_b]; ++p) {
    250       1.1    tls 		c = *p;
    251       1.1    tls 		for (i = 7; i >= 0; --i) {
    252       1.1    tls 			if (((c >> i) & 1) != last) {
    253       1.1    tls 				endrun(rc, last, run);
    254       1.1    tls 				run = 0;
    255       1.1    tls 				last = (c >> i) & 1;
    256       1.1    tls 			}
    257       1.1    tls 			++run;
    258       1.1    tls 		}
    259       1.1    tls 	}
    260       1.1    tls 	endrun(rc, last, run);
    261       1.1    tls 
    262       1.1    tls 	for (run = 1; run <= 6; ++run) {
    263       1.1    tls 		for (last = 0; last <= 1; ++last) {
    264       1.1    tls 			if (rc->rt_runs[last][run] <= minrun[run]) {
    265       1.1    tls 				printf("Kernel RNG \"%s\" runs test FAILURE: "
    266  1.2.28.1  skrll 				       "too few runs of %d %ds (%d <= %d)\n",
    267       1.1    tls 				       rc->rt_name, run, last,
    268       1.1    tls 				       rc->rt_runs[last][run], minrun[run]);
    269       1.1    tls 				++rc->rt_nerrs;
    270       1.1    tls 			} else if (rc->rt_runs[last][run] >= maxrun[run]) {
    271       1.1    tls 				printf("Kernel RNG \"%s\" runs test FAILURE: "
    272  1.2.28.1  skrll 				       "too many runs of %d %ds (%d >= %d)\n",
    273       1.1    tls 				       rc->rt_name, run, last,
    274       1.1    tls 				       rc->rt_runs[last][run], maxrun[run]);
    275       1.1    tls 				++rc->rt_nerrs;
    276       1.1    tls 			}
    277       1.1    tls 		}
    278       1.1    tls 	}
    279       1.1    tls 	memset(rc->rt_b, 0, sizeof(rc->rt_b));
    280       1.1    tls 	return rc->rt_nerrs;
    281       1.1    tls }
    282