xref: /optee_os/lib/libmbedtls/mbedtls/library/ctr_drbg.c (revision 32b3180828fa15a49ccc86ecb4be9d274c140c89)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  CTR_DRBG implementation based on AES-256 (NIST SP 800-90)
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
57901324dSJerome Forissier  *  SPDX-License-Identifier: Apache-2.0
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9817466cbSJens Wiklander  *  You may obtain a copy of the License at
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17817466cbSJens Wiklander  *  limitations under the License.
18817466cbSJens Wiklander  */
19817466cbSJens Wiklander /*
203d3b0591SJens Wiklander  *  The NIST SP 800-90 DRBGs are described in the following publication.
21817466cbSJens Wiklander  *
22817466cbSJens Wiklander  *  http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
23817466cbSJens Wiklander  */
24817466cbSJens Wiklander 
257901324dSJerome Forissier #include "common.h"
26817466cbSJens Wiklander 
27817466cbSJens Wiklander #if defined(MBEDTLS_CTR_DRBG_C)
28817466cbSJens Wiklander 
29817466cbSJens Wiklander #include "mbedtls/ctr_drbg.h"
303d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
3111fa71b9SJerome Forissier #include "mbedtls/error.h"
32817466cbSJens Wiklander 
33817466cbSJens Wiklander #include <string.h>
34817466cbSJens Wiklander 
35817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
36817466cbSJens Wiklander #include <stdio.h>
37817466cbSJens Wiklander #endif
38817466cbSJens Wiklander 
39817466cbSJens Wiklander #include "mbedtls/platform.h"
40817466cbSJens Wiklander 
41817466cbSJens Wiklander /*
42817466cbSJens Wiklander  * CTR_DRBG context initialization
43817466cbSJens Wiklander  */
44817466cbSJens Wiklander void mbedtls_ctr_drbg_init(mbedtls_ctr_drbg_context *ctx)
45817466cbSJens Wiklander {
46817466cbSJens Wiklander     memset(ctx, 0, sizeof(mbedtls_ctr_drbg_context));
47*32b31808SJens Wiklander     mbedtls_aes_init(&ctx->aes_ctx);
4811fa71b9SJerome Forissier     /* Indicate that the entropy nonce length is not set explicitly.
4911fa71b9SJerome Forissier      * See mbedtls_ctr_drbg_set_nonce_len(). */
5011fa71b9SJerome Forissier     ctx->reseed_counter = -1;
51817466cbSJens Wiklander 
527901324dSJerome Forissier     ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
53817466cbSJens Wiklander }
54817466cbSJens Wiklander 
557901324dSJerome Forissier /*
567901324dSJerome Forissier  *  This function resets CTR_DRBG context to the state immediately
577901324dSJerome Forissier  *  after initial call of mbedtls_ctr_drbg_init().
587901324dSJerome Forissier  */
59817466cbSJens Wiklander void mbedtls_ctr_drbg_free(mbedtls_ctr_drbg_context *ctx)
60817466cbSJens Wiklander {
61*32b31808SJens Wiklander     if (ctx == NULL) {
62817466cbSJens Wiklander         return;
63*32b31808SJens Wiklander     }
64817466cbSJens Wiklander 
65817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
667901324dSJerome Forissier     /* The mutex is initialized iff f_entropy is set. */
67*32b31808SJens Wiklander     if (ctx->f_entropy != NULL) {
68817466cbSJens Wiklander         mbedtls_mutex_free(&ctx->mutex);
69*32b31808SJens Wiklander     }
70817466cbSJens Wiklander #endif
71817466cbSJens Wiklander     mbedtls_aes_free(&ctx->aes_ctx);
723d3b0591SJens Wiklander     mbedtls_platform_zeroize(ctx, sizeof(mbedtls_ctr_drbg_context));
737901324dSJerome Forissier     ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
747901324dSJerome Forissier     ctx->reseed_counter = -1;
75817466cbSJens Wiklander }
76817466cbSJens Wiklander 
7711fa71b9SJerome Forissier void mbedtls_ctr_drbg_set_prediction_resistance(mbedtls_ctr_drbg_context *ctx,
7811fa71b9SJerome Forissier                                                 int resistance)
79817466cbSJens Wiklander {
80817466cbSJens Wiklander     ctx->prediction_resistance = resistance;
81817466cbSJens Wiklander }
82817466cbSJens Wiklander 
8311fa71b9SJerome Forissier void mbedtls_ctr_drbg_set_entropy_len(mbedtls_ctr_drbg_context *ctx,
8411fa71b9SJerome Forissier                                       size_t len)
85817466cbSJens Wiklander {
86817466cbSJens Wiklander     ctx->entropy_len = len;
87817466cbSJens Wiklander }
88817466cbSJens Wiklander 
8911fa71b9SJerome Forissier int mbedtls_ctr_drbg_set_nonce_len(mbedtls_ctr_drbg_context *ctx,
9011fa71b9SJerome Forissier                                    size_t len)
9111fa71b9SJerome Forissier {
9211fa71b9SJerome Forissier     /* If mbedtls_ctr_drbg_seed() has already been called, it's
9311fa71b9SJerome Forissier      * too late. Return the error code that's closest to making sense. */
94*32b31808SJens Wiklander     if (ctx->f_entropy != NULL) {
95*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
96*32b31808SJens Wiklander     }
9711fa71b9SJerome Forissier 
98*32b31808SJens Wiklander     if (len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) {
99*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
100*32b31808SJens Wiklander     }
101*32b31808SJens Wiklander 
10211fa71b9SJerome Forissier     /* This shouldn't be an issue because
10311fa71b9SJerome Forissier      * MBEDTLS_CTR_DRBG_MAX_SEED_INPUT < INT_MAX in any sensible
10411fa71b9SJerome Forissier      * configuration, but make sure anyway. */
105*32b31808SJens Wiklander     if (len > INT_MAX) {
106*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
107*32b31808SJens Wiklander     }
10811fa71b9SJerome Forissier 
10911fa71b9SJerome Forissier     /* For backward compatibility with Mbed TLS <= 2.19, store the
11011fa71b9SJerome Forissier      * entropy nonce length in a field that already exists, but isn't
11111fa71b9SJerome Forissier      * used until after the initial seeding. */
11211fa71b9SJerome Forissier     /* Due to the capping of len above, the value fits in an int. */
11311fa71b9SJerome Forissier     ctx->reseed_counter = (int) len;
114*32b31808SJens Wiklander     return 0;
11511fa71b9SJerome Forissier }
11611fa71b9SJerome Forissier 
11711fa71b9SJerome Forissier void mbedtls_ctr_drbg_set_reseed_interval(mbedtls_ctr_drbg_context *ctx,
11811fa71b9SJerome Forissier                                           int interval)
119817466cbSJens Wiklander {
120817466cbSJens Wiklander     ctx->reseed_interval = interval;
121817466cbSJens Wiklander }
122817466cbSJens Wiklander 
123817466cbSJens Wiklander static int block_cipher_df(unsigned char *output,
124817466cbSJens Wiklander                            const unsigned char *data, size_t data_len)
125817466cbSJens Wiklander {
12611fa71b9SJerome Forissier     unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
12711fa71b9SJerome Forissier                       MBEDTLS_CTR_DRBG_BLOCKSIZE + 16];
128817466cbSJens Wiklander     unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
129817466cbSJens Wiklander     unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
130817466cbSJens Wiklander     unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE];
131817466cbSJens Wiklander     unsigned char *p, *iv;
132817466cbSJens Wiklander     mbedtls_aes_context aes_ctx;
1333d3b0591SJens Wiklander     int ret = 0;
134817466cbSJens Wiklander 
135817466cbSJens Wiklander     int i, j;
136817466cbSJens Wiklander     size_t buf_len, use_len;
137817466cbSJens Wiklander 
138*32b31808SJens Wiklander     if (data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) {
139*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
140*32b31808SJens Wiklander     }
141817466cbSJens Wiklander 
14211fa71b9SJerome Forissier     memset(buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
14311fa71b9SJerome Forissier            MBEDTLS_CTR_DRBG_BLOCKSIZE + 16);
144817466cbSJens Wiklander     mbedtls_aes_init(&aes_ctx);
145817466cbSJens Wiklander 
146817466cbSJens Wiklander     /*
147817466cbSJens Wiklander      * Construct IV (16 bytes) and S in buffer
148817466cbSJens Wiklander      * IV = Counter (in 32-bits) padded to 16 with zeroes
149817466cbSJens Wiklander      * S = Length input string (in 32-bits) || Length of output (in 32-bits) ||
150817466cbSJens Wiklander      *     data || 0x80
151817466cbSJens Wiklander      *     (Total is padded to a multiple of 16-bytes with zeroes)
152817466cbSJens Wiklander      */
153817466cbSJens Wiklander     p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE;
154039e02dfSJerome Forissier     MBEDTLS_PUT_UINT32_BE(data_len, p, 0);
155039e02dfSJerome Forissier     p += 4 + 3;
156817466cbSJens Wiklander     *p++ = MBEDTLS_CTR_DRBG_SEEDLEN;
157817466cbSJens Wiklander     memcpy(p, data, data_len);
158817466cbSJens Wiklander     p[data_len] = 0x80;
159817466cbSJens Wiklander 
160817466cbSJens Wiklander     buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1;
161817466cbSJens Wiklander 
162*32b31808SJens Wiklander     for (i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++) {
163817466cbSJens Wiklander         key[i] = i;
164*32b31808SJens Wiklander     }
165817466cbSJens Wiklander 
16611fa71b9SJerome Forissier     if ((ret = mbedtls_aes_setkey_enc(&aes_ctx, key,
167*32b31808SJens Wiklander                                       MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
1683d3b0591SJens Wiklander         goto exit;
1693d3b0591SJens Wiklander     }
170817466cbSJens Wiklander 
171817466cbSJens Wiklander     /*
172817466cbSJens Wiklander      * Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data
173817466cbSJens Wiklander      */
174*32b31808SJens Wiklander     for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
175817466cbSJens Wiklander         p = buf;
176817466cbSJens Wiklander         memset(chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE);
177817466cbSJens Wiklander         use_len = buf_len;
178817466cbSJens Wiklander 
179*32b31808SJens Wiklander         while (use_len > 0) {
180*32b31808SJens Wiklander             mbedtls_xor(chain, chain, p, MBEDTLS_CTR_DRBG_BLOCKSIZE);
181817466cbSJens Wiklander             p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
182817466cbSJens Wiklander             use_len -= (use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE) ?
183817466cbSJens Wiklander                        MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len;
184817466cbSJens Wiklander 
18511fa71b9SJerome Forissier             if ((ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT,
186*32b31808SJens Wiklander                                              chain, chain)) != 0) {
1873d3b0591SJens Wiklander                 goto exit;
1883d3b0591SJens Wiklander             }
189817466cbSJens Wiklander         }
190817466cbSJens Wiklander 
191817466cbSJens Wiklander         memcpy(tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE);
192817466cbSJens Wiklander 
193817466cbSJens Wiklander         /*
194817466cbSJens Wiklander          * Update IV
195817466cbSJens Wiklander          */
196817466cbSJens Wiklander         buf[3]++;
197817466cbSJens Wiklander     }
198817466cbSJens Wiklander 
199817466cbSJens Wiklander     /*
200817466cbSJens Wiklander      * Do final encryption with reduced data
201817466cbSJens Wiklander      */
20211fa71b9SJerome Forissier     if ((ret = mbedtls_aes_setkey_enc(&aes_ctx, tmp,
203*32b31808SJens Wiklander                                       MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
2043d3b0591SJens Wiklander         goto exit;
2053d3b0591SJens Wiklander     }
206817466cbSJens Wiklander     iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE;
207817466cbSJens Wiklander     p = output;
208817466cbSJens Wiklander 
209*32b31808SJens Wiklander     for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
21011fa71b9SJerome Forissier         if ((ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT,
211*32b31808SJens Wiklander                                          iv, iv)) != 0) {
2123d3b0591SJens Wiklander             goto exit;
2133d3b0591SJens Wiklander         }
214817466cbSJens Wiklander         memcpy(p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE);
215817466cbSJens Wiklander         p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
216817466cbSJens Wiklander     }
2173d3b0591SJens Wiklander exit:
218817466cbSJens Wiklander     mbedtls_aes_free(&aes_ctx);
2193d3b0591SJens Wiklander     /*
2203d3b0591SJens Wiklander      * tidy up the stack
2213d3b0591SJens Wiklander      */
2223d3b0591SJens Wiklander     mbedtls_platform_zeroize(buf, sizeof(buf));
2233d3b0591SJens Wiklander     mbedtls_platform_zeroize(tmp, sizeof(tmp));
2243d3b0591SJens Wiklander     mbedtls_platform_zeroize(key, sizeof(key));
2253d3b0591SJens Wiklander     mbedtls_platform_zeroize(chain, sizeof(chain));
226*32b31808SJens Wiklander     if (0 != ret) {
2273d3b0591SJens Wiklander         /*
2283d3b0591SJens Wiklander          * wipe partial seed from memory
2293d3b0591SJens Wiklander          */
2303d3b0591SJens Wiklander         mbedtls_platform_zeroize(output, MBEDTLS_CTR_DRBG_SEEDLEN);
231817466cbSJens Wiklander     }
232817466cbSJens Wiklander 
233*32b31808SJens Wiklander     return ret;
2343d3b0591SJens Wiklander }
2353d3b0591SJens Wiklander 
2363d3b0591SJens Wiklander /* CTR_DRBG_Update (SP 800-90A &sect;10.2.1.2)
2373d3b0591SJens Wiklander  * ctr_drbg_update_internal(ctx, provided_data)
2383d3b0591SJens Wiklander  * implements
2393d3b0591SJens Wiklander  * CTR_DRBG_Update(provided_data, Key, V)
2403d3b0591SJens Wiklander  * with inputs and outputs
2413d3b0591SJens Wiklander  *   ctx->aes_ctx = Key
2423d3b0591SJens Wiklander  *   ctx->counter = V
2433d3b0591SJens Wiklander  */
244817466cbSJens Wiklander static int ctr_drbg_update_internal(mbedtls_ctr_drbg_context *ctx,
245817466cbSJens Wiklander                                     const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN])
246817466cbSJens Wiklander {
247817466cbSJens Wiklander     unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
248817466cbSJens Wiklander     unsigned char *p = tmp;
249817466cbSJens Wiklander     int i, j;
2503d3b0591SJens Wiklander     int ret = 0;
251817466cbSJens Wiklander 
252817466cbSJens Wiklander     memset(tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN);
253817466cbSJens Wiklander 
254*32b31808SJens Wiklander     for (j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE) {
255817466cbSJens Wiklander         /*
256817466cbSJens Wiklander          * Increase counter
257817466cbSJens Wiklander          */
258*32b31808SJens Wiklander         for (i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i--) {
259*32b31808SJens Wiklander             if (++ctx->counter[i - 1] != 0) {
260817466cbSJens Wiklander                 break;
261*32b31808SJens Wiklander             }
262*32b31808SJens Wiklander         }
263817466cbSJens Wiklander 
264817466cbSJens Wiklander         /*
265817466cbSJens Wiklander          * Crypt counter block
266817466cbSJens Wiklander          */
26711fa71b9SJerome Forissier         if ((ret = mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
268*32b31808SJens Wiklander                                          ctx->counter, p)) != 0) {
2693d3b0591SJens Wiklander             goto exit;
27011fa71b9SJerome Forissier         }
271817466cbSJens Wiklander 
272817466cbSJens Wiklander         p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
273817466cbSJens Wiklander     }
274817466cbSJens Wiklander 
275*32b31808SJens Wiklander     for (i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++) {
276817466cbSJens Wiklander         tmp[i] ^= data[i];
277*32b31808SJens Wiklander     }
278817466cbSJens Wiklander 
279817466cbSJens Wiklander     /*
280817466cbSJens Wiklander      * Update key and counter
281817466cbSJens Wiklander      */
28211fa71b9SJerome Forissier     if ((ret = mbedtls_aes_setkey_enc(&ctx->aes_ctx, tmp,
283*32b31808SJens Wiklander                                       MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
2843d3b0591SJens Wiklander         goto exit;
28511fa71b9SJerome Forissier     }
28611fa71b9SJerome Forissier     memcpy(ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE,
28711fa71b9SJerome Forissier            MBEDTLS_CTR_DRBG_BLOCKSIZE);
288817466cbSJens Wiklander 
2893d3b0591SJens Wiklander exit:
2903d3b0591SJens Wiklander     mbedtls_platform_zeroize(tmp, sizeof(tmp));
291*32b31808SJens Wiklander     return ret;
292817466cbSJens Wiklander }
293817466cbSJens Wiklander 
2943d3b0591SJens Wiklander /* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
2953d3b0591SJens Wiklander  * mbedtls_ctr_drbg_update(ctx, additional, add_len)
2963d3b0591SJens Wiklander  * implements
2973d3b0591SJens Wiklander  * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
2983d3b0591SJens Wiklander  *                      security_strength) -> initial_working_state
2993d3b0591SJens Wiklander  * with inputs
3003d3b0591SJens Wiklander  *   ctx->counter = all-bits-0
3013d3b0591SJens Wiklander  *   ctx->aes_ctx = context from all-bits-0 key
3023d3b0591SJens Wiklander  *   additional[:add_len] = entropy_input || nonce || personalization_string
3033d3b0591SJens Wiklander  * and with outputs
3043d3b0591SJens Wiklander  *   ctx = initial_working_state
3053d3b0591SJens Wiklander  */
306*32b31808SJens Wiklander int mbedtls_ctr_drbg_update(mbedtls_ctr_drbg_context *ctx,
3073d3b0591SJens Wiklander                             const unsigned char *additional,
3083d3b0591SJens Wiklander                             size_t add_len)
309817466cbSJens Wiklander {
310817466cbSJens Wiklander     unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
31111fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
312817466cbSJens Wiklander 
313*32b31808SJens Wiklander     if (add_len == 0) {
314*32b31808SJens Wiklander         return 0;
315*32b31808SJens Wiklander     }
3163d3b0591SJens Wiklander 
317*32b31808SJens Wiklander     if ((ret = block_cipher_df(add_input, additional, add_len)) != 0) {
3183d3b0591SJens Wiklander         goto exit;
319*32b31808SJens Wiklander     }
320*32b31808SJens Wiklander     if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
3213d3b0591SJens Wiklander         goto exit;
322*32b31808SJens Wiklander     }
3233d3b0591SJens Wiklander 
3243d3b0591SJens Wiklander exit:
3253d3b0591SJens Wiklander     mbedtls_platform_zeroize(add_input, sizeof(add_input));
326*32b31808SJens Wiklander     return ret;
3273d3b0591SJens Wiklander }
3283d3b0591SJens Wiklander 
3293d3b0591SJens Wiklander /* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
33011fa71b9SJerome Forissier  * mbedtls_ctr_drbg_reseed(ctx, additional, len, nonce_len)
3313d3b0591SJens Wiklander  * implements
3323d3b0591SJens Wiklander  * CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
3333d3b0591SJens Wiklander  *                -> new_working_state
3343d3b0591SJens Wiklander  * with inputs
3353d3b0591SJens Wiklander  *   ctx contains working_state
3363d3b0591SJens Wiklander  *   additional[:len] = additional_input
3373d3b0591SJens Wiklander  * and entropy_input comes from calling ctx->f_entropy
33811fa71b9SJerome Forissier  *                              for (ctx->entropy_len + nonce_len) bytes
3393d3b0591SJens Wiklander  * and with output
3403d3b0591SJens Wiklander  *   ctx contains new_working_state
3413d3b0591SJens Wiklander  */
34211fa71b9SJerome Forissier static int mbedtls_ctr_drbg_reseed_internal(mbedtls_ctr_drbg_context *ctx,
34311fa71b9SJerome Forissier                                             const unsigned char *additional,
34411fa71b9SJerome Forissier                                             size_t len,
34511fa71b9SJerome Forissier                                             size_t nonce_len)
346817466cbSJens Wiklander {
347817466cbSJens Wiklander     unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
348817466cbSJens Wiklander     size_t seedlen = 0;
34911fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
350817466cbSJens Wiklander 
351*32b31808SJens Wiklander     if (ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) {
352*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
353*32b31808SJens Wiklander     }
354*32b31808SJens Wiklander     if (nonce_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len) {
355*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
356*32b31808SJens Wiklander     }
357*32b31808SJens Wiklander     if (len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len - nonce_len) {
358*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
359*32b31808SJens Wiklander     }
360817466cbSJens Wiklander 
361817466cbSJens Wiklander     memset(seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT);
362817466cbSJens Wiklander 
36311fa71b9SJerome Forissier     /* Gather entropy_len bytes of entropy to seed state. */
364*32b31808SJens Wiklander     if (0 != ctx->f_entropy(ctx->p_entropy, seed, ctx->entropy_len)) {
365*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
366817466cbSJens Wiklander     }
367817466cbSJens Wiklander     seedlen += ctx->entropy_len;
368817466cbSJens Wiklander 
36911fa71b9SJerome Forissier     /* Gather entropy for a nonce if requested. */
370*32b31808SJens Wiklander     if (nonce_len != 0) {
371*32b31808SJens Wiklander         if (0 != ctx->f_entropy(ctx->p_entropy, seed + seedlen, nonce_len)) {
372*32b31808SJens Wiklander             return MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED;
37311fa71b9SJerome Forissier         }
37411fa71b9SJerome Forissier         seedlen += nonce_len;
37511fa71b9SJerome Forissier     }
37611fa71b9SJerome Forissier 
37711fa71b9SJerome Forissier     /* Add additional data if provided. */
378*32b31808SJens Wiklander     if (additional != NULL && len != 0) {
379817466cbSJens Wiklander         memcpy(seed + seedlen, additional, len);
380817466cbSJens Wiklander         seedlen += len;
381817466cbSJens Wiklander     }
382817466cbSJens Wiklander 
38311fa71b9SJerome Forissier     /* Reduce to 384 bits. */
384*32b31808SJens Wiklander     if ((ret = block_cipher_df(seed, seed, seedlen)) != 0) {
3853d3b0591SJens Wiklander         goto exit;
386*32b31808SJens Wiklander     }
387817466cbSJens Wiklander 
38811fa71b9SJerome Forissier     /* Update state. */
389*32b31808SJens Wiklander     if ((ret = ctr_drbg_update_internal(ctx, seed)) != 0) {
3903d3b0591SJens Wiklander         goto exit;
391*32b31808SJens Wiklander     }
392817466cbSJens Wiklander     ctx->reseed_counter = 1;
393817466cbSJens Wiklander 
3943d3b0591SJens Wiklander exit:
3953d3b0591SJens Wiklander     mbedtls_platform_zeroize(seed, sizeof(seed));
396*32b31808SJens Wiklander     return ret;
397817466cbSJens Wiklander }
398817466cbSJens Wiklander 
39911fa71b9SJerome Forissier int mbedtls_ctr_drbg_reseed(mbedtls_ctr_drbg_context *ctx,
40011fa71b9SJerome Forissier                             const unsigned char *additional, size_t len)
40111fa71b9SJerome Forissier {
402*32b31808SJens Wiklander     return mbedtls_ctr_drbg_reseed_internal(ctx, additional, len, 0);
40311fa71b9SJerome Forissier }
40411fa71b9SJerome Forissier 
40511fa71b9SJerome Forissier /* Return a "good" nonce length for CTR_DRBG. The chosen nonce length
40611fa71b9SJerome Forissier  * is sufficient to achieve the maximum security strength given the key
40711fa71b9SJerome Forissier  * size and entropy length. If there is enough entropy in the initial
40811fa71b9SJerome Forissier  * call to the entropy function to serve as both the entropy input and
40911fa71b9SJerome Forissier  * the nonce, don't make a second call to get a nonce. */
41011fa71b9SJerome Forissier static size_t good_nonce_len(size_t entropy_len)
41111fa71b9SJerome Forissier {
412*32b31808SJens Wiklander     if (entropy_len >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2) {
413*32b31808SJens Wiklander         return 0;
414*32b31808SJens Wiklander     } else {
415*32b31808SJens Wiklander         return (entropy_len + 1) / 2;
416*32b31808SJens Wiklander     }
41711fa71b9SJerome Forissier }
41811fa71b9SJerome Forissier 
4195b25c76aSJerome Forissier /* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
4205b25c76aSJerome Forissier  * mbedtls_ctr_drbg_seed(ctx, f_entropy, p_entropy, custom, len)
4215b25c76aSJerome Forissier  * implements
4225b25c76aSJerome Forissier  * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
4235b25c76aSJerome Forissier  *                      security_strength) -> initial_working_state
4245b25c76aSJerome Forissier  * with inputs
4255b25c76aSJerome Forissier  *   custom[:len] = nonce || personalization_string
4265b25c76aSJerome Forissier  * where entropy_input comes from f_entropy for ctx->entropy_len bytes
4275b25c76aSJerome Forissier  * and with outputs
4285b25c76aSJerome Forissier  *   ctx = initial_working_state
4295b25c76aSJerome Forissier  */
4305b25c76aSJerome Forissier int mbedtls_ctr_drbg_seed(mbedtls_ctr_drbg_context *ctx,
4315b25c76aSJerome Forissier                           int (*f_entropy)(void *, unsigned char *, size_t),
4325b25c76aSJerome Forissier                           void *p_entropy,
4335b25c76aSJerome Forissier                           const unsigned char *custom,
4345b25c76aSJerome Forissier                           size_t len)
4355b25c76aSJerome Forissier {
43611fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
4375b25c76aSJerome Forissier     unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
43811fa71b9SJerome Forissier     size_t nonce_len;
4395b25c76aSJerome Forissier 
4405b25c76aSJerome Forissier     memset(key, 0, MBEDTLS_CTR_DRBG_KEYSIZE);
4415b25c76aSJerome Forissier 
4427901324dSJerome Forissier     /* The mutex is initialized iff f_entropy is set. */
4437901324dSJerome Forissier #if defined(MBEDTLS_THREADING_C)
4447901324dSJerome Forissier     mbedtls_mutex_init(&ctx->mutex);
4457901324dSJerome Forissier #endif
4467901324dSJerome Forissier 
4475b25c76aSJerome Forissier     ctx->f_entropy = f_entropy;
4485b25c76aSJerome Forissier     ctx->p_entropy = p_entropy;
4495b25c76aSJerome Forissier 
450*32b31808SJens Wiklander     if (ctx->entropy_len == 0) {
4515b25c76aSJerome Forissier         ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
452*32b31808SJens Wiklander     }
45311fa71b9SJerome Forissier     /* ctx->reseed_counter contains the desired amount of entropy to
45411fa71b9SJerome Forissier      * grab for a nonce (see mbedtls_ctr_drbg_set_nonce_len()).
45511fa71b9SJerome Forissier      * If it's -1, indicating that the entropy nonce length was not set
45611fa71b9SJerome Forissier      * explicitly, use a sufficiently large nonce for security. */
45711fa71b9SJerome Forissier     nonce_len = (ctx->reseed_counter >= 0 ?
45811fa71b9SJerome Forissier                  (size_t) ctx->reseed_counter :
45911fa71b9SJerome Forissier                  good_nonce_len(ctx->entropy_len));
46011fa71b9SJerome Forissier 
46111fa71b9SJerome Forissier     /* Initialize with an empty key. */
46211fa71b9SJerome Forissier     if ((ret = mbedtls_aes_setkey_enc(&ctx->aes_ctx, key,
463*32b31808SJens Wiklander                                       MBEDTLS_CTR_DRBG_KEYBITS)) != 0) {
464*32b31808SJens Wiklander         return ret;
4655b25c76aSJerome Forissier     }
4665b25c76aSJerome Forissier 
46711fa71b9SJerome Forissier     /* Do the initial seeding. */
46811fa71b9SJerome Forissier     if ((ret = mbedtls_ctr_drbg_reseed_internal(ctx, custom, len,
469*32b31808SJens Wiklander                                                 nonce_len)) != 0) {
470*32b31808SJens Wiklander         return ret;
4715b25c76aSJerome Forissier     }
472*32b31808SJens Wiklander     return 0;
4735b25c76aSJerome Forissier }
4745b25c76aSJerome Forissier 
4753d3b0591SJens Wiklander /* CTR_DRBG_Generate with derivation function (SP 800-90A &sect;10.2.1.5.2)
4763d3b0591SJens Wiklander  * mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len)
4773d3b0591SJens Wiklander  * implements
4783d3b0591SJens Wiklander  * CTR_DRBG_Reseed(working_state, entropy_input, additional[:add_len])
4793d3b0591SJens Wiklander  *                -> working_state_after_reseed
4803d3b0591SJens Wiklander  *                if required, then
4813d3b0591SJens Wiklander  * CTR_DRBG_Generate(working_state_after_reseed,
4823d3b0591SJens Wiklander  *                   requested_number_of_bits, additional_input)
4833d3b0591SJens Wiklander  *                -> status, returned_bits, new_working_state
4843d3b0591SJens Wiklander  * with inputs
4853d3b0591SJens Wiklander  *   ctx contains working_state
4863d3b0591SJens Wiklander  *   requested_number_of_bits = 8 * output_len
4873d3b0591SJens Wiklander  *   additional[:add_len] = additional_input
4883d3b0591SJens Wiklander  * and entropy_input comes from calling ctx->f_entropy
4893d3b0591SJens Wiklander  * and with outputs
4903d3b0591SJens Wiklander  *   status = SUCCESS (this function does the reseed internally)
4913d3b0591SJens Wiklander  *   returned_bits = output[:output_len]
4923d3b0591SJens Wiklander  *   ctx contains new_working_state
4933d3b0591SJens Wiklander  */
494817466cbSJens Wiklander int mbedtls_ctr_drbg_random_with_add(void *p_rng,
495817466cbSJens Wiklander                                      unsigned char *output, size_t output_len,
496817466cbSJens Wiklander                                      const unsigned char *additional, size_t add_len)
497817466cbSJens Wiklander {
498817466cbSJens Wiklander     int ret = 0;
499817466cbSJens Wiklander     mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
500817466cbSJens Wiklander     unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
501817466cbSJens Wiklander     unsigned char *p = output;
502817466cbSJens Wiklander     unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE];
503817466cbSJens Wiklander     int i;
504817466cbSJens Wiklander     size_t use_len;
505817466cbSJens Wiklander 
506*32b31808SJens Wiklander     if (output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST) {
507*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG;
508*32b31808SJens Wiklander     }
509817466cbSJens Wiklander 
510*32b31808SJens Wiklander     if (add_len > MBEDTLS_CTR_DRBG_MAX_INPUT) {
511*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
512*32b31808SJens Wiklander     }
513817466cbSJens Wiklander 
514817466cbSJens Wiklander     memset(add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN);
515817466cbSJens Wiklander 
516817466cbSJens Wiklander     if (ctx->reseed_counter > ctx->reseed_interval ||
517*32b31808SJens Wiklander         ctx->prediction_resistance) {
518*32b31808SJens Wiklander         if ((ret = mbedtls_ctr_drbg_reseed(ctx, additional, add_len)) != 0) {
519*32b31808SJens Wiklander             return ret;
5203d3b0591SJens Wiklander         }
521817466cbSJens Wiklander         add_len = 0;
522817466cbSJens Wiklander     }
523817466cbSJens Wiklander 
524*32b31808SJens Wiklander     if (add_len > 0) {
525*32b31808SJens Wiklander         if ((ret = block_cipher_df(add_input, additional, add_len)) != 0) {
5263d3b0591SJens Wiklander             goto exit;
527817466cbSJens Wiklander         }
528*32b31808SJens Wiklander         if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
529*32b31808SJens Wiklander             goto exit;
530*32b31808SJens Wiklander         }
531*32b31808SJens Wiklander     }
532817466cbSJens Wiklander 
533*32b31808SJens Wiklander     while (output_len > 0) {
534817466cbSJens Wiklander         /*
535817466cbSJens Wiklander          * Increase counter
536817466cbSJens Wiklander          */
537*32b31808SJens Wiklander         for (i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i--) {
538*32b31808SJens Wiklander             if (++ctx->counter[i - 1] != 0) {
539817466cbSJens Wiklander                 break;
540*32b31808SJens Wiklander             }
541*32b31808SJens Wiklander         }
542817466cbSJens Wiklander 
543817466cbSJens Wiklander         /*
544817466cbSJens Wiklander          * Crypt counter block
545817466cbSJens Wiklander          */
54611fa71b9SJerome Forissier         if ((ret = mbedtls_aes_crypt_ecb(&ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
547*32b31808SJens Wiklander                                          ctx->counter, tmp)) != 0) {
5483d3b0591SJens Wiklander             goto exit;
54911fa71b9SJerome Forissier         }
550817466cbSJens Wiklander 
55111fa71b9SJerome Forissier         use_len = (output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE)
55211fa71b9SJerome Forissier             ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len;
553817466cbSJens Wiklander         /*
554817466cbSJens Wiklander          * Copy random block to destination
555817466cbSJens Wiklander          */
556817466cbSJens Wiklander         memcpy(p, tmp, use_len);
557817466cbSJens Wiklander         p += use_len;
558817466cbSJens Wiklander         output_len -= use_len;
559817466cbSJens Wiklander     }
560817466cbSJens Wiklander 
561*32b31808SJens Wiklander     if ((ret = ctr_drbg_update_internal(ctx, add_input)) != 0) {
5623d3b0591SJens Wiklander         goto exit;
563*32b31808SJens Wiklander     }
564817466cbSJens Wiklander 
565817466cbSJens Wiklander     ctx->reseed_counter++;
566817466cbSJens Wiklander 
5673d3b0591SJens Wiklander exit:
5683d3b0591SJens Wiklander     mbedtls_platform_zeroize(add_input, sizeof(add_input));
5693d3b0591SJens Wiklander     mbedtls_platform_zeroize(tmp, sizeof(tmp));
570*32b31808SJens Wiklander     return ret;
571817466cbSJens Wiklander }
572817466cbSJens Wiklander 
57311fa71b9SJerome Forissier int mbedtls_ctr_drbg_random(void *p_rng, unsigned char *output,
57411fa71b9SJerome Forissier                             size_t output_len)
575817466cbSJens Wiklander {
57611fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
577817466cbSJens Wiklander     mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
578817466cbSJens Wiklander 
579817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
580*32b31808SJens Wiklander     if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0) {
581*32b31808SJens Wiklander         return ret;
582*32b31808SJens Wiklander     }
583817466cbSJens Wiklander #endif
584817466cbSJens Wiklander 
585817466cbSJens Wiklander     ret = mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, NULL, 0);
586817466cbSJens Wiklander 
587817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
588*32b31808SJens Wiklander     if (mbedtls_mutex_unlock(&ctx->mutex) != 0) {
589*32b31808SJens Wiklander         return MBEDTLS_ERR_THREADING_MUTEX_ERROR;
590*32b31808SJens Wiklander     }
591817466cbSJens Wiklander #endif
592817466cbSJens Wiklander 
593*32b31808SJens Wiklander     return ret;
594817466cbSJens Wiklander }
595817466cbSJens Wiklander 
596817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
59711fa71b9SJerome Forissier int mbedtls_ctr_drbg_write_seed_file(mbedtls_ctr_drbg_context *ctx,
59811fa71b9SJerome Forissier                                      const char *path)
599817466cbSJens Wiklander {
600817466cbSJens Wiklander     int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
601817466cbSJens Wiklander     FILE *f;
602817466cbSJens Wiklander     unsigned char buf[MBEDTLS_CTR_DRBG_MAX_INPUT];
603817466cbSJens Wiklander 
604*32b31808SJens Wiklander     if ((f = fopen(path, "wb")) == NULL) {
605*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
606*32b31808SJens Wiklander     }
607*32b31808SJens Wiklander 
608*32b31808SJens Wiklander     /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
609*32b31808SJens Wiklander     mbedtls_setbuf(f, NULL);
610817466cbSJens Wiklander 
61111fa71b9SJerome Forissier     if ((ret = mbedtls_ctr_drbg_random(ctx, buf,
612*32b31808SJens Wiklander                                        MBEDTLS_CTR_DRBG_MAX_INPUT)) != 0) {
613817466cbSJens Wiklander         goto exit;
614*32b31808SJens Wiklander     }
615817466cbSJens Wiklander 
61611fa71b9SJerome Forissier     if (fwrite(buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f) !=
617*32b31808SJens Wiklander         MBEDTLS_CTR_DRBG_MAX_INPUT) {
618817466cbSJens Wiklander         ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
619*32b31808SJens Wiklander     } else {
620817466cbSJens Wiklander         ret = 0;
62111fa71b9SJerome Forissier     }
622817466cbSJens Wiklander 
623817466cbSJens Wiklander exit:
6243d3b0591SJens Wiklander     mbedtls_platform_zeroize(buf, sizeof(buf));
6253d3b0591SJens Wiklander 
626817466cbSJens Wiklander     fclose(f);
627*32b31808SJens Wiklander     return ret;
628817466cbSJens Wiklander }
629817466cbSJens Wiklander 
63011fa71b9SJerome Forissier int mbedtls_ctr_drbg_update_seed_file(mbedtls_ctr_drbg_context *ctx,
63111fa71b9SJerome Forissier                                       const char *path)
632817466cbSJens Wiklander {
6333d3b0591SJens Wiklander     int ret = 0;
6343d3b0591SJens Wiklander     FILE *f = NULL;
635817466cbSJens Wiklander     size_t n;
636817466cbSJens Wiklander     unsigned char buf[MBEDTLS_CTR_DRBG_MAX_INPUT];
6373d3b0591SJens Wiklander     unsigned char c;
638817466cbSJens Wiklander 
639*32b31808SJens Wiklander     if ((f = fopen(path, "rb")) == NULL) {
640*32b31808SJens Wiklander         return MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
641*32b31808SJens Wiklander     }
642*32b31808SJens Wiklander 
643*32b31808SJens Wiklander     /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
644*32b31808SJens Wiklander     mbedtls_setbuf(f, NULL);
645817466cbSJens Wiklander 
6463d3b0591SJens Wiklander     n = fread(buf, 1, sizeof(buf), f);
647*32b31808SJens Wiklander     if (fread(&c, 1, 1, f) != 0) {
6483d3b0591SJens Wiklander         ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
6493d3b0591SJens Wiklander         goto exit;
650817466cbSJens Wiklander     }
651*32b31808SJens Wiklander     if (n == 0 || ferror(f)) {
6523d3b0591SJens Wiklander         ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
6533d3b0591SJens Wiklander         goto exit;
654817466cbSJens Wiklander     }
655817466cbSJens Wiklander     fclose(f);
6563d3b0591SJens Wiklander     f = NULL;
657817466cbSJens Wiklander 
658*32b31808SJens Wiklander     ret = mbedtls_ctr_drbg_update(ctx, buf, n);
659817466cbSJens Wiklander 
6603d3b0591SJens Wiklander exit:
6613d3b0591SJens Wiklander     mbedtls_platform_zeroize(buf, sizeof(buf));
662*32b31808SJens Wiklander     if (f != NULL) {
6633d3b0591SJens Wiklander         fclose(f);
664*32b31808SJens Wiklander     }
665*32b31808SJens Wiklander     if (ret != 0) {
666*32b31808SJens Wiklander         return ret;
667*32b31808SJens Wiklander     }
668*32b31808SJens Wiklander     return mbedtls_ctr_drbg_write_seed_file(ctx, path);
669817466cbSJens Wiklander }
670817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
671817466cbSJens Wiklander 
672817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
673817466cbSJens Wiklander 
6747901324dSJerome Forissier /* The CTR_DRBG NIST test vectors used here are available at
6757901324dSJerome Forissier  * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/drbg/drbgtestvectors.zip
6767901324dSJerome Forissier  *
6777901324dSJerome Forissier  * The parameters used to derive the test data are:
6787901324dSJerome Forissier  *
6797901324dSJerome Forissier  * [AES-128 use df]
6807901324dSJerome Forissier  * [PredictionResistance = True/False]
6817901324dSJerome Forissier  * [EntropyInputLen = 128]
6827901324dSJerome Forissier  * [NonceLen = 64]
6837901324dSJerome Forissier  * [PersonalizationStringLen = 128]
6847901324dSJerome Forissier  * [AdditionalInputLen = 0]
6857901324dSJerome Forissier  * [ReturnedBitsLen = 512]
6867901324dSJerome Forissier  *
6877901324dSJerome Forissier  * [AES-256 use df]
6887901324dSJerome Forissier  * [PredictionResistance = True/False]
6897901324dSJerome Forissier  * [EntropyInputLen = 256]
6907901324dSJerome Forissier  * [NonceLen = 128]
6917901324dSJerome Forissier  * [PersonalizationStringLen = 256]
6927901324dSJerome Forissier  * [AdditionalInputLen = 0]
6937901324dSJerome Forissier  * [ReturnedBitsLen = 512]
6947901324dSJerome Forissier  *
6957901324dSJerome Forissier  */
696817466cbSJens Wiklander 
69711fa71b9SJerome Forissier #if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY)
6987901324dSJerome Forissier static const unsigned char entropy_source_pr[] =
6997901324dSJerome Forissier { 0x04, 0xd9, 0x49, 0xa6, 0xdc, 0xe8, 0x6e, 0xbb,
7007901324dSJerome Forissier   0xf1, 0x08, 0x77, 0x2b, 0x9e, 0x08, 0xca, 0x92,
7017901324dSJerome Forissier   0x65, 0x16, 0xda, 0x99, 0xa2, 0x59, 0xf3, 0xe8,
7027901324dSJerome Forissier   0x38, 0x7e, 0x3f, 0x6b, 0x51, 0x70, 0x7b, 0x20,
7037901324dSJerome Forissier   0xec, 0x53, 0xd0, 0x66, 0xc3, 0x0f, 0xe3, 0xb0,
7047901324dSJerome Forissier   0xe0, 0x86, 0xa6, 0xaa, 0x5f, 0x72, 0x2f, 0xad,
7057901324dSJerome Forissier   0xf7, 0xef, 0x06, 0xb8, 0xd6, 0x9c, 0x9d, 0xe8 };
70611fa71b9SJerome Forissier 
7077901324dSJerome Forissier static const unsigned char entropy_source_nopr[] =
7087901324dSJerome Forissier { 0x07, 0x0d, 0x59, 0x63, 0x98, 0x73, 0xa5, 0x45,
7097901324dSJerome Forissier   0x27, 0x38, 0x22, 0x7b, 0x76, 0x85, 0xd1, 0xa9,
7107901324dSJerome Forissier   0x74, 0x18, 0x1f, 0x3c, 0x22, 0xf6, 0x49, 0x20,
7117901324dSJerome Forissier   0x4a, 0x47, 0xc2, 0xf3, 0x85, 0x16, 0xb4, 0x6f,
7127901324dSJerome Forissier   0x00, 0x2e, 0x71, 0xda, 0xed, 0x16, 0x9b, 0x5c };
7137901324dSJerome Forissier 
7147901324dSJerome Forissier static const unsigned char pers_pr[] =
7157901324dSJerome Forissier { 0xbf, 0xa4, 0x9a, 0x8f, 0x7b, 0xd8, 0xb1, 0x7a,
7167901324dSJerome Forissier   0x9d, 0xfa, 0x45, 0xed, 0x21, 0x52, 0xb3, 0xad };
7177901324dSJerome Forissier 
7187901324dSJerome Forissier static const unsigned char pers_nopr[] =
7197901324dSJerome Forissier { 0x4e, 0x61, 0x79, 0xd4, 0xc2, 0x72, 0xa1, 0x4c,
7207901324dSJerome Forissier   0xf1, 0x3d, 0xf6, 0x5e, 0xa3, 0xa6, 0xe5, 0x0f };
7217901324dSJerome Forissier 
7227901324dSJerome Forissier static const unsigned char result_pr[] =
7237901324dSJerome Forissier { 0xc9, 0x0a, 0xaf, 0x85, 0x89, 0x71, 0x44, 0x66,
7247901324dSJerome Forissier   0x4f, 0x25, 0x0b, 0x2b, 0xde, 0xd8, 0xfa, 0xff,
7257901324dSJerome Forissier   0x52, 0x5a, 0x1b, 0x32, 0x5e, 0x41, 0x7a, 0x10,
7267901324dSJerome Forissier   0x1f, 0xef, 0x1e, 0x62, 0x23, 0xe9, 0x20, 0x30,
7277901324dSJerome Forissier   0xc9, 0x0d, 0xad, 0x69, 0xb4, 0x9c, 0x5b, 0xf4,
7287901324dSJerome Forissier   0x87, 0x42, 0xd5, 0xae, 0x5e, 0x5e, 0x43, 0xcc,
7297901324dSJerome Forissier   0xd9, 0xfd, 0x0b, 0x93, 0x4a, 0xe3, 0xd4, 0x06,
7307901324dSJerome Forissier   0x37, 0x36, 0x0f, 0x3f, 0x72, 0x82, 0x0c, 0xcf };
7317901324dSJerome Forissier 
7327901324dSJerome Forissier static const unsigned char result_nopr[] =
7337901324dSJerome Forissier { 0x31, 0xc9, 0x91, 0x09, 0xf8, 0xc5, 0x10, 0x13,
7347901324dSJerome Forissier   0x3c, 0xd3, 0x96, 0xf9, 0xbc, 0x2c, 0x12, 0xc0,
7357901324dSJerome Forissier   0x7c, 0xc1, 0x61, 0x5f, 0xa3, 0x09, 0x99, 0xaf,
7367901324dSJerome Forissier   0xd7, 0xf2, 0x36, 0xfd, 0x40, 0x1a, 0x8b, 0xf2,
7377901324dSJerome Forissier   0x33, 0x38, 0xee, 0x1d, 0x03, 0x5f, 0x83, 0xb7,
7387901324dSJerome Forissier   0xa2, 0x53, 0xdc, 0xee, 0x18, 0xfc, 0xa7, 0xf2,
7397901324dSJerome Forissier   0xee, 0x96, 0xc6, 0xc2, 0xcd, 0x0c, 0xff, 0x02,
7407901324dSJerome Forissier   0x76, 0x70, 0x69, 0xaa, 0x69, 0xd1, 0x3b, 0xe8 };
74111fa71b9SJerome Forissier #else /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
742817466cbSJens Wiklander 
7437901324dSJerome Forissier static const unsigned char entropy_source_pr[] =
7447901324dSJerome Forissier { 0xca, 0x58, 0xfd, 0xf2, 0xb9, 0x77, 0xcb, 0x49,
7457901324dSJerome Forissier   0xd4, 0xe0, 0x5b, 0xe2, 0x39, 0x50, 0xd9, 0x8a,
7467901324dSJerome Forissier   0x6a, 0xb3, 0xc5, 0x2f, 0xdf, 0x74, 0xd5, 0x85,
7477901324dSJerome Forissier   0x8f, 0xd1, 0xba, 0x64, 0x54, 0x7b, 0xdb, 0x1e,
7487901324dSJerome Forissier   0xc5, 0xea, 0x24, 0xc0, 0xfa, 0x0c, 0x90, 0x15,
7497901324dSJerome Forissier   0x09, 0x20, 0x92, 0x42, 0x32, 0x36, 0x45, 0x45,
7507901324dSJerome Forissier   0x7d, 0x20, 0x76, 0x6b, 0xcf, 0xa2, 0x15, 0xc8,
7517901324dSJerome Forissier   0x2f, 0x9f, 0xbc, 0x88, 0x3f, 0x80, 0xd1, 0x2c,
7527901324dSJerome Forissier   0xb7, 0x16, 0xd1, 0x80, 0x9e, 0xe1, 0xc9, 0xb3,
7537901324dSJerome Forissier   0x88, 0x1b, 0x21, 0x45, 0xef, 0xa1, 0x7f, 0xce,
7547901324dSJerome Forissier   0xc8, 0x92, 0x35, 0x55, 0x2a, 0xd9, 0x1d, 0x8e,
7557901324dSJerome Forissier   0x12, 0x38, 0xac, 0x01, 0x4e, 0x38, 0x18, 0x76,
7567901324dSJerome Forissier   0x9c, 0xf2, 0xb6, 0xd4, 0x13, 0xb6, 0x2c, 0x77,
7577901324dSJerome Forissier   0xc0, 0xe7, 0xe6, 0x0c, 0x47, 0x44, 0x95, 0xbe };
7587901324dSJerome Forissier 
7597901324dSJerome Forissier static const unsigned char entropy_source_nopr[] =
7607901324dSJerome Forissier { 0x4c, 0xfb, 0x21, 0x86, 0x73, 0x34, 0x6d, 0x9d,
7617901324dSJerome Forissier   0x50, 0xc9, 0x22, 0xe4, 0x9b, 0x0d, 0xfc, 0xd0,
7627901324dSJerome Forissier   0x90, 0xad, 0xf0, 0x4f, 0x5c, 0x3b, 0xa4, 0x73,
7637901324dSJerome Forissier   0x27, 0xdf, 0xcd, 0x6f, 0xa6, 0x3a, 0x78, 0x5c,
7647901324dSJerome Forissier   0x01, 0x69, 0x62, 0xa7, 0xfd, 0x27, 0x87, 0xa2,
7657901324dSJerome Forissier   0x4b, 0xf6, 0xbe, 0x47, 0xef, 0x37, 0x83, 0xf1,
7667901324dSJerome Forissier   0xb7, 0xec, 0x46, 0x07, 0x23, 0x63, 0x83, 0x4a,
7677901324dSJerome Forissier   0x1b, 0x01, 0x33, 0xf2, 0xc2, 0x38, 0x91, 0xdb,
7687901324dSJerome Forissier   0x4f, 0x11, 0xa6, 0x86, 0x51, 0xf2, 0x3e, 0x3a,
7697901324dSJerome Forissier   0x8b, 0x1f, 0xdc, 0x03, 0xb1, 0x92, 0xc7, 0xe7 };
7707901324dSJerome Forissier 
7717901324dSJerome Forissier static const unsigned char pers_pr[] =
7727901324dSJerome Forissier { 0x5a, 0x70, 0x95, 0xe9, 0x81, 0x40, 0x52, 0x33,
7737901324dSJerome Forissier   0x91, 0x53, 0x7e, 0x75, 0xd6, 0x19, 0x9d, 0x1e,
7747901324dSJerome Forissier   0xad, 0x0d, 0xc6, 0xa7, 0xde, 0x6c, 0x1f, 0xe0,
7757901324dSJerome Forissier   0xea, 0x18, 0x33, 0xa8, 0x7e, 0x06, 0x20, 0xe9 };
7767901324dSJerome Forissier 
7777901324dSJerome Forissier static const unsigned char pers_nopr[] =
7787901324dSJerome Forissier { 0x88, 0xee, 0xb8, 0xe0, 0xe8, 0x3b, 0xf3, 0x29,
7797901324dSJerome Forissier   0x4b, 0xda, 0xcd, 0x60, 0x99, 0xeb, 0xe4, 0xbf,
7807901324dSJerome Forissier   0x55, 0xec, 0xd9, 0x11, 0x3f, 0x71, 0xe5, 0xeb,
7817901324dSJerome Forissier   0xcb, 0x45, 0x75, 0xf3, 0xd6, 0xa6, 0x8a, 0x6b };
7827901324dSJerome Forissier 
7837901324dSJerome Forissier static const unsigned char result_pr[] =
7847901324dSJerome Forissier { 0xce, 0x2f, 0xdb, 0xb6, 0xd9, 0xb7, 0x39, 0x85,
7857901324dSJerome Forissier   0x04, 0xc5, 0xc0, 0x42, 0xc2, 0x31, 0xc6, 0x1d,
7867901324dSJerome Forissier   0x9b, 0x5a, 0x59, 0xf8, 0x7e, 0x0d, 0xcc, 0x62,
7877901324dSJerome Forissier   0x7b, 0x65, 0x11, 0x55, 0x10, 0xeb, 0x9e, 0x3d,
7887901324dSJerome Forissier   0xa4, 0xfb, 0x1c, 0x6a, 0x18, 0xc0, 0x74, 0xdb,
7897901324dSJerome Forissier   0xdd, 0xe7, 0x02, 0x23, 0x63, 0x21, 0xd0, 0x39,
7907901324dSJerome Forissier   0xf9, 0xa7, 0xc4, 0x52, 0x84, 0x3b, 0x49, 0x40,
7917901324dSJerome Forissier   0x72, 0x2b, 0xb0, 0x6c, 0x9c, 0xdb, 0xc3, 0x43 };
7927901324dSJerome Forissier 
7937901324dSJerome Forissier static const unsigned char result_nopr[] =
7947901324dSJerome Forissier { 0xa5, 0x51, 0x80, 0xa1, 0x90, 0xbe, 0xf3, 0xad,
7957901324dSJerome Forissier   0xaf, 0x28, 0xf6, 0xb7, 0x95, 0xe9, 0xf1, 0xf3,
7967901324dSJerome Forissier   0xd6, 0xdf, 0xa1, 0xb2, 0x7d, 0xd0, 0x46, 0x7b,
7977901324dSJerome Forissier   0x0c, 0x75, 0xf5, 0xfa, 0x93, 0x1e, 0x97, 0x14,
7987901324dSJerome Forissier   0x75, 0xb2, 0x7c, 0xae, 0x03, 0xa2, 0x96, 0x54,
7997901324dSJerome Forissier   0xe2, 0xf4, 0x09, 0x66, 0xea, 0x33, 0x64, 0x30,
8007901324dSJerome Forissier   0x40, 0xd1, 0x40, 0x0f, 0xe6, 0x77, 0x87, 0x3a,
8017901324dSJerome Forissier   0xf8, 0x09, 0x7c, 0x1f, 0xe9, 0xf0, 0x02, 0x98 };
80211fa71b9SJerome Forissier #endif /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
803817466cbSJens Wiklander 
804817466cbSJens Wiklander static size_t test_offset;
805817466cbSJens Wiklander static int ctr_drbg_self_test_entropy(void *data, unsigned char *buf,
806817466cbSJens Wiklander                                       size_t len)
807817466cbSJens Wiklander {
808817466cbSJens Wiklander     const unsigned char *p = data;
809817466cbSJens Wiklander     memcpy(buf, p + test_offset, len);
810817466cbSJens Wiklander     test_offset += len;
811*32b31808SJens Wiklander     return 0;
812817466cbSJens Wiklander }
813817466cbSJens Wiklander 
814817466cbSJens Wiklander #define CHK(c)    if ((c) != 0)                          \
815817466cbSJens Wiklander     {                                       \
816817466cbSJens Wiklander         if (verbose != 0)                  \
817817466cbSJens Wiklander         mbedtls_printf("failed\n");  \
818*32b31808SJens Wiklander         return 1;                        \
819817466cbSJens Wiklander     }
820817466cbSJens Wiklander 
821039e02dfSJerome Forissier #define SELF_TEST_OUTPUT_DISCARD_LENGTH 64
8227901324dSJerome Forissier 
823817466cbSJens Wiklander /*
824817466cbSJens Wiklander  * Checkup routine
825817466cbSJens Wiklander  */
826817466cbSJens Wiklander int mbedtls_ctr_drbg_self_test(int verbose)
827817466cbSJens Wiklander {
828817466cbSJens Wiklander     mbedtls_ctr_drbg_context ctx;
8297901324dSJerome Forissier     unsigned char buf[sizeof(result_pr)];
830817466cbSJens Wiklander 
831817466cbSJens Wiklander     mbedtls_ctr_drbg_init(&ctx);
832817466cbSJens Wiklander 
833817466cbSJens Wiklander     /*
834817466cbSJens Wiklander      * Based on a NIST CTR_DRBG test vector (PR = True)
835817466cbSJens Wiklander      */
836*32b31808SJens Wiklander     if (verbose != 0) {
837817466cbSJens Wiklander         mbedtls_printf("  CTR_DRBG (PR = TRUE) : ");
838*32b31808SJens Wiklander     }
839817466cbSJens Wiklander 
840817466cbSJens Wiklander     test_offset = 0;
8417901324dSJerome Forissier     mbedtls_ctr_drbg_set_entropy_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE);
8427901324dSJerome Forissier     mbedtls_ctr_drbg_set_nonce_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2);
8435b25c76aSJerome Forissier     CHK(mbedtls_ctr_drbg_seed(&ctx,
8445b25c76aSJerome Forissier                               ctr_drbg_self_test_entropy,
8455b25c76aSJerome Forissier                               (void *) entropy_source_pr,
8467901324dSJerome Forissier                               pers_pr, MBEDTLS_CTR_DRBG_KEYSIZE));
847817466cbSJens Wiklander     mbedtls_ctr_drbg_set_prediction_resistance(&ctx, MBEDTLS_CTR_DRBG_PR_ON);
848039e02dfSJerome Forissier     CHK(mbedtls_ctr_drbg_random(&ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH));
8497901324dSJerome Forissier     CHK(mbedtls_ctr_drbg_random(&ctx, buf, sizeof(result_pr)));
8507901324dSJerome Forissier     CHK(memcmp(buf, result_pr, sizeof(result_pr)));
851817466cbSJens Wiklander 
852817466cbSJens Wiklander     mbedtls_ctr_drbg_free(&ctx);
853817466cbSJens Wiklander 
854*32b31808SJens Wiklander     if (verbose != 0) {
855817466cbSJens Wiklander         mbedtls_printf("passed\n");
856*32b31808SJens Wiklander     }
857817466cbSJens Wiklander 
858817466cbSJens Wiklander     /*
859817466cbSJens Wiklander      * Based on a NIST CTR_DRBG test vector (PR = FALSE)
860817466cbSJens Wiklander      */
861*32b31808SJens Wiklander     if (verbose != 0) {
862817466cbSJens Wiklander         mbedtls_printf("  CTR_DRBG (PR = FALSE): ");
863*32b31808SJens Wiklander     }
864817466cbSJens Wiklander 
865817466cbSJens Wiklander     mbedtls_ctr_drbg_init(&ctx);
866817466cbSJens Wiklander 
867817466cbSJens Wiklander     test_offset = 0;
8687901324dSJerome Forissier     mbedtls_ctr_drbg_set_entropy_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE);
8697901324dSJerome Forissier     mbedtls_ctr_drbg_set_nonce_len(&ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2);
8705b25c76aSJerome Forissier     CHK(mbedtls_ctr_drbg_seed(&ctx,
8715b25c76aSJerome Forissier                               ctr_drbg_self_test_entropy,
8725b25c76aSJerome Forissier                               (void *) entropy_source_nopr,
8737901324dSJerome Forissier                               pers_nopr, MBEDTLS_CTR_DRBG_KEYSIZE));
874817466cbSJens Wiklander     CHK(mbedtls_ctr_drbg_reseed(&ctx, NULL, 0));
875039e02dfSJerome Forissier     CHK(mbedtls_ctr_drbg_random(&ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH));
8767901324dSJerome Forissier     CHK(mbedtls_ctr_drbg_random(&ctx, buf, sizeof(result_nopr)));
8777901324dSJerome Forissier     CHK(memcmp(buf, result_nopr, sizeof(result_nopr)));
878817466cbSJens Wiklander 
879817466cbSJens Wiklander     mbedtls_ctr_drbg_free(&ctx);
880817466cbSJens Wiklander 
881*32b31808SJens Wiklander     if (verbose != 0) {
882817466cbSJens Wiklander         mbedtls_printf("passed\n");
883*32b31808SJens Wiklander     }
884817466cbSJens Wiklander 
885*32b31808SJens Wiklander     if (verbose != 0) {
886817466cbSJens Wiklander         mbedtls_printf("\n");
887*32b31808SJens Wiklander     }
888817466cbSJens Wiklander 
889*32b31808SJens Wiklander     return 0;
890817466cbSJens Wiklander }
891817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
892817466cbSJens Wiklander 
893817466cbSJens Wiklander #endif /* MBEDTLS_CTR_DRBG_C */
894