/* * Generates |outlen| random bytes and stores them in |out|. It will * using the given |drbg| to generate the bytes. * * Requires that drbg->lock is already locked for write, if non-null. * * Returns 1 on success 0 on failure. */ int RAND_DRBG_bytes(RAND_DRBG *drbg, unsigned char *out, size_t outlen) { unsigned char *additional = NULL; size_t additional_len; size_t chunk; size_t ret = 0; if (drbg->adin_pool == NULL) { if (drbg->type == 0) goto err; drbg->adin_pool = rand_pool_new(0, 0, drbg->max_adinlen); if (drbg->adin_pool == NULL) goto err; } additional_len = rand_drbg_get_additional_data(drbg->adin_pool, &additional); for ( ; outlen > 0; outlen -= chunk, out += chunk) { chunk = outlen; if (chunk > drbg->max_request) chunk = drbg->max_request; ret = RAND_DRBG_generate(drbg, out, chunk, 0, additional, additional_len); if (!ret) goto err; } ret = 1; err: if (additional != NULL) rand_drbg_cleanup_additional_data(drbg->adin_pool, additional); return ret; }
/* * Restart |drbg|, using the specified entropy or additional input * * Tries its best to get the drbg instantiated by all means, * regardless of its current state. * * Optionally, a |buffer| of |len| random bytes can be passed, * which is assumed to contain at least |entropy| bits of entropy. * * If |entropy| > 0, the buffer content is used as entropy input. * * If |entropy| == 0, the buffer content is used as additional input * * Returns 1 on success, 0 on failure. * * This function is used internally only. */ int rand_drbg_restart(RAND_DRBG *drbg, const unsigned char *buffer, size_t len, size_t entropy) { int reseeded = 0; const unsigned char *adin = NULL; size_t adinlen = 0; if (drbg->pool != NULL) { RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR); rand_pool_free(drbg->pool); drbg->pool = NULL; } if (buffer != NULL) { if (entropy > 0) { if (drbg->max_entropylen < len) { RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_INPUT_TOO_LONG); return 0; } if (entropy > 8 * len) { RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_OUT_OF_RANGE); return 0; } /* will be picked up by the rand_drbg_get_entropy() callback */ drbg->pool = rand_pool_new(entropy, len, len); if (drbg->pool == NULL) return 0; rand_pool_add(drbg->pool, buffer, len, entropy); } else { if (drbg->max_adinlen < len) { RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ADDITIONAL_INPUT_TOO_LONG); return 0; } adin = buffer; adinlen = len; } } /* repair error state */ if (drbg->state == DRBG_ERROR) RAND_DRBG_uninstantiate(drbg); /* repair uninitialized state */ if (drbg->state == DRBG_UNINITIALISED) { /* reinstantiate drbg */ RAND_DRBG_instantiate(drbg, (const unsigned char *) ossl_pers_string, sizeof(ossl_pers_string) - 1); /* already reseeded. prevent second reseeding below */ reseeded = (drbg->state == DRBG_READY); } /* refresh current state if entropy or additional input has been provided */ if (drbg->state == DRBG_READY) { if (adin != NULL) { /* * mix in additional input without reseeding * * Similar to RAND_DRBG_reseed(), but the provided additional * data |adin| is mixed into the current state without pulling * entropy from the trusted entropy source using get_entropy(). * This is not a reseeding in the strict sense of NIST SP 800-90A. */ drbg->meth->reseed(drbg, adin, adinlen, NULL, 0); } else if (reseeded == 0) { /* do a full reseeding if it has not been done yet above */ RAND_DRBG_reseed(drbg, NULL, 0, 0); } } /* check whether a given entropy pool was cleared properly during reseed */ if (drbg->pool != NULL) { drbg->state = DRBG_ERROR; RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR); rand_pool_free(drbg->pool); drbg->pool = NULL; return 0; } return drbg->state == DRBG_READY; }