blob: fdd753d1cdf0678ac4ba09141f7f9c359241a35b [file] [log] [blame]
Paul Bakker0e04d0e2011-11-27 14:46:59 +00001/*
2 * CTR_DRBG implementation based on AES-256 (NIST SP 800-90)
3 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Paul Bakker0e04d0e2011-11-27 14:46:59 +000018 */
19/*
Paul Sokolovsky8d6d8c82018-02-10 11:11:41 +020020 * The NIST SP 800-90 DRBGs are described in the following publication.
Paul Bakker0e04d0e2011-11-27 14:46:59 +000021 *
Tom Cosgrovece37c5e2023-08-04 13:53:36 +010022 * https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-90r.pdf
Paul Bakker0e04d0e2011-11-27 14:46:59 +000023 */
24
Gilles Peskinedb09ef62020-06-03 01:43:33 +020025#include "common.h"
Paul Bakker0e04d0e2011-11-27 14:46:59 +000026
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020027#if defined(MBEDTLS_CTR_DRBG_C)
Paul Bakker0e04d0e2011-11-27 14:46:59 +000028
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000029#include "mbedtls/ctr_drbg.h"
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -050030#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000031#include "mbedtls/error.h"
Paul Bakker0e04d0e2011-11-27 14:46:59 +000032
Rich Evans00ab4702015-02-06 13:43:58 +000033#include <string.h>
34
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020035#if defined(MBEDTLS_FS_IO)
Paul Bakkerfc754a92011-12-05 13:23:51 +000036#include <stdio.h>
37#endif
38
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000039#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010040
Paul Bakker18d32912011-12-10 21:42:49 +000041/*
Manuel Pégourié-Gonnard8d128ef2015-04-28 22:38:08 +020042 * CTR_DRBG context initialization
43 */
Gilles Peskine449bd832023-01-11 14:50:10 +010044void mbedtls_ctr_drbg_init(mbedtls_ctr_drbg_context *ctx)
Manuel Pégourié-Gonnard8d128ef2015-04-28 22:38:08 +020045{
Gilles Peskine449bd832023-01-11 14:50:10 +010046 memset(ctx, 0, sizeof(mbedtls_ctr_drbg_context));
47 mbedtls_aes_init(&ctx->aes_ctx);
Gilles Peskinee9a34542019-10-22 20:43:24 +020048 /* Indicate that the entropy nonce length is not set explicitly.
49 * See mbedtls_ctr_drbg_set_nonce_len(). */
50 ctx->reseed_counter = -1;
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +010051
Gavin Acquroff6aceb512020-03-01 17:06:11 -080052 ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
Manuel Pégourié-Gonnard8d128ef2015-04-28 22:38:08 +020053}
54
Gavin Acquroff6aceb512020-03-01 17:06:11 -080055/*
56 * This function resets CTR_DRBG context to the state immediately
57 * after initial call of mbedtls_ctr_drbg_init().
58 */
Gilles Peskine449bd832023-01-11 14:50:10 +010059void mbedtls_ctr_drbg_free(mbedtls_ctr_drbg_context *ctx)
Paul Bakkerfff03662014-06-18 16:21:25 +020060{
Gilles Peskine449bd832023-01-11 14:50:10 +010061 if (ctx == NULL) {
Paul Bakkerfff03662014-06-18 16:21:25 +020062 return;
Gilles Peskine449bd832023-01-11 14:50:10 +010063 }
Paul Bakkerfff03662014-06-18 16:21:25 +020064
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +010065#if defined(MBEDTLS_THREADING_C)
Gilles Peskineda290f92021-02-09 18:44:02 +010066 /* The mutex is initialized iff f_entropy is set. */
Gilles Peskine449bd832023-01-11 14:50:10 +010067 if (ctx->f_entropy != NULL) {
68 mbedtls_mutex_free(&ctx->mutex);
69 }
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +010070#endif
Gilles Peskine449bd832023-01-11 14:50:10 +010071 mbedtls_aes_free(&ctx->aes_ctx);
72 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ctr_drbg_context));
Gavin Acquroff6aceb512020-03-01 17:06:11 -080073 ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
74 ctx->reseed_counter = -1;
Paul Bakkerfff03662014-06-18 16:21:25 +020075}
76
Gilles Peskine449bd832023-01-11 14:50:10 +010077void mbedtls_ctr_drbg_set_prediction_resistance(mbedtls_ctr_drbg_context *ctx,
78 int resistance)
Paul Bakker0e04d0e2011-11-27 14:46:59 +000079{
80 ctx->prediction_resistance = resistance;
81}
82
Gilles Peskine449bd832023-01-11 14:50:10 +010083void mbedtls_ctr_drbg_set_entropy_len(mbedtls_ctr_drbg_context *ctx,
84 size_t len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +000085{
86 ctx->entropy_len = len;
87}
Paul Bakkerb6c5d2e2013-06-25 16:25:17 +020088
Gilles Peskine449bd832023-01-11 14:50:10 +010089int mbedtls_ctr_drbg_set_nonce_len(mbedtls_ctr_drbg_context *ctx,
90 size_t len)
Gilles Peskine9be50982019-10-22 18:42:27 +020091{
92 /* If mbedtls_ctr_drbg_seed() has already been called, it's
93 * too late. Return the error code that's closest to making sense. */
Gilles Peskine449bd832023-01-11 14:50:10 +010094 if (ctx->f_entropy != NULL) {
95 return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
96 }
Gilles Peskine9be50982019-10-22 18:42:27 +020097
Gilles Peskine449bd832023-01-11 14:50:10 +010098 if (len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) {
99 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
100 }
Dave Rodgman4a5c9ee2023-02-10 16:03:44 +0000101
Gilles Peskine9be50982019-10-22 18:42:27 +0200102 /* This shouldn't be an issue because
103 * MBEDTLS_CTR_DRBG_MAX_SEED_INPUT < INT_MAX in any sensible
104 * configuration, but make sure anyway. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100105 if (len > INT_MAX) {
106 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
107 }
Gilles Peskine9be50982019-10-22 18:42:27 +0200108
109 /* For backward compatibility with Mbed TLS <= 2.19, store the
110 * entropy nonce length in a field that already exists, but isn't
111 * used until after the initial seeding. */
112 /* Due to the capping of len above, the value fits in an int. */
113 ctx->reseed_counter = (int) len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100114 return 0;
Gilles Peskine9be50982019-10-22 18:42:27 +0200115}
116
Gilles Peskine449bd832023-01-11 14:50:10 +0100117void mbedtls_ctr_drbg_set_reseed_interval(mbedtls_ctr_drbg_context *ctx,
118 int interval)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000119{
120 ctx->reseed_interval = interval;
121}
Paul Bakkerb6c5d2e2013-06-25 16:25:17 +0200122
Gilles Peskine449bd832023-01-11 14:50:10 +0100123static int block_cipher_df(unsigned char *output,
124 const unsigned char *data, size_t data_len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000125{
Hanno Beckera08651f2018-10-05 09:38:59 +0100126 unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
127 MBEDTLS_CTR_DRBG_BLOCKSIZE + 16];
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200128 unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
129 unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
130 unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE];
Manuel Pégourié-Gonnard7c593632014-01-20 10:27:13 +0100131 unsigned char *p, *iv;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200132 mbedtls_aes_context aes_ctx;
Dvir Markovich1b364992017-06-26 13:43:34 +0300133 int ret = 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000134
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200135 int i, j;
136 size_t buf_len, use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000137
Gilles Peskine449bd832023-01-11 14:50:10 +0100138 if (data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) {
139 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
140 }
Manuel Pégourié-Gonnard5cb4b312014-11-25 17:41:50 +0100141
Gilles Peskine449bd832023-01-11 14:50:10 +0100142 memset(buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
143 MBEDTLS_CTR_DRBG_BLOCKSIZE + 16);
144 mbedtls_aes_init(&aes_ctx);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000145
146 /*
147 * Construct IV (16 bytes) and S in buffer
148 * IV = Counter (in 32-bits) padded to 16 with zeroes
149 * S = Length input string (in 32-bits) || Length of output (in 32-bits) ||
150 * data || 0x80
151 * (Total is padded to a multiple of 16-bytes with zeroes)
152 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200153 p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE;
Gilles Peskine449bd832023-01-11 14:50:10 +0100154 MBEDTLS_PUT_UINT32_BE(data_len, p, 0);
Joe Subbiania5cb0d22021-08-23 11:35:25 +0100155 p += 4 + 3;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200156 *p++ = MBEDTLS_CTR_DRBG_SEEDLEN;
Gilles Peskine449bd832023-01-11 14:50:10 +0100157 memcpy(p, data, data_len);
Paul Bakker2bc7cf12011-11-29 10:50:51 +0000158 p[data_len] = 0x80;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000159
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200160 buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000161
Gilles Peskine449bd832023-01-11 14:50:10 +0100162 for (i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000163 key[i] = i;
Gilles Peskine449bd832023-01-11 14:50:10 +0100164 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000165
Gilles Peskine449bd832023-01-11 14:50:10 +0100166 if ((ret = mbedtls_aes_setkey_enc(&aes_ctx, key,
167 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300168 goto exit;
169 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000170
171 /*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200172 * Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000173 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100174 for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000175 p = buf;
Gilles Peskine449bd832023-01-11 14:50:10 +0100176 memset(chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000177 use_len = buf_len;
178
Gilles Peskine449bd832023-01-11 14:50:10 +0100179 while (use_len > 0) {
180 mbedtls_xor(chain, chain, p, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200181 p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
Gilles Peskine449bd832023-01-11 14:50:10 +0100182 use_len -= (use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE) ?
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200183 MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000184
Gilles Peskine449bd832023-01-11 14:50:10 +0100185 if ((ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT,
186 chain, chain)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300187 goto exit;
188 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000189 }
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200190
Gilles Peskine449bd832023-01-11 14:50:10 +0100191 memcpy(tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000192
193 /*
194 * Update IV
195 */
196 buf[3]++;
197 }
198
199 /*
200 * Do final encryption with reduced data
201 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100202 if ((ret = mbedtls_aes_setkey_enc(&aes_ctx, tmp,
203 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300204 goto exit;
205 }
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200206 iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000207 p = output;
208
Gilles Peskine449bd832023-01-11 14:50:10 +0100209 for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
210 if ((ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT,
211 iv, iv)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300212 goto exit;
213 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100214 memcpy(p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200215 p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000216 }
Dvir Markovich1b364992017-06-26 13:43:34 +0300217exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100218 mbedtls_aes_free(&aes_ctx);
Dvir Markovich1b364992017-06-26 13:43:34 +0300219 /*
Gilles Peskine449bd832023-01-11 14:50:10 +0100220 * tidy up the stack
221 */
222 mbedtls_platform_zeroize(buf, sizeof(buf));
223 mbedtls_platform_zeroize(tmp, sizeof(tmp));
224 mbedtls_platform_zeroize(key, sizeof(key));
225 mbedtls_platform_zeroize(chain, sizeof(chain));
226 if (0 != ret) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300227 /*
Gilles Peskine449bd832023-01-11 14:50:10 +0100228 * wipe partial seed from memory
229 */
230 mbedtls_platform_zeroize(output, MBEDTLS_CTR_DRBG_SEEDLEN);
Dvir Markovich1b364992017-06-26 13:43:34 +0300231 }
Paul Bakkerc7ea99a2014-06-18 11:12:03 +0200232
Gilles Peskine449bd832023-01-11 14:50:10 +0100233 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000234}
235
Gilles Peskineed7da592018-08-03 20:16:52 +0200236/* CTR_DRBG_Update (SP 800-90A &sect;10.2.1.2)
237 * ctr_drbg_update_internal(ctx, provided_data)
238 * implements
239 * CTR_DRBG_Update(provided_data, Key, V)
240 * with inputs and outputs
241 * ctx->aes_ctx = Key
242 * ctx->counter = V
243 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100244static int ctr_drbg_update_internal(mbedtls_ctr_drbg_context *ctx,
245 const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN])
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000246{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200247 unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000248 unsigned char *p = tmp;
Paul Bakker369e14b2012-04-18 14:16:09 +0000249 int i, j;
Dvir Markovich1b364992017-06-26 13:43:34 +0300250 int ret = 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000251
Gilles Peskine449bd832023-01-11 14:50:10 +0100252 memset(tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000253
Gilles Peskine449bd832023-01-11 14:50:10 +0100254 for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000255 /*
256 * Increase counter
257 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100258 for (i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i--) {
259 if (++ctx->counter[i - 1] != 0) {
Paul Bakker369e14b2012-04-18 14:16:09 +0000260 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100261 }
262 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000263
264 /*
265 * Crypt counter block
266 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100267 if ((ret = mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
268 ctx->counter, p)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200269 goto exit;
Dvir Markovich1b364992017-06-26 13:43:34 +0300270 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000271
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200272 p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000273 }
274
Gilles Peskine449bd832023-01-11 14:50:10 +0100275 for (i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000276 tmp[i] ^= data[i];
Gilles Peskine449bd832023-01-11 14:50:10 +0100277 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000278
279 /*
280 * Update key and counter
281 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100282 if ((ret = mbedtls_aes_setkey_enc(&ctx->aes_ctx, tmp,
283 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200284 goto exit;
Dvir Markovich1b364992017-06-26 13:43:34 +0300285 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100286 memcpy(ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE,
287 MBEDTLS_CTR_DRBG_BLOCKSIZE);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000288
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200289exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100290 mbedtls_platform_zeroize(tmp, sizeof(tmp));
291 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000292}
293
Gilles Peskineed7da592018-08-03 20:16:52 +0200294/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
TRodziewicz26371e42021-06-08 16:45:41 +0200295 * mbedtls_ctr_drbg_update(ctx, additional, add_len)
Gilles Peskineed7da592018-08-03 20:16:52 +0200296 * implements
297 * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
298 * security_strength) -> initial_working_state
299 * with inputs
300 * ctx->counter = all-bits-0
301 * ctx->aes_ctx = context from all-bits-0 key
302 * additional[:add_len] = entropy_input || nonce || personalization_string
303 * and with outputs
304 * ctx = initial_working_state
305 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100306int mbedtls_ctr_drbg_update(mbedtls_ctr_drbg_context *ctx,
307 const unsigned char *additional,
308 size_t add_len)
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000309{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200310 unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
Janos Follath24eed8d2019-11-22 13:21:35 +0000311 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000312
Gilles Peskine449bd832023-01-11 14:50:10 +0100313 if (add_len == 0) {
314 return 0;
315 }
Manuel Pégourié-Gonnard5cb4b312014-11-25 17:41:50 +0100316
Gilles Peskine449bd832023-01-11 14:50:10 +0100317 if ((ret = block_cipher_df(add_input, additional, add_len)) != 0) {
Gilles Peskined9199932018-09-11 16:41:54 +0200318 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100319 }
320 if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
Gilles Peskined9199932018-09-11 16:41:54 +0200321 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100322 }
Gilles Peskined9199932018-09-11 16:41:54 +0200323
324exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100325 mbedtls_platform_zeroize(add_input, sizeof(add_input));
326 return ret;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000327}
328
Gilles Peskineed7da592018-08-03 20:16:52 +0200329/* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
Gilles Peskine9be50982019-10-22 18:42:27 +0200330 * mbedtls_ctr_drbg_reseed(ctx, additional, len, nonce_len)
Gilles Peskineed7da592018-08-03 20:16:52 +0200331 * implements
332 * CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
333 * -> new_working_state
334 * with inputs
335 * ctx contains working_state
336 * additional[:len] = additional_input
337 * and entropy_input comes from calling ctx->f_entropy
Gilles Peskine9be50982019-10-22 18:42:27 +0200338 * for (ctx->entropy_len + nonce_len) bytes
Gilles Peskineed7da592018-08-03 20:16:52 +0200339 * and with output
340 * ctx contains new_working_state
341 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100342static int mbedtls_ctr_drbg_reseed_internal(mbedtls_ctr_drbg_context *ctx,
343 const unsigned char *additional,
344 size_t len,
345 size_t nonce_len)
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000346{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200347 unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000348 size_t seedlen = 0;
Janos Follath24eed8d2019-11-22 13:21:35 +0000349 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000350
Gilles Peskine449bd832023-01-11 14:50:10 +0100351 if (ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) {
352 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
353 }
354 if (nonce_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len) {
355 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
356 }
357 if (len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len - nonce_len) {
358 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
359 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000360
Gilles Peskine449bd832023-01-11 14:50:10 +0100361 memset(seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT);
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000362
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200363 /* Gather entropy_len bytes of entropy to seed state. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100364 if (0 != ctx->f_entropy(ctx->p_entropy, seed, ctx->entropy_len)) {
365 return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000366 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000367 seedlen += ctx->entropy_len;
368
Gilles Peskine9be50982019-10-22 18:42:27 +0200369 /* Gather entropy for a nonce if requested. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100370 if (nonce_len != 0) {
371 if (0 != ctx->f_entropy(ctx->p_entropy, seed + seedlen, nonce_len)) {
372 return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
Gilles Peskine9be50982019-10-22 18:42:27 +0200373 }
374 seedlen += nonce_len;
375 }
376
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200377 /* Add additional data if provided. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100378 if (additional != NULL && len != 0) {
379 memcpy(seed + seedlen, additional, len);
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000380 seedlen += len;
381 }
382
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200383 /* Reduce to 384 bits. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100384 if ((ret = block_cipher_df(seed, seed, seedlen)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200385 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100386 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000387
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200388 /* Update state. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100389 if ((ret = ctr_drbg_update_internal(ctx, seed)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200390 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100391 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000392 ctx->reseed_counter = 1;
393
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200394exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100395 mbedtls_platform_zeroize(seed, sizeof(seed));
396 return ret;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000397}
Paul Bakker9af723c2014-05-01 13:03:14 +0200398
Gilles Peskine449bd832023-01-11 14:50:10 +0100399int mbedtls_ctr_drbg_reseed(mbedtls_ctr_drbg_context *ctx,
400 const unsigned char *additional, size_t len)
Gilles Peskine9be50982019-10-22 18:42:27 +0200401{
Gilles Peskine449bd832023-01-11 14:50:10 +0100402 return mbedtls_ctr_drbg_reseed_internal(ctx, additional, len, 0);
Gilles Peskine9be50982019-10-22 18:42:27 +0200403}
404
Gilles Peskinee9a34542019-10-22 20:43:24 +0200405/* Return a "good" nonce length for CTR_DRBG. The chosen nonce length
406 * is sufficient to achieve the maximum security strength given the key
407 * size and entropy length. If there is enough entropy in the initial
408 * call to the entropy function to serve as both the entropy input and
409 * the nonce, don't make a second call to get a nonce. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100410static size_t good_nonce_len(size_t entropy_len)
Gilles Peskinee9a34542019-10-22 20:43:24 +0200411{
Gilles Peskine449bd832023-01-11 14:50:10 +0100412 if (entropy_len >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2) {
413 return 0;
414 } else {
415 return (entropy_len + 1) / 2;
416 }
Gilles Peskinee9a34542019-10-22 20:43:24 +0200417}
418
Gilles Peskine8bf56132019-10-02 20:31:54 +0200419/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
Gilles Peskine379561f2019-10-18 16:57:48 +0200420 * mbedtls_ctr_drbg_seed(ctx, f_entropy, p_entropy, custom, len)
Gilles Peskine8bf56132019-10-02 20:31:54 +0200421 * implements
422 * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
423 * security_strength) -> initial_working_state
424 * with inputs
425 * custom[:len] = nonce || personalization_string
Gilles Peskine379561f2019-10-18 16:57:48 +0200426 * where entropy_input comes from f_entropy for ctx->entropy_len bytes
Gilles Peskine8bf56132019-10-02 20:31:54 +0200427 * and with outputs
428 * ctx = initial_working_state
429 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100430int mbedtls_ctr_drbg_seed(mbedtls_ctr_drbg_context *ctx,
431 int (*f_entropy)(void *, unsigned char *, size_t),
432 void *p_entropy,
433 const unsigned char *custom,
434 size_t len)
Gilles Peskine8bf56132019-10-02 20:31:54 +0200435{
Janos Follath24eed8d2019-11-22 13:21:35 +0000436 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200437 unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
Gilles Peskinee9a34542019-10-22 20:43:24 +0200438 size_t nonce_len;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200439
Gilles Peskine449bd832023-01-11 14:50:10 +0100440 memset(key, 0, MBEDTLS_CTR_DRBG_KEYSIZE);
Gilles Peskine8bf56132019-10-02 20:31:54 +0200441
Gilles Peskineda290f92021-02-09 18:44:02 +0100442 /* The mutex is initialized iff f_entropy is set. */
Gilles Peskinef4b34292021-01-30 13:05:32 +0100443#if defined(MBEDTLS_THREADING_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100444 mbedtls_mutex_init(&ctx->mutex);
Gilles Peskinef4b34292021-01-30 13:05:32 +0100445#endif
446
Gilles Peskine8bf56132019-10-02 20:31:54 +0200447 ctx->f_entropy = f_entropy;
448 ctx->p_entropy = p_entropy;
449
Gilles Peskine449bd832023-01-11 14:50:10 +0100450 if (ctx->entropy_len == 0) {
Gilles Peskine50ed86b2019-10-04 12:15:55 +0200451 ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
Gilles Peskine449bd832023-01-11 14:50:10 +0100452 }
Gilles Peskinee9a34542019-10-22 20:43:24 +0200453 /* ctx->reseed_counter contains the desired amount of entropy to
454 * grab for a nonce (see mbedtls_ctr_drbg_set_nonce_len()).
455 * If it's -1, indicating that the entropy nonce length was not set
456 * explicitly, use a sufficiently large nonce for security. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100457 nonce_len = (ctx->reseed_counter >= 0 ?
458 (size_t) ctx->reseed_counter :
459 good_nonce_len(ctx->entropy_len));
Gilles Peskinee9a34542019-10-22 20:43:24 +0200460
Gilles Peskine9be50982019-10-22 18:42:27 +0200461 /* Initialize with an empty key. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100462 if ((ret = mbedtls_aes_setkey_enc(&ctx->aes_ctx, key,
463 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
464 return ret;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200465 }
466
Gilles Peskinee9a34542019-10-22 20:43:24 +0200467 /* Do the initial seeding. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100468 if ((ret = mbedtls_ctr_drbg_reseed_internal(ctx, custom, len,
469 nonce_len)) != 0) {
470 return ret;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200471 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100472 return 0;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200473}
474
Gilles Peskineed7da592018-08-03 20:16:52 +0200475/* CTR_DRBG_Generate with derivation function (SP 800-90A &sect;10.2.1.5.2)
476 * mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len)
477 * implements
478 * CTR_DRBG_Reseed(working_state, entropy_input, additional[:add_len])
479 * -> working_state_after_reseed
480 * if required, then
481 * CTR_DRBG_Generate(working_state_after_reseed,
482 * requested_number_of_bits, additional_input)
483 * -> status, returned_bits, new_working_state
484 * with inputs
485 * ctx contains working_state
486 * requested_number_of_bits = 8 * output_len
487 * additional[:add_len] = additional_input
488 * and entropy_input comes from calling ctx->f_entropy
489 * and with outputs
490 * status = SUCCESS (this function does the reseed internally)
491 * returned_bits = output[:output_len]
492 * ctx contains new_working_state
493 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100494int mbedtls_ctr_drbg_random_with_add(void *p_rng,
495 unsigned char *output, size_t output_len,
496 const unsigned char *additional, size_t add_len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000497{
498 int ret = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200499 mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
500 unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000501 unsigned char *p = output;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200502 unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE];
Paul Bakker369e14b2012-04-18 14:16:09 +0000503 int i;
Paul Bakker23fd5ea2011-11-29 15:56:12 +0000504 size_t use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000505
Gilles Peskine449bd832023-01-11 14:50:10 +0100506 if (output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST) {
507 return MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG;
508 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000509
Gilles Peskine449bd832023-01-11 14:50:10 +0100510 if (add_len > MBEDTLS_CTR_DRBG_MAX_INPUT) {
511 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
512 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000513
Gilles Peskine449bd832023-01-11 14:50:10 +0100514 memset(add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000515
Gilles Peskine449bd832023-01-11 14:50:10 +0100516 if (ctx->reseed_counter > ctx->reseed_interval ||
517 ctx->prediction_resistance) {
518 if ((ret = mbedtls_ctr_drbg_reseed(ctx, additional, add_len)) != 0) {
519 return ret;
Dvir Markovich1b364992017-06-26 13:43:34 +0300520 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000521 add_len = 0;
522 }
523
Gilles Peskine449bd832023-01-11 14:50:10 +0100524 if (add_len > 0) {
525 if ((ret = block_cipher_df(add_input, additional, add_len)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200526 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100527 }
528 if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200529 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100530 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000531 }
532
Gilles Peskine449bd832023-01-11 14:50:10 +0100533 while (output_len > 0) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000534 /*
535 * Increase counter
536 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100537 for (i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i--) {
538 if (++ctx->counter[i - 1] != 0) {
Paul Bakker369e14b2012-04-18 14:16:09 +0000539 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100540 }
541 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000542
543 /*
544 * Crypt counter block
545 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100546 if ((ret = mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
547 ctx->counter, tmp)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200548 goto exit;
Dvir Markovich1b364992017-06-26 13:43:34 +0300549 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000550
Gilles Peskine449bd832023-01-11 14:50:10 +0100551 use_len = (output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE)
Hanno Beckera08651f2018-10-05 09:38:59 +0100552 ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000553 /*
554 * Copy random block to destination
555 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100556 memcpy(p, tmp, use_len);
Paul Bakker23fd5ea2011-11-29 15:56:12 +0000557 p += use_len;
558 output_len -= use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000559 }
560
Gilles Peskine449bd832023-01-11 14:50:10 +0100561 if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200562 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100563 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000564
565 ctx->reseed_counter++;
566
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200567exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100568 mbedtls_platform_zeroize(add_input, sizeof(add_input));
569 mbedtls_platform_zeroize(tmp, sizeof(tmp));
570 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000571}
572
Gilles Peskine449bd832023-01-11 14:50:10 +0100573int mbedtls_ctr_drbg_random(void *p_rng, unsigned char *output,
574 size_t output_len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000575{
Janos Follath24eed8d2019-11-22 13:21:35 +0000576 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100577 mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
578
579#if defined(MBEDTLS_THREADING_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100580 if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {
581 return ret;
582 }
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100583#endif
584
Gilles Peskine449bd832023-01-11 14:50:10 +0100585 ret = mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, NULL, 0);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100586
587#if defined(MBEDTLS_THREADING_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100588 if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
589 return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
590 }
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100591#endif
592
Gilles Peskine449bd832023-01-11 14:50:10 +0100593 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000594}
595
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200596#if defined(MBEDTLS_FS_IO)
Gilles Peskine449bd832023-01-11 14:50:10 +0100597int mbedtls_ctr_drbg_write_seed_file(mbedtls_ctr_drbg_context *ctx,
598 const char *path)
Paul Bakkerfc754a92011-12-05 13:23:51 +0000599{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200600 int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000601 FILE *f;
Gilles Peskine449bd832023-01-11 14:50:10 +0100602 unsigned char buf[MBEDTLS_CTR_DRBG_MAX_INPUT];
Paul Bakkerfc754a92011-12-05 13:23:51 +0000603
Gilles Peskine449bd832023-01-11 14:50:10 +0100604 if ((f = fopen(path, "wb")) == NULL) {
605 return MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
606 }
Paul Bakkerfc754a92011-12-05 13:23:51 +0000607
Gilles Peskineda0913b2022-06-30 17:03:40 +0200608 /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100609 mbedtls_setbuf(f, NULL);
Gilles Peskineda0913b2022-06-30 17:03:40 +0200610
Gilles Peskine449bd832023-01-11 14:50:10 +0100611 if ((ret = mbedtls_ctr_drbg_random(ctx, buf,
612 MBEDTLS_CTR_DRBG_MAX_INPUT)) != 0) {
Paul Bakkerc72d3f72013-05-14 13:22:41 +0200613 goto exit;
Hanno Beckera08651f2018-10-05 09:38:59 +0100614 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100615
616 if (fwrite(buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f) !=
617 MBEDTLS_CTR_DRBG_MAX_INPUT) {
618 ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
619 } else {
Andres Amaya Garcia13f41e12017-06-26 10:56:58 +0100620 ret = 0;
Hanno Beckera08651f2018-10-05 09:38:59 +0100621 }
Paul Bakkerfc754a92011-12-05 13:23:51 +0000622
Andres Amaya Garcia4e2c07c2017-06-27 16:57:26 +0100623exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100624 mbedtls_platform_zeroize(buf, sizeof(buf));
Paul Bakkerc72d3f72013-05-14 13:22:41 +0200625
Gilles Peskine449bd832023-01-11 14:50:10 +0100626 fclose(f);
627 return ret;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000628}
629
Gilles Peskine449bd832023-01-11 14:50:10 +0100630int mbedtls_ctr_drbg_update_seed_file(mbedtls_ctr_drbg_context *ctx,
631 const char *path)
Paul Bakkerfc754a92011-12-05 13:23:51 +0000632{
Andres Amaya Garcia13f41e12017-06-26 10:56:58 +0100633 int ret = 0;
Gilles Peskine82204662018-09-11 18:43:09 +0200634 FILE *f = NULL;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000635 size_t n;
Gilles Peskine449bd832023-01-11 14:50:10 +0100636 unsigned char buf[MBEDTLS_CTR_DRBG_MAX_INPUT];
Gilles Peskine82204662018-09-11 18:43:09 +0200637 unsigned char c;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000638
Gilles Peskine449bd832023-01-11 14:50:10 +0100639 if ((f = fopen(path, "rb")) == NULL) {
640 return MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
641 }
Paul Bakkerfc754a92011-12-05 13:23:51 +0000642
Gilles Peskineda0913b2022-06-30 17:03:40 +0200643 /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100644 mbedtls_setbuf(f, NULL);
Gilles Peskineda0913b2022-06-30 17:03:40 +0200645
Gilles Peskine449bd832023-01-11 14:50:10 +0100646 n = fread(buf, 1, sizeof(buf), f);
647 if (fread(&c, 1, 1, f) != 0) {
Gilles Peskine82204662018-09-11 18:43:09 +0200648 ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
649 goto exit;
Andres Amaya Garcia4e2c07c2017-06-27 16:57:26 +0100650 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100651 if (n == 0 || ferror(f)) {
Andres Amaya Garcia13f41e12017-06-26 10:56:58 +0100652 ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
Gilles Peskine82204662018-09-11 18:43:09 +0200653 goto exit;
654 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100655 fclose(f);
Gilles Peskine82204662018-09-11 18:43:09 +0200656 f = NULL;
Paul Bakkerc72d3f72013-05-14 13:22:41 +0200657
Gilles Peskine449bd832023-01-11 14:50:10 +0100658 ret = mbedtls_ctr_drbg_update(ctx, buf, n);
Gilles Peskine82204662018-09-11 18:43:09 +0200659
660exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100661 mbedtls_platform_zeroize(buf, sizeof(buf));
662 if (f != NULL) {
663 fclose(f);
664 }
665 if (ret != 0) {
666 return ret;
667 }
668 return mbedtls_ctr_drbg_write_seed_file(ctx, path);
Paul Bakkerfc754a92011-12-05 13:23:51 +0000669}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200670#endif /* MBEDTLS_FS_IO */
Paul Bakkerfc754a92011-12-05 13:23:51 +0000671
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200672#if defined(MBEDTLS_SELF_TEST)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000673
ENT\stroej170f63d02020-12-28 08:50:23 -0600674/* The CTR_DRBG NIST test vectors used here are available at
675 * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/drbg/drbgtestvectors.zip
676 *
677 * The parameters used to derive the test data are:
678 *
679 * [AES-128 use df]
680 * [PredictionResistance = True/False]
681 * [EntropyInputLen = 128]
682 * [NonceLen = 64]
683 * [PersonalizationStringLen = 128]
684 * [AdditionalInputLen = 0]
685 * [ReturnedBitsLen = 512]
686 *
687 * [AES-256 use df]
688 * [PredictionResistance = True/False]
689 * [EntropyInputLen = 256]
690 * [NonceLen = 128]
691 * [PersonalizationStringLen = 256]
692 * [AdditionalInputLen = 0]
693 * [ReturnedBitsLen = 512]
694 *
695 */
696
Gilles Peskine02e79a42019-10-07 17:06:06 +0200697#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY)
ENT\stroej1df307002020-12-26 12:41:04 -0600698static const unsigned char entropy_source_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100699{ 0x04, 0xd9, 0x49, 0xa6, 0xdc, 0xe8, 0x6e, 0xbb,
700 0xf1, 0x08, 0x77, 0x2b, 0x9e, 0x08, 0xca, 0x92,
701 0x65, 0x16, 0xda, 0x99, 0xa2, 0x59, 0xf3, 0xe8,
702 0x38, 0x7e, 0x3f, 0x6b, 0x51, 0x70, 0x7b, 0x20,
703 0xec, 0x53, 0xd0, 0x66, 0xc3, 0x0f, 0xe3, 0xb0,
704 0xe0, 0x86, 0xa6, 0xaa, 0x5f, 0x72, 0x2f, 0xad,
705 0xf7, 0xef, 0x06, 0xb8, 0xd6, 0x9c, 0x9d, 0xe8 };
Gilles Peskine02e79a42019-10-07 17:06:06 +0200706
ENT\stroej1df307002020-12-26 12:41:04 -0600707static const unsigned char entropy_source_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100708{ 0x07, 0x0d, 0x59, 0x63, 0x98, 0x73, 0xa5, 0x45,
709 0x27, 0x38, 0x22, 0x7b, 0x76, 0x85, 0xd1, 0xa9,
710 0x74, 0x18, 0x1f, 0x3c, 0x22, 0xf6, 0x49, 0x20,
711 0x4a, 0x47, 0xc2, 0xf3, 0x85, 0x16, 0xb4, 0x6f,
712 0x00, 0x2e, 0x71, 0xda, 0xed, 0x16, 0x9b, 0x5c };
ENT\stroej1df307002020-12-26 12:41:04 -0600713
stroebeljcd4de1b52021-01-04 18:14:32 -0600714static const unsigned char pers_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100715{ 0xbf, 0xa4, 0x9a, 0x8f, 0x7b, 0xd8, 0xb1, 0x7a,
716 0x9d, 0xfa, 0x45, 0xed, 0x21, 0x52, 0xb3, 0xad };
ENT\stroej1df307002020-12-26 12:41:04 -0600717
stroebeljcd4de1b52021-01-04 18:14:32 -0600718static const unsigned char pers_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100719{ 0x4e, 0x61, 0x79, 0xd4, 0xc2, 0x72, 0xa1, 0x4c,
720 0xf1, 0x3d, 0xf6, 0x5e, 0xa3, 0xa6, 0xe5, 0x0f };
ENT\stroej1df307002020-12-26 12:41:04 -0600721
722static const unsigned char result_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100723{ 0xc9, 0x0a, 0xaf, 0x85, 0x89, 0x71, 0x44, 0x66,
724 0x4f, 0x25, 0x0b, 0x2b, 0xde, 0xd8, 0xfa, 0xff,
725 0x52, 0x5a, 0x1b, 0x32, 0x5e, 0x41, 0x7a, 0x10,
726 0x1f, 0xef, 0x1e, 0x62, 0x23, 0xe9, 0x20, 0x30,
727 0xc9, 0x0d, 0xad, 0x69, 0xb4, 0x9c, 0x5b, 0xf4,
728 0x87, 0x42, 0xd5, 0xae, 0x5e, 0x5e, 0x43, 0xcc,
729 0xd9, 0xfd, 0x0b, 0x93, 0x4a, 0xe3, 0xd4, 0x06,
730 0x37, 0x36, 0x0f, 0x3f, 0x72, 0x82, 0x0c, 0xcf };
ENT\stroej1df307002020-12-26 12:41:04 -0600731
732static const unsigned char result_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100733{ 0x31, 0xc9, 0x91, 0x09, 0xf8, 0xc5, 0x10, 0x13,
734 0x3c, 0xd3, 0x96, 0xf9, 0xbc, 0x2c, 0x12, 0xc0,
735 0x7c, 0xc1, 0x61, 0x5f, 0xa3, 0x09, 0x99, 0xaf,
736 0xd7, 0xf2, 0x36, 0xfd, 0x40, 0x1a, 0x8b, 0xf2,
737 0x33, 0x38, 0xee, 0x1d, 0x03, 0x5f, 0x83, 0xb7,
738 0xa2, 0x53, 0xdc, 0xee, 0x18, 0xfc, 0xa7, 0xf2,
739 0xee, 0x96, 0xc6, 0xc2, 0xcd, 0x0c, 0xff, 0x02,
740 0x76, 0x70, 0x69, 0xaa, 0x69, 0xd1, 0x3b, 0xe8 };
Gilles Peskine02e79a42019-10-07 17:06:06 +0200741#else /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000742
ENT\stroej1df307002020-12-26 12:41:04 -0600743static const unsigned char entropy_source_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100744{ 0xca, 0x58, 0xfd, 0xf2, 0xb9, 0x77, 0xcb, 0x49,
745 0xd4, 0xe0, 0x5b, 0xe2, 0x39, 0x50, 0xd9, 0x8a,
746 0x6a, 0xb3, 0xc5, 0x2f, 0xdf, 0x74, 0xd5, 0x85,
747 0x8f, 0xd1, 0xba, 0x64, 0x54, 0x7b, 0xdb, 0x1e,
748 0xc5, 0xea, 0x24, 0xc0, 0xfa, 0x0c, 0x90, 0x15,
749 0x09, 0x20, 0x92, 0x42, 0x32, 0x36, 0x45, 0x45,
750 0x7d, 0x20, 0x76, 0x6b, 0xcf, 0xa2, 0x15, 0xc8,
751 0x2f, 0x9f, 0xbc, 0x88, 0x3f, 0x80, 0xd1, 0x2c,
752 0xb7, 0x16, 0xd1, 0x80, 0x9e, 0xe1, 0xc9, 0xb3,
753 0x88, 0x1b, 0x21, 0x45, 0xef, 0xa1, 0x7f, 0xce,
754 0xc8, 0x92, 0x35, 0x55, 0x2a, 0xd9, 0x1d, 0x8e,
755 0x12, 0x38, 0xac, 0x01, 0x4e, 0x38, 0x18, 0x76,
756 0x9c, 0xf2, 0xb6, 0xd4, 0x13, 0xb6, 0x2c, 0x77,
757 0xc0, 0xe7, 0xe6, 0x0c, 0x47, 0x44, 0x95, 0xbe };
ENT\stroej1df307002020-12-26 12:41:04 -0600758
759static const unsigned char entropy_source_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100760{ 0x4c, 0xfb, 0x21, 0x86, 0x73, 0x34, 0x6d, 0x9d,
761 0x50, 0xc9, 0x22, 0xe4, 0x9b, 0x0d, 0xfc, 0xd0,
762 0x90, 0xad, 0xf0, 0x4f, 0x5c, 0x3b, 0xa4, 0x73,
763 0x27, 0xdf, 0xcd, 0x6f, 0xa6, 0x3a, 0x78, 0x5c,
764 0x01, 0x69, 0x62, 0xa7, 0xfd, 0x27, 0x87, 0xa2,
765 0x4b, 0xf6, 0xbe, 0x47, 0xef, 0x37, 0x83, 0xf1,
766 0xb7, 0xec, 0x46, 0x07, 0x23, 0x63, 0x83, 0x4a,
767 0x1b, 0x01, 0x33, 0xf2, 0xc2, 0x38, 0x91, 0xdb,
768 0x4f, 0x11, 0xa6, 0x86, 0x51, 0xf2, 0x3e, 0x3a,
769 0x8b, 0x1f, 0xdc, 0x03, 0xb1, 0x92, 0xc7, 0xe7 };
ENT\stroej1df307002020-12-26 12:41:04 -0600770
stroebeljcd4de1b52021-01-04 18:14:32 -0600771static const unsigned char pers_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100772{ 0x5a, 0x70, 0x95, 0xe9, 0x81, 0x40, 0x52, 0x33,
773 0x91, 0x53, 0x7e, 0x75, 0xd6, 0x19, 0x9d, 0x1e,
774 0xad, 0x0d, 0xc6, 0xa7, 0xde, 0x6c, 0x1f, 0xe0,
775 0xea, 0x18, 0x33, 0xa8, 0x7e, 0x06, 0x20, 0xe9 };
ENT\stroej1df307002020-12-26 12:41:04 -0600776
stroebeljcd4de1b52021-01-04 18:14:32 -0600777static const unsigned char pers_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100778{ 0x88, 0xee, 0xb8, 0xe0, 0xe8, 0x3b, 0xf3, 0x29,
779 0x4b, 0xda, 0xcd, 0x60, 0x99, 0xeb, 0xe4, 0xbf,
780 0x55, 0xec, 0xd9, 0x11, 0x3f, 0x71, 0xe5, 0xeb,
781 0xcb, 0x45, 0x75, 0xf3, 0xd6, 0xa6, 0x8a, 0x6b };
ENT\stroej1df307002020-12-26 12:41:04 -0600782
783static const unsigned char result_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100784{ 0xce, 0x2f, 0xdb, 0xb6, 0xd9, 0xb7, 0x39, 0x85,
785 0x04, 0xc5, 0xc0, 0x42, 0xc2, 0x31, 0xc6, 0x1d,
786 0x9b, 0x5a, 0x59, 0xf8, 0x7e, 0x0d, 0xcc, 0x62,
787 0x7b, 0x65, 0x11, 0x55, 0x10, 0xeb, 0x9e, 0x3d,
788 0xa4, 0xfb, 0x1c, 0x6a, 0x18, 0xc0, 0x74, 0xdb,
789 0xdd, 0xe7, 0x02, 0x23, 0x63, 0x21, 0xd0, 0x39,
790 0xf9, 0xa7, 0xc4, 0x52, 0x84, 0x3b, 0x49, 0x40,
791 0x72, 0x2b, 0xb0, 0x6c, 0x9c, 0xdb, 0xc3, 0x43 };
ENT\stroej1df307002020-12-26 12:41:04 -0600792
793static const unsigned char result_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100794{ 0xa5, 0x51, 0x80, 0xa1, 0x90, 0xbe, 0xf3, 0xad,
795 0xaf, 0x28, 0xf6, 0xb7, 0x95, 0xe9, 0xf1, 0xf3,
796 0xd6, 0xdf, 0xa1, 0xb2, 0x7d, 0xd0, 0x46, 0x7b,
797 0x0c, 0x75, 0xf5, 0xfa, 0x93, 0x1e, 0x97, 0x14,
798 0x75, 0xb2, 0x7c, 0xae, 0x03, 0xa2, 0x96, 0x54,
799 0xe2, 0xf4, 0x09, 0x66, 0xea, 0x33, 0x64, 0x30,
800 0x40, 0xd1, 0x40, 0x0f, 0xe6, 0x77, 0x87, 0x3a,
801 0xf8, 0x09, 0x7c, 0x1f, 0xe9, 0xf0, 0x02, 0x98 };
Gilles Peskine02e79a42019-10-07 17:06:06 +0200802#endif /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000803
Manuel Pégourié-Gonnard95924852014-03-21 10:54:55 +0100804static size_t test_offset;
Gilles Peskine449bd832023-01-11 14:50:10 +0100805static int ctr_drbg_self_test_entropy(void *data, unsigned char *buf,
806 size_t len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000807{
Manuel Pégourié-Gonnardb3b205e2014-01-31 12:04:06 +0100808 const unsigned char *p = data;
Gilles Peskine449bd832023-01-11 14:50:10 +0100809 memcpy(buf, p + test_offset, len);
Manuel Pégourié-Gonnardb3b205e2014-01-31 12:04:06 +0100810 test_offset += len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100811 return 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000812}
813
Gilles Peskine449bd832023-01-11 14:50:10 +0100814#define CHK(c) if ((c) != 0) \
815 { \
816 if (verbose != 0) \
817 mbedtls_printf("failed\n"); \
818 return 1; \
819 }
Manuel Pégourié-Gonnardb3b205e2014-01-31 12:04:06 +0100820
bootstrap-prime6dbbf442022-05-17 19:30:44 -0400821#define SELF_TEST_OUTPUT_DISCARD_LENGTH 64
stroebeljcd4de1b52021-01-04 18:14:32 -0600822
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000823/*
824 * Checkup routine
825 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100826int mbedtls_ctr_drbg_self_test(int verbose)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000827{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200828 mbedtls_ctr_drbg_context ctx;
Gilles Peskine449bd832023-01-11 14:50:10 +0100829 unsigned char buf[sizeof(result_pr)];
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000830
Gilles Peskine449bd832023-01-11 14:50:10 +0100831 mbedtls_ctr_drbg_init(&ctx);
Manuel Pégourié-Gonnard8d128ef2015-04-28 22:38:08 +0200832
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000833 /*
834 * Based on a NIST CTR_DRBG test vector (PR = True)
835 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100836 if (verbose != 0) {
837 mbedtls_printf(" CTR_DRBG (PR = TRUE) : ");
838 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000839
840 test_offset = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100841 mbedtls_ctr_drbg_set_entropy_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE);
842 mbedtls_ctr_drbg_set_nonce_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2);
843 CHK(mbedtls_ctr_drbg_seed(&ctx,
844 ctr_drbg_self_test_entropy,
845 (void *) entropy_source_pr,
846 pers_pr, MBEDTLS_CTR_DRBG_KEYSIZE));
847 mbedtls_ctr_drbg_set_prediction_resistance(&ctx, MBEDTLS_CTR_DRBG_PR_ON);
848 CHK(mbedtls_ctr_drbg_random(&ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH));
849 CHK(mbedtls_ctr_drbg_random(&ctx, buf, sizeof(result_pr)));
850 CHK(memcmp(buf, result_pr, sizeof(result_pr)));
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000851
Gilles Peskine449bd832023-01-11 14:50:10 +0100852 mbedtls_ctr_drbg_free(&ctx);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100853
Gilles Peskine449bd832023-01-11 14:50:10 +0100854 if (verbose != 0) {
855 mbedtls_printf("passed\n");
856 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000857
858 /*
859 * Based on a NIST CTR_DRBG test vector (PR = FALSE)
860 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100861 if (verbose != 0) {
862 mbedtls_printf(" CTR_DRBG (PR = FALSE): ");
863 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000864
Gilles Peskine449bd832023-01-11 14:50:10 +0100865 mbedtls_ctr_drbg_init(&ctx);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100866
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000867 test_offset = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100868 mbedtls_ctr_drbg_set_entropy_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE);
869 mbedtls_ctr_drbg_set_nonce_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2);
870 CHK(mbedtls_ctr_drbg_seed(&ctx,
871 ctr_drbg_self_test_entropy,
872 (void *) entropy_source_nopr,
873 pers_nopr, MBEDTLS_CTR_DRBG_KEYSIZE));
874 CHK(mbedtls_ctr_drbg_reseed(&ctx, NULL, 0));
875 CHK(mbedtls_ctr_drbg_random(&ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH));
876 CHK(mbedtls_ctr_drbg_random(&ctx, buf, sizeof(result_nopr)));
877 CHK(memcmp(buf, result_nopr, sizeof(result_nopr)));
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000878
Gilles Peskine449bd832023-01-11 14:50:10 +0100879 mbedtls_ctr_drbg_free(&ctx);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100880
Gilles Peskine449bd832023-01-11 14:50:10 +0100881 if (verbose != 0) {
882 mbedtls_printf("passed\n");
883 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000884
Gilles Peskine449bd832023-01-11 14:50:10 +0100885 if (verbose != 0) {
886 mbedtls_printf("\n");
887 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000888
Gilles Peskine449bd832023-01-11 14:50:10 +0100889 return 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000890}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200891#endif /* MBEDTLS_SELF_TEST */
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000892
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200893#endif /* MBEDTLS_CTR_DRBG_C */