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;