/* Implements the default OpenSSL RAND_add() method */ static int drbg_add(const void *buf, int num, double randomness) { int ret = 0; RAND_DRBG *drbg = RAND_DRBG_get0_master(); size_t buflen; size_t seedlen; if (drbg == NULL) return 0; if (num < 0 || randomness < 0.0) return 0; rand_drbg_lock(drbg); seedlen = rand_drbg_seedlen(drbg); buflen = (size_t)num; if (buflen < seedlen || randomness < (double) seedlen) { #if defined(OPENSSL_RAND_SEED_NONE) /* * If no os entropy source is available, a reseeding will fail * inevitably. So we use a trick to mix the buffer contents into * the DRBG state without forcing a reseeding: we generate a * dummy random byte, using the buffer content as additional data. * Note: This won't work with RAND_DRBG_FLAG_CTR_NO_DF. */ unsigned char dummy[1]; ret = RAND_DRBG_generate(drbg, dummy, sizeof(dummy), 0, buf, buflen); rand_drbg_unlock(drbg); return ret; #else /* * If an os entropy source is avaible then we declare the buffer content * as additional data by setting randomness to zero and trigger a regular * reseeding. */ randomness = 0.0; #endif } if (randomness > (double)seedlen) { /* * The purpose of this check is to bound |randomness| by a * relatively small value in order to prevent an integer * overflow when multiplying by 8 in the rand_drbg_restart() * call below. Note that randomness is measured in bytes, * not bits, so this value corresponds to eight times the * security strength. */ randomness = (double)seedlen; } ret = rand_drbg_restart(drbg, buf, buflen, (size_t)(8 * randomness)); rand_drbg_unlock(drbg); return ret; }
/* * Allocate memory and initialize a new DRBG. The DRBG is allocated on * the secure heap if |secure| is nonzero and the secure heap is enabled. * The |parent|, if not NULL, will be used as random source for reseeding. * * Returns a pointer to the new DRBG instance on success, NULL on failure. */ static RAND_DRBG *rand_drbg_new(int secure, int type, unsigned int flags, RAND_DRBG *parent) { RAND_DRBG *drbg = secure ? OPENSSL_secure_zalloc(sizeof(*drbg)) : OPENSSL_zalloc(sizeof(*drbg)); if (drbg == NULL) { RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE); return NULL; } drbg->secure = secure && CRYPTO_secure_allocated(drbg); drbg->fork_count = rand_fork_count; drbg->parent = parent; if (parent == NULL) { drbg->reseed_interval = master_reseed_interval; drbg->reseed_time_interval = master_reseed_time_interval; } else { drbg->reseed_interval = slave_reseed_interval; drbg->reseed_time_interval = slave_reseed_time_interval; } if (RAND_DRBG_set(drbg, type, flags) == 0) goto err; if (parent != NULL) { rand_drbg_lock(parent); if (drbg->strength > parent->strength) { /* * We currently don't support the algorithm from NIST SP 800-90C * 10.1.2 to use a weaker DRBG as source */ rand_drbg_unlock(parent); RANDerr(RAND_F_RAND_DRBG_NEW, RAND_R_PARENT_STRENGTH_TOO_WEAK); goto err; } rand_drbg_unlock(parent); } if (!RAND_DRBG_set_callbacks(drbg, rand_drbg_get_entropy, rand_drbg_cleanup_entropy, NULL, NULL)) goto err; return drbg; err: if (drbg->secure) OPENSSL_secure_free(drbg); else OPENSSL_free(drbg); return NULL; }
/* Implements the default OpenSSL RAND_add() method */ static int drbg_add(const void *buf, int num, double randomness) { int ret = 0; RAND_DRBG *drbg = RAND_DRBG_get0_master(); if (drbg == NULL) return 0; if (num < 0 || randomness < 0.0) return 0; if (randomness > (double)drbg->max_entropylen) { /* * The purpose of this check is to bound |randomness| by a * relatively small value in order to prevent an integer * overflow when multiplying by 8 in the rand_drbg_restart() * call below. */ return 0; } rand_drbg_lock(drbg); ret = rand_drbg_restart(drbg, buf, (size_t)(unsigned int)num, (size_t)(8*randomness)); rand_drbg_unlock(drbg); return ret; }
/* * 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. (Note: taking the lock will be a no-op * if locking if drbg->parent->lock == NULL.) */ rand_drbg_lock(drbg->parent); if (RAND_DRBG_generate(drbg->parent, buffer, bytes_needed, 0, (unsigned char *)drbg, sizeof(*drbg)) != 0) bytes = bytes_needed; rand_drbg_unlock(drbg->parent); 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; }
/* Implements the default OpenSSL RAND_status() method */ static int drbg_status(void) { int ret; RAND_DRBG *drbg = RAND_DRBG_get0_master(); if (drbg == NULL) return 0; rand_drbg_lock(drbg); ret = drbg->state == DRBG_READY ? 1 : 0; rand_drbg_unlock(drbg); 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; rand_drbg_lock(drbg); ret = rand_drbg_restart(drbg, NULL, 0, 0); rand_drbg_unlock(drbg); 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; }
/* * This function is not part of RAND_METHOD, so if we're not using * the default method, then just call RAND_bytes(). Otherwise make * sure we're instantiated and use the private DRBG. */ int RAND_priv_bytes(unsigned char *buf, int num) { const RAND_METHOD *meth = RAND_get_rand_method(); RAND_DRBG *drbg; int ret; if (meth != RAND_OpenSSL()) return RAND_bytes(buf, num); drbg = RAND_DRBG_get0_private(); if (drbg == NULL) return 0; /* We have to lock the DRBG before generating bits from it. */ rand_drbg_lock(drbg); ret = RAND_DRBG_bytes(drbg, buf, num); rand_drbg_unlock(drbg); return ret; }
/* * Allocate memory and initialize a new DRBG. The DRBG is allocated on * the secure heap if |secure| is nonzero and the secure heap is enabled. * The |parent|, if not NULL, will be used as random source for reseeding. * * Returns a pointer to the new DRBG instance on success, NULL on failure. */ static RAND_DRBG *rand_drbg_new(int secure, int type, unsigned int flags, RAND_DRBG *parent) { RAND_DRBG *drbg = secure ? OPENSSL_secure_zalloc(sizeof(*drbg)) : OPENSSL_zalloc(sizeof(*drbg)); if (drbg == NULL) { RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE); return NULL; } drbg->secure = secure && CRYPTO_secure_allocated(drbg); drbg->fork_count = rand_fork_count; drbg->parent = parent; if (parent == NULL) { drbg->get_entropy = rand_drbg_get_entropy; drbg->cleanup_entropy = rand_drbg_cleanup_entropy; #ifndef RAND_DRBG_GET_RANDOM_NONCE drbg->get_nonce = rand_drbg_get_nonce; drbg->cleanup_nonce = rand_drbg_cleanup_nonce; #endif drbg->reseed_interval = master_reseed_interval; drbg->reseed_time_interval = master_reseed_time_interval; } else { drbg->get_entropy = rand_drbg_get_entropy; drbg->cleanup_entropy = rand_drbg_cleanup_entropy; /* * Do not provide nonce callbacks, the child DRBGs will * obtain their nonce using random bits from the parent. */ drbg->reseed_interval = slave_reseed_interval; drbg->reseed_time_interval = slave_reseed_time_interval; } if (RAND_DRBG_set(drbg, type, flags) == 0) goto err; if (parent != NULL) { rand_drbg_lock(parent); if (drbg->strength > parent->strength) { /* * We currently don't support the algorithm from NIST SP 800-90C * 10.1.2 to use a weaker DRBG as source */ rand_drbg_unlock(parent); RANDerr(RAND_F_RAND_DRBG_NEW, RAND_R_PARENT_STRENGTH_TOO_WEAK); goto err; } rand_drbg_unlock(parent); } return drbg; err: if (drbg->secure) OPENSSL_secure_free(drbg); else OPENSSL_free(drbg); return NULL; }