diff options
Diffstat (limited to 'security/nss/lib/freebl/prng_fips1861.c')
-rw-r--r-- | security/nss/lib/freebl/prng_fips1861.c | 586 |
1 files changed, 0 insertions, 586 deletions
diff --git a/security/nss/lib/freebl/prng_fips1861.c b/security/nss/lib/freebl/prng_fips1861.c deleted file mode 100644 index 900b98ab8..000000000 --- a/security/nss/lib/freebl/prng_fips1861.c +++ /dev/null @@ -1,586 +0,0 @@ -/* - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -/* $Id$ */ - -#include "prerr.h" -#include "secerr.h" - -#include "prtypes.h" -#include "prinit.h" -#include "blapi.h" -#include "nssilock.h" -#include "secitem.h" -#include "sha_fast.h" -#include "secrng.h" /* for RNG_GetNoise() */ -#include "secmpi.h" - -/* - * The minimum amount of seed data required before the generator will - * provide data. - * Note that this is a measure of the number of bytes sent to - * RNG_RandomUpdate, not the actual amount of entropy present in the - * generator. Naturally, it is impossible to know (at this level) just - * how much entropy is present in the provided seed data. A bare minimum - * of entropy would be 20 bytes, so by requiring 1K this code is making - * the tacit assumption that at least 1 byte of pure entropy is provided - * with every 8 bytes supplied to RNG_RandomUpdate. The reality of this - * assumption is left up to the caller. - */ -#define MIN_SEED_COUNT 1024 - -/* - * Steps taken from Algorithm 1 of FIPS 186-2 Change Notice 1 - */ - -/* - * According to FIPS 186-2, 160 <= b <= 512. - * For our purposes, we will assume b == 160, - * 256, or 512 (the output size of SHA-1, - * SHA-256, or SHA-512). - */ -#define FIPS_B 256 -#define B_HASH_BUF SHA256_HashBuf -#define BSIZE (FIPS_B / PR_BITS_PER_BYTE) - -/* Output size of the G function */ -#define FIPS_G 160 -#define GSIZE (FIPS_G / PR_BITS_PER_BYTE) - -/* - * Add two b-bit numbers represented as arrays of BSIZE bytes. - * The numbers are big-endian, MSB first, so addition is done - * from the end of the buffer to the beginning. - */ -#define ADD_B_BIT_PLUS_CARRY(dest, add1, add2, cy) \ - carry = cy; \ - for (k=BSIZE-1; k>=0; --k) { \ - carry += add1[k] + add2[k]; \ - dest[k] = (PRUint8)carry; \ - carry >>= 8; \ - } - -#define ADD_B_BIT_2(dest, add1, add2) \ - ADD_B_BIT_PLUS_CARRY(dest, add1, add2, 0) - - -/* - * FIPS requires result from Step 3.3 to be reduced mod q when generating - * random numbers for DSA. - * - * Input: w, 2*GSIZE bytes - * q, DSA_SUBPRIME_LEN bytes - * Output: xj, DSA_SUBPRIME_LEN bytes - */ -static SECStatus -dsa_reduce_mod_q(const unsigned char *w, const unsigned char *q, - unsigned char *xj) -{ - mp_int W, Q, Xj; - mp_err err; - SECStatus rv = SECSuccess; - - /* Initialize MPI integers. */ - MP_DIGITS(&W) = 0; - MP_DIGITS(&Q) = 0; - MP_DIGITS(&Xj) = 0; - CHECK_MPI_OK( mp_init(&W) ); - CHECK_MPI_OK( mp_init(&Q) ); - CHECK_MPI_OK( mp_init(&Xj) ); - /* - * Convert input arguments into MPI integers. - */ - CHECK_MPI_OK( mp_read_unsigned_octets(&W, w, 2*GSIZE) ); - CHECK_MPI_OK( mp_read_unsigned_octets(&Q, q, DSA_SUBPRIME_LEN) ); - /* - * Algorithm 1 of FIPS 186-2 Change Notice 1, Step 3.3 - * - * xj = (w0 || w1) mod q - */ - CHECK_MPI_OK( mp_mod(&W, &Q, &Xj) ); - CHECK_MPI_OK( mp_to_fixlen_octets(&Xj, xj, DSA_SUBPRIME_LEN) ); -cleanup: - mp_clear(&W); - mp_clear(&Q); - mp_clear(&Xj); - if (err) { - MP_TO_SEC_ERROR(err); - rv = SECFailure; - } - return rv; -} - -/* - * Specialized SHA1-like function. This function appends zeroes to a - * single input block and runs a single instance of the compression function, - * as specified in FIPS 186-2 appendix 3.3. - */ -static void -RNG_UpdateAndEnd_FIPS186_2(SHA1Context *ctx, - unsigned char *input, unsigned int inputLen, - unsigned char *hashout, unsigned int *pDigestLen, - unsigned int maxDigestLen); - -/* - * Global RNG context - */ -struct RNGContextStr { - PRUint8 XKEY[BSIZE]; /* Seed for next SHA iteration */ - PRUint8 Xj[2*GSIZE]; /* Output from previous operation. */ - PZLock *lock; /* Lock to serialize access to global rng */ - PRUint8 avail; /* # bytes of output available, [0...2*GSIZE] */ - PRUint32 seedCount; /* number of seed bytes given to generator */ - PRBool isValid; /* false if RNG reaches an invalid state */ -}; -typedef struct RNGContextStr RNGContext; -static RNGContext *globalrng = NULL; - -/* - * Free the global RNG context - */ -static void -freeRNGContext() -{ - PZ_DestroyLock(globalrng->lock); - PORT_ZFree(globalrng, sizeof *globalrng); - globalrng = NULL; -} - -/* - * Implementation of Algorithm 1 of FIPS 186-2 Change Notice 1, - * hereinafter called alg_cn_1(). It is assumed a lock for the global - * rng context has already been acquired. - * Calling this function with XSEEDj == NULL is equivalent to saying there - * is no optional user input, which is further equivalent to saying that - * the optional user input is 0. - */ -static SECStatus -alg_fips186_2_cn_1(RNGContext *rng, const unsigned char *XSEEDj) -{ - /* SHA1 context for G(t, XVAL) function */ - SHA1Context sha1cx; - /* XKEY for iteration 1 */ - PRUint8 XKEY_1[BSIZE]; - const PRUint8 *XKEY_old; - PRUint8 *XKEY_new; - /* input to hash function */ - PRUint8 XVAL[BSIZE]; - /* store a copy of the output to compare with the previous output */ - PRUint8 x_j[2*GSIZE]; - /* used by ADD_B_BIT macros */ - int k, carry; - /* store the output of G(t, XVAL) in the rightmost GSIZE bytes */ - PRUint8 w_i[BSIZE]; - int i; - unsigned int len; - SECStatus rv = SECSuccess; - - if (!rng->isValid) { - /* RNG has alread entered an invalid state. */ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } -#if GSIZE < BSIZE - /* zero the leftmost bytes so we can pass it to ADD_B_BIT_PLUS_CARRY */ - memset(w_i, 0, BSIZE - GSIZE); -#endif - /* - * <Step 2> Initialize t, taken care of in SHA-1 (same initial values) - * - * <Step 3.1> XSEEDj is optional user input - */ - for (i = 0; i < 2; i++) { - /* only update rng->XKEY when both iterations have been completed */ - if (i == 0) { - /* for iteration 0 */ - XKEY_old = rng->XKEY; - XKEY_new = XKEY_1; - } else { - /* for iteration 1 */ - XKEY_old = XKEY_1; - XKEY_new = rng->XKEY; - } - /* - * <Step 3.2a> XVAL = (XKEY + XSEEDj) mod 2^b - * :always reduced mod 2^b, since storing as b-bit value - */ - if (XSEEDj) { - /* XSEEDj > 0 */ - if (memcmp(XKEY_old, XSEEDj, BSIZE) == 0) { - /* Should we add the error code SEC_ERROR_BAD_RNG_SEED? */ - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - goto done; - } - ADD_B_BIT_2(XVAL, XKEY_old, XSEEDj); - } else { - /* XSEEDj == 0 */ - memcpy(XVAL, XKEY_old, BSIZE); - } - /* - * <Step 3.2b> Wi = G(t, XVAL) - * :FIPS 186-2 specifies a different padding than the SHA1 180-1 - * :specification, this function is implemented in - * :RNG_UpdateAndEnd_FIPS186_2 below. - */ - SHA1_Begin(&sha1cx); - RNG_UpdateAndEnd_FIPS186_2(&sha1cx, XVAL, BSIZE, - &w_i[BSIZE - GSIZE], &len, GSIZE); - /* - * <Step 3.2c> XKEY = (1 + XKEY + Wi) mod 2^b - * :always reduced mod 2^b, since storing as 160-bit value - */ - ADD_B_BIT_PLUS_CARRY(XKEY_new, XKEY_old, w_i, 1); - /* - * <Step 3.3> Xj = (W0 || W1) - */ - memcpy(&x_j[i*GSIZE], &w_i[BSIZE - GSIZE], GSIZE); - } - /* [FIPS 140-2] verify output does not match previous output */ - if (memcmp(x_j, rng->Xj, 2*GSIZE) == 0) { - /* failed FIPS 140-2 continuous RNG test. RNG now invalid. */ - rng->isValid = PR_FALSE; - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - rv = SECFailure; - goto done; - } - /* Xj is the output */ - memcpy(rng->Xj, x_j, 2*GSIZE); - /* Always have a full buffer after executing alg_cn_1() */ - rng->avail = 2*GSIZE; - -done: - /* housekeeping */ - memset(&w_i[BSIZE - GSIZE], 0, GSIZE); - memset(x_j, 0, 2*GSIZE); - memset(XVAL, 0, BSIZE); - memset(XKEY_1, 0, BSIZE); - return rv; -} - -/* Use NSPR to prevent RNG_RNGInit from being called from separate - * threads, creating a race condition. - */ -static PRCallOnceType coRNGInit = { 0, 0, 0 }; -static PRStatus rng_init(void) -{ - unsigned char bytes[120]; - unsigned int numBytes; - if (globalrng == NULL) { - /* create a new global RNG context */ - globalrng = (RNGContext *)PORT_ZAlloc(sizeof(RNGContext)); - if (globalrng == NULL) { - PORT_SetError(PR_OUT_OF_MEMORY_ERROR); - return PR_FAILURE; - } - /* create a lock for it */ - globalrng->lock = PZ_NewLock(nssILockOther); - if (globalrng->lock == NULL) { - PORT_Free(globalrng); - globalrng = NULL; - PORT_SetError(PR_OUT_OF_MEMORY_ERROR); - return PR_FAILURE; - } - /* the RNG is in a valid state */ - globalrng->isValid = PR_TRUE; - /* Try to get some seed data for the RNG */ - numBytes = RNG_GetNoise(bytes, sizeof bytes); - RNG_RandomUpdate(bytes, numBytes); - } - return PR_SUCCESS; -} - -/* - * Initialize the global RNG context and give it some seed input taken - * from the system. This function is thread-safe and will only allow - * the global context to be initialized once. The seed input is likely - * small, so it is imperative that RNG_RandomUpdate() be called with - * additional seed data before the generator is used. A good way to - * provide the generator with additional entropy is to call - * RNG_SystemInfoForRNG(). Note that NSS_Init() does exactly that. - */ -SECStatus -RNG_RNGInit(void) -{ - /* Allow only one call to initialize the context */ - PR_CallOnce(&coRNGInit, rng_init); - /* Make sure there is a context */ - return (globalrng != NULL) ? PR_SUCCESS : PR_FAILURE; -} - -/* -** Update the global random number generator with more seeding -** material -*/ -static SECStatus -prng_RandomUpdate(RNGContext *rng, const void *data, size_t bytes) -{ - SECStatus rv = SECSuccess; - unsigned char inputhash[BSIZE]; - /* check for a valid global RNG context */ - PORT_Assert(rng != NULL); - if (rng == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - /* RNG_SystemInfoForRNG() sometimes does this, not really an error */ - if (bytes == 0) - return SECSuccess; - /* If received 20 bytes of input, use it, else hash the input before - * locking. - */ - if (bytes == BSIZE) - memcpy(inputhash, data, BSIZE); - else - rv = B_HASH_BUF(inputhash, data, bytes); - if (rv != SECSuccess) { - /* B_HASH_BUF set error */ - return SECFailure; - } - /* --- LOCKED --- */ - PZ_Lock(rng->lock); - /* - * Random information is initially supplied by a call to - * RNG_SystemInfoForRNG(). That function collects entropy from - * the system and calls RNG_RandomUpdate() to seed the generator. - * Algorithm 1 of FIPS 186-2 Change Notice 1, step 1 specifies that - * a secret value for the seed-key must be chosen before the - * generator can begin. The size of XKEY is b bits, so fill it - * with the first b bits sent to RNG_RandomUpdate(). - */ - if (rng->seedCount == 0) { - /* This is the first call to RandomUpdate(). Use a hash - * of the input to set the seed, XKEY. - * - * <Step 1> copy seed bytes into context's XKEY - */ - memcpy(rng->XKEY, inputhash, BSIZE); - /* - * Now continue with algorithm. Since the input was used to - * initialize XKEY, the "optional user input" at this stage - * will be a pad of zeros, XSEEDj = 0. - */ - rv = alg_fips186_2_cn_1(rng, NULL); - /* As per FIPS 140-2 continuous RNG test requirement, the first - * iteration of output is discarded. So here there is really - * no output available. This forces another execution of alg_cn_1() - * before any bytes can be extracted from the generator. - */ - rng->avail = 0; - } else { - /* Execute the algorithm from FIPS 186-2 Change Notice 1 */ - rv = alg_fips186_2_cn_1(rng, inputhash); - } - /* If got this far, have added bytes of seed data. */ - if (rv == SECSuccess) - rng->seedCount += bytes; - PZ_Unlock(rng->lock); - /* --- UNLOCKED --- */ - /* housekeeping */ - memset(inputhash, 0, BSIZE); - return rv; -} - -/* -** Update the global random number generator with more seeding -** material. -*/ -SECStatus -RNG_RandomUpdate(const void *data, size_t bytes) -{ - return prng_RandomUpdate(globalrng, data, bytes); -} - -/* -** Generate some random bytes, using the global random number generator -** object. -*/ -SECStatus -prng_GenerateGlobalRandomBytes(RNGContext *rng, - void *dest, size_t len) -{ - PRUint8 num; - SECStatus rv = SECSuccess; - unsigned char *output = dest; - /* check for a valid global RNG context */ - PORT_Assert(rng != NULL); - if (rng == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - /* --- LOCKED --- */ - PZ_Lock(rng->lock); - /* Check the amount of seed data in the generator. If not enough, - * don't produce any data. - */ - if (rng->seedCount < MIN_SEED_COUNT) { - PZ_Unlock(rng->lock); - PORT_SetError(SEC_ERROR_NEED_RANDOM); - return SECFailure; - } - /* - * If there are enough bytes of random data, send back Xj, - * else call alg_cn_1() with 0's to generate more random data. - */ - while (len > 0 && rv == SECSuccess) { - if (rng->avail == 0) { - /* All available bytes are used, so generate more. */ - rv = alg_fips186_2_cn_1(rng, NULL); - } - /* number of bytes to obtain on this iteration (max of 40) */ - num = PR_MIN(rng->avail, len); - /* - * if avail < 2*GSIZE, the first 2*GSIZE - avail bytes have - * already been used. - */ - if (num) { - memcpy(output, rng->Xj + (2*GSIZE - rng->avail), num); - rng->avail -= num; - len -= num; - output += num; - } - } - PZ_Unlock(rng->lock); - /* --- UNLOCKED --- */ - return rv; -} - -/* -** Generate some random bytes, using the global random number generator -** object. -*/ -SECStatus -RNG_GenerateGlobalRandomBytes(void *dest, size_t len) -{ - return prng_GenerateGlobalRandomBytes(globalrng, dest, len); -} - -void -RNG_RNGShutdown(void) -{ - /* check for a valid global RNG context */ - PORT_Assert(globalrng != NULL); - if (globalrng == NULL) { - /* Should set a "not initialized" error code. */ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return; - } - /* clear */ - freeRNGContext(); - /* zero the callonce struct to allow a new call to RNG_RNGInit() */ - memset(&coRNGInit, 0, sizeof coRNGInit); -} - -/* - * SHA: Generate hash value from context - * Specialized function for PRNG - * The PRNG specified in FIPS 186-2 3.3 uses a function, G, - * which has the same initialization and compression functions - * as SHA1 180-1, but uses different padding. FIPS 186-2 3.3 - * specifies that the message be padded with 0's until the size - * reaches 512 bits. - */ -static void -RNG_UpdateAndEnd_FIPS186_2(SHA1Context *ctx, - unsigned char *input, unsigned int inputLen, - unsigned char *hashout, unsigned int *pDigestLen, - unsigned int maxDigestLen) -{ -#if defined(SHA_NEED_TMP_VARIABLE) - register PRUint32 tmp; -#endif - static const unsigned char bulk_pad0[64] = { 0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; - - PORT_Assert(maxDigestLen >= SHA1_LENGTH); - PORT_Assert(inputLen <= SHA1_INPUT_LEN); - - /* - * Add the input - */ - SHA1_Update(ctx, input, inputLen); - /* - * Pad with zeroes - * This will fill the input block and cause the compression function - * to be called. - */ - SHA1_Update(ctx, bulk_pad0, SHA1_INPUT_LEN - inputLen); - - /* - * Output hash - */ - SHA_STORE_RESULT; - *pDigestLen = SHA1_LENGTH; -} - -/* - * Specialized RNG for DSA - * - * As per Algorithm 1 of FIPS 186-2 Change Notice 1, in step 3.3 the value - * Xj should be reduced mod q, a 160-bit prime number. Since this parameter - * is only meaningful in the context of DSA, the above RNG functions - * were implemented without it. They are re-implemented below for use - * with DSA. - * - */ - -/* -** Generate some random bytes, using the global random number generator -** object. In DSA mode, so there is a q. -*/ -SECStatus -DSA_GenerateGlobalRandomBytes(void *dest, size_t len, const unsigned char *q) -{ - SECStatus rv; - unsigned char w[2*GSIZE]; - - PORT_Assert(q && len == DSA_SUBPRIME_LEN); - if (len != DSA_SUBPRIME_LEN) { - PORT_SetError(SEC_ERROR_OUTPUT_LEN); - return SECFailure; - } - if (*q == 0) { - ++q; - } - rv = prng_GenerateGlobalRandomBytes(globalrng, w, 2*GSIZE); - if (rv != SECSuccess) { - return rv; - } - dsa_reduce_mod_q(w, q, (unsigned char *)dest); - return rv; -} |