(Resending with attachment) Hello, Attached is an alternative pseudo-random number generator for OpenSSL, based upon the FIPS186-2 specification. Tested on x86 and PPC, linux-elf. Hope you find it useful.
Yair This email and any files transmitted with it are confidential material. They are intended solely for the use of the designated individual or entity to whom they are addressed. If the reader of this message is not the intended recipient, you are hereby notified that any dissemination, use, distribution or copying of this communication is strictly prohibited and may be unlawful. If you have received this email in error please immediately notify the sender and delete or destroy any copy of this message
diff -urN openssl-0.9.8-stable-SNAP-20080112/crypto/rand/Makefile openssl-0.9.8-stable-SNAP-devel/crypto/rand/Makefile --- openssl-0.9.8-stable-SNAP-20080112/crypto/rand/Makefile 2006-02-04 04:06:21.000000000 +0200 +++ openssl-0.9.8-stable-SNAP-devel/crypto/rand/Makefile 2008-01-15 11:29:47.000000000 +0200 @@ -18,9 +18,9 @@ LIB=$(TOP)/libcrypto.a LIBSRC=md_rand.c randfile.c rand_lib.c rand_err.c rand_egd.c \ - rand_win.c rand_unix.c rand_os2.c rand_nw.c + rand_win.c rand_unix.c rand_os2.c rand_nw.c rand_fips186.c LIBOBJ=md_rand.o randfile.o rand_lib.o rand_err.o rand_egd.o \ - rand_win.o rand_unix.o rand_os2.o rand_nw.o + rand_win.o rand_unix.o rand_os2.o rand_nw.o rand_fips186.o SRC= $(LIBSRC) diff -urN openssl-0.9.8-stable-SNAP-20080112/crypto/rand/rand_fips186.c openssl-0.9.8-stable-SNAP-devel/crypto/rand/rand_fips186.c --- openssl-0.9.8-stable-SNAP-20080112/crypto/rand/rand_fips186.c 1970-01-01 02:00:00.000000000 +0200 +++ openssl-0.9.8-stable-SNAP-devel/crypto/rand/rand_fips186.c 2008-01-15 11:36:04.000000000 +0200 @@ -0,0 +1,253 @@ +/* FIPS 186-2 random number generator + * by Yair Elharrar, Jan 2008 + * + * Adapted from FIPS186-2 at http://csrc.nist.gov/publications/fips/fips186-2/fips186-2-change1.pdf + * + * Usage: RAND_set_rand_method(RAND_FIPS186()), followed by RAND_cleanup(). + * Self-test and set the seed-key as required. + * + * + * Values used for implementation: b=160 bits, G(t,c) implemented using SHA1 (see below), m=1. + * Annotated text from the standard follows. + * + * Appendix 3 section 3.1 "ALGORITHM FOR COMPUTING m VALUES OF x": + * =============================================================== + * + * "Step 1. Choose a new, secret value for the seed-key, XKEY." + * YE: This is implemented by the function fips186_rng_setkey, which allows the user to specify a 20-byte key. + * YE: XKEY is stored in global variable "fips186_rng_state_xkey". + + * "Step 2. In hexadecimal notation let + * t = 67452301 EFCDAB89 98BADCFE 10325476 C3D2E1F0. + * This is the initial value for H0 || H1 || H2 || H3 || H4 in the SHS." + * YE: This is the initial value set by any SHA1 implementation, SHA1_Init() handles it. + * + * "Step 3. For j = 0 to m - 1 do + * a. XSEEDj = optional user input. + * b. XVAL = (XKEY + XSEEDj) mod 2b." + * YE: XSEED is added by the function "fips186_rng_seed", which performs SHA1 on some given data. + * + * "c. xj = G(t,XVAL) mod q." + * YE: First of all, "mod q" was removed on page 74 of the standard. See below for construction of G(t,c). + * + * "d. XKEY = (1 + XKEY + xj) mod 2b." + * YE: Implemented as a carry-sum of XKEY and xj. + * + * + * Appendix 3 section 3.3 "CONSTRUCTING THE FUNCTION G FROM THE SHA-1": + * ==================================================================== + * + * "G(t,c) may be constructed using steps (a) - (e) in section 7 of the Specifications for the Secure Hash + * Standard. Before executing these steps, {Hj} and M1 must be initialized as follows: + * i. Initialize the {Hj} by dividing the 160 bit value t into five 32-bit segments as follows: + * t = t0 || t1 || t2 || t3 || t4 + * Then Hj = tj for j = 0 through 4." + * YE: This is still the initial value handled by SHA1_Init. + * + * "ii. There will be only one message block, M1, which is initialized as follows: + * M1 = c || 0512-b + * (The first b bits of M1 contain c, and the remaining (512-b) bits are set to zero)." + * YE: This is the tricky part. SHA1 usually pads every message with a "1" bit followed by zeroes, then by a 64-bit + * YE: representation of the total message length. This padding does not exist in FIPS186-2, therefore we should + * YE: feed SHA1 with a full 512-bit message and skip the padding step (so we don't call SHA1_Final). + * + * "Then steps (a) through (e) of section 7 are executed, and G(t,c) is the 160 bit string represented by + * the five words: + * H0 || H1 || H2 || H3 || H4 + * at the end of step (e)." + * YE: Since we don't call SHA1_Final, we must extract the five H words from the SHA_CTX structure. + * + * + * + * TESTING + * ======= + * Testing is performed by the function fips186_rng_selftest, which has the following stages: + * 1. Set XKEY to "bd029bbe 7f51960b cf9edb2b 61f06f0f eb5a38b6" as in FIPS186-2 appendix 5. + * 2. Get 20 bytes of data (called X). + * 3. Comparing X to "2070b322 3dba372f de1c0ffc 7b2e3b49 8b260614" as in FIPS186-2 appendix 5. + * 4. Get another 20 bytes of data (called Y). + * 5. Compare X to Y and verify they are different. + * 6. Zeroize XKEY. + * + */ + + +#include <string.h> +#include <stdio.h> +#include <memory.h> +#include <openssl/ssl.h> +#include "e_os.h" +#include <openssl/rand.h> + + +/* Global state variables */ +unsigned char fips186_rng_state_xkey[20]; +unsigned char fips186_rng_state_seed[20]; +unsigned char fips186_rng_state_block[20]; +unsigned int fips186_rng_current_block_remaining=0; + +void fips186_rng_zero(void); +void fips186_rng_seed(const void *buf, int num); +void fips186_rng_add(const void *buf, int num, double add_entropy); +int fips186_rng_bytes(unsigned char *buf, int num); + +RAND_METHOD rand_fips186_meth={ + fips186_rng_seed, + fips186_rng_bytes, + fips186_rng_zero, + fips186_rng_add, + fips186_rng_bytes, + NULL + }; + +RAND_METHOD *RAND_FIPS186(void) + { + return(&rand_fips186_meth); + } + +void fips186_rng_setkey(unsigned char *newkey) +{ + int i; + for (i=0; i<20; i++) + { + fips186_rng_state_xkey[i] = newkey[i]; + } + fips186_rng_current_block_remaining = 0; +} + +void fips186_rng_seed(const void *data, int len) +{ + SHA_CTX c; + int i, carry; + + SHA1_Init(&c); + SHA1_Update(&c, data, len); + SHA1_Final(fips186_rng_state_seed, &c); +} + +void fips186_rng_add(const void *buf, int num, double add_entropy) +{ + fips186_rng_seed(buf, num); +} + +void fips186_rng_newblock(void) +{ + SHA_CTX c; + unsigned char xval[64]; + int i, carry; + + /* Create XVAL by adding XKEY and XSEED. */ + carry=0; + for (i=19; i>=0; i--) + { + unsigned int sum = carry + fips186_rng_state_xkey[i] + fips186_rng_state_seed[i]; + xval[i] = sum & 0xFF; + carry = sum >> 8; + + fips186_rng_state_seed[i] = 0; /* Clear out the seed for subsequent calls */ + } + + /* add zero padding to 512 bits */ + for (i=20; i<64; i++) + xval[i] = 0; + + /* Compute G(t,XVAL) */ + SHA1_Init(&c); + SHA1_Update(&c, xval, 64); + + /* we don't do SHA1_Final intentionally, in order to skip the padding step. */ + /* Instead, we must extract the five H-words from the SHA_CTX. */ + *(unsigned int *)(fips186_rng_state_block+ 0) = htonl(c.h0); + *(unsigned int *)(fips186_rng_state_block+ 4) = htonl(c.h1); + *(unsigned int *)(fips186_rng_state_block+ 8) = htonl(c.h2); + *(unsigned int *)(fips186_rng_state_block+12) = htonl(c.h3); + *(unsigned int *)(fips186_rng_state_block+16) = htonl(c.h4); + + /* Now add the result to the key. We start with a carry of 1 because xkey=1+xkey+result. */ + carry=1; + for (i=19; i>=0; i--) + { + unsigned int sum = carry + fips186_rng_state_xkey[i] + fips186_rng_state_block[i]; + fips186_rng_state_xkey[i] = sum & 0xFF; + carry = sum >> 8; + } + + fips186_rng_current_block_remaining = 20; +} + +int fips186_rng_bytes(unsigned char *out, int n) +{ + /* Get some bytes out of the PRNG */ + + while (n>0) + { + /* Get a new 160-bit block if we need more bits */ + if (fips186_rng_current_block_remaining == 0) + fips186_rng_newblock(); + + int remaining = fips186_rng_current_block_remaining; + if (remaining > n) + remaining = n; + memcpy(out, fips186_rng_state_block + (20 - fips186_rng_current_block_remaining), remaining); + out += remaining; + n -= remaining; + fips186_rng_current_block_remaining -= remaining; + } + + return 1; +} + +void fips186_rng_zero(void) +{ + /* Zeroization of the RNG key. */ + int i; + + for (i=0; i<20; i++) + { + fips186_rng_state_xkey[i] = 0; + fips186_rng_state_seed[i] = 0; + fips186_rng_state_block[i] = 0; + } + fips186_rng_current_block_remaining = 0; +} + +int fips186_rng_selftest(void) +{ + /* Self-tests the FIPS186-2 PRNG. Returns 0 on success, -1 on failure. */ + unsigned char x[20], y[20]; + int i=0; + + /* Set XKEY to "bd029bbe 7f51960b cf9edb2b 61f06f0f eb5a38b6" */ + unsigned char xkey[20] = { 0xbd, 0x02, 0x9b, 0xbe, + 0x7f, 0x51, 0x96, 0x0b, + 0xcf, 0x9e, 0xdb, 0x2b, + 0x61, 0xf0, 0x6f, 0x0f, + 0xeb, 0x5a, 0x38, 0xb6 }; + unsigned char known[20] = { 0x20, 0x70, 0xb3, 0x22, + 0x3d, 0xba, 0x37, 0x2f, + 0xde, 0x1c, 0x0f, 0xfc, + 0x7b, 0x2e, 0x3b, 0x49, + 0x8b, 0x26, 0x06, 0x14 }; + fips186_rng_zero(); + fips186_rng_setkey(xkey); + + for (i=0; i<20; i++) + x[i] = y[i] = 0; + + /* Get 20 bytes and compare to known answer. */ + fips186_rng_bytes(x, 20); + if (memcmp(x, known, 20)) + return -1; + + /* Get another 20 bytes and compare */ + fips186_rng_bytes(y, 20); + if (memcmp(x, y, 20)==0) + return -1; + + /* Zeroize */ + fips186_rng_zero(); + + return 0; +} + + diff -urN openssl-0.9.8-stable-SNAP-20080112/crypto/rand/rand.h openssl-0.9.8-stable-SNAP-devel/crypto/rand/rand.h --- openssl-0.9.8-stable-SNAP-20080112/crypto/rand/rand.h 2004-05-17 18:49:12.000000000 +0300 +++ openssl-0.9.8-stable-SNAP-devel/crypto/rand/rand.h 2008-01-15 11:32:43.000000000 +0200 @@ -112,6 +112,10 @@ int RAND_egd_bytes(const char *path,int bytes); int RAND_poll(void); +RAND_METHOD *RAND_FIPS186(void); +int fips186_rng_selftest(void); +void fips186_rng_setkey(unsigned char *newkey); + #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) void RAND_screen(void);