prng_fips1861.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 507 行 · 第 1/2 页
C
507 行
/* * * 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: prng_fips1861.c,v 1.7 2000/09/06 23:27:34 mcgreer%netscape.com Exp $ */#include "prerr.h"#include "secerr.h"#include "prtypes.h"#include "prinit.h"#include "blapi.h"#include "prlock.h"#include "secitem.h"#include "sha_fast.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 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 */ PRLock *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 voidfreeRNGContext(){ PR_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 SECStatusalg_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 = PR_NewLock(); 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
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?