Merge entropy read in FIPS mode. When seeding a DRBG for the first time we currently make two reads: one to start the CRNGT and a second to read the actual seed. These reads can be merged to save I/O. Change-Id: I2a83edf7f3c8b9d6cebcde02195845be9fde19b2 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/52526 Commit-Queue: Adam Langley <agl@google.com> Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/fipsmodule/rand/rand.c b/crypto/fipsmodule/rand/rand.c index 7d6daed..f78e66a 100644 --- a/crypto/fipsmodule/rand/rand.c +++ b/crypto/fipsmodule/rand/rand.c
@@ -184,7 +184,8 @@ struct entropy_buffer { // bytes contains entropy suitable for seeding a DRBG. - uint8_t bytes[CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD]; + uint8_t + bytes[CRNGT_BLOCK_SIZE + CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD]; // bytes_valid indicates the number of bytes of |bytes| that contain valid // data. size_t bytes_valid; @@ -248,36 +249,46 @@ static void rand_get_seed(struct rand_thread_state *state, uint8_t seed[CTR_DRBG_ENTROPY_LEN], int *out_want_additional_input) { - if (!state->last_block_valid) { - int unused; - get_seed_entropy(state->last_block, sizeof(state->last_block), &unused); - state->last_block_valid = 1; + uint8_t entropy_bytes[sizeof(state->last_block) + + CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD]; + uint8_t *entropy = entropy_bytes; + size_t entropy_len = sizeof(entropy_bytes); + + if (state->last_block_valid) { + // No need to fill |state->last_block| with entropy from the read. + entropy += sizeof(state->last_block); + entropy_len -= sizeof(state->last_block); } - uint8_t entropy[CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD]; - get_seed_entropy(entropy, sizeof(entropy), out_want_additional_input); + get_seed_entropy(entropy, entropy_len, out_want_additional_input); + + if (!state->last_block_valid) { + OPENSSL_memcpy(state->last_block, entropy, sizeof(state->last_block)); + entropy += sizeof(state->last_block); + entropy_len -= sizeof(state->last_block); + } // See FIPS 140-2, section 4.9.2. This is the “continuous random number // generator test” which causes the program to randomly abort. Hopefully the // rate of failure is small enough not to be a problem in practice. - if (CRYPTO_memcmp(state->last_block, entropy, CRNGT_BLOCK_SIZE) == 0) { + if (CRYPTO_memcmp(state->last_block, entropy, sizeof(state->last_block)) == + 0) { fprintf(stderr, "CRNGT failed.\n"); BORINGSSL_FIPS_abort(); } - OPENSSL_STATIC_ASSERT(sizeof(entropy) % CRNGT_BLOCK_SIZE == 0, ""); - for (size_t i = CRNGT_BLOCK_SIZE; i < sizeof(entropy); - i += CRNGT_BLOCK_SIZE) { + assert(entropy_len % CRNGT_BLOCK_SIZE == 0); + for (size_t i = CRNGT_BLOCK_SIZE; i < entropy_len; i += CRNGT_BLOCK_SIZE) { if (CRYPTO_memcmp(entropy + i - CRNGT_BLOCK_SIZE, entropy + i, CRNGT_BLOCK_SIZE) == 0) { fprintf(stderr, "CRNGT failed.\n"); BORINGSSL_FIPS_abort(); } } - OPENSSL_memcpy(state->last_block, - entropy + sizeof(entropy) - CRNGT_BLOCK_SIZE, + OPENSSL_memcpy(state->last_block, entropy + entropy_len - CRNGT_BLOCK_SIZE, CRNGT_BLOCK_SIZE); + assert(entropy_len == BORINGSSL_FIPS_OVERREAD * CTR_DRBG_ENTROPY_LEN); OPENSSL_memcpy(seed, entropy, CTR_DRBG_ENTROPY_LEN); for (size_t i = 1; i < BORINGSSL_FIPS_OVERREAD; i++) {
diff --git a/crypto/fipsmodule/rand/urandom_test.cc b/crypto/fipsmodule/rand/urandom_test.cc index 2c89912..dabaf39 100644 --- a/crypto/fipsmodule/rand/urandom_test.cc +++ b/crypto/fipsmodule/rand/urandom_test.cc
@@ -420,8 +420,7 @@ if (!have_rdrand()) { if ((!have_fork_detection() && !sysrand(true, kAdditionalDataLength)) || // Initialise CRNGT. - (is_fips && !sysrand(true, 16)) || - !sysrand(true, kSeedLength) || + !sysrand(true, kSeedLength + (is_fips ? 16 : 0)) || // Second entropy draw. (!have_fork_detection() && !sysrand(true, kAdditionalDataLength))) { return ret;
diff --git a/crypto/rand_extra/passive.c b/crypto/rand_extra/passive.c index da7359b..f27803b 100644 --- a/crypto/rand_extra/passive.c +++ b/crypto/rand_extra/passive.c
@@ -21,7 +21,8 @@ // RAND_need_entropy is called by the FIPS module when it has blocked because of // a lack of entropy. This signal is used as an indication to feed it more. void RAND_need_entropy(size_t bytes_needed) { - uint8_t buf[CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD]; + uint8_t buf[/* last_block size */ 16 + + CTR_DRBG_ENTROPY_LEN * BORINGSSL_FIPS_OVERREAD]; size_t todo = sizeof(buf); if (todo > bytes_needed) { todo = bytes_needed;