blob: 13fa6d4ebee16e541fb645ed265a1265bc7efbef [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 *
22 * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
23 */
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 }
Gilles Peskine9be50982019-10-22 18:42:27 +0200101#if SIZE_MAX > INT_MAX
102 /* 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#endif
109
110 /* For backward compatibility with Mbed TLS <= 2.19, store the
111 * entropy nonce length in a field that already exists, but isn't
112 * used until after the initial seeding. */
113 /* Due to the capping of len above, the value fits in an int. */
114 ctx->reseed_counter = (int) len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100115 return 0;
Gilles Peskine9be50982019-10-22 18:42:27 +0200116}
117
Gilles Peskine449bd832023-01-11 14:50:10 +0100118void mbedtls_ctr_drbg_set_reseed_interval(mbedtls_ctr_drbg_context *ctx,
119 int interval)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000120{
121 ctx->reseed_interval = interval;
122}
Paul Bakkerb6c5d2e2013-06-25 16:25:17 +0200123
Gilles Peskine449bd832023-01-11 14:50:10 +0100124static int block_cipher_df(unsigned char *output,
125 const unsigned char *data, size_t data_len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000126{
Hanno Beckera08651f2018-10-05 09:38:59 +0100127 unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
128 MBEDTLS_CTR_DRBG_BLOCKSIZE + 16];
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200129 unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
130 unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
131 unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE];
Manuel Pégourié-Gonnard7c593632014-01-20 10:27:13 +0100132 unsigned char *p, *iv;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200133 mbedtls_aes_context aes_ctx;
Dvir Markovich1b364992017-06-26 13:43:34 +0300134 int ret = 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000135
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200136 int i, j;
137 size_t buf_len, use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000138
Gilles Peskine449bd832023-01-11 14:50:10 +0100139 if (data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) {
140 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
141 }
Manuel Pégourié-Gonnard5cb4b312014-11-25 17:41:50 +0100142
Gilles Peskine449bd832023-01-11 14:50:10 +0100143 memset(buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
144 MBEDTLS_CTR_DRBG_BLOCKSIZE + 16);
145 mbedtls_aes_init(&aes_ctx);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000146
147 /*
148 * Construct IV (16 bytes) and S in buffer
149 * IV = Counter (in 32-bits) padded to 16 with zeroes
150 * S = Length input string (in 32-bits) || Length of output (in 32-bits) ||
151 * data || 0x80
152 * (Total is padded to a multiple of 16-bytes with zeroes)
153 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200154 p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE;
Gilles Peskine449bd832023-01-11 14:50:10 +0100155 MBEDTLS_PUT_UINT32_BE(data_len, p, 0);
Joe Subbiania5cb0d22021-08-23 11:35:25 +0100156 p += 4 + 3;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200157 *p++ = MBEDTLS_CTR_DRBG_SEEDLEN;
Gilles Peskine449bd832023-01-11 14:50:10 +0100158 memcpy(p, data, data_len);
Paul Bakker2bc7cf12011-11-29 10:50:51 +0000159 p[data_len] = 0x80;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000160
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200161 buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000162
Gilles Peskine449bd832023-01-11 14:50:10 +0100163 for (i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000164 key[i] = i;
Gilles Peskine449bd832023-01-11 14:50:10 +0100165 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000166
Gilles Peskine449bd832023-01-11 14:50:10 +0100167 if ((ret = mbedtls_aes_setkey_enc(&aes_ctx, key,
168 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300169 goto exit;
170 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000171
172 /*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200173 * Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000174 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100175 for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000176 p = buf;
Gilles Peskine449bd832023-01-11 14:50:10 +0100177 memset(chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000178 use_len = buf_len;
179
Gilles Peskine449bd832023-01-11 14:50:10 +0100180 while (use_len > 0) {
181 mbedtls_xor(chain, chain, p, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200182 p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
Gilles Peskine449bd832023-01-11 14:50:10 +0100183 use_len -= (use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE) ?
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200184 MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000185
Gilles Peskine449bd832023-01-11 14:50:10 +0100186 if ((ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT,
187 chain, chain)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300188 goto exit;
189 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000190 }
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200191
Gilles Peskine449bd832023-01-11 14:50:10 +0100192 memcpy(tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000193
194 /*
195 * Update IV
196 */
197 buf[3]++;
198 }
199
200 /*
201 * Do final encryption with reduced data
202 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100203 if ((ret = mbedtls_aes_setkey_enc(&aes_ctx, tmp,
204 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300205 goto exit;
206 }
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200207 iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000208 p = output;
209
Gilles Peskine449bd832023-01-11 14:50:10 +0100210 for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
211 if ((ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT,
212 iv, iv)) != 0) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300213 goto exit;
214 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100215 memcpy(p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200216 p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000217 }
Dvir Markovich1b364992017-06-26 13:43:34 +0300218exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100219 mbedtls_aes_free(&aes_ctx);
Dvir Markovich1b364992017-06-26 13:43:34 +0300220 /*
Gilles Peskine449bd832023-01-11 14:50:10 +0100221 * tidy up the stack
222 */
223 mbedtls_platform_zeroize(buf, sizeof(buf));
224 mbedtls_platform_zeroize(tmp, sizeof(tmp));
225 mbedtls_platform_zeroize(key, sizeof(key));
226 mbedtls_platform_zeroize(chain, sizeof(chain));
227 if (0 != ret) {
Dvir Markovich1b364992017-06-26 13:43:34 +0300228 /*
Gilles Peskine449bd832023-01-11 14:50:10 +0100229 * wipe partial seed from memory
230 */
231 mbedtls_platform_zeroize(output, MBEDTLS_CTR_DRBG_SEEDLEN);
Dvir Markovich1b364992017-06-26 13:43:34 +0300232 }
Paul Bakkerc7ea99a2014-06-18 11:12:03 +0200233
Gilles Peskine449bd832023-01-11 14:50:10 +0100234 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000235}
236
Gilles Peskineed7da592018-08-03 20:16:52 +0200237/* CTR_DRBG_Update (SP 800-90A &sect;10.2.1.2)
238 * ctr_drbg_update_internal(ctx, provided_data)
239 * implements
240 * CTR_DRBG_Update(provided_data, Key, V)
241 * with inputs and outputs
242 * ctx->aes_ctx = Key
243 * ctx->counter = V
244 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100245static int ctr_drbg_update_internal(mbedtls_ctr_drbg_context *ctx,
246 const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN])
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000247{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200248 unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000249 unsigned char *p = tmp;
Paul Bakker369e14b2012-04-18 14:16:09 +0000250 int i, j;
Dvir Markovich1b364992017-06-26 13:43:34 +0300251 int ret = 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000252
Gilles Peskine449bd832023-01-11 14:50:10 +0100253 memset(tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000254
Gilles Peskine449bd832023-01-11 14:50:10 +0100255 for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000256 /*
257 * Increase counter
258 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100259 for (i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i--) {
260 if (++ctx->counter[i - 1] != 0) {
Paul Bakker369e14b2012-04-18 14:16:09 +0000261 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100262 }
263 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000264
265 /*
266 * Crypt counter block
267 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100268 if ((ret = mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
269 ctx->counter, p)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200270 goto exit;
Dvir Markovich1b364992017-06-26 13:43:34 +0300271 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000272
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200273 p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000274 }
275
Gilles Peskine449bd832023-01-11 14:50:10 +0100276 for (i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000277 tmp[i] ^= data[i];
Gilles Peskine449bd832023-01-11 14:50:10 +0100278 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000279
280 /*
281 * Update key and counter
282 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100283 if ((ret = mbedtls_aes_setkey_enc(&ctx->aes_ctx, tmp,
284 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200285 goto exit;
Dvir Markovich1b364992017-06-26 13:43:34 +0300286 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100287 memcpy(ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE,
288 MBEDTLS_CTR_DRBG_BLOCKSIZE);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000289
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200290exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100291 mbedtls_platform_zeroize(tmp, sizeof(tmp));
292 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000293}
294
Gilles Peskineed7da592018-08-03 20:16:52 +0200295/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
TRodziewicz26371e42021-06-08 16:45:41 +0200296 * mbedtls_ctr_drbg_update(ctx, additional, add_len)
Gilles Peskineed7da592018-08-03 20:16:52 +0200297 * implements
298 * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
299 * security_strength) -> initial_working_state
300 * with inputs
301 * ctx->counter = all-bits-0
302 * ctx->aes_ctx = context from all-bits-0 key
303 * additional[:add_len] = entropy_input || nonce || personalization_string
304 * and with outputs
305 * ctx = initial_working_state
306 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100307int mbedtls_ctr_drbg_update(mbedtls_ctr_drbg_context *ctx,
308 const unsigned char *additional,
309 size_t add_len)
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000310{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200311 unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
Janos Follath24eed8d2019-11-22 13:21:35 +0000312 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000313
Gilles Peskine449bd832023-01-11 14:50:10 +0100314 if (add_len == 0) {
315 return 0;
316 }
Manuel Pégourié-Gonnard5cb4b312014-11-25 17:41:50 +0100317
Gilles Peskine449bd832023-01-11 14:50:10 +0100318 if ((ret = block_cipher_df(add_input, additional, add_len)) != 0) {
Gilles Peskined9199932018-09-11 16:41:54 +0200319 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100320 }
321 if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
Gilles Peskined9199932018-09-11 16:41:54 +0200322 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100323 }
Gilles Peskined9199932018-09-11 16:41:54 +0200324
325exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100326 mbedtls_platform_zeroize(add_input, sizeof(add_input));
327 return ret;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000328}
329
Gilles Peskineed7da592018-08-03 20:16:52 +0200330/* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
Gilles Peskine9be50982019-10-22 18:42:27 +0200331 * mbedtls_ctr_drbg_reseed(ctx, additional, len, nonce_len)
Gilles Peskineed7da592018-08-03 20:16:52 +0200332 * implements
333 * CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
334 * -> new_working_state
335 * with inputs
336 * ctx contains working_state
337 * additional[:len] = additional_input
338 * and entropy_input comes from calling ctx->f_entropy
Gilles Peskine9be50982019-10-22 18:42:27 +0200339 * for (ctx->entropy_len + nonce_len) bytes
Gilles Peskineed7da592018-08-03 20:16:52 +0200340 * and with output
341 * ctx contains new_working_state
342 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100343static int mbedtls_ctr_drbg_reseed_internal(mbedtls_ctr_drbg_context *ctx,
344 const unsigned char *additional,
345 size_t len,
346 size_t nonce_len)
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000347{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200348 unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000349 size_t seedlen = 0;
Janos Follath24eed8d2019-11-22 13:21:35 +0000350 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000351
Gilles Peskine449bd832023-01-11 14:50:10 +0100352 if (ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) {
353 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
354 }
355 if (nonce_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len) {
356 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
357 }
358 if (len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len - nonce_len) {
359 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
360 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000361
Gilles Peskine449bd832023-01-11 14:50:10 +0100362 memset(seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT);
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000363
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200364 /* Gather entropy_len bytes of entropy to seed state. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100365 if (0 != ctx->f_entropy(ctx->p_entropy, seed, ctx->entropy_len)) {
366 return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000367 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000368 seedlen += ctx->entropy_len;
369
Gilles Peskine9be50982019-10-22 18:42:27 +0200370 /* Gather entropy for a nonce if requested. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100371 if (nonce_len != 0) {
372 if (0 != ctx->f_entropy(ctx->p_entropy, seed + seedlen, nonce_len)) {
373 return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
Gilles Peskine9be50982019-10-22 18:42:27 +0200374 }
375 seedlen += nonce_len;
376 }
377
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200378 /* Add additional data if provided. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100379 if (additional != NULL && len != 0) {
380 memcpy(seed + seedlen, additional, len);
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000381 seedlen += len;
382 }
383
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200384 /* Reduce to 384 bits. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100385 if ((ret = block_cipher_df(seed, seed, seedlen)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200386 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100387 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000388
Gilles Peskinedbd3f7c2019-10-22 17:25:30 +0200389 /* Update state. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100390 if ((ret = ctr_drbg_update_internal(ctx, seed)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200391 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100392 }
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000393 ctx->reseed_counter = 1;
394
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200395exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100396 mbedtls_platform_zeroize(seed, sizeof(seed));
397 return ret;
Paul Bakker1bc9efc2011-12-03 11:29:32 +0000398}
Paul Bakker9af723c2014-05-01 13:03:14 +0200399
Gilles Peskine449bd832023-01-11 14:50:10 +0100400int mbedtls_ctr_drbg_reseed(mbedtls_ctr_drbg_context *ctx,
401 const unsigned char *additional, size_t len)
Gilles Peskine9be50982019-10-22 18:42:27 +0200402{
Gilles Peskine449bd832023-01-11 14:50:10 +0100403 return mbedtls_ctr_drbg_reseed_internal(ctx, additional, len, 0);
Gilles Peskine9be50982019-10-22 18:42:27 +0200404}
405
Gilles Peskinee9a34542019-10-22 20:43:24 +0200406/* Return a "good" nonce length for CTR_DRBG. The chosen nonce length
407 * is sufficient to achieve the maximum security strength given the key
408 * size and entropy length. If there is enough entropy in the initial
409 * call to the entropy function to serve as both the entropy input and
410 * the nonce, don't make a second call to get a nonce. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100411static size_t good_nonce_len(size_t entropy_len)
Gilles Peskinee9a34542019-10-22 20:43:24 +0200412{
Gilles Peskine449bd832023-01-11 14:50:10 +0100413 if (entropy_len >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2) {
414 return 0;
415 } else {
416 return (entropy_len + 1) / 2;
417 }
Gilles Peskinee9a34542019-10-22 20:43:24 +0200418}
419
Gilles Peskine8bf56132019-10-02 20:31:54 +0200420/* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
Gilles Peskine379561f2019-10-18 16:57:48 +0200421 * mbedtls_ctr_drbg_seed(ctx, f_entropy, p_entropy, custom, len)
Gilles Peskine8bf56132019-10-02 20:31:54 +0200422 * implements
423 * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
424 * security_strength) -> initial_working_state
425 * with inputs
426 * custom[:len] = nonce || personalization_string
Gilles Peskine379561f2019-10-18 16:57:48 +0200427 * where entropy_input comes from f_entropy for ctx->entropy_len bytes
Gilles Peskine8bf56132019-10-02 20:31:54 +0200428 * and with outputs
429 * ctx = initial_working_state
430 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100431int mbedtls_ctr_drbg_seed(mbedtls_ctr_drbg_context *ctx,
432 int (*f_entropy)(void *, unsigned char *, size_t),
433 void *p_entropy,
434 const unsigned char *custom,
435 size_t len)
Gilles Peskine8bf56132019-10-02 20:31:54 +0200436{
Janos Follath24eed8d2019-11-22 13:21:35 +0000437 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200438 unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
Gilles Peskinee9a34542019-10-22 20:43:24 +0200439 size_t nonce_len;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200440
Gilles Peskine449bd832023-01-11 14:50:10 +0100441 memset(key, 0, MBEDTLS_CTR_DRBG_KEYSIZE);
Gilles Peskine8bf56132019-10-02 20:31:54 +0200442
Gilles Peskineda290f92021-02-09 18:44:02 +0100443 /* The mutex is initialized iff f_entropy is set. */
Gilles Peskinef4b34292021-01-30 13:05:32 +0100444#if defined(MBEDTLS_THREADING_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100445 mbedtls_mutex_init(&ctx->mutex);
Gilles Peskinef4b34292021-01-30 13:05:32 +0100446#endif
447
Gilles Peskine8bf56132019-10-02 20:31:54 +0200448 ctx->f_entropy = f_entropy;
449 ctx->p_entropy = p_entropy;
450
Gilles Peskine449bd832023-01-11 14:50:10 +0100451 if (ctx->entropy_len == 0) {
Gilles Peskine50ed86b2019-10-04 12:15:55 +0200452 ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
Gilles Peskine449bd832023-01-11 14:50:10 +0100453 }
Gilles Peskinee9a34542019-10-22 20:43:24 +0200454 /* ctx->reseed_counter contains the desired amount of entropy to
455 * grab for a nonce (see mbedtls_ctr_drbg_set_nonce_len()).
456 * If it's -1, indicating that the entropy nonce length was not set
457 * explicitly, use a sufficiently large nonce for security. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100458 nonce_len = (ctx->reseed_counter >= 0 ?
459 (size_t) ctx->reseed_counter :
460 good_nonce_len(ctx->entropy_len));
Gilles Peskinee9a34542019-10-22 20:43:24 +0200461
Gilles Peskine9be50982019-10-22 18:42:27 +0200462 /* Initialize with an empty key. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100463 if ((ret = mbedtls_aes_setkey_enc(&ctx->aes_ctx, key,
464 MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
465 return ret;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200466 }
467
Gilles Peskinee9a34542019-10-22 20:43:24 +0200468 /* Do the initial seeding. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100469 if ((ret = mbedtls_ctr_drbg_reseed_internal(ctx, custom, len,
470 nonce_len)) != 0) {
471 return ret;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200472 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100473 return 0;
Gilles Peskine8bf56132019-10-02 20:31:54 +0200474}
475
Gilles Peskineed7da592018-08-03 20:16:52 +0200476/* CTR_DRBG_Generate with derivation function (SP 800-90A &sect;10.2.1.5.2)
477 * mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len)
478 * implements
479 * CTR_DRBG_Reseed(working_state, entropy_input, additional[:add_len])
480 * -> working_state_after_reseed
481 * if required, then
482 * CTR_DRBG_Generate(working_state_after_reseed,
483 * requested_number_of_bits, additional_input)
484 * -> status, returned_bits, new_working_state
485 * with inputs
486 * ctx contains working_state
487 * requested_number_of_bits = 8 * output_len
488 * additional[:add_len] = additional_input
489 * and entropy_input comes from calling ctx->f_entropy
490 * and with outputs
491 * status = SUCCESS (this function does the reseed internally)
492 * returned_bits = output[:output_len]
493 * ctx contains new_working_state
494 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100495int mbedtls_ctr_drbg_random_with_add(void *p_rng,
496 unsigned char *output, size_t output_len,
497 const unsigned char *additional, size_t add_len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000498{
499 int ret = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200500 mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
501 unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000502 unsigned char *p = output;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200503 unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE];
Paul Bakker369e14b2012-04-18 14:16:09 +0000504 int i;
Paul Bakker23fd5ea2011-11-29 15:56:12 +0000505 size_t use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000506
Gilles Peskine449bd832023-01-11 14:50:10 +0100507 if (output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST) {
508 return MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG;
509 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000510
Gilles Peskine449bd832023-01-11 14:50:10 +0100511 if (add_len > MBEDTLS_CTR_DRBG_MAX_INPUT) {
512 return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
513 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000514
Gilles Peskine449bd832023-01-11 14:50:10 +0100515 memset(add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN);
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000516
Gilles Peskine449bd832023-01-11 14:50:10 +0100517 if (ctx->reseed_counter > ctx->reseed_interval ||
518 ctx->prediction_resistance) {
519 if ((ret = mbedtls_ctr_drbg_reseed(ctx, additional, add_len)) != 0) {
520 return ret;
Dvir Markovich1b364992017-06-26 13:43:34 +0300521 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000522 add_len = 0;
523 }
524
Gilles Peskine449bd832023-01-11 14:50:10 +0100525 if (add_len > 0) {
526 if ((ret = block_cipher_df(add_input, additional, add_len)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200527 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100528 }
529 if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200530 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100531 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000532 }
533
Gilles Peskine449bd832023-01-11 14:50:10 +0100534 while (output_len > 0) {
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000535 /*
536 * Increase counter
537 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100538 for (i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i--) {
539 if (++ctx->counter[i - 1] != 0) {
Paul Bakker369e14b2012-04-18 14:16:09 +0000540 break;
Gilles Peskine449bd832023-01-11 14:50:10 +0100541 }
542 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000543
544 /*
545 * Crypt counter block
546 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100547 if ((ret = mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
548 ctx->counter, tmp)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200549 goto exit;
Dvir Markovich1b364992017-06-26 13:43:34 +0300550 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000551
Gilles Peskine449bd832023-01-11 14:50:10 +0100552 use_len = (output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE)
Hanno Beckera08651f2018-10-05 09:38:59 +0100553 ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000554 /*
555 * Copy random block to destination
556 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100557 memcpy(p, tmp, use_len);
Paul Bakker23fd5ea2011-11-29 15:56:12 +0000558 p += use_len;
559 output_len -= use_len;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000560 }
561
Gilles Peskine449bd832023-01-11 14:50:10 +0100562 if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200563 goto exit;
Gilles Peskine449bd832023-01-11 14:50:10 +0100564 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000565
566 ctx->reseed_counter++;
567
Gilles Peskined9aa84d2018-09-11 15:34:17 +0200568exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100569 mbedtls_platform_zeroize(add_input, sizeof(add_input));
570 mbedtls_platform_zeroize(tmp, sizeof(tmp));
571 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000572}
573
Gilles Peskine449bd832023-01-11 14:50:10 +0100574int mbedtls_ctr_drbg_random(void *p_rng, unsigned char *output,
575 size_t output_len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000576{
Janos Follath24eed8d2019-11-22 13:21:35 +0000577 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100578 mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
579
580#if defined(MBEDTLS_THREADING_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100581 if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {
582 return ret;
583 }
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100584#endif
585
Gilles Peskine449bd832023-01-11 14:50:10 +0100586 ret = mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, NULL, 0);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100587
588#if defined(MBEDTLS_THREADING_C)
Gilles Peskine449bd832023-01-11 14:50:10 +0100589 if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
590 return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
591 }
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100592#endif
593
Gilles Peskine449bd832023-01-11 14:50:10 +0100594 return ret;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000595}
596
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200597#if defined(MBEDTLS_FS_IO)
Gilles Peskine449bd832023-01-11 14:50:10 +0100598int mbedtls_ctr_drbg_write_seed_file(mbedtls_ctr_drbg_context *ctx,
599 const char *path)
Paul Bakkerfc754a92011-12-05 13:23:51 +0000600{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200601 int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000602 FILE *f;
Gilles Peskine449bd832023-01-11 14:50:10 +0100603 unsigned char buf[MBEDTLS_CTR_DRBG_MAX_INPUT];
Paul Bakkerfc754a92011-12-05 13:23:51 +0000604
Gilles Peskine449bd832023-01-11 14:50:10 +0100605 if ((f = fopen(path, "wb")) == NULL) {
606 return MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
607 }
Paul Bakkerfc754a92011-12-05 13:23:51 +0000608
Gilles Peskineda0913b2022-06-30 17:03:40 +0200609 /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100610 mbedtls_setbuf(f, NULL);
Gilles Peskineda0913b2022-06-30 17:03:40 +0200611
Gilles Peskine449bd832023-01-11 14:50:10 +0100612 if ((ret = mbedtls_ctr_drbg_random(ctx, buf,
613 MBEDTLS_CTR_DRBG_MAX_INPUT)) != 0) {
Paul Bakkerc72d3f72013-05-14 13:22:41 +0200614 goto exit;
Hanno Beckera08651f2018-10-05 09:38:59 +0100615 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100616
617 if (fwrite(buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f) !=
618 MBEDTLS_CTR_DRBG_MAX_INPUT) {
619 ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
620 } else {
Andres Amaya Garcia13f41e12017-06-26 10:56:58 +0100621 ret = 0;
Hanno Beckera08651f2018-10-05 09:38:59 +0100622 }
Paul Bakkerfc754a92011-12-05 13:23:51 +0000623
Andres Amaya Garcia4e2c07c2017-06-27 16:57:26 +0100624exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100625 mbedtls_platform_zeroize(buf, sizeof(buf));
Paul Bakkerc72d3f72013-05-14 13:22:41 +0200626
Gilles Peskine449bd832023-01-11 14:50:10 +0100627 fclose(f);
628 return ret;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000629}
630
Gilles Peskine449bd832023-01-11 14:50:10 +0100631int mbedtls_ctr_drbg_update_seed_file(mbedtls_ctr_drbg_context *ctx,
632 const char *path)
Paul Bakkerfc754a92011-12-05 13:23:51 +0000633{
Andres Amaya Garcia13f41e12017-06-26 10:56:58 +0100634 int ret = 0;
Gilles Peskine82204662018-09-11 18:43:09 +0200635 FILE *f = NULL;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000636 size_t n;
Gilles Peskine449bd832023-01-11 14:50:10 +0100637 unsigned char buf[MBEDTLS_CTR_DRBG_MAX_INPUT];
Gilles Peskine82204662018-09-11 18:43:09 +0200638 unsigned char c;
Paul Bakkerfc754a92011-12-05 13:23:51 +0000639
Gilles Peskine449bd832023-01-11 14:50:10 +0100640 if ((f = fopen(path, "rb")) == NULL) {
641 return MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
642 }
Paul Bakkerfc754a92011-12-05 13:23:51 +0000643
Gilles Peskineda0913b2022-06-30 17:03:40 +0200644 /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100645 mbedtls_setbuf(f, NULL);
Gilles Peskineda0913b2022-06-30 17:03:40 +0200646
Gilles Peskine449bd832023-01-11 14:50:10 +0100647 n = fread(buf, 1, sizeof(buf), f);
648 if (fread(&c, 1, 1, f) != 0) {
Gilles Peskine82204662018-09-11 18:43:09 +0200649 ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
650 goto exit;
Andres Amaya Garcia4e2c07c2017-06-27 16:57:26 +0100651 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100652 if (n == 0 || ferror(f)) {
Andres Amaya Garcia13f41e12017-06-26 10:56:58 +0100653 ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
Gilles Peskine82204662018-09-11 18:43:09 +0200654 goto exit;
655 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100656 fclose(f);
Gilles Peskine82204662018-09-11 18:43:09 +0200657 f = NULL;
Paul Bakkerc72d3f72013-05-14 13:22:41 +0200658
Gilles Peskine449bd832023-01-11 14:50:10 +0100659 ret = mbedtls_ctr_drbg_update(ctx, buf, n);
Gilles Peskine82204662018-09-11 18:43:09 +0200660
661exit:
Gilles Peskine449bd832023-01-11 14:50:10 +0100662 mbedtls_platform_zeroize(buf, sizeof(buf));
663 if (f != NULL) {
664 fclose(f);
665 }
666 if (ret != 0) {
667 return ret;
668 }
669 return mbedtls_ctr_drbg_write_seed_file(ctx, path);
Paul Bakkerfc754a92011-12-05 13:23:51 +0000670}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200671#endif /* MBEDTLS_FS_IO */
Paul Bakkerfc754a92011-12-05 13:23:51 +0000672
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200673#if defined(MBEDTLS_SELF_TEST)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000674
ENT\stroej170f63d02020-12-28 08:50:23 -0600675/* The CTR_DRBG NIST test vectors used here are available at
676 * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/drbg/drbgtestvectors.zip
677 *
678 * The parameters used to derive the test data are:
679 *
680 * [AES-128 use df]
681 * [PredictionResistance = True/False]
682 * [EntropyInputLen = 128]
683 * [NonceLen = 64]
684 * [PersonalizationStringLen = 128]
685 * [AdditionalInputLen = 0]
686 * [ReturnedBitsLen = 512]
687 *
688 * [AES-256 use df]
689 * [PredictionResistance = True/False]
690 * [EntropyInputLen = 256]
691 * [NonceLen = 128]
692 * [PersonalizationStringLen = 256]
693 * [AdditionalInputLen = 0]
694 * [ReturnedBitsLen = 512]
695 *
696 */
697
Gilles Peskine02e79a42019-10-07 17:06:06 +0200698#if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY)
ENT\stroej1df307002020-12-26 12:41:04 -0600699static const unsigned char entropy_source_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100700{ 0x04, 0xd9, 0x49, 0xa6, 0xdc, 0xe8, 0x6e, 0xbb,
701 0xf1, 0x08, 0x77, 0x2b, 0x9e, 0x08, 0xca, 0x92,
702 0x65, 0x16, 0xda, 0x99, 0xa2, 0x59, 0xf3, 0xe8,
703 0x38, 0x7e, 0x3f, 0x6b, 0x51, 0x70, 0x7b, 0x20,
704 0xec, 0x53, 0xd0, 0x66, 0xc3, 0x0f, 0xe3, 0xb0,
705 0xe0, 0x86, 0xa6, 0xaa, 0x5f, 0x72, 0x2f, 0xad,
706 0xf7, 0xef, 0x06, 0xb8, 0xd6, 0x9c, 0x9d, 0xe8 };
Gilles Peskine02e79a42019-10-07 17:06:06 +0200707
ENT\stroej1df307002020-12-26 12:41:04 -0600708static const unsigned char entropy_source_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100709{ 0x07, 0x0d, 0x59, 0x63, 0x98, 0x73, 0xa5, 0x45,
710 0x27, 0x38, 0x22, 0x7b, 0x76, 0x85, 0xd1, 0xa9,
711 0x74, 0x18, 0x1f, 0x3c, 0x22, 0xf6, 0x49, 0x20,
712 0x4a, 0x47, 0xc2, 0xf3, 0x85, 0x16, 0xb4, 0x6f,
713 0x00, 0x2e, 0x71, 0xda, 0xed, 0x16, 0x9b, 0x5c };
ENT\stroej1df307002020-12-26 12:41:04 -0600714
stroebeljcd4de1b52021-01-04 18:14:32 -0600715static const unsigned char pers_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100716{ 0xbf, 0xa4, 0x9a, 0x8f, 0x7b, 0xd8, 0xb1, 0x7a,
717 0x9d, 0xfa, 0x45, 0xed, 0x21, 0x52, 0xb3, 0xad };
ENT\stroej1df307002020-12-26 12:41:04 -0600718
stroebeljcd4de1b52021-01-04 18:14:32 -0600719static const unsigned char pers_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100720{ 0x4e, 0x61, 0x79, 0xd4, 0xc2, 0x72, 0xa1, 0x4c,
721 0xf1, 0x3d, 0xf6, 0x5e, 0xa3, 0xa6, 0xe5, 0x0f };
ENT\stroej1df307002020-12-26 12:41:04 -0600722
723static const unsigned char result_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100724{ 0xc9, 0x0a, 0xaf, 0x85, 0x89, 0x71, 0x44, 0x66,
725 0x4f, 0x25, 0x0b, 0x2b, 0xde, 0xd8, 0xfa, 0xff,
726 0x52, 0x5a, 0x1b, 0x32, 0x5e, 0x41, 0x7a, 0x10,
727 0x1f, 0xef, 0x1e, 0x62, 0x23, 0xe9, 0x20, 0x30,
728 0xc9, 0x0d, 0xad, 0x69, 0xb4, 0x9c, 0x5b, 0xf4,
729 0x87, 0x42, 0xd5, 0xae, 0x5e, 0x5e, 0x43, 0xcc,
730 0xd9, 0xfd, 0x0b, 0x93, 0x4a, 0xe3, 0xd4, 0x06,
731 0x37, 0x36, 0x0f, 0x3f, 0x72, 0x82, 0x0c, 0xcf };
ENT\stroej1df307002020-12-26 12:41:04 -0600732
733static const unsigned char result_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100734{ 0x31, 0xc9, 0x91, 0x09, 0xf8, 0xc5, 0x10, 0x13,
735 0x3c, 0xd3, 0x96, 0xf9, 0xbc, 0x2c, 0x12, 0xc0,
736 0x7c, 0xc1, 0x61, 0x5f, 0xa3, 0x09, 0x99, 0xaf,
737 0xd7, 0xf2, 0x36, 0xfd, 0x40, 0x1a, 0x8b, 0xf2,
738 0x33, 0x38, 0xee, 0x1d, 0x03, 0x5f, 0x83, 0xb7,
739 0xa2, 0x53, 0xdc, 0xee, 0x18, 0xfc, 0xa7, 0xf2,
740 0xee, 0x96, 0xc6, 0xc2, 0xcd, 0x0c, 0xff, 0x02,
741 0x76, 0x70, 0x69, 0xaa, 0x69, 0xd1, 0x3b, 0xe8 };
Gilles Peskine02e79a42019-10-07 17:06:06 +0200742#else /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000743
ENT\stroej1df307002020-12-26 12:41:04 -0600744static const unsigned char entropy_source_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100745{ 0xca, 0x58, 0xfd, 0xf2, 0xb9, 0x77, 0xcb, 0x49,
746 0xd4, 0xe0, 0x5b, 0xe2, 0x39, 0x50, 0xd9, 0x8a,
747 0x6a, 0xb3, 0xc5, 0x2f, 0xdf, 0x74, 0xd5, 0x85,
748 0x8f, 0xd1, 0xba, 0x64, 0x54, 0x7b, 0xdb, 0x1e,
749 0xc5, 0xea, 0x24, 0xc0, 0xfa, 0x0c, 0x90, 0x15,
750 0x09, 0x20, 0x92, 0x42, 0x32, 0x36, 0x45, 0x45,
751 0x7d, 0x20, 0x76, 0x6b, 0xcf, 0xa2, 0x15, 0xc8,
752 0x2f, 0x9f, 0xbc, 0x88, 0x3f, 0x80, 0xd1, 0x2c,
753 0xb7, 0x16, 0xd1, 0x80, 0x9e, 0xe1, 0xc9, 0xb3,
754 0x88, 0x1b, 0x21, 0x45, 0xef, 0xa1, 0x7f, 0xce,
755 0xc8, 0x92, 0x35, 0x55, 0x2a, 0xd9, 0x1d, 0x8e,
756 0x12, 0x38, 0xac, 0x01, 0x4e, 0x38, 0x18, 0x76,
757 0x9c, 0xf2, 0xb6, 0xd4, 0x13, 0xb6, 0x2c, 0x77,
758 0xc0, 0xe7, 0xe6, 0x0c, 0x47, 0x44, 0x95, 0xbe };
ENT\stroej1df307002020-12-26 12:41:04 -0600759
760static const unsigned char entropy_source_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100761{ 0x4c, 0xfb, 0x21, 0x86, 0x73, 0x34, 0x6d, 0x9d,
762 0x50, 0xc9, 0x22, 0xe4, 0x9b, 0x0d, 0xfc, 0xd0,
763 0x90, 0xad, 0xf0, 0x4f, 0x5c, 0x3b, 0xa4, 0x73,
764 0x27, 0xdf, 0xcd, 0x6f, 0xa6, 0x3a, 0x78, 0x5c,
765 0x01, 0x69, 0x62, 0xa7, 0xfd, 0x27, 0x87, 0xa2,
766 0x4b, 0xf6, 0xbe, 0x47, 0xef, 0x37, 0x83, 0xf1,
767 0xb7, 0xec, 0x46, 0x07, 0x23, 0x63, 0x83, 0x4a,
768 0x1b, 0x01, 0x33, 0xf2, 0xc2, 0x38, 0x91, 0xdb,
769 0x4f, 0x11, 0xa6, 0x86, 0x51, 0xf2, 0x3e, 0x3a,
770 0x8b, 0x1f, 0xdc, 0x03, 0xb1, 0x92, 0xc7, 0xe7 };
ENT\stroej1df307002020-12-26 12:41:04 -0600771
stroebeljcd4de1b52021-01-04 18:14:32 -0600772static const unsigned char pers_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100773{ 0x5a, 0x70, 0x95, 0xe9, 0x81, 0x40, 0x52, 0x33,
774 0x91, 0x53, 0x7e, 0x75, 0xd6, 0x19, 0x9d, 0x1e,
775 0xad, 0x0d, 0xc6, 0xa7, 0xde, 0x6c, 0x1f, 0xe0,
776 0xea, 0x18, 0x33, 0xa8, 0x7e, 0x06, 0x20, 0xe9 };
ENT\stroej1df307002020-12-26 12:41:04 -0600777
stroebeljcd4de1b52021-01-04 18:14:32 -0600778static const unsigned char pers_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100779{ 0x88, 0xee, 0xb8, 0xe0, 0xe8, 0x3b, 0xf3, 0x29,
780 0x4b, 0xda, 0xcd, 0x60, 0x99, 0xeb, 0xe4, 0xbf,
781 0x55, 0xec, 0xd9, 0x11, 0x3f, 0x71, 0xe5, 0xeb,
782 0xcb, 0x45, 0x75, 0xf3, 0xd6, 0xa6, 0x8a, 0x6b };
ENT\stroej1df307002020-12-26 12:41:04 -0600783
784static const unsigned char result_pr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100785{ 0xce, 0x2f, 0xdb, 0xb6, 0xd9, 0xb7, 0x39, 0x85,
786 0x04, 0xc5, 0xc0, 0x42, 0xc2, 0x31, 0xc6, 0x1d,
787 0x9b, 0x5a, 0x59, 0xf8, 0x7e, 0x0d, 0xcc, 0x62,
788 0x7b, 0x65, 0x11, 0x55, 0x10, 0xeb, 0x9e, 0x3d,
789 0xa4, 0xfb, 0x1c, 0x6a, 0x18, 0xc0, 0x74, 0xdb,
790 0xdd, 0xe7, 0x02, 0x23, 0x63, 0x21, 0xd0, 0x39,
791 0xf9, 0xa7, 0xc4, 0x52, 0x84, 0x3b, 0x49, 0x40,
792 0x72, 0x2b, 0xb0, 0x6c, 0x9c, 0xdb, 0xc3, 0x43 };
ENT\stroej1df307002020-12-26 12:41:04 -0600793
794static const unsigned char result_nopr[] =
Gilles Peskine449bd832023-01-11 14:50:10 +0100795{ 0xa5, 0x51, 0x80, 0xa1, 0x90, 0xbe, 0xf3, 0xad,
796 0xaf, 0x28, 0xf6, 0xb7, 0x95, 0xe9, 0xf1, 0xf3,
797 0xd6, 0xdf, 0xa1, 0xb2, 0x7d, 0xd0, 0x46, 0x7b,
798 0x0c, 0x75, 0xf5, 0xfa, 0x93, 0x1e, 0x97, 0x14,
799 0x75, 0xb2, 0x7c, 0xae, 0x03, 0xa2, 0x96, 0x54,
800 0xe2, 0xf4, 0x09, 0x66, 0xea, 0x33, 0x64, 0x30,
801 0x40, 0xd1, 0x40, 0x0f, 0xe6, 0x77, 0x87, 0x3a,
802 0xf8, 0x09, 0x7c, 0x1f, 0xe9, 0xf0, 0x02, 0x98 };
Gilles Peskine02e79a42019-10-07 17:06:06 +0200803#endif /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000804
Manuel Pégourié-Gonnard95924852014-03-21 10:54:55 +0100805static size_t test_offset;
Gilles Peskine449bd832023-01-11 14:50:10 +0100806static int ctr_drbg_self_test_entropy(void *data, unsigned char *buf,
807 size_t len)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000808{
Manuel Pégourié-Gonnardb3b205e2014-01-31 12:04:06 +0100809 const unsigned char *p = data;
Gilles Peskine449bd832023-01-11 14:50:10 +0100810 memcpy(buf, p + test_offset, len);
Manuel Pégourié-Gonnardb3b205e2014-01-31 12:04:06 +0100811 test_offset += len;
Gilles Peskine449bd832023-01-11 14:50:10 +0100812 return 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000813}
814
Gilles Peskine449bd832023-01-11 14:50:10 +0100815#define CHK(c) if ((c) != 0) \
816 { \
817 if (verbose != 0) \
818 mbedtls_printf("failed\n"); \
819 return 1; \
820 }
Manuel Pégourié-Gonnardb3b205e2014-01-31 12:04:06 +0100821
bootstrap-prime6dbbf442022-05-17 19:30:44 -0400822#define SELF_TEST_OUTPUT_DISCARD_LENGTH 64
stroebeljcd4de1b52021-01-04 18:14:32 -0600823
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000824/*
825 * Checkup routine
826 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100827int mbedtls_ctr_drbg_self_test(int verbose)
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000828{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200829 mbedtls_ctr_drbg_context ctx;
Gilles Peskine449bd832023-01-11 14:50:10 +0100830 unsigned char buf[sizeof(result_pr)];
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000831
Gilles Peskine449bd832023-01-11 14:50:10 +0100832 mbedtls_ctr_drbg_init(&ctx);
Manuel Pégourié-Gonnard8d128ef2015-04-28 22:38:08 +0200833
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000834 /*
835 * Based on a NIST CTR_DRBG test vector (PR = True)
836 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100837 if (verbose != 0) {
838 mbedtls_printf(" CTR_DRBG (PR = TRUE) : ");
839 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000840
841 test_offset = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100842 mbedtls_ctr_drbg_set_entropy_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE);
843 mbedtls_ctr_drbg_set_nonce_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2);
844 CHK(mbedtls_ctr_drbg_seed(&ctx,
845 ctr_drbg_self_test_entropy,
846 (void *) entropy_source_pr,
847 pers_pr, MBEDTLS_CTR_DRBG_KEYSIZE));
848 mbedtls_ctr_drbg_set_prediction_resistance(&ctx, MBEDTLS_CTR_DRBG_PR_ON);
849 CHK(mbedtls_ctr_drbg_random(&ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH));
850 CHK(mbedtls_ctr_drbg_random(&ctx, buf, sizeof(result_pr)));
851 CHK(memcmp(buf, result_pr, sizeof(result_pr)));
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000852
Gilles Peskine449bd832023-01-11 14:50:10 +0100853 mbedtls_ctr_drbg_free(&ctx);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100854
Gilles Peskine449bd832023-01-11 14:50:10 +0100855 if (verbose != 0) {
856 mbedtls_printf("passed\n");
857 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000858
859 /*
860 * Based on a NIST CTR_DRBG test vector (PR = FALSE)
861 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100862 if (verbose != 0) {
863 mbedtls_printf(" CTR_DRBG (PR = FALSE): ");
864 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000865
Gilles Peskine449bd832023-01-11 14:50:10 +0100866 mbedtls_ctr_drbg_init(&ctx);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100867
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000868 test_offset = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100869 mbedtls_ctr_drbg_set_entropy_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE);
870 mbedtls_ctr_drbg_set_nonce_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2);
871 CHK(mbedtls_ctr_drbg_seed(&ctx,
872 ctr_drbg_self_test_entropy,
873 (void *) entropy_source_nopr,
874 pers_nopr, MBEDTLS_CTR_DRBG_KEYSIZE));
875 CHK(mbedtls_ctr_drbg_reseed(&ctx, NULL, 0));
876 CHK(mbedtls_ctr_drbg_random(&ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH));
877 CHK(mbedtls_ctr_drbg_random(&ctx, buf, sizeof(result_nopr)));
878 CHK(memcmp(buf, result_nopr, sizeof(result_nopr)));
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000879
Gilles Peskine449bd832023-01-11 14:50:10 +0100880 mbedtls_ctr_drbg_free(&ctx);
Manuel Pégourié-Gonnard0a4fb092015-05-07 12:50:31 +0100881
Gilles Peskine449bd832023-01-11 14:50:10 +0100882 if (verbose != 0) {
883 mbedtls_printf("passed\n");
884 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000885
Gilles Peskine449bd832023-01-11 14:50:10 +0100886 if (verbose != 0) {
887 mbedtls_printf("\n");
888 }
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000889
Gilles Peskine449bd832023-01-11 14:50:10 +0100890 return 0;
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000891}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200892#endif /* MBEDTLS_SELF_TEST */
Paul Bakker0e04d0e2011-11-27 14:46:59 +0000893
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200894#endif /* MBEDTLS_CTR_DRBG_C */