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 + -
显示快捷键?