/* * Hash_DRBG Instantiate NIST SP 800-80 10.1.1.2 * * NOTE: bytes & len are entropy || nonce || personalization_string. In * normal operation, NSS calculates them all together in a single call. */ static SECStatus prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len) { if (len < PRNG_SEEDLEN) { /* if the seedlen is to small, it's probably because we failed to get * enough random data */ PORT_SetError(SEC_ERROR_NEED_RANDOM); return SECFailure; } prng_Hash_df(V(rng), VSize(rng), bytes, len, NULL, 0); rng->V_type = prngCGenerateType; prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0); PRNG_RESET_RESEED_COUNT(rng) return SECSuccess; }
/* * Hash_DRBG Instantiate NIST SP 800-90 10.1.1.2 * * NOTE: bytes & len are entropy || nonce || personalization_string. In * normal operation, NSS calculates them all together in a single call. */ static SECStatus prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len) { if (!rng->isKatTest && len < PRNG_SEEDLEN) { /* If the seedlen is too small, it's probably because we failed to get * enough random data. * This is stricter than NIST SP800-90A requires. Don't enforce it for * tests. */ PORT_SetError(SEC_ERROR_NEED_RANDOM); return SECFailure; } prng_Hash_df(V(rng), VSize(rng), bytes, len, NULL, 0); rng->V_type = prngCGenerateType; prng_Hash_df(rng->C, sizeof rng->C, rng->V_Data, sizeof rng->V_Data, NULL, 0); PRNG_RESET_RESEED_COUNT(rng) return SECSuccess; }
/* * Clean up the global RNG context */ static void prng_freeRNGContext(RNGContext *rng) { PRUint8 inputhash[VSize(rng) + (sizeof rng->C)]; /* destroy context lock */ SKIP_AFTER_FORK(PZ_DestroyLock(globalrng->lock)); /* zero global RNG context except for C & V to preserve entropy */ prng_Hash_df(inputhash, sizeof rng->C, rng->C, sizeof rng->C, NULL, 0); prng_Hash_df(&inputhash[sizeof rng->C], VSize(rng), V(rng), VSize(rng), NULL, 0); memset(rng, 0, sizeof *rng); memcpy(rng->C, inputhash, sizeof rng->C); memcpy(V(rng), &inputhash[sizeof rng->C], VSize(rng)); memset(inputhash, 0, sizeof inputhash); }
/* * Update the global random number generator with more seeding * material. Use the Hash_DRBG reseed algorithm from NIST SP-800-90 * section 10.1.1.3 * * If entropy is NULL, it is fetched from the noise generator. */ static SECStatus prng_reseed(RNGContext *rng, const PRUint8 *entropy, unsigned int entropy_len, const PRUint8 *additional_input, unsigned int additional_input_len) { PRUint8 noiseData[(sizeof rng->V_Data)+PRNG_SEEDLEN]; PRUint8 *noise = &noiseData[0]; /* if entropy wasn't supplied, fetch it. (normal operation case) */ if (entropy == NULL) { entropy_len = (unsigned int) RNG_SystemRNG( &noiseData[sizeof rng->V_Data], PRNG_SEEDLEN); } else { /* NOTE: this code is only available for testing, not to applications */ /* if entropy was too big for the stack variable, get it from malloc */ if (entropy_len > PRNG_SEEDLEN) { noise = PORT_Alloc(entropy_len + (sizeof rng->V_Data)); if (noise == NULL) { return SECFailure; } } PORT_Memcpy(&noise[sizeof rng->V_Data],entropy, entropy_len); } if (entropy_len < 256/PR_BITS_PER_BYTE) { /* noise == &noiseData[0] at this point, so nothing to free */ PORT_SetError(SEC_ERROR_NEED_RANDOM); return SECFailure; } rng->V_type = prngReseedType; PORT_Memcpy(noise, rng->V_Data, sizeof rng->V_Data); prng_Hash_df(V(rng), VSize(rng), noise, (sizeof rng->V_Data) + entropy_len, additional_input, additional_input_len); /* clear potential CSP */ PORT_Memset(noise, 0, (sizeof rng->V_Data) + entropy_len); rng->V_type = prngCGenerateType; prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0); PRNG_RESET_RESEED_COUNT(rng) if (noise != &noiseData[0]) { PORT_Free(noise); } return SECSuccess; }