diff options
Diffstat (limited to 'security/nss/lib/freebl/prng_fips1861.c')
-rw-r--r-- | security/nss/lib/freebl/prng_fips1861.c | 513 |
1 files changed, 0 insertions, 513 deletions
diff --git a/security/nss/lib/freebl/prng_fips1861.c b/security/nss/lib/freebl/prng_fips1861.c deleted file mode 100644 index bf0199926..000000000 --- a/security/nss/lib/freebl/prng_fips1861.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * - * 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 Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - * - * $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() */ - -/* - * 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 FIPS 186-1 Appendix 3.1 - */ - -/* - * According to FIPS 186-1, 160 <= b <= 512 - * For our purposes, we will assume b == 160 - */ -#define FIPS_B 160 -#define BSIZE FIPS_B / BITS_PER_BYTE - -/* - * Add two 160-bit numbers represented as arrays of 20 bytes. - * The numbers are big-endian, MSB first, so addition is done - * from the end of the buffer to the beginning. - */ -#define ADD_160BIT_PLUS_CARRY(dest, add1, add2, cy) \ - carry = cy; \ - for (i=BSIZE-1; i>=0; --i) { \ - carry += add1[i] + add2[i]; \ - dest[i] = (PRUint8)carry; \ - carry >>= 8; \ - } - -#define ADD_160BIT_2(dest, add1, add2) \ - ADD_160BIT_PLUS_CARRY(dest, add1, add2, 0) - - -/* - * FIPS requires result from Step 3c to be reduced mod q when generating - * random numbers for DSA. - * by definition q >= 2^159 + 1, thus xj < 2q - * thus reducing mod q is simple subtraction when xj > q - */ -#define dsa_reduce_mod_q(xj, q) \ - PORT_Assert(q[0] >= 0x80); \ - if (memcmp(xj,q,BSIZE) > 0) { \ - carry = 0; \ - for (i=BSIZE-1; i>=0; --i) { \ - carry += (signed int)xj[i] - (signed int)q[i]; \ - xj[i] = (PRUint8)carry; \ - carry >>= 8; \ - } \ - } - -/* - * 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-1 appendix 3.3. - */ -void -RNG_UpdateAndEnd_FIPS186_1(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[BSIZE]; /* Output from previous operation */ - PZLock *lock; /* Lock to serialize access to global rng */ - PRUint8 avail; /* # bytes of output available, [0...20] */ - 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 the algorithm in FIPS 186-1 appendix 3.1, heretofore - * called alg3_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_1_x3_1(RNGContext *rng, - const unsigned char *XSEEDj, unsigned char *q) -{ - /* SHA1 context for G(t, XVAL) function */ - SHA1Context sha1cx; - /* input to hash function */ - PRUint8 XVAL[BSIZE]; - /* store a copy of the output to compare with the previous output */ - PRUint8 x_j[BSIZE]; - /* used by ADD_160BIT macros */ - int i, carry; - unsigned int len; - if (!rng->isValid) { - /* RNG has alread entered an invalid state. */ - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - /* initialize the SHA1 context */ - memset(&sha1cx, 0, sizeof(sha1cx)); - /* - * <Step 2> Initialize t, taken care of in SHA-1 (same initial values) - */ - SHA1_Begin(&sha1cx); - /* - * <Step 3a> XSEEDj is optional user input - * - * <Step 3b> XVAL = (XKEY + XSEEDj) mod 2^b - * :always reduced mod 2^b, since storing as 160-bit value - */ - if (XSEEDj) { - /* XSEEDj > 0 */ - ADD_160BIT_2(XVAL, rng->XKEY, XSEEDj); - } else { - /* XSEEDj == 0 */ - memcpy(XVAL, rng->XKEY, BSIZE); - } - /* - * <Step 3c> Xj = G(t, XVAL) mod q - * :In this code, (mod q) is only understood for DSA ops, - * :not general RNG (what would q be in non-DSA uses?). - * :If a q is specified, use it. - * :FIPS 186-1 specifies a different padding than the SHA1 180-1 - * :specification, this function is implemented below. - */ - RNG_UpdateAndEnd_FIPS186_1(&sha1cx, XVAL, BSIZE, x_j, &len, BSIZE); - if (q != NULL) { - dsa_reduce_mod_q(x_j, q); - } - /* [FIPS 140-1] verify output does not match previous output */ - if (memcmp(x_j, rng->Xj, BSIZE) == 0) { - /* failed FIPS 140-1 continuous RNG condition. RNG now invalid. */ - rng->isValid = PR_FALSE; - return SECFailure; - } - /* Xj is the output */ - memcpy(rng->Xj, x_j, BSIZE); - /* - * <Step 3d> XKEY = (1 + XKEY + Xj) mod 2^b - * :always reduced mod 2^b, since storing as 160-bit value - */ - ADD_160BIT_PLUS_CARRY(rng->XKEY, rng->XKEY, x_j, 1); - /* Always have a full buffer after executing alg3_1() */ - rng->avail = BSIZE; - /* housekeeping */ - memset(x_j, 0, BSIZE); - memset(XVAL, 0, BSIZE); - return SECSuccess; -} - -/* 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_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 (globalrng != NULL) ? PR_SUCCESS : PR_FAILURE; -} - -/* - * 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 -*/ -SECStatus -prng_RandomUpdate(RNGContext *rng, const void *data, size_t bytes, - unsigned char *q) -{ - 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 = SHA1_HashBuf(inputhash, data, bytes); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - 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. - * FIPS 186-1 3.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-bytes, so fill it with the first b-bytes - * sent to RNG_RandomUpdate(). - */ - if (rng->seedCount == 0) { - /* This is the first call to RandomUpdate(). Use a SHA1 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_1_x3_1(rng, NULL, q); - /* As per FIPS 140-1 continuous RNG requirement, the first - * iteration of output is discarded. So here there is really - * no output available. This forces another execution of alg3_1() - * before any bytes can be extracted from the generator. - */ - rng->avail = 0; - } else { - /* Execute the algorithm from FIPS 186-1 appendix 3.1 */ - rv = alg_fips186_1_x3_1(rng, inputhash, q); - } - /* If got this far, have added bytes of seed data. */ - 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. Not DSA, so no q. -*/ -SECStatus -RNG_RandomUpdate(const void *data, size_t bytes) -{ - return prng_RandomUpdate(globalrng, data, bytes, NULL); -} - -/* -** Generate some random bytes, using the global random number generator -** object. -*/ -SECStatus -prng_GenerateGlobalRandomBytes(RNGContext *rng, - void *dest, size_t len, unsigned char *q) -{ - 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 alg3_1() with 0's to generate more random data. - */ - while (len > 0) { - if (rng->avail == 0) - /* All available bytes are used, so generate more. */ - rv = alg_fips186_1_x3_1(rng, NULL, q); - /* number of bytes to obtain on this iteration (max of 20) */ - num = PR_MIN(rng->avail, len); - /* if avail < BSIZE, the first avail bytes have already been used. */ - memcpy(output, rng->Xj + (BSIZE - 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. Not DSA, so no q. -*/ -SECStatus -RNG_GenerateGlobalRandomBytes(void *dest, size_t len) -{ - return prng_GenerateGlobalRandomBytes(globalrng, dest, len, NULL); -} - -void -RNG_RNGShutdown(void) -{ - /* check for a valid global RNG context */ - PORT_Assert(globalrng != NULL); - if (globalrng == NULL) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - 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-1 3.3 uses a function, G, - * which has the same initialization and compression functions - * as SHA1 180-1, but uses different padding. FIPS 186-1 3.3 - * specifies that the message be padded with 0's until the size - * reaches 512 bits. - */ -void -RNG_UpdateAndEnd_FIPS186_1(SHA1Context *ctx, - unsigned char *input, unsigned int inputLen, - unsigned char *hashout, unsigned int *pDigestLen, - unsigned int maxDigestLen) -{ - register PRUint32 A; - 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 - */ -#if defined(IS_LITTLE_ENDIAN) - SHA_BYTESWAP(ctx->H[0]); - SHA_BYTESWAP(ctx->H[1]); - SHA_BYTESWAP(ctx->H[2]); - SHA_BYTESWAP(ctx->H[3]); - SHA_BYTESWAP(ctx->H[4]); -#endif - memcpy(hashout, ctx->H, SHA1_LENGTH); - *pDigestLen = SHA1_LENGTH; - - /* - * Re-initialize the context (also zeroizes contents) - */ - SHA1_Begin(ctx); -} - -/* - * Specialized RNG for DSA - * - * As per FIPS 186-1 appendix 3.1, in step 5 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. - * - */ - -/* -** Update the global random number generator with more seeding -** material. DSA needs a q parameter. -*/ -SECStatus -DSA_RandomUpdate(void *data, size_t bytes, unsigned char *q) -{ - if( q && (*q == 0) ) { - ++q; - } - return prng_RandomUpdate(globalrng, data, bytes, q); -} - -/* -** 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, unsigned char *q) -{ - if( q && (*q == 0) ) { - ++q; - } - return prng_GenerateGlobalRandomBytes(globalrng, dest, len, q); -} |