prng_fips1861.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 507 行 · 第 1/2 页

C
507
字号
 * 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, 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 --- */    PR_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;    PR_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(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 --- */    PR_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) {	PR_Unlock(rng->lock);	/* XXX this should be a new error code */	PORT_SetError(SEC_ERROR_INVALID_ARGS);	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;    }    PR_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);}voidRNG_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){    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){    return prng_GenerateGlobalRandomBytes(globalrng, dest, len, q);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?