blob: cf3816e9fde10103958b174012c4f430bc5da6dd [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
Dave Rodgman16799db2023-11-02 19:47:20 +00005 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Paul Bakker0e04d0e2011-11-27 14:46:59 +00006 */
7/*
Paul Sokolovsky8d6d8c82018-02-10 11:11:41 +02008 * The NIST SP 800-90 DRBGs are described in the following publication.
Paul Bakker0e04d0e2011-11-27 14:46:59 +00009 *
Tom Cosgrovece37c5e2023-08-04 13:53:36 +010010 * https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-90r.pdf
Paul Bakker0e04d0e2011-11-27 14:46:59 +000011 */
12
Gilles Peskinedb09ef62020-06-03 01:43:33 +020013#include "common.h"
Paul Bakker0e04d0e2011-11-27 14:46:59 +000014
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020015#if defined(MBEDTLS_CTR_DRBG_C)
Paul Bakker0e04d0e2011-11-27 14:46:59 +000016
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000017#include "mbedtls/ctr_drbg.h"
Andres Amaya Garcia1f6301b2018-04-17 09:51:09 -050018#include "mbedtls/platform_util.h"
Janos Follath24eed8d2019-11-22 13:21:35 +000019#include "mbedtls/error.h"
Paul Bakker0e04d0e2011-11-27 14:46:59 +000020
Rich Evans00ab4702015-02-06 13:43:58 +000021#include <string.h>
22
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020023#if defined(MBEDTLS_FS_IO)
Paul Bakkerfc754a92011-12-05 13:23:51 +000024#include <stdio.h>
25#endif
26
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000027#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010028
Paul Bakker18d32912011-12-10 21:42:49 +000029/*
Manuel Pégourié-Gonnard8d128ef2015-04-28 22:38:08 +020030 * CTR_DRBG context initialization
31 */
Gilles Peskine449bd832023-01-11 14:50:10 +010032void mbedtls_ctr_drbg_init(mbedtls_ctr_drbg_context *ctx)
Manuel Pégourié-Gonnard8d128ef2015-04-28 22:38:08 +020033{
Gilles Peskine449bd832023-01-11 14:50:10 +010034 memset(ctx, 0, sizeof(mbedtls_ctr_drbg_context));
35 mbedtls_aes_init(&ctx->aes_ctx);
Gilles Peskinee9a34542019-10-22 20:43:24 +020036 /* Indicate that the entropy nonce length is not set explicitly.
37 * See mbedtls_ctr_drbg_set_nonce_len(). */
38 ctx->reseed_counter = -1;
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +010039
Gavin Acquroff6aceb512020-03-01 17:06:11 -080040 ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
Manuel Pégourié-Gonnard8d128ef2015-04-28 22:38:08 +020041}
42
Gavin Acquroff6aceb512020-03-01 17:06:11 -080043/*
44 * This function resets CTR_DRBG context to the state immediately
45 * after initial call of mbedtls_ctr_drbg_init().
46 */
Gilles Peskine449bd832023-01-11 14:50:10 +010047void mbedtls_ctr_drbg_free(mbedtls_ctr_drbg_context *ctx)
Paul Bakkerfff03662014-06-18 16:21:25 +020048{
Gilles Peskine449bd832023-01-11 14:50:10 +010049 if (ctx == NULL) {
Paul Bakkerfff03662014-06-18 16:21:25 +020050 return;
Gilles Peskine449bd832023-01-11 14:50:10 +010051 }
Paul Bakkerfff03662014-06-18 16:21:25 +020052
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +010053#if defined(MBEDTLS_THREADING_C)
Gilles Peskineda290f92021-02-09 18:44:02 +010054 /* The mutex is initialized iff f_entropy is set. */
Gilles Peskine449bd832023-01-11 14:50:10 +010055 if (ctx->f_entropy != NULL) {
56 mbedtls_mutex_free(&ctx->mutex);
57 }
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +010058#endif
Gilles Peskine449bd832023-01-11 14:50:10 +010059 mbedtls_aes_free(&ctx->aes_ctx);
60 mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ctr_drbg_context));
Gavin Acquroff6aceb512020-03-01 17:06:11 -080061 ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
62 ctx->reseed_counter = -1;
Paul Bakkerfff03662014-06-18 16:21:25 +020063}
64
Gilles Peskine449bd832023-01-11 14:50:10 +010065void mbedtls_ctr_drbg_set_prediction_resistance(mbedtls_ctr_drbg_context *ctx,
66 int resistance)
Paul Bakker0e04d0e2011-11-27 14:46:59 +000067{
68 ctx->prediction_resistance = resistance;
69}
70
Gilles Peskine449bd832023-01-11 14:50:10 +010071void mbedtls_ctr_drbg_set_entropy_len(mbedtls_ctr_drbg_context *ctx,
72 size_t len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +000073{
74 ctx->entropy_len = len;
75}
Paul Bakkerb6c5d2e2013-06-25 16:25:17 +020076
Gilles Peskine449bd832023-01-11 14:50:10 +010077int mbedtls_ctr_drbg_set_nonce_len(mbedtls_ctr_drbg_context *ctx,
78 size_t len)
Gilles Peskine9be50982019-10-22 18:42:27 +020079{
80 /* If mbedtls_ctr_drbg_seed() has already been called, it's
81 * too late. Return the error code that's closest to making sense. */
Gilles Peskine449bd832023-01-11 14:50:10 +010082 if (ctx->f_entropy != NULL) {
83 return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
84 }
Gilles Peskine9be50982019-10-22 18:42:27 +020085
Gilles Peskine449bd832023-01-11 14:50:10 +010086 if (len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) {
87 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
88 }
Dave Rodgman4a5c9ee2023-02-10 16:03:44 +000089
Gilles Peskine9be50982019-10-22 18:42:27 +020090 /* This shouldn't be an issue because
91 * MBEDTLS_CTR_DRBG_MAX_SEED_INPUT < INT_MAX in any sensible
92 * configuration, but make sure anyway. */
Gilles Peskine449bd832023-01-11 14:50:10 +010093 if (len > INT_MAX) {
94 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
95 }
Gilles Peskine9be50982019-10-22 18:42:27 +020096
97 /* For backward compatibility with Mbed TLS <= 2.19, store the
98 * entropy nonce length in a field that already exists, but isn't
99 * used until after the initial seeding. */
100 /* Due to the capping of len above, the value fits in an int. */
101 ctx->reseed_counter = (int) len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100102 return 0;
Gilles Peskine9be50982019-10-22 18:42:27 +0200103}
104
Gilles Peskine449bd832023-01-11 14:50:10 +0100105void mbedtls_ctr_drbg_set_reseed_interval(mbedtls_ctr_drbg_context *ctx,
106 int interval)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000107{
108 ctx->reseed_interval = interval;
109}
Paul Bakkerb6c5d2e2013-06-25 16:25:17 +0200110
Gilles Peskine449bd832023-01-11 14:50:10 +0100111static int block_cipher_df(unsigned char *output,
112 const unsigned char *data, size_t data_len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000113{
Hanno Beckera08651f2018-10-05 09:38:59 +0100114 unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
115 MBEDTLS_CTR_DRBG_BLOCKSIZE + 16];
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200116 unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
117 unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
118 unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE];
Manuel Pégourié-Gonnard7c593632014-01-20 10:27:13 +0100119 unsigned char *p, *iv;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200120 mbedtls_aes_context aes_ctx;
Dvir Markovich1b364992017-06-26 13:43:34 +0300121 int ret = 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000122
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200123 int i, j;
124 size_t buf_len, use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000125
Gilles Peskine449bd832023-01-11 14:50:10 +0100126 if (data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) {
127 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
128 }
Manuel Pégourié-Gonnard5cb4b312014-11-25 17:41:50 +0100129
Gilles Peskine449bd832023-01-11 14:50:10 +0100130 memset(buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
131 MBEDTLS_CTR_DRBG_BLOCKSIZE + 16);
132 mbedtls_aes_init(&aes_ctx);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000133
134 /*
135 * Construct IV (16 bytes) and S in buffer
136 * IV = Counter (in 32-bits) padded to 16 with zeroes
137 * S = Length input string (in 32-bits) || Length of output (in 32-bits) ||
138 * data || 0x80
139 * (Total is padded to a multiple of 16-bytes with zeroes)
140 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200141 p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE;
Gilles Peskine449bd832023-01-11 14:50:10 +0100142 MBEDTLS_PUT_UINT32_BE(data_len, p, 0);
Joe Subbiania5cb0d22021-08-23 11:35:25 +0100143 p += 4 + 3;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200144 *p++ = MBEDTLS_CTR_DRBG_SEEDLEN;
Gilles Peskine449bd832023-01-11 14:50:10 +0100145 memcpy(p, data, data_len);
Paul Bakker2bc7cf12011-11-29 10:50:51 +0000146 p[data_len] = 0x80;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000147
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200148 buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000149
Gilles Peskine449bd832023-01-11 14:50:10 +0100150 for (i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000151 key[i] = i;
Gilles Peskine449bd832023-01-11 14:50:10 +0100152 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000153
Gilles Peskine449bd832023-01-11 14:50:10 +0100154 if ((ret = mbedtls_aes_setkey_enc(&aes_ctx, key,
155 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300156 goto exit;
157 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000158
159 /*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200160 * Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000161 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100162 for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000163 p = buf;
Gilles Peskine449bd832023-01-11 14:50:10 +0100164 memset(chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000165 use_len = buf_len;
166
Gilles Peskine449bd832023-01-11 14:50:10 +0100167 while (use_len > 0) {
168 mbedtls_xor(chain, chain, p, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200169 p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
Gilles Peskine449bd832023-01-11 14:50:10 +0100170 use_len -= (use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE) ?
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200171 MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000172
Gilles Peskine449bd832023-01-11 14:50:10 +0100173 if ((ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT,
174 chain, chain)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300175 goto exit;
176 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000177 }
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200178
Gilles Peskine449bd832023-01-11 14:50:10 +0100179 memcpy(tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000180
181 /*
182 * Update IV
183 */
184 buf[3]++;
185 }
186
187 /*
188 * Do final encryption with reduced data
189 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100190 if ((ret = mbedtls_aes_setkey_enc(&aes_ctx, tmp,
191 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300192 goto exit;
193 }
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200194 iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000195 p = output;
196
Gilles Peskine449bd832023-01-11 14:50:10 +0100197 for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
198 if ((ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT,
199 iv, iv)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300200 goto exit;
201 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100202 memcpy(p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200203 p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000204 }
Dvir Markovich1b364992017-06-26 13:43:34 +0300205exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100206 mbedtls_aes_free(&aes_ctx);
Dvir Markovich1b364992017-06-26 13:43:34 +0300207 /*
Gilles Peskine449bd832023-01-11 14:50:10 +0100208 * tidy up the stack
209 */
210 mbedtls_platform_zeroize(buf, sizeof(buf));
211 mbedtls_platform_zeroize(tmp, sizeof(tmp));
212 mbedtls_platform_zeroize(key, sizeof(key));
213 mbedtls_platform_zeroize(chain, sizeof(chain));
214 if (0 != ret) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300215 /*
Gilles Peskine449bd832023-01-11 14:50:10 +0100216 * wipe partial seed from memory
217 */
218 mbedtls_platform_zeroize(output, MBEDTLS_CTR_DRBG_SEEDLEN);
Dvir Markovich1b364992017-06-26 13:43:34 +0300219 }
Paul Bakkerc7ea99a2014-06-18 11:12:03 +0200220
Gilles Peskine449bd832023-01-11 14:50:10 +0100221 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000222}
223
Gilles Peskineed7da592018-08-03 20:16:52 +0200224/* CTR_DRBG_Update (SP 800-90A &sect;10.2.1.2)
225 * ctr_drbg_update_internal(ctx, provided_data)
226 * implements
227 * CTR_DRBG_Update(provided_data, Key, V)
228 * with inputs and outputs
229 * ctx->aes_ctx = Key
230 * ctx->counter = V
231 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100232static int ctr_drbg_update_internal(mbedtls_ctr_drbg_context *ctx,
233 const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN])
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000234{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200235 unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000236 unsigned char *p = tmp;
Paul Bakker369e14b2012-04-18 14:16:09 +0000237 int i, j;
Dvir Markovich1b364992017-06-26 13:43:34 +0300238 int ret = 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000239
Gilles Peskine449bd832023-01-11 14:50:10 +0100240 memset(tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000241
Gilles Peskine449bd832023-01-11 14:50:10 +0100242 for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000243 /*
244 * Increase counter
245 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100246 for (i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i--) {
247 if (++ctx->counter[i - 1] != 0) {
Paul Bakker369e14b2012-04-18 14:16:09 +0000248 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100249 }
250 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000251
252 /*
253 * Crypt counter block
254 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100255 if ((ret = mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
256 ctx->counter, p)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200257 goto exit;
Dvir Markovich1b364992017-06-26 13:43:34 +0300258 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000259
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200260 p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000261 }
262
Gilles Peskine449bd832023-01-11 14:50:10 +0100263 for (i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000264 tmp[i] ^= data[i];
Gilles Peskine449bd832023-01-11 14:50:10 +0100265 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000266
267 /*
268 * Update key and counter
269 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100270 if ((ret = mbedtls_aes_setkey_enc(&ctx->aes_ctx, tmp,
271 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200272 goto exit;
Dvir Markovich1b364992017-06-26 13:43:34 +0300273 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100274 memcpy(ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE,
275 MBEDTLS_CTR_DRBG_BLOCKSIZE);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000276
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200277exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100278 mbedtls_platform_zeroize(tmp, sizeof(tmp));
279 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000280}
281
Gilles Peskineed7da592018-08-03 20:16:52 +0200282/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
TRodziewicz26371e42021-06-08 16:45:41 +0200283 * mbedtls_ctr_drbg_update(ctx, additional, add_len)
Gilles Peskineed7da592018-08-03 20:16:52 +0200284 * implements
285 * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
286 * security_strength) -> initial_working_state
287 * with inputs
288 * ctx->counter = all-bits-0
289 * ctx->aes_ctx = context from all-bits-0 key
290 * additional[:add_len] = entropy_input || nonce || personalization_string
291 * and with outputs
292 * ctx = initial_working_state
293 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100294int mbedtls_ctr_drbg_update(mbedtls_ctr_drbg_context *ctx,
295 const unsigned char *additional,
296 size_t add_len)
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000297{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200298 unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
Janos Follath24eed8d2019-11-22 13:21:35 +0000299 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000300
Gilles Peskine449bd832023-01-11 14:50:10 +0100301 if (add_len == 0) {
302 return 0;
303 }
Manuel Pégourié-Gonnard5cb4b312014-11-25 17:41:50 +0100304
Gilles Peskine449bd832023-01-11 14:50:10 +0100305 if ((ret = block_cipher_df(add_input, additional, add_len)) != 0) {
Gilles Peskined9199932018-09-11 16:41:54 +0200306 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100307 }
308 if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
Gilles Peskined9199932018-09-11 16:41:54 +0200309 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100310 }
Gilles Peskined9199932018-09-11 16:41:54 +0200311
312exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100313 mbedtls_platform_zeroize(add_input, sizeof(add_input));
314 return ret;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000315}
316
Gilles Peskineed7da592018-08-03 20:16:52 +0200317/* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
Gilles Peskine9be50982019-10-22 18:42:27 +0200318 * mbedtls_ctr_drbg_reseed(ctx, additional, len, nonce_len)
Gilles Peskineed7da592018-08-03 20:16:52 +0200319 * implements
320 * CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
321 * -> new_working_state
322 * with inputs
323 * ctx contains working_state
324 * additional[:len] = additional_input
325 * and entropy_input comes from calling ctx->f_entropy
Gilles Peskine9be50982019-10-22 18:42:27 +0200326 * for (ctx->entropy_len + nonce_len) bytes
Gilles Peskineed7da592018-08-03 20:16:52 +0200327 * and with output
328 * ctx contains new_working_state
329 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100330static int mbedtls_ctr_drbg_reseed_internal(mbedtls_ctr_drbg_context *ctx,
331 const unsigned char *additional,
332 size_t len,
333 size_t nonce_len)
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000334{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200335 unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000336 size_t seedlen = 0;
Janos Follath24eed8d2019-11-22 13:21:35 +0000337 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000338
Gilles Peskine449bd832023-01-11 14:50:10 +0100339 if (ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) {
340 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
341 }
342 if (nonce_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len) {
343 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
344 }
345 if (len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len - nonce_len) {
346 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
347 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000348
Gilles Peskine449bd832023-01-11 14:50:10 +0100349 memset(seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT);
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000350
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200351 /* Gather entropy_len bytes of entropy to seed state. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100352 if (0 != ctx->f_entropy(ctx->p_entropy, seed, ctx->entropy_len)) {
353 return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000354 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000355 seedlen += ctx->entropy_len;
356
Gilles Peskine9be50982019-10-22 18:42:27 +0200357 /* Gather entropy for a nonce if requested. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100358 if (nonce_len != 0) {
359 if (0 != ctx->f_entropy(ctx->p_entropy, seed + seedlen, nonce_len)) {
360 return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
Gilles Peskine9be50982019-10-22 18:42:27 +0200361 }
362 seedlen += nonce_len;
363 }
364
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200365 /* Add additional data if provided. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100366 if (additional != NULL && len != 0) {
367 memcpy(seed + seedlen, additional, len);
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000368 seedlen += len;
369 }
370
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200371 /* Reduce to 384 bits. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100372 if ((ret = block_cipher_df(seed, seed, seedlen)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200373 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100374 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000375
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200376 /* Update state. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100377 if ((ret = ctr_drbg_update_internal(ctx, seed)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200378 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100379 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000380 ctx->reseed_counter = 1;
381
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200382exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100383 mbedtls_platform_zeroize(seed, sizeof(seed));
384 return ret;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000385}
Paul Bakker9af723c2014-05-01 13:03:14 +0200386
Gilles Peskine449bd832023-01-11 14:50:10 +0100387int mbedtls_ctr_drbg_reseed(mbedtls_ctr_drbg_context *ctx,
388 const unsigned char *additional, size_t len)
Gilles Peskine9be50982019-10-22 18:42:27 +0200389{
Gilles Peskine449bd832023-01-11 14:50:10 +0100390 return mbedtls_ctr_drbg_reseed_internal(ctx, additional, len, 0);
Gilles Peskine9be50982019-10-22 18:42:27 +0200391}
392
Gilles Peskinee9a34542019-10-22 20:43:24 +0200393/* Return a "good" nonce length for CTR_DRBG. The chosen nonce length
394 * is sufficient to achieve the maximum security strength given the key
395 * size and entropy length. If there is enough entropy in the initial
396 * call to the entropy function to serve as both the entropy input and
397 * the nonce, don't make a second call to get a nonce. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100398static size_t good_nonce_len(size_t entropy_len)
Gilles Peskinee9a34542019-10-22 20:43:24 +0200399{
Gilles Peskine449bd832023-01-11 14:50:10 +0100400 if (entropy_len >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2) {
401 return 0;
402 } else {
403 return (entropy_len + 1) / 2;
404 }
Gilles Peskinee9a34542019-10-22 20:43:24 +0200405}
406
Gilles Peskine8bf56132019-10-02 20:31:54 +0200407/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
Gilles Peskine379561f2019-10-18 16:57:48 +0200408 * mbedtls_ctr_drbg_seed(ctx, f_entropy, p_entropy, custom, len)
Gilles Peskine8bf56132019-10-02 20:31:54 +0200409 * implements
410 * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
411 * security_strength) -> initial_working_state
412 * with inputs
413 * custom[:len] = nonce || personalization_string
Gilles Peskine379561f2019-10-18 16:57:48 +0200414 * where entropy_input comes from f_entropy for ctx->entropy_len bytes
Gilles Peskine8bf56132019-10-02 20:31:54 +0200415 * and with outputs
416 * ctx = initial_working_state
417 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100418int mbedtls_ctr_drbg_seed(mbedtls_ctr_drbg_context *ctx,
419 int (*f_entropy)(void *, unsigned char *, size_t),
420 void *p_entropy,
421 const unsigned char *custom,
422 size_t len)
Gilles Peskine8bf56132019-10-02 20:31:54 +0200423{
Janos Follath24eed8d2019-11-22 13:21:35 +0000424 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200425 unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
Gilles Peskinee9a34542019-10-22 20:43:24 +0200426 size_t nonce_len;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200427
Gilles Peskine449bd832023-01-11 14:50:10 +0100428 memset(key, 0, MBEDTLS_CTR_DRBG_KEYSIZE);
Gilles Peskine8bf56132019-10-02 20:31:54 +0200429
Gilles Peskineda290f92021-02-09 18:44:02 +0100430 /* The mutex is initialized iff f_entropy is set. */
Gilles Peskinef4b34292021-01-30 13:05:32 +0100431#if defined(MBEDTLS_THREADING_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100432 mbedtls_mutex_init(&ctx->mutex);
Gilles Peskinef4b34292021-01-30 13:05:32 +0100433#endif
434
Gilles Peskine8bf56132019-10-02 20:31:54 +0200435 ctx->f_entropy = f_entropy;
436 ctx->p_entropy = p_entropy;
437
Gilles Peskine449bd832023-01-11 14:50:10 +0100438 if (ctx->entropy_len == 0) {
Gilles Peskine50ed86b2019-10-04 12:15:55 +0200439 ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
Gilles Peskine449bd832023-01-11 14:50:10 +0100440 }
Gilles Peskinee9a34542019-10-22 20:43:24 +0200441 /* ctx->reseed_counter contains the desired amount of entropy to
442 * grab for a nonce (see mbedtls_ctr_drbg_set_nonce_len()).
443 * If it's -1, indicating that the entropy nonce length was not set
444 * explicitly, use a sufficiently large nonce for security. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100445 nonce_len = (ctx->reseed_counter >= 0 ?
446 (size_t) ctx->reseed_counter :
447 good_nonce_len(ctx->entropy_len));
Gilles Peskinee9a34542019-10-22 20:43:24 +0200448
Gilles Peskine9be50982019-10-22 18:42:27 +0200449 /* Initialize with an empty key. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100450 if ((ret = mbedtls_aes_setkey_enc(&ctx->aes_ctx, key,
451 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
452 return ret;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200453 }
454
Gilles Peskinee9a34542019-10-22 20:43:24 +0200455 /* Do the initial seeding. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100456 if ((ret = mbedtls_ctr_drbg_reseed_internal(ctx, custom, len,
457 nonce_len)) != 0) {
458 return ret;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200459 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100460 return 0;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200461}
462
Gilles Peskineed7da592018-08-03 20:16:52 +0200463/* CTR_DRBG_Generate with derivation function (SP 800-90A &sect;10.2.1.5.2)
464 * mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len)
465 * implements
466 * CTR_DRBG_Reseed(working_state, entropy_input, additional[:add_len])
467 * -> working_state_after_reseed
468 * if required, then
469 * CTR_DRBG_Generate(working_state_after_reseed,
470 * requested_number_of_bits, additional_input)
471 * -> status, returned_bits, new_working_state
472 * with inputs
473 * ctx contains working_state
474 * requested_number_of_bits = 8 * output_len
475 * additional[:add_len] = additional_input
476 * and entropy_input comes from calling ctx->f_entropy
477 * and with outputs
478 * status = SUCCESS (this function does the reseed internally)
479 * returned_bits = output[:output_len]
480 * ctx contains new_working_state
481 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100482int mbedtls_ctr_drbg_random_with_add(void *p_rng,
483 unsigned char *output, size_t output_len,
484 const unsigned char *additional, size_t add_len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000485{
486 int ret = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200487 mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
488 unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000489 unsigned char *p = output;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200490 unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE];
Paul Bakker369e14b2012-04-18 14:16:09 +0000491 int i;
Paul Bakker23fd5ea2011-11-29 15:56:12 +0000492 size_t use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000493
Gilles Peskine449bd832023-01-11 14:50:10 +0100494 if (output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST) {
495 return MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG;
496 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000497
Gilles Peskine449bd832023-01-11 14:50:10 +0100498 if (add_len > MBEDTLS_CTR_DRBG_MAX_INPUT) {
499 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
500 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000501
Gilles Peskine449bd832023-01-11 14:50:10 +0100502 memset(add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000503
Gilles Peskine449bd832023-01-11 14:50:10 +0100504 if (ctx->reseed_counter > ctx->reseed_interval ||
505 ctx->prediction_resistance) {
506 if ((ret = mbedtls_ctr_drbg_reseed(ctx, additional, add_len)) != 0) {
507 return ret;
Dvir Markovich1b364992017-06-26 13:43:34 +0300508 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000509 add_len = 0;
510 }
511
Gilles Peskine449bd832023-01-11 14:50:10 +0100512 if (add_len > 0) {
513 if ((ret = block_cipher_df(add_input, additional, add_len)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200514 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100515 }
516 if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200517 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100518 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000519 }
520
Gilles Peskine449bd832023-01-11 14:50:10 +0100521 while (output_len > 0) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000522 /*
523 * Increase counter
524 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100525 for (i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i--) {
526 if (++ctx->counter[i - 1] != 0) {
Paul Bakker369e14b2012-04-18 14:16:09 +0000527 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100528 }
529 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000530
531 /*
532 * Crypt counter block
533 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100534 if ((ret = mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
535 ctx->counter, tmp)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200536 goto exit;
Dvir Markovich1b364992017-06-26 13:43:34 +0300537 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000538
Gilles Peskine449bd832023-01-11 14:50:10 +0100539 use_len = (output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE)
Hanno Beckera08651f2018-10-05 09:38:59 +0100540 ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000541 /*
542 * Copy random block to destination
543 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100544 memcpy(p, tmp, use_len);
Paul Bakker23fd5ea2011-11-29 15:56:12 +0000545 p += use_len;
546 output_len -= use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000547 }
548
Gilles Peskine449bd832023-01-11 14:50:10 +0100549 if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200550 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100551 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000552
553 ctx->reseed_counter++;
554
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200555exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100556 mbedtls_platform_zeroize(add_input, sizeof(add_input));
557 mbedtls_platform_zeroize(tmp, sizeof(tmp));
558 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000559}
560
Gilles Peskine449bd832023-01-11 14:50:10 +0100561int mbedtls_ctr_drbg_random(void *p_rng, unsigned char *output,
562 size_t output_len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000563{
Janos Follath24eed8d2019-11-22 13:21:35 +0000564 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100565 mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
566
567#if defined(MBEDTLS_THREADING_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100568 if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {
569 return ret;
570 }
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100571#endif
572
Gilles Peskine449bd832023-01-11 14:50:10 +0100573 ret = mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, NULL, 0);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100574
575#if defined(MBEDTLS_THREADING_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100576 if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
577 return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
578 }
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100579#endif
580
Gilles Peskine449bd832023-01-11 14:50:10 +0100581 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000582}
583
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200584#if defined(MBEDTLS_FS_IO)
Gilles Peskine449bd832023-01-11 14:50:10 +0100585int mbedtls_ctr_drbg_write_seed_file(mbedtls_ctr_drbg_context *ctx,
586 const char *path)
Paul Bakkerfc754a92011-12-05 13:23:51 +0000587{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200588 int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000589 FILE *f;
Gilles Peskine449bd832023-01-11 14:50:10 +0100590 unsigned char buf[MBEDTLS_CTR_DRBG_MAX_INPUT];
Paul Bakkerfc754a92011-12-05 13:23:51 +0000591
Gilles Peskine449bd832023-01-11 14:50:10 +0100592 if ((f = fopen(path, "wb")) == NULL) {
593 return MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
594 }
Paul Bakkerfc754a92011-12-05 13:23:51 +0000595
Gilles Peskineda0913b2022-06-30 17:03:40 +0200596 /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100597 mbedtls_setbuf(f, NULL);
Gilles Peskineda0913b2022-06-30 17:03:40 +0200598
Gilles Peskine449bd832023-01-11 14:50:10 +0100599 if ((ret = mbedtls_ctr_drbg_random(ctx, buf,
600 MBEDTLS_CTR_DRBG_MAX_INPUT)) != 0) {
Paul Bakkerc72d3f72013-05-14 13:22:41 +0200601 goto exit;
Hanno Beckera08651f2018-10-05 09:38:59 +0100602 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100603
604 if (fwrite(buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f) !=
605 MBEDTLS_CTR_DRBG_MAX_INPUT) {
606 ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
607 } else {
Andres Amaya Garcia13f41e12017-06-26 10:56:58 +0100608 ret = 0;
Hanno Beckera08651f2018-10-05 09:38:59 +0100609 }
Paul Bakkerfc754a92011-12-05 13:23:51 +0000610
Andres Amaya Garcia4e2c07c2017-06-27 16:57:26 +0100611exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100612 mbedtls_platform_zeroize(buf, sizeof(buf));
Paul Bakkerc72d3f72013-05-14 13:22:41 +0200613
Gilles Peskine449bd832023-01-11 14:50:10 +0100614 fclose(f);
615 return ret;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000616}
617
Gilles Peskine449bd832023-01-11 14:50:10 +0100618int mbedtls_ctr_drbg_update_seed_file(mbedtls_ctr_drbg_context *ctx,
619 const char *path)
Paul Bakkerfc754a92011-12-05 13:23:51 +0000620{
Andres Amaya Garcia13f41e12017-06-26 10:56:58 +0100621 int ret = 0;
Gilles Peskine82204662018-09-11 18:43:09 +0200622 FILE *f = NULL;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000623 size_t n;
Gilles Peskine449bd832023-01-11 14:50:10 +0100624 unsigned char buf[MBEDTLS_CTR_DRBG_MAX_INPUT];
Gilles Peskine82204662018-09-11 18:43:09 +0200625 unsigned char c;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000626
Gilles Peskine449bd832023-01-11 14:50:10 +0100627 if ((f = fopen(path, "rb")) == NULL) {
628 return MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
629 }
Paul Bakkerfc754a92011-12-05 13:23:51 +0000630
Gilles Peskineda0913b2022-06-30 17:03:40 +0200631 /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100632 mbedtls_setbuf(f, NULL);
Gilles Peskineda0913b2022-06-30 17:03:40 +0200633
Gilles Peskine449bd832023-01-11 14:50:10 +0100634 n = fread(buf, 1, sizeof(buf), f);
635 if (fread(&c, 1, 1, f) != 0) {
Gilles Peskine82204662018-09-11 18:43:09 +0200636 ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
637 goto exit;
Andres Amaya Garcia4e2c07c2017-06-27 16:57:26 +0100638 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100639 if (n == 0 || ferror(f)) {
Andres Amaya Garcia13f41e12017-06-26 10:56:58 +0100640 ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
Gilles Peskine82204662018-09-11 18:43:09 +0200641 goto exit;
642 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100643 fclose(f);
Gilles Peskine82204662018-09-11 18:43:09 +0200644 f = NULL;
Paul Bakkerc72d3f72013-05-14 13:22:41 +0200645
Gilles Peskine449bd832023-01-11 14:50:10 +0100646 ret = mbedtls_ctr_drbg_update(ctx, buf, n);
Gilles Peskine82204662018-09-11 18:43:09 +0200647
648exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100649 mbedtls_platform_zeroize(buf, sizeof(buf));
650 if (f != NULL) {
651 fclose(f);
652 }
653 if (ret != 0) {
654 return ret;
655 }
656 return mbedtls_ctr_drbg_write_seed_file(ctx, path);
Paul Bakkerfc754a92011-12-05 13:23:51 +0000657}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200658#endif /* MBEDTLS_FS_IO */
Paul Bakkerfc754a92011-12-05 13:23:51 +0000659
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200660#if defined(MBEDTLS_SELF_TEST)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000661
ENT\stroej170f63d02020-12-28 08:50:23 -0600662/* The CTR_DRBG NIST test vectors used here are available at
663 * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/drbg/drbgtestvectors.zip
664 *
665 * The parameters used to derive the test data are:
666 *
667 * [AES-128 use df]
668 * [PredictionResistance = True/False]
669 * [EntropyInputLen = 128]
670 * [NonceLen = 64]
671 * [PersonalizationStringLen = 128]
672 * [AdditionalInputLen = 0]
673 * [ReturnedBitsLen = 512]
674 *
675 * [AES-256 use df]
676 * [PredictionResistance = True/False]
677 * [EntropyInputLen = 256]
678 * [NonceLen = 128]
679 * [PersonalizationStringLen = 256]
680 * [AdditionalInputLen = 0]
681 * [ReturnedBitsLen = 512]
682 *
683 */
684
Gilles Peskine02e79a42019-10-07 17:06:06 +0200685#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY)
ENT\stroej1df307002020-12-26 12:41:04 -0600686static const unsigned char entropy_source_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100687{ 0x04, 0xd9, 0x49, 0xa6, 0xdc, 0xe8, 0x6e, 0xbb,
688 0xf1, 0x08, 0x77, 0x2b, 0x9e, 0x08, 0xca, 0x92,
689 0x65, 0x16, 0xda, 0x99, 0xa2, 0x59, 0xf3, 0xe8,
690 0x38, 0x7e, 0x3f, 0x6b, 0x51, 0x70, 0x7b, 0x20,
691 0xec, 0x53, 0xd0, 0x66, 0xc3, 0x0f, 0xe3, 0xb0,
692 0xe0, 0x86, 0xa6, 0xaa, 0x5f, 0x72, 0x2f, 0xad,
693 0xf7, 0xef, 0x06, 0xb8, 0xd6, 0x9c, 0x9d, 0xe8 };
Gilles Peskine02e79a42019-10-07 17:06:06 +0200694
ENT\stroej1df307002020-12-26 12:41:04 -0600695static const unsigned char entropy_source_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100696{ 0x07, 0x0d, 0x59, 0x63, 0x98, 0x73, 0xa5, 0x45,
697 0x27, 0x38, 0x22, 0x7b, 0x76, 0x85, 0xd1, 0xa9,
698 0x74, 0x18, 0x1f, 0x3c, 0x22, 0xf6, 0x49, 0x20,
699 0x4a, 0x47, 0xc2, 0xf3, 0x85, 0x16, 0xb4, 0x6f,
700 0x00, 0x2e, 0x71, 0xda, 0xed, 0x16, 0x9b, 0x5c };
ENT\stroej1df307002020-12-26 12:41:04 -0600701
stroebeljcd4de1b52021-01-04 18:14:32 -0600702static const unsigned char pers_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100703{ 0xbf, 0xa4, 0x9a, 0x8f, 0x7b, 0xd8, 0xb1, 0x7a,
704 0x9d, 0xfa, 0x45, 0xed, 0x21, 0x52, 0xb3, 0xad };
ENT\stroej1df307002020-12-26 12:41:04 -0600705
stroebeljcd4de1b52021-01-04 18:14:32 -0600706static const unsigned char pers_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100707{ 0x4e, 0x61, 0x79, 0xd4, 0xc2, 0x72, 0xa1, 0x4c,
708 0xf1, 0x3d, 0xf6, 0x5e, 0xa3, 0xa6, 0xe5, 0x0f };
ENT\stroej1df307002020-12-26 12:41:04 -0600709
710static const unsigned char result_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100711{ 0xc9, 0x0a, 0xaf, 0x85, 0x89, 0x71, 0x44, 0x66,
712 0x4f, 0x25, 0x0b, 0x2b, 0xde, 0xd8, 0xfa, 0xff,
713 0x52, 0x5a, 0x1b, 0x32, 0x5e, 0x41, 0x7a, 0x10,
714 0x1f, 0xef, 0x1e, 0x62, 0x23, 0xe9, 0x20, 0x30,
715 0xc9, 0x0d, 0xad, 0x69, 0xb4, 0x9c, 0x5b, 0xf4,
716 0x87, 0x42, 0xd5, 0xae, 0x5e, 0x5e, 0x43, 0xcc,
717 0xd9, 0xfd, 0x0b, 0x93, 0x4a, 0xe3, 0xd4, 0x06,
718 0x37, 0x36, 0x0f, 0x3f, 0x72, 0x82, 0x0c, 0xcf };
ENT\stroej1df307002020-12-26 12:41:04 -0600719
720static const unsigned char result_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100721{ 0x31, 0xc9, 0x91, 0x09, 0xf8, 0xc5, 0x10, 0x13,
722 0x3c, 0xd3, 0x96, 0xf9, 0xbc, 0x2c, 0x12, 0xc0,
723 0x7c, 0xc1, 0x61, 0x5f, 0xa3, 0x09, 0x99, 0xaf,
724 0xd7, 0xf2, 0x36, 0xfd, 0x40, 0x1a, 0x8b, 0xf2,
725 0x33, 0x38, 0xee, 0x1d, 0x03, 0x5f, 0x83, 0xb7,
726 0xa2, 0x53, 0xdc, 0xee, 0x18, 0xfc, 0xa7, 0xf2,
727 0xee, 0x96, 0xc6, 0xc2, 0xcd, 0x0c, 0xff, 0x02,
728 0x76, 0x70, 0x69, 0xaa, 0x69, 0xd1, 0x3b, 0xe8 };
Gilles Peskine02e79a42019-10-07 17:06:06 +0200729#else /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000730
ENT\stroej1df307002020-12-26 12:41:04 -0600731static const unsigned char entropy_source_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100732{ 0xca, 0x58, 0xfd, 0xf2, 0xb9, 0x77, 0xcb, 0x49,
733 0xd4, 0xe0, 0x5b, 0xe2, 0x39, 0x50, 0xd9, 0x8a,
734 0x6a, 0xb3, 0xc5, 0x2f, 0xdf, 0x74, 0xd5, 0x85,
735 0x8f, 0xd1, 0xba, 0x64, 0x54, 0x7b, 0xdb, 0x1e,
736 0xc5, 0xea, 0x24, 0xc0, 0xfa, 0x0c, 0x90, 0x15,
737 0x09, 0x20, 0x92, 0x42, 0x32, 0x36, 0x45, 0x45,
738 0x7d, 0x20, 0x76, 0x6b, 0xcf, 0xa2, 0x15, 0xc8,
739 0x2f, 0x9f, 0xbc, 0x88, 0x3f, 0x80, 0xd1, 0x2c,
740 0xb7, 0x16, 0xd1, 0x80, 0x9e, 0xe1, 0xc9, 0xb3,
741 0x88, 0x1b, 0x21, 0x45, 0xef, 0xa1, 0x7f, 0xce,
742 0xc8, 0x92, 0x35, 0x55, 0x2a, 0xd9, 0x1d, 0x8e,
743 0x12, 0x38, 0xac, 0x01, 0x4e, 0x38, 0x18, 0x76,
744 0x9c, 0xf2, 0xb6, 0xd4, 0x13, 0xb6, 0x2c, 0x77,
745 0xc0, 0xe7, 0xe6, 0x0c, 0x47, 0x44, 0x95, 0xbe };
ENT\stroej1df307002020-12-26 12:41:04 -0600746
747static const unsigned char entropy_source_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100748{ 0x4c, 0xfb, 0x21, 0x86, 0x73, 0x34, 0x6d, 0x9d,
749 0x50, 0xc9, 0x22, 0xe4, 0x9b, 0x0d, 0xfc, 0xd0,
750 0x90, 0xad, 0xf0, 0x4f, 0x5c, 0x3b, 0xa4, 0x73,
751 0x27, 0xdf, 0xcd, 0x6f, 0xa6, 0x3a, 0x78, 0x5c,
752 0x01, 0x69, 0x62, 0xa7, 0xfd, 0x27, 0x87, 0xa2,
753 0x4b, 0xf6, 0xbe, 0x47, 0xef, 0x37, 0x83, 0xf1,
754 0xb7, 0xec, 0x46, 0x07, 0x23, 0x63, 0x83, 0x4a,
755 0x1b, 0x01, 0x33, 0xf2, 0xc2, 0x38, 0x91, 0xdb,
756 0x4f, 0x11, 0xa6, 0x86, 0x51, 0xf2, 0x3e, 0x3a,
757 0x8b, 0x1f, 0xdc, 0x03, 0xb1, 0x92, 0xc7, 0xe7 };
ENT\stroej1df307002020-12-26 12:41:04 -0600758
stroebeljcd4de1b52021-01-04 18:14:32 -0600759static const unsigned char pers_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100760{ 0x5a, 0x70, 0x95, 0xe9, 0x81, 0x40, 0x52, 0x33,
761 0x91, 0x53, 0x7e, 0x75, 0xd6, 0x19, 0x9d, 0x1e,
762 0xad, 0x0d, 0xc6, 0xa7, 0xde, 0x6c, 0x1f, 0xe0,
763 0xea, 0x18, 0x33, 0xa8, 0x7e, 0x06, 0x20, 0xe9 };
ENT\stroej1df307002020-12-26 12:41:04 -0600764
stroebeljcd4de1b52021-01-04 18:14:32 -0600765static const unsigned char pers_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100766{ 0x88, 0xee, 0xb8, 0xe0, 0xe8, 0x3b, 0xf3, 0x29,
767 0x4b, 0xda, 0xcd, 0x60, 0x99, 0xeb, 0xe4, 0xbf,
768 0x55, 0xec, 0xd9, 0x11, 0x3f, 0x71, 0xe5, 0xeb,
769 0xcb, 0x45, 0x75, 0xf3, 0xd6, 0xa6, 0x8a, 0x6b };
ENT\stroej1df307002020-12-26 12:41:04 -0600770
771static const unsigned char result_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100772{ 0xce, 0x2f, 0xdb, 0xb6, 0xd9, 0xb7, 0x39, 0x85,
773 0x04, 0xc5, 0xc0, 0x42, 0xc2, 0x31, 0xc6, 0x1d,
774 0x9b, 0x5a, 0x59, 0xf8, 0x7e, 0x0d, 0xcc, 0x62,
775 0x7b, 0x65, 0x11, 0x55, 0x10, 0xeb, 0x9e, 0x3d,
776 0xa4, 0xfb, 0x1c, 0x6a, 0x18, 0xc0, 0x74, 0xdb,
777 0xdd, 0xe7, 0x02, 0x23, 0x63, 0x21, 0xd0, 0x39,
778 0xf9, 0xa7, 0xc4, 0x52, 0x84, 0x3b, 0x49, 0x40,
779 0x72, 0x2b, 0xb0, 0x6c, 0x9c, 0xdb, 0xc3, 0x43 };
ENT\stroej1df307002020-12-26 12:41:04 -0600780
781static const unsigned char result_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100782{ 0xa5, 0x51, 0x80, 0xa1, 0x90, 0xbe, 0xf3, 0xad,
783 0xaf, 0x28, 0xf6, 0xb7, 0x95, 0xe9, 0xf1, 0xf3,
784 0xd6, 0xdf, 0xa1, 0xb2, 0x7d, 0xd0, 0x46, 0x7b,
785 0x0c, 0x75, 0xf5, 0xfa, 0x93, 0x1e, 0x97, 0x14,
786 0x75, 0xb2, 0x7c, 0xae, 0x03, 0xa2, 0x96, 0x54,
787 0xe2, 0xf4, 0x09, 0x66, 0xea, 0x33, 0x64, 0x30,
788 0x40, 0xd1, 0x40, 0x0f, 0xe6, 0x77, 0x87, 0x3a,
789 0xf8, 0x09, 0x7c, 0x1f, 0xe9, 0xf0, 0x02, 0x98 };
Gilles Peskine02e79a42019-10-07 17:06:06 +0200790#endif /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000791
Manuel Pégourié-Gonnard95924852014-03-21 10:54:55 +0100792static size_t test_offset;
Gilles Peskine449bd832023-01-11 14:50:10 +0100793static int ctr_drbg_self_test_entropy(void *data, unsigned char *buf,
794 size_t len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000795{
Manuel Pégourié-Gonnardb3b205e2014-01-31 12:04:06 +0100796 const unsigned char *p = data;
Gilles Peskine449bd832023-01-11 14:50:10 +0100797 memcpy(buf, p + test_offset, len);
Manuel Pégourié-Gonnardb3b205e2014-01-31 12:04:06 +0100798 test_offset += len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100799 return 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000800}
801
Gilles Peskine449bd832023-01-11 14:50:10 +0100802#define CHK(c) if ((c) != 0) \
803 { \
804 if (verbose != 0) \
805 mbedtls_printf("failed\n"); \
806 return 1; \
807 }
Manuel Pégourié-Gonnardb3b205e2014-01-31 12:04:06 +0100808
bootstrap-prime6dbbf442022-05-17 19:30:44 -0400809#define SELF_TEST_OUTPUT_DISCARD_LENGTH 64
stroebeljcd4de1b52021-01-04 18:14:32 -0600810
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000811/*
812 * Checkup routine
813 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100814int mbedtls_ctr_drbg_self_test(int verbose)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000815{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200816 mbedtls_ctr_drbg_context ctx;
Gilles Peskine449bd832023-01-11 14:50:10 +0100817 unsigned char buf[sizeof(result_pr)];
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000818
Gilles Peskine449bd832023-01-11 14:50:10 +0100819 mbedtls_ctr_drbg_init(&ctx);
Manuel Pégourié-Gonnard8d128ef2015-04-28 22:38:08 +0200820
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000821 /*
822 * Based on a NIST CTR_DRBG test vector (PR = True)
823 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100824 if (verbose != 0) {
825 mbedtls_printf(" CTR_DRBG (PR = TRUE) : ");
826 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000827
828 test_offset = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100829 mbedtls_ctr_drbg_set_entropy_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE);
830 mbedtls_ctr_drbg_set_nonce_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2);
831 CHK(mbedtls_ctr_drbg_seed(&ctx,
832 ctr_drbg_self_test_entropy,
833 (void *) entropy_source_pr,
834 pers_pr, MBEDTLS_CTR_DRBG_KEYSIZE));
835 mbedtls_ctr_drbg_set_prediction_resistance(&ctx, MBEDTLS_CTR_DRBG_PR_ON);
836 CHK(mbedtls_ctr_drbg_random(&ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH));
837 CHK(mbedtls_ctr_drbg_random(&ctx, buf, sizeof(result_pr)));
838 CHK(memcmp(buf, result_pr, sizeof(result_pr)));
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000839
Gilles Peskine449bd832023-01-11 14:50:10 +0100840 mbedtls_ctr_drbg_free(&ctx);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100841
Gilles Peskine449bd832023-01-11 14:50:10 +0100842 if (verbose != 0) {
843 mbedtls_printf("passed\n");
844 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000845
846 /*
847 * Based on a NIST CTR_DRBG test vector (PR = FALSE)
848 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100849 if (verbose != 0) {
850 mbedtls_printf(" CTR_DRBG (PR = FALSE): ");
851 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000852
Gilles Peskine449bd832023-01-11 14:50:10 +0100853 mbedtls_ctr_drbg_init(&ctx);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100854
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000855 test_offset = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100856 mbedtls_ctr_drbg_set_entropy_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE);
857 mbedtls_ctr_drbg_set_nonce_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2);
858 CHK(mbedtls_ctr_drbg_seed(&ctx,
859 ctr_drbg_self_test_entropy,
860 (void *) entropy_source_nopr,
861 pers_nopr, MBEDTLS_CTR_DRBG_KEYSIZE));
862 CHK(mbedtls_ctr_drbg_reseed(&ctx, NULL, 0));
863 CHK(mbedtls_ctr_drbg_random(&ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH));
864 CHK(mbedtls_ctr_drbg_random(&ctx, buf, sizeof(result_nopr)));
865 CHK(memcmp(buf, result_nopr, sizeof(result_nopr)));
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000866
Gilles Peskine449bd832023-01-11 14:50:10 +0100867 mbedtls_ctr_drbg_free(&ctx);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100868
Gilles Peskine449bd832023-01-11 14:50:10 +0100869 if (verbose != 0) {
870 mbedtls_printf("passed\n");
871 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000872
Gilles Peskine449bd832023-01-11 14:50:10 +0100873 if (verbose != 0) {
874 mbedtls_printf("\n");
875 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000876
Gilles Peskine449bd832023-01-11 14:50:10 +0100877 return 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000878}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200879#endif /* MBEDTLS_SELF_TEST */
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000880
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200881#endif /* MBEDTLS_CTR_DRBG_C */