static void rand_get_seed(struct rand_state *state, uint8_t seed[CTR_DRBG_ENTROPY_LEN]) { if (!state->last_block_valid) { if (!hwrand(state->last_block, sizeof(state->last_block))) { CRYPTO_sysrand(state->last_block, sizeof(state->last_block)); } state->last_block_valid = 1; } // We overread from /dev/urandom or RDRAND by a factor of 10 and XOR to // whiten. #define FIPS_OVERREAD 10 uint8_t entropy[CTR_DRBG_ENTROPY_LEN * FIPS_OVERREAD]; if (!hwrand(entropy, sizeof(entropy))) { CRYPTO_sysrand(entropy, sizeof(entropy)); } // 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) { fprintf(stderr, "CRNGT failed.\n"); BORINGSSL_FIPS_abort(); } for (size_t i = CRNGT_BLOCK_SIZE; i < sizeof(entropy); 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, CRNGT_BLOCK_SIZE); OPENSSL_memcpy(seed, entropy, CTR_DRBG_ENTROPY_LEN); for (size_t i = 1; i < FIPS_OVERREAD; i++) { for (size_t j = 0; j < CTR_DRBG_ENTROPY_LEN; j++) { seed[j] ^= entropy[CTR_DRBG_ENTROPY_LEN * i + j]; } } }
void RAND_bytes_with_additional_data(uint8_t *out, size_t out_len, const uint8_t user_additional_data[32]) { if (out_len == 0) { return; } // Additional data is mixed into every CTR-DRBG call to protect, as best we // can, against forks & VM clones. We do not over-read this information and // don't reseed with it so, from the point of view of FIPS, this doesn't // provide “prediction resistance”. But, in practice, it does. uint8_t additional_data[32]; if (!hwrand(additional_data, sizeof(additional_data))) { // Without a hardware RNG to save us from address-space duplication, the OS // entropy is used. This can be expensive (one read per |RAND_bytes| call) // and so can be disabled by applications that we have ensured don't fork // and aren't at risk of VM cloning. if (!rand_fork_unsafe_buffering_enabled()) { CRYPTO_sysrand(additional_data, sizeof(additional_data)); } else { OPENSSL_memset(additional_data, 0, sizeof(additional_data)); } } for (size_t i = 0; i < sizeof(additional_data); i++) { additional_data[i] ^= user_additional_data[i]; } struct rand_state stack_state; struct rand_state *state = rand_state_get(); if (state == NULL) { // If the system is out of memory, use an ephemeral state on the // stack. state = &stack_state; rand_state_init(state); } if (state->calls >= kReseedInterval) { uint8_t seed[CTR_DRBG_ENTROPY_LEN]; rand_get_seed(state, seed); #if defined(BORINGSSL_FIPS) // Take a read lock around accesses to |state->drbg|. This is needed to // avoid returning bad entropy if we race with // |rand_state_clear_all|. // // This lock must be taken after any calls to |CRYPTO_sysrand| to avoid a // bug on ppc64le. glibc may implement pthread locks by wrapping user code // in a hardware transaction, but, on some older versions of glibc and the // kernel, syscalls made with |syscall| did not abort the transaction. CRYPTO_STATIC_MUTEX_lock_read(rand_drbg_lock_bss_get()); #endif if (!CTR_DRBG_reseed(&state->drbg, seed, NULL, 0)) { abort(); } state->calls = 0; } else { #if defined(BORINGSSL_FIPS) CRYPTO_STATIC_MUTEX_lock_read(rand_drbg_lock_bss_get()); #endif } int first_call = 1; while (out_len > 0) { size_t todo = out_len; if (todo > CTR_DRBG_MAX_GENERATE_LENGTH) { todo = CTR_DRBG_MAX_GENERATE_LENGTH; } if (!CTR_DRBG_generate(&state->drbg, out, todo, additional_data, first_call ? sizeof(additional_data) : 0)) { abort(); } out += todo; out_len -= todo; state->calls++; first_call = 0; } if (state == &stack_state) { CTR_DRBG_clear(&state->drbg); } #if defined(BORINGSSL_FIPS) CRYPTO_STATIC_MUTEX_unlock_read(rand_drbg_lock_bss_get()); #endif if (state != &stack_state) { rand_state_put(state); } }
static void rand_get_seed(struct rand_state *state, uint8_t seed[CTR_DRBG_ENTROPY_LEN]) { // If not in FIPS mode, we don't overread from the system entropy source and // we don't depend only on the hardware RDRAND. CRYPTO_sysrand(seed, CTR_DRBG_ENTROPY_LEN); }
int RAND_bytes(uint8_t *buf, size_t len) { if (len == 0) { return 1; } if (!CRYPTO_have_hwrand() || !CRYPTO_hwrand(buf, len)) { /* Without a hardware RNG to save us from address-space duplication, the OS * entropy is used directly. */ CRYPTO_sysrand(buf, len); return 1; } struct rand_thread_state *state = CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_RAND); if (state == NULL) { state = OPENSSL_malloc(sizeof(struct rand_thread_state)); if (state == NULL || !CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_RAND, state, rand_thread_state_free)) { CRYPTO_sysrand(buf, len); return 1; } memset(state->partial_block, 0, sizeof(state->partial_block)); state->calls_used = kMaxCallsPerRefresh; } if (state->calls_used >= kMaxCallsPerRefresh || state->bytes_used >= kMaxBytesPerRefresh) { CRYPTO_sysrand(state->key, sizeof(state->key)); state->calls_used = 0; state->bytes_used = 0; state->partial_block_used = sizeof(state->partial_block); } if (len >= sizeof(state->partial_block)) { size_t remaining = len; while (remaining > 0) { // kMaxBytesPerCall is only 2GB, while ChaCha can handle 256GB. But this // is sufficient and easier on 32-bit. static const size_t kMaxBytesPerCall = 0x80000000; size_t todo = remaining; if (todo > kMaxBytesPerCall) { todo = kMaxBytesPerCall; } CRYPTO_chacha_20(buf, buf, todo, state->key, (uint8_t *)&state->calls_used, 0); buf += todo; remaining -= todo; state->calls_used++; } } else { if (sizeof(state->partial_block) - state->partial_block_used < len) { CRYPTO_chacha_20(state->partial_block, state->partial_block, sizeof(state->partial_block), state->key, (uint8_t *)&state->calls_used, 0); state->partial_block_used = 0; } unsigned i; for (i = 0; i < len; i++) { buf[i] ^= state->partial_block[state->partial_block_used++]; } state->calls_used++; } state->bytes_used += len; return 1; }