123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- /*
- * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License").
- * You may not use this file except in compliance with the License.
- * A copy of the License is located at
- *
- * http://aws.amazon.com/apache2.0
- *
- * or in the "license" file accompanying this file. This file is distributed
- * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
- #include "crypto/s2n_drbg.h"
- #include <openssl/evp.h>
- #include <sys/param.h>
- #include "utils/s2n_blob.h"
- #include "utils/s2n_random.h"
- #include "utils/s2n_safety.h"
- static bool ignore_prediction_resistance_for_testing = false;
- #define s2n_drbg_key_size(drgb) EVP_CIPHER_CTX_key_length((drbg)->ctx)
- #define s2n_drbg_seed_size(drgb) (S2N_DRBG_BLOCK_SIZE + s2n_drbg_key_size(drgb))
- /* This function is the same as s2n_increment_sequence_number
- but it does not check for overflow, since overflow is
- acceptable in DRBG */
- S2N_RESULT s2n_increment_drbg_counter(struct s2n_blob *counter)
- {
- for (uint32_t i = (uint32_t) counter->size; i > 0; i--) {
- counter->data[i - 1] += 1;
- if (counter->data[i - 1]) {
- break;
- }
- /* seq[i] wrapped, so let it carry */
- }
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_drbg_block_encrypt(EVP_CIPHER_CTX *ctx, uint8_t in[S2N_DRBG_BLOCK_SIZE], uint8_t out[S2N_DRBG_BLOCK_SIZE])
- {
- RESULT_ENSURE_REF(ctx);
- /* len is set by EVP_EncryptUpdate and checked post operation */
- int len = S2N_DRBG_BLOCK_SIZE;
- RESULT_GUARD_OSSL(EVP_EncryptUpdate(ctx, out, &len, in, S2N_DRBG_BLOCK_SIZE), S2N_ERR_DRBG);
- RESULT_ENSURE_EQ(len, S2N_DRBG_BLOCK_SIZE);
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_drbg_bits(struct s2n_drbg *drbg, struct s2n_blob *out)
- {
- RESULT_ENSURE_REF(drbg);
- RESULT_ENSURE_REF(drbg->ctx);
- RESULT_ENSURE_REF(out);
- struct s2n_blob value = { 0 };
- RESULT_GUARD_POSIX(s2n_blob_init(&value, drbg->v, sizeof(drbg->v)));
- uint32_t block_aligned_size = out->size - (out->size % S2N_DRBG_BLOCK_SIZE);
- /* Per NIST SP800-90A 10.2.1.2: */
- for (size_t i = 0; i < block_aligned_size; i += S2N_DRBG_BLOCK_SIZE) {
- RESULT_GUARD(s2n_increment_drbg_counter(&value));
- RESULT_GUARD(s2n_drbg_block_encrypt(drbg->ctx, drbg->v, out->data + i));
- drbg->bytes_used += S2N_DRBG_BLOCK_SIZE;
- }
- if (out->size <= block_aligned_size) {
- return S2N_RESULT_OK;
- }
- uint8_t spare_block[S2N_DRBG_BLOCK_SIZE];
- RESULT_GUARD(s2n_increment_drbg_counter(&value));
- RESULT_GUARD(s2n_drbg_block_encrypt(drbg->ctx, drbg->v, spare_block));
- drbg->bytes_used += S2N_DRBG_BLOCK_SIZE;
- RESULT_CHECKED_MEMCPY(out->data + block_aligned_size, spare_block, out->size - block_aligned_size);
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_drbg_update(struct s2n_drbg *drbg, struct s2n_blob *provided_data)
- {
- RESULT_ENSURE_REF(drbg);
- RESULT_ENSURE_REF(drbg->ctx);
- RESULT_ENSURE_REF(provided_data);
- RESULT_STACK_BLOB(temp_blob, s2n_drbg_seed_size(drgb), S2N_DRBG_MAX_SEED_SIZE);
- RESULT_ENSURE_EQ(provided_data->size, (uint32_t) s2n_drbg_seed_size(drbg));
- RESULT_GUARD(s2n_drbg_bits(drbg, &temp_blob));
- /* XOR in the provided data */
- for (uint32_t i = 0; i < provided_data->size; i++) {
- temp_blob.data[i] ^= provided_data->data[i];
- }
- /* Update the key and value */
- RESULT_GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, NULL, NULL, temp_blob.data, NULL), S2N_ERR_DRBG);
- RESULT_CHECKED_MEMCPY(drbg->v, temp_blob.data + s2n_drbg_key_size(drbg), S2N_DRBG_BLOCK_SIZE);
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_drbg_mix_in_entropy(struct s2n_drbg *drbg, struct s2n_blob *entropy, struct s2n_blob *ps)
- {
- RESULT_ENSURE_REF(drbg);
- RESULT_ENSURE_REF(drbg->ctx);
- RESULT_ENSURE_REF(entropy);
- RESULT_ENSURE_GTE(entropy->size, ps->size);
- for (uint32_t i = 0; i < ps->size; i++) {
- entropy->data[i] ^= ps->data[i];
- }
- RESULT_GUARD(s2n_drbg_update(drbg, entropy));
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_drbg_seed(struct s2n_drbg *drbg, struct s2n_blob *ps)
- {
- RESULT_STACK_BLOB(blob, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE);
- RESULT_GUARD(s2n_get_seed_entropy(&blob));
- RESULT_GUARD(s2n_drbg_mix_in_entropy(drbg, &blob, ps));
- drbg->bytes_used = 0;
- return S2N_RESULT_OK;
- }
- static S2N_RESULT s2n_drbg_mix(struct s2n_drbg *drbg, struct s2n_blob *ps)
- {
- if (s2n_unlikely(ignore_prediction_resistance_for_testing)) {
- RESULT_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST);
- return S2N_RESULT_OK;
- }
- RESULT_STACK_BLOB(blob, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE);
- RESULT_GUARD(s2n_get_mix_entropy(&blob));
- RESULT_GUARD(s2n_drbg_mix_in_entropy(drbg, &blob, ps));
- drbg->mixes += 1;
- return S2N_RESULT_OK;
- }
- S2N_RESULT s2n_drbg_instantiate(struct s2n_drbg *drbg, struct s2n_blob *personalization_string, const s2n_drbg_mode mode)
- {
- RESULT_ENSURE_REF(drbg);
- RESULT_ENSURE_REF(personalization_string);
- drbg->ctx = EVP_CIPHER_CTX_new();
- RESULT_GUARD_PTR(drbg->ctx);
- RESULT_EVP_CTX_INIT(drbg->ctx);
- switch (mode) {
- case S2N_AES_128_CTR_NO_DF_PR:
- RESULT_GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, EVP_aes_128_ecb(), NULL, NULL, NULL), S2N_ERR_DRBG);
- break;
- case S2N_AES_256_CTR_NO_DF_PR:
- RESULT_GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, EVP_aes_256_ecb(), NULL, NULL, NULL), S2N_ERR_DRBG);
- break;
- default:
- RESULT_BAIL(S2N_ERR_DRBG);
- }
- RESULT_ENSURE_LTE(s2n_drbg_key_size(drbg), S2N_DRBG_MAX_KEY_SIZE);
- RESULT_ENSURE_LTE(s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE);
- static const uint8_t zero_key[S2N_DRBG_MAX_KEY_SIZE] = { 0 };
- /* Start off with zeroed data, per 10.2.1.3.1 item 4 and 5 */
- memset(drbg->v, 0, sizeof(drbg->v));
- RESULT_GUARD_OSSL(EVP_EncryptInit_ex(drbg->ctx, NULL, NULL, zero_key, NULL), S2N_ERR_DRBG);
- /* Copy the personalization string */
- RESULT_STACK_BLOB(ps, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE);
- RESULT_GUARD_POSIX(s2n_blob_zero(&ps));
- RESULT_CHECKED_MEMCPY(ps.data, personalization_string->data, MIN(ps.size, personalization_string->size));
- /* Seed the DRBG */
- RESULT_GUARD(s2n_drbg_seed(drbg, &ps));
- return S2N_RESULT_OK;
- }
- S2N_RESULT s2n_drbg_generate(struct s2n_drbg *drbg, struct s2n_blob *blob)
- {
- RESULT_ENSURE_REF(drbg);
- RESULT_ENSURE_REF(drbg->ctx);
- RESULT_STACK_BLOB(zeros, s2n_drbg_seed_size(drbg), S2N_DRBG_MAX_SEED_SIZE);
- RESULT_ENSURE(blob->size <= S2N_DRBG_GENERATE_LIMIT, S2N_ERR_DRBG_REQUEST_SIZE);
- /* Mix in additional entropy for every randomness generation call. This
- * defense mechanism is referred to as "prediction resistance".
- * If we ever relax this defense, we must:
- * 1. Implement reseeding according to limit specified in
- * NIST SP800-90A 10.2.1 Table 3.
- * 2. Re-consider whether the current fork detection strategy is still
- * sufficient.
- */
- RESULT_GUARD(s2n_drbg_mix(drbg, &zeros));
- RESULT_GUARD(s2n_drbg_bits(drbg, blob));
- RESULT_GUARD(s2n_drbg_update(drbg, &zeros));
- return S2N_RESULT_OK;
- }
- S2N_RESULT s2n_drbg_wipe(struct s2n_drbg *drbg)
- {
- RESULT_ENSURE_REF(drbg);
- if (drbg->ctx) {
- RESULT_GUARD_OSSL(EVP_CIPHER_CTX_cleanup(drbg->ctx), S2N_ERR_DRBG);
- EVP_CIPHER_CTX_free(drbg->ctx);
- drbg->ctx = NULL;
- }
- *drbg = (struct s2n_drbg){ 0 };
- return S2N_RESULT_OK;
- }
- S2N_RESULT s2n_drbg_bytes_used(struct s2n_drbg *drbg, uint64_t *bytes_used)
- {
- RESULT_ENSURE_REF(drbg);
- RESULT_ENSURE_REF(bytes_used);
- *bytes_used = drbg->bytes_used;
- return S2N_RESULT_OK;
- }
- S2N_RESULT s2n_ignore_prediction_resistance_for_testing(bool ignore_bool)
- {
- RESULT_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST);
- ignore_prediction_resistance_for_testing = ignore_bool;
- return S2N_RESULT_OK;
- }
|