/* * Implements the get_entropy() callback (see RAND_DRBG_set_callbacks()) * * If the DRBG has a parent, then the required amount of entropy input * is fetched using the parent's RAND_DRBG_generate(). * * Otherwise, the entropy is polled from the system entropy sources * using RAND_POOL_acquire_entropy(). * * If a random pool has been added to the DRBG using RAND_add(), then * its entropy will be used up first. */ size_t rand_drbg_get_entropy(RAND_DRBG *drbg, unsigned char **pout, int entropy, size_t min_len, size_t max_len) { size_t ret = 0; size_t entropy_available = 0; RAND_POOL *pool = RAND_POOL_new(entropy, min_len, max_len); if (pool == NULL) return 0; if (drbg->pool) { RAND_POOL_add(pool, RAND_POOL_buffer(drbg->pool), RAND_POOL_length(drbg->pool), RAND_POOL_entropy(drbg->pool)); RAND_POOL_free(drbg->pool); drbg->pool = NULL; } if (drbg->parent) { size_t bytes_needed = RAND_POOL_bytes_needed(pool, 8); unsigned char *buffer = RAND_POOL_add_begin(pool, bytes_needed); if (buffer != NULL) { size_t bytes = 0; /* * Get random from parent, include our state as additional input. * Our lock is already held, but we need to lock our parent before * generating bits from it. */ if (drbg->parent->lock) CRYPTO_THREAD_write_lock(drbg->parent->lock); if (RAND_DRBG_generate(drbg->parent, buffer, bytes_needed, 0, (unsigned char *)drbg, sizeof(*drbg)) != 0) bytes = bytes_needed; if (drbg->parent->lock) CRYPTO_THREAD_unlock(drbg->parent->lock); entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes); } } else { /* Get entropy by polling system entropy sources. */ entropy_available = RAND_POOL_acquire_entropy(pool); } if (entropy_available > 0) { ret = RAND_POOL_length(pool); *pout = RAND_POOL_detach(pool); } RAND_POOL_free(pool); return ret; }
/* * RAND_poll() reseeds the default RNG using random input * * The random input is obtained from polling various entropy * sources which depend on the operating system and are * configurable via the --with-rand-seed configure option. */ int RAND_poll(void) { int ret = 0; RAND_POOL *pool = NULL; const RAND_METHOD *meth = RAND_get_rand_method(); if (meth == RAND_OpenSSL()) { /* fill random pool and seed the master DRBG */ RAND_DRBG *drbg = RAND_DRBG_get0_master(); if (drbg == NULL) return 0; CRYPTO_THREAD_write_lock(drbg->lock); ret = rand_drbg_restart(drbg, NULL, 0, 0); CRYPTO_THREAD_unlock(drbg->lock); return ret; } else { /* fill random pool and seed the current legacy RNG */ pool = RAND_POOL_new(RAND_DRBG_STRENGTH, RAND_DRBG_STRENGTH / 8, DRBG_MINMAX_FACTOR * (RAND_DRBG_STRENGTH / 8)); if (pool == NULL) return 0; if (RAND_POOL_acquire_entropy(pool) == 0) goto err; if (meth->add == NULL || meth->add(RAND_POOL_buffer(pool), RAND_POOL_length(pool), (RAND_POOL_entropy(pool) / 8.0)) == 0) goto err; ret = 1; } err: RAND_POOL_free(pool); return ret; }
/* * Generate additional data that can be used for the drbg. The data does * not need to contain entropy, but it's useful if it contains at least * some bits that are unpredictable. * * Returns 0 on failure. * * On success it allocates a buffer at |*pout| and returns the length of * the data. The buffer should get freed using OPENSSL_secure_clear_free(). */ size_t rand_drbg_get_additional_data(unsigned char **pout, size_t max_len) { RAND_POOL *pool; CRYPTO_THREAD_ID thread_id; size_t len; #ifdef OPENSSL_SYS_UNIX pid_t pid; #elif defined(OPENSSL_SYS_WIN32) DWORD pid; #endif uint64_t tbits; pool = RAND_POOL_new(0, 0, max_len); if (pool == NULL) return 0; #ifdef OPENSSL_SYS_UNIX pid = getpid(); RAND_POOL_add(pool, (unsigned char *)&pid, sizeof(pid), 0); #elif defined(OPENSSL_SYS_WIN32) pid = GetCurrentProcessId(); RAND_POOL_add(pool, (unsigned char *)&pid, sizeof(pid), 0); #endif thread_id = CRYPTO_THREAD_get_current_id(); if (thread_id != 0) RAND_POOL_add(pool, (unsigned char *)&thread_id, sizeof(thread_id), 0); tbits = get_timer_bits(); if (tbits != 0) RAND_POOL_add(pool, (unsigned char *)&tbits, sizeof(tbits), 0); /* TODO: Use RDSEED? */ len = RAND_POOL_length(pool); if (len != 0) *pout = RAND_POOL_detach(pool); RAND_POOL_free(pool); return len; }