/* * fips.c -- Performs FIPS 140-1/140-2 RNG tests * * Copyright (C) 2001 Philipp Rumpf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ #define _GNU_SOURCE #ifndef HAVE_CONFIG_H #error Invalid or missing autoconf build environment #endif #include "rng-tools-config.h" #include #include #include "fips.h" /* * Names for the FIPS tests, and bitmask */ const char *fips_test_names[N_FIPS_TESTS] = { "FIPS 140-2(2001-10-10) Monobit", "FIPS 140-2(2001-10-10) Poker", "FIPS 140-2(2001-10-10) Runs", "FIPS 140-2(2001-10-10) Long run", "FIPS 140-2(2001-10-10) Continuous run" }; const unsigned int fips_test_mask[N_FIPS_TESTS] = { FIPS_RNG_MONOBIT, FIPS_RNG_POKER, FIPS_RNG_RUNS, FIPS_RNG_LONGRUN, FIPS_RNG_CONTINUOUS_RUN }; /* These are the startup tests suggested by the FIPS 140-1 spec section * 4.11.1 (http://csrc.nist.gov/fips/fips1401.htm), and updated by FIPS * 140-2 4.9, errata of 2001-10-10. FIPS 140-2, errata of 2002-12-03 * removed all requirements for non-deterministic RNGs, and thus most of * the tests we need are not mentioned in FIPS 140-2 anymore. We also * implement FIPS 140-1 4.11.2/FIPS 140-2 4.9 Continuous Run test. * * The Monobit, Poker, Runs, and Long Runs tests are implemented below. * This test must be run at periodic intervals to verify data is * sufficiently random. If the tests are failed the RNG module shall * no longer submit data to the entropy pool, but the tests shall * continue to run at the given interval. If at a later time the RNG * passes all tests it shall be re-enabled for the next period. * * The reason for this is that it is not unlikely that at some time * during normal operation one of the tests will fail. This does not * necessarily mean the RNG is not operating properly, it is just a * statistically rare event. In that case we don't want to forever * disable the RNG, we will just leave it disabled for the period of * time until the tests are rerun and passed. * * For the continuous run test, we need to check all bits of data, so * "periodic" above shall be read as "for every back-to-back block of * 20000 bits". We verify 32 bits to accomodate the AMD TRNG, and * to reduce false positives with other TRNGs. */ /* * fips_test_store - store 8 bits of entropy in FIPS * internal test data pool */ static void fips_test_store(fips_ctx_t *ctx, unsigned int rng_data) { int j; ctx->poker[rng_data >> 4]++; ctx->poker[rng_data & 15]++; /* Note in the loop below rlength is always one less than the actual run length. This makes things easier. */ for (j = 7; j >= 0; j--) { ctx->ones += ctx->current_bit = ((rng_data >> j) & 1); if (ctx->current_bit != ctx->last_bit) { /* If runlength is 1-6 count it in correct bucket. 0's go in runs[0-5] 1's go in runs[6-11] hence the 6*current_bit below */ if (ctx->rlength < 5) { ctx->runs[ctx->rlength + (6 * ctx->current_bit)]++; } else { ctx->runs[5 + (6 * ctx->current_bit)]++; } /* Check if we just failed longrun test */ if (ctx->rlength >= 25) ctx->longrun = 1; ctx->rlength = 0; /* flip the current run type */ ctx->last_bit = ctx->current_bit; } else { ctx->rlength++; } } } int fips_run_rng_test (fips_ctx_t *ctx, const void *buf) { int i, j; int rng_test = 0; unsigned char *rngdatabuf; if (!ctx) return -1; if (!buf) return -1; rngdatabuf = (unsigned char *)buf; for (i=0; ilast32) rng_test |= FIPS_RNG_CONTINUOUS_RUN; ctx->last32 = new32; fips_test_store(ctx, rngdatabuf[i]); fips_test_store(ctx, rngdatabuf[i+1]); fips_test_store(ctx, rngdatabuf[i+2]); fips_test_store(ctx, rngdatabuf[i+3]); } /* add in the last (possibly incomplete) run */ if (ctx->rlength < 5) ctx->runs[ctx->rlength + (6 * ctx->current_bit)]++; else { ctx->runs[5 + (6 * ctx->current_bit)]++; if (ctx->rlength >= 25) rng_test |= FIPS_RNG_LONGRUN; } if (ctx->longrun) { rng_test |= FIPS_RNG_LONGRUN; ctx->longrun = 0; } /* Ones test */ if ((ctx->ones >= 10275) || (ctx->ones <= 9725)) rng_test |= FIPS_RNG_MONOBIT; /* Poker calcs */ for (i = 0, j = 0; i < 16; i++) j += ctx->poker[i] * ctx->poker[i]; /* 16/5000*1563176-5000 = 2.1632 */ /* 16/5000*1576928-5000 = 46.1696 */ if ((j > 1576928) || (j < 1563176)) rng_test |= FIPS_RNG_POKER; if ((ctx->runs[0] < 2315) || (ctx->runs[0] > 2685) || (ctx->runs[1] < 1114) || (ctx->runs[1] > 1386) || (ctx->runs[2] < 527) || (ctx->runs[2] > 723) || (ctx->runs[3] < 240) || (ctx->runs[3] > 384) || (ctx->runs[4] < 103) || (ctx->runs[4] > 209) || (ctx->runs[5] < 103) || (ctx->runs[5] > 209) || (ctx->runs[6] < 2315) || (ctx->runs[6] > 2685) || (ctx->runs[7] < 1114) || (ctx->runs[7] > 1386) || (ctx->runs[8] < 527) || (ctx->runs[8] > 723) || (ctx->runs[9] < 240) || (ctx->runs[9] > 384) || (ctx->runs[10] < 103) || (ctx->runs[10] > 209) || (ctx->runs[11] < 103) || (ctx->runs[11] > 209)) { rng_test |= FIPS_RNG_RUNS; } /* finally, clear out FIPS variables for start of next run */ memset (ctx->poker, 0, sizeof (ctx->poker)); memset (ctx->runs, 0, sizeof (ctx->runs)); ctx->ones = 0; ctx->rlength = -1; ctx->current_bit = 0; return rng_test; } void fips_init(fips_ctx_t *ctx, unsigned int last32) { if (ctx) { memset (ctx->poker, 0, sizeof (ctx->poker)); memset (ctx->runs, 0, sizeof (ctx->runs)); ctx->longrun = 0; ctx->ones = 0; ctx->rlength = -1; ctx->current_bit = 0; ctx->last_bit = 0; ctx->last32 = last32; } }