xref: /optee_os/lib/libmbedtls/mbedtls/library/ctr_drbg.c (revision 039e02df2716a0ed886b56e1e07b7ac1d8597228)
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 #if defined(MBEDTLS_SELF_TEST)
40817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
41817466cbSJens Wiklander #include "mbedtls/platform.h"
42817466cbSJens Wiklander #else
43817466cbSJens Wiklander #include <stdio.h>
44817466cbSJens Wiklander #define mbedtls_printf printf
45817466cbSJens Wiklander #endif /* MBEDTLS_PLATFORM_C */
46817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
47817466cbSJens Wiklander 
48817466cbSJens Wiklander /*
49817466cbSJens Wiklander  * CTR_DRBG context initialization
50817466cbSJens Wiklander  */
51817466cbSJens Wiklander void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx )
52817466cbSJens Wiklander {
53817466cbSJens Wiklander     memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) );
5411fa71b9SJerome Forissier     /* Indicate that the entropy nonce length is not set explicitly.
5511fa71b9SJerome Forissier      * See mbedtls_ctr_drbg_set_nonce_len(). */
5611fa71b9SJerome Forissier     ctx->reseed_counter = -1;
57817466cbSJens Wiklander 
587901324dSJerome Forissier     ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
59817466cbSJens Wiklander }
60817466cbSJens Wiklander 
617901324dSJerome Forissier /*
627901324dSJerome Forissier  *  This function resets CTR_DRBG context to the state immediately
637901324dSJerome Forissier  *  after initial call of mbedtls_ctr_drbg_init().
647901324dSJerome Forissier  */
65817466cbSJens Wiklander void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
66817466cbSJens Wiklander {
67817466cbSJens Wiklander     if( ctx == NULL )
68817466cbSJens Wiklander         return;
69817466cbSJens Wiklander 
70817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
717901324dSJerome Forissier     /* The mutex is initialized iff f_entropy is set. */
727901324dSJerome Forissier     if( ctx->f_entropy != NULL )
73817466cbSJens Wiklander         mbedtls_mutex_free( &ctx->mutex );
74817466cbSJens Wiklander #endif
75817466cbSJens Wiklander     mbedtls_aes_free( &ctx->aes_ctx );
763d3b0591SJens Wiklander     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) );
777901324dSJerome Forissier     ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
787901324dSJerome Forissier     ctx->reseed_counter = -1;
79817466cbSJens Wiklander }
80817466cbSJens Wiklander 
8111fa71b9SJerome Forissier void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx,
8211fa71b9SJerome Forissier                                                  int resistance )
83817466cbSJens Wiklander {
84817466cbSJens Wiklander     ctx->prediction_resistance = resistance;
85817466cbSJens Wiklander }
86817466cbSJens Wiklander 
8711fa71b9SJerome Forissier void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx,
8811fa71b9SJerome Forissier                                        size_t len )
89817466cbSJens Wiklander {
90817466cbSJens Wiklander     ctx->entropy_len = len;
91817466cbSJens Wiklander }
92817466cbSJens Wiklander 
9311fa71b9SJerome Forissier int mbedtls_ctr_drbg_set_nonce_len( mbedtls_ctr_drbg_context *ctx,
9411fa71b9SJerome Forissier                                     size_t len )
9511fa71b9SJerome Forissier {
9611fa71b9SJerome Forissier     /* If mbedtls_ctr_drbg_seed() has already been called, it's
9711fa71b9SJerome Forissier      * too late. Return the error code that's closest to making sense. */
9811fa71b9SJerome Forissier     if( ctx->f_entropy != NULL )
9911fa71b9SJerome Forissier         return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
10011fa71b9SJerome Forissier 
10111fa71b9SJerome Forissier     if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
10211fa71b9SJerome Forissier         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
10311fa71b9SJerome Forissier #if SIZE_MAX > INT_MAX
10411fa71b9SJerome Forissier     /* This shouldn't be an issue because
10511fa71b9SJerome Forissier      * MBEDTLS_CTR_DRBG_MAX_SEED_INPUT < INT_MAX in any sensible
10611fa71b9SJerome Forissier      * configuration, but make sure anyway. */
10711fa71b9SJerome Forissier     if( len > INT_MAX )
10811fa71b9SJerome Forissier         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
10911fa71b9SJerome Forissier #endif
11011fa71b9SJerome Forissier 
11111fa71b9SJerome Forissier     /* For backward compatibility with Mbed TLS <= 2.19, store the
11211fa71b9SJerome Forissier      * entropy nonce length in a field that already exists, but isn't
11311fa71b9SJerome Forissier      * used until after the initial seeding. */
11411fa71b9SJerome Forissier     /* Due to the capping of len above, the value fits in an int. */
11511fa71b9SJerome Forissier     ctx->reseed_counter = (int) len;
11611fa71b9SJerome Forissier     return( 0 );
11711fa71b9SJerome Forissier }
11811fa71b9SJerome Forissier 
11911fa71b9SJerome Forissier void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx,
12011fa71b9SJerome Forissier                                            int interval )
121817466cbSJens Wiklander {
122817466cbSJens Wiklander     ctx->reseed_interval = interval;
123817466cbSJens Wiklander }
124817466cbSJens Wiklander 
125817466cbSJens Wiklander static int block_cipher_df( unsigned char *output,
126817466cbSJens Wiklander                             const unsigned char *data, size_t data_len )
127817466cbSJens Wiklander {
12811fa71b9SJerome Forissier     unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
12911fa71b9SJerome Forissier                       MBEDTLS_CTR_DRBG_BLOCKSIZE + 16];
130817466cbSJens Wiklander     unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
131817466cbSJens Wiklander     unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
132817466cbSJens Wiklander     unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE];
133817466cbSJens Wiklander     unsigned char *p, *iv;
134817466cbSJens Wiklander     mbedtls_aes_context aes_ctx;
1353d3b0591SJens Wiklander     int ret = 0;
136817466cbSJens Wiklander 
137817466cbSJens Wiklander     int i, j;
138817466cbSJens Wiklander     size_t buf_len, use_len;
139817466cbSJens Wiklander 
140817466cbSJens Wiklander     if( data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
141817466cbSJens Wiklander         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
142817466cbSJens Wiklander 
14311fa71b9SJerome Forissier     memset( buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
14411fa71b9SJerome Forissier             MBEDTLS_CTR_DRBG_BLOCKSIZE + 16 );
145817466cbSJens Wiklander     mbedtls_aes_init( &aes_ctx );
146817466cbSJens Wiklander 
147817466cbSJens Wiklander     /*
148817466cbSJens Wiklander      * Construct IV (16 bytes) and S in buffer
149817466cbSJens Wiklander      * IV = Counter (in 32-bits) padded to 16 with zeroes
150817466cbSJens Wiklander      * S = Length input string (in 32-bits) || Length of output (in 32-bits) ||
151817466cbSJens Wiklander      *     data || 0x80
152817466cbSJens Wiklander      *     (Total is padded to a multiple of 16-bytes with zeroes)
153817466cbSJens Wiklander      */
154817466cbSJens Wiklander     p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE;
155*039e02dfSJerome Forissier     MBEDTLS_PUT_UINT32_BE( data_len, p, 0);
156*039e02dfSJerome Forissier     p += 4 + 3;
157817466cbSJens Wiklander     *p++ = MBEDTLS_CTR_DRBG_SEEDLEN;
158817466cbSJens Wiklander     memcpy( p, data, data_len );
159817466cbSJens Wiklander     p[data_len] = 0x80;
160817466cbSJens Wiklander 
161817466cbSJens Wiklander     buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1;
162817466cbSJens Wiklander 
163817466cbSJens Wiklander     for( i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++ )
164817466cbSJens Wiklander         key[i] = i;
165817466cbSJens Wiklander 
16611fa71b9SJerome Forissier     if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, key,
16711fa71b9SJerome Forissier                                         MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
1683d3b0591SJens Wiklander     {
1693d3b0591SJens Wiklander         goto exit;
1703d3b0591SJens Wiklander     }
171817466cbSJens Wiklander 
172817466cbSJens Wiklander     /*
173817466cbSJens Wiklander      * Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data
174817466cbSJens Wiklander      */
175817466cbSJens Wiklander     for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
176817466cbSJens Wiklander     {
177817466cbSJens Wiklander         p = buf;
178817466cbSJens Wiklander         memset( chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE );
179817466cbSJens Wiklander         use_len = buf_len;
180817466cbSJens Wiklander 
181817466cbSJens Wiklander         while( use_len > 0 )
182817466cbSJens Wiklander         {
183817466cbSJens Wiklander             for( i = 0; i < MBEDTLS_CTR_DRBG_BLOCKSIZE; i++ )
184817466cbSJens Wiklander                 chain[i] ^= p[i];
185817466cbSJens Wiklander             p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
186817466cbSJens Wiklander             use_len -= ( use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE ) ?
187817466cbSJens Wiklander                        MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len;
188817466cbSJens Wiklander 
18911fa71b9SJerome Forissier             if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT,
19011fa71b9SJerome Forissier                                                chain, chain ) ) != 0 )
1913d3b0591SJens Wiklander             {
1923d3b0591SJens Wiklander                 goto exit;
1933d3b0591SJens Wiklander             }
194817466cbSJens Wiklander         }
195817466cbSJens Wiklander 
196817466cbSJens Wiklander         memcpy( tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE );
197817466cbSJens Wiklander 
198817466cbSJens Wiklander         /*
199817466cbSJens Wiklander          * Update IV
200817466cbSJens Wiklander          */
201817466cbSJens Wiklander         buf[3]++;
202817466cbSJens Wiklander     }
203817466cbSJens Wiklander 
204817466cbSJens Wiklander     /*
205817466cbSJens Wiklander      * Do final encryption with reduced data
206817466cbSJens Wiklander      */
20711fa71b9SJerome Forissier     if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, tmp,
20811fa71b9SJerome Forissier                                         MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
2093d3b0591SJens Wiklander     {
2103d3b0591SJens Wiklander         goto exit;
2113d3b0591SJens Wiklander     }
212817466cbSJens Wiklander     iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE;
213817466cbSJens Wiklander     p = output;
214817466cbSJens Wiklander 
215817466cbSJens Wiklander     for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
216817466cbSJens Wiklander     {
21711fa71b9SJerome Forissier         if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT,
21811fa71b9SJerome Forissier                                            iv, iv ) ) != 0 )
2193d3b0591SJens Wiklander         {
2203d3b0591SJens Wiklander             goto exit;
2213d3b0591SJens Wiklander         }
222817466cbSJens Wiklander         memcpy( p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE );
223817466cbSJens Wiklander         p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
224817466cbSJens Wiklander     }
2253d3b0591SJens Wiklander exit:
226817466cbSJens Wiklander     mbedtls_aes_free( &aes_ctx );
2273d3b0591SJens Wiklander     /*
2283d3b0591SJens Wiklander     * tidy up the stack
2293d3b0591SJens Wiklander     */
2303d3b0591SJens Wiklander     mbedtls_platform_zeroize( buf, sizeof( buf ) );
2313d3b0591SJens Wiklander     mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
2323d3b0591SJens Wiklander     mbedtls_platform_zeroize( key, sizeof( key ) );
2333d3b0591SJens Wiklander     mbedtls_platform_zeroize( chain, sizeof( chain ) );
2343d3b0591SJens Wiklander     if( 0 != ret )
2353d3b0591SJens Wiklander     {
2363d3b0591SJens Wiklander         /*
2373d3b0591SJens Wiklander         * wipe partial seed from memory
2383d3b0591SJens Wiklander         */
2393d3b0591SJens Wiklander         mbedtls_platform_zeroize( output, MBEDTLS_CTR_DRBG_SEEDLEN );
240817466cbSJens Wiklander     }
241817466cbSJens Wiklander 
2423d3b0591SJens Wiklander     return( ret );
2433d3b0591SJens Wiklander }
2443d3b0591SJens Wiklander 
2453d3b0591SJens Wiklander /* CTR_DRBG_Update (SP 800-90A &sect;10.2.1.2)
2463d3b0591SJens Wiklander  * ctr_drbg_update_internal(ctx, provided_data)
2473d3b0591SJens Wiklander  * implements
2483d3b0591SJens Wiklander  * CTR_DRBG_Update(provided_data, Key, V)
2493d3b0591SJens Wiklander  * with inputs and outputs
2503d3b0591SJens Wiklander  *   ctx->aes_ctx = Key
2513d3b0591SJens Wiklander  *   ctx->counter = V
2523d3b0591SJens Wiklander  */
253817466cbSJens Wiklander static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx,
254817466cbSJens Wiklander                           const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] )
255817466cbSJens Wiklander {
256817466cbSJens Wiklander     unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
257817466cbSJens Wiklander     unsigned char *p = tmp;
258817466cbSJens Wiklander     int i, j;
2593d3b0591SJens Wiklander     int ret = 0;
260817466cbSJens Wiklander 
261817466cbSJens Wiklander     memset( tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN );
262817466cbSJens Wiklander 
263817466cbSJens Wiklander     for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
264817466cbSJens Wiklander     {
265817466cbSJens Wiklander         /*
266817466cbSJens Wiklander          * Increase counter
267817466cbSJens Wiklander          */
268817466cbSJens Wiklander         for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- )
269817466cbSJens Wiklander             if( ++ctx->counter[i - 1] != 0 )
270817466cbSJens Wiklander                 break;
271817466cbSJens Wiklander 
272817466cbSJens Wiklander         /*
273817466cbSJens Wiklander          * Crypt counter block
274817466cbSJens Wiklander          */
27511fa71b9SJerome Forissier         if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
27611fa71b9SJerome Forissier                                            ctx->counter, p ) ) != 0 )
27711fa71b9SJerome Forissier         {
2783d3b0591SJens Wiklander             goto exit;
27911fa71b9SJerome Forissier         }
280817466cbSJens Wiklander 
281817466cbSJens Wiklander         p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
282817466cbSJens Wiklander     }
283817466cbSJens Wiklander 
284817466cbSJens Wiklander     for( i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++ )
285817466cbSJens Wiklander         tmp[i] ^= data[i];
286817466cbSJens Wiklander 
287817466cbSJens Wiklander     /*
288817466cbSJens Wiklander      * Update key and counter
289817466cbSJens Wiklander      */
29011fa71b9SJerome Forissier     if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp,
29111fa71b9SJerome Forissier                                         MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
29211fa71b9SJerome Forissier     {
2933d3b0591SJens Wiklander         goto exit;
29411fa71b9SJerome Forissier     }
29511fa71b9SJerome Forissier     memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE,
29611fa71b9SJerome Forissier             MBEDTLS_CTR_DRBG_BLOCKSIZE );
297817466cbSJens Wiklander 
2983d3b0591SJens Wiklander exit:
2993d3b0591SJens Wiklander     mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
3003d3b0591SJens Wiklander     return( ret );
301817466cbSJens Wiklander }
302817466cbSJens Wiklander 
3033d3b0591SJens Wiklander /* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
3043d3b0591SJens Wiklander  * mbedtls_ctr_drbg_update(ctx, additional, add_len)
3053d3b0591SJens Wiklander  * implements
3063d3b0591SJens Wiklander  * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
3073d3b0591SJens Wiklander  *                      security_strength) -> initial_working_state
3083d3b0591SJens Wiklander  * with inputs
3093d3b0591SJens Wiklander  *   ctx->counter = all-bits-0
3103d3b0591SJens Wiklander  *   ctx->aes_ctx = context from all-bits-0 key
3113d3b0591SJens Wiklander  *   additional[:add_len] = entropy_input || nonce || personalization_string
3123d3b0591SJens Wiklander  * and with outputs
3133d3b0591SJens Wiklander  *   ctx = initial_working_state
3143d3b0591SJens Wiklander  */
3153d3b0591SJens Wiklander int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx,
3163d3b0591SJens Wiklander                                  const unsigned char *additional,
3173d3b0591SJens Wiklander                                  size_t add_len )
318817466cbSJens Wiklander {
319817466cbSJens Wiklander     unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
32011fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
321817466cbSJens Wiklander 
3223d3b0591SJens Wiklander     if( add_len == 0 )
3233d3b0591SJens Wiklander         return( 0 );
3243d3b0591SJens Wiklander 
3253d3b0591SJens Wiklander     if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 )
3263d3b0591SJens Wiklander         goto exit;
3273d3b0591SJens Wiklander     if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
3283d3b0591SJens Wiklander         goto exit;
3293d3b0591SJens Wiklander 
3303d3b0591SJens Wiklander exit:
3313d3b0591SJens Wiklander     mbedtls_platform_zeroize( add_input, sizeof( add_input ) );
3323d3b0591SJens Wiklander     return( ret );
3333d3b0591SJens Wiklander }
3343d3b0591SJens Wiklander 
3353d3b0591SJens Wiklander #if !defined(MBEDTLS_DEPRECATED_REMOVED)
3363d3b0591SJens Wiklander void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
3373d3b0591SJens Wiklander                               const unsigned char *additional,
3383d3b0591SJens Wiklander                               size_t add_len )
339817466cbSJens Wiklander {
340817466cbSJens Wiklander     /* MAX_INPUT would be more logical here, but we have to match
341817466cbSJens Wiklander      * block_cipher_df()'s limits since we can't propagate errors */
342817466cbSJens Wiklander     if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
343817466cbSJens Wiklander         add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT;
3443d3b0591SJens Wiklander     (void) mbedtls_ctr_drbg_update_ret( ctx, additional, add_len );
345817466cbSJens Wiklander }
3463d3b0591SJens Wiklander #endif /* MBEDTLS_DEPRECATED_REMOVED */
347817466cbSJens Wiklander 
3483d3b0591SJens Wiklander /* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
34911fa71b9SJerome Forissier  * mbedtls_ctr_drbg_reseed(ctx, additional, len, nonce_len)
3503d3b0591SJens Wiklander  * implements
3513d3b0591SJens Wiklander  * CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
3523d3b0591SJens Wiklander  *                -> new_working_state
3533d3b0591SJens Wiklander  * with inputs
3543d3b0591SJens Wiklander  *   ctx contains working_state
3553d3b0591SJens Wiklander  *   additional[:len] = additional_input
3563d3b0591SJens Wiklander  * and entropy_input comes from calling ctx->f_entropy
35711fa71b9SJerome Forissier  *                              for (ctx->entropy_len + nonce_len) bytes
3583d3b0591SJens Wiklander  * and with output
3593d3b0591SJens Wiklander  *   ctx contains new_working_state
3603d3b0591SJens Wiklander  */
36111fa71b9SJerome Forissier static int mbedtls_ctr_drbg_reseed_internal( mbedtls_ctr_drbg_context *ctx,
36211fa71b9SJerome Forissier                                              const unsigned char *additional,
36311fa71b9SJerome Forissier                                              size_t len,
36411fa71b9SJerome Forissier                                              size_t nonce_len )
365817466cbSJens Wiklander {
366817466cbSJens Wiklander     unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
367817466cbSJens Wiklander     size_t seedlen = 0;
36811fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
369817466cbSJens Wiklander 
37011fa71b9SJerome Forissier     if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
37111fa71b9SJerome Forissier         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
37211fa71b9SJerome Forissier     if( nonce_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len )
37311fa71b9SJerome Forissier         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
37411fa71b9SJerome Forissier     if( len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len - nonce_len )
375817466cbSJens Wiklander         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
376817466cbSJens Wiklander 
377817466cbSJens Wiklander     memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT );
378817466cbSJens Wiklander 
37911fa71b9SJerome Forissier     /* Gather entropy_len bytes of entropy to seed state. */
38011fa71b9SJerome Forissier     if( 0 != ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) )
381817466cbSJens Wiklander     {
382817466cbSJens Wiklander         return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
383817466cbSJens Wiklander     }
384817466cbSJens Wiklander     seedlen += ctx->entropy_len;
385817466cbSJens Wiklander 
38611fa71b9SJerome Forissier     /* Gather entropy for a nonce if requested. */
38711fa71b9SJerome Forissier     if( nonce_len != 0 )
38811fa71b9SJerome Forissier     {
3897901324dSJerome Forissier         if( 0 != ctx->f_entropy( ctx->p_entropy, seed + seedlen, nonce_len ) )
39011fa71b9SJerome Forissier         {
39111fa71b9SJerome Forissier             return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
39211fa71b9SJerome Forissier         }
39311fa71b9SJerome Forissier         seedlen += nonce_len;
39411fa71b9SJerome Forissier     }
39511fa71b9SJerome Forissier 
39611fa71b9SJerome Forissier     /* Add additional data if provided. */
39711fa71b9SJerome Forissier     if( additional != NULL && len != 0 )
398817466cbSJens Wiklander     {
399817466cbSJens Wiklander         memcpy( seed + seedlen, additional, len );
400817466cbSJens Wiklander         seedlen += len;
401817466cbSJens Wiklander     }
402817466cbSJens Wiklander 
40311fa71b9SJerome Forissier     /* Reduce to 384 bits. */
4043d3b0591SJens Wiklander     if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 )
4053d3b0591SJens Wiklander         goto exit;
406817466cbSJens Wiklander 
40711fa71b9SJerome Forissier     /* Update state. */
4083d3b0591SJens Wiklander     if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 )
4093d3b0591SJens Wiklander         goto exit;
410817466cbSJens Wiklander     ctx->reseed_counter = 1;
411817466cbSJens Wiklander 
4123d3b0591SJens Wiklander exit:
4133d3b0591SJens Wiklander     mbedtls_platform_zeroize( seed, sizeof( seed ) );
4143d3b0591SJens Wiklander     return( ret );
415817466cbSJens Wiklander }
416817466cbSJens Wiklander 
41711fa71b9SJerome Forissier int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
41811fa71b9SJerome Forissier                              const unsigned char *additional, size_t len )
41911fa71b9SJerome Forissier {
42011fa71b9SJerome Forissier     return( mbedtls_ctr_drbg_reseed_internal( ctx, additional, len, 0 ) );
42111fa71b9SJerome Forissier }
42211fa71b9SJerome Forissier 
42311fa71b9SJerome Forissier /* Return a "good" nonce length for CTR_DRBG. The chosen nonce length
42411fa71b9SJerome Forissier  * is sufficient to achieve the maximum security strength given the key
42511fa71b9SJerome Forissier  * size and entropy length. If there is enough entropy in the initial
42611fa71b9SJerome Forissier  * call to the entropy function to serve as both the entropy input and
42711fa71b9SJerome Forissier  * the nonce, don't make a second call to get a nonce. */
42811fa71b9SJerome Forissier static size_t good_nonce_len( size_t entropy_len )
42911fa71b9SJerome Forissier {
43011fa71b9SJerome Forissier     if( entropy_len >= MBEDTLS_CTR_DRBG_KEYSIZE * 3 / 2 )
43111fa71b9SJerome Forissier         return( 0 );
43211fa71b9SJerome Forissier     else
43311fa71b9SJerome Forissier         return( ( entropy_len + 1 ) / 2 );
43411fa71b9SJerome Forissier }
43511fa71b9SJerome Forissier 
4365b25c76aSJerome Forissier /* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
4375b25c76aSJerome Forissier  * mbedtls_ctr_drbg_seed(ctx, f_entropy, p_entropy, custom, len)
4385b25c76aSJerome Forissier  * implements
4395b25c76aSJerome Forissier  * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
4405b25c76aSJerome Forissier  *                      security_strength) -> initial_working_state
4415b25c76aSJerome Forissier  * with inputs
4425b25c76aSJerome Forissier  *   custom[:len] = nonce || personalization_string
4435b25c76aSJerome Forissier  * where entropy_input comes from f_entropy for ctx->entropy_len bytes
4445b25c76aSJerome Forissier  * and with outputs
4455b25c76aSJerome Forissier  *   ctx = initial_working_state
4465b25c76aSJerome Forissier  */
4475b25c76aSJerome Forissier int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
4485b25c76aSJerome Forissier                            int (*f_entropy)(void *, unsigned char *, size_t),
4495b25c76aSJerome Forissier                            void *p_entropy,
4505b25c76aSJerome Forissier                            const unsigned char *custom,
4515b25c76aSJerome Forissier                            size_t len )
4525b25c76aSJerome Forissier {
45311fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
4545b25c76aSJerome Forissier     unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
45511fa71b9SJerome Forissier     size_t nonce_len;
4565b25c76aSJerome Forissier 
4575b25c76aSJerome Forissier     memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
4585b25c76aSJerome Forissier 
4597901324dSJerome Forissier     /* The mutex is initialized iff f_entropy is set. */
4607901324dSJerome Forissier #if defined(MBEDTLS_THREADING_C)
4617901324dSJerome Forissier     mbedtls_mutex_init( &ctx->mutex );
4627901324dSJerome Forissier #endif
4637901324dSJerome Forissier 
4645b25c76aSJerome Forissier     mbedtls_aes_init( &ctx->aes_ctx );
4655b25c76aSJerome Forissier 
4665b25c76aSJerome Forissier     ctx->f_entropy = f_entropy;
4675b25c76aSJerome Forissier     ctx->p_entropy = p_entropy;
4685b25c76aSJerome Forissier 
4695b25c76aSJerome Forissier     if( ctx->entropy_len == 0 )
4705b25c76aSJerome Forissier         ctx->entropy_len = MBEDTLS_CTR_DRBG_ENTROPY_LEN;
47111fa71b9SJerome Forissier     /* ctx->reseed_counter contains the desired amount of entropy to
47211fa71b9SJerome Forissier      * grab for a nonce (see mbedtls_ctr_drbg_set_nonce_len()).
47311fa71b9SJerome Forissier      * If it's -1, indicating that the entropy nonce length was not set
47411fa71b9SJerome Forissier      * explicitly, use a sufficiently large nonce for security. */
47511fa71b9SJerome Forissier     nonce_len = ( ctx->reseed_counter >= 0 ?
47611fa71b9SJerome Forissier                   (size_t) ctx->reseed_counter :
47711fa71b9SJerome Forissier                   good_nonce_len( ctx->entropy_len ) );
47811fa71b9SJerome Forissier 
47911fa71b9SJerome Forissier     /* Initialize with an empty key. */
48011fa71b9SJerome Forissier     if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx, key,
48111fa71b9SJerome Forissier                                         MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
4825b25c76aSJerome Forissier     {
4835b25c76aSJerome Forissier         return( ret );
4845b25c76aSJerome Forissier     }
4855b25c76aSJerome Forissier 
48611fa71b9SJerome Forissier     /* Do the initial seeding. */
48711fa71b9SJerome Forissier     if( ( ret = mbedtls_ctr_drbg_reseed_internal( ctx, custom, len,
48811fa71b9SJerome Forissier                                                   nonce_len ) ) != 0 )
4895b25c76aSJerome Forissier     {
4905b25c76aSJerome Forissier         return( ret );
4915b25c76aSJerome Forissier     }
4925b25c76aSJerome Forissier     return( 0 );
4935b25c76aSJerome Forissier }
4945b25c76aSJerome Forissier 
4953d3b0591SJens Wiklander /* CTR_DRBG_Generate with derivation function (SP 800-90A &sect;10.2.1.5.2)
4963d3b0591SJens Wiklander  * mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len)
4973d3b0591SJens Wiklander  * implements
4983d3b0591SJens Wiklander  * CTR_DRBG_Reseed(working_state, entropy_input, additional[:add_len])
4993d3b0591SJens Wiklander  *                -> working_state_after_reseed
5003d3b0591SJens Wiklander  *                if required, then
5013d3b0591SJens Wiklander  * CTR_DRBG_Generate(working_state_after_reseed,
5023d3b0591SJens Wiklander  *                   requested_number_of_bits, additional_input)
5033d3b0591SJens Wiklander  *                -> status, returned_bits, new_working_state
5043d3b0591SJens Wiklander  * with inputs
5053d3b0591SJens Wiklander  *   ctx contains working_state
5063d3b0591SJens Wiklander  *   requested_number_of_bits = 8 * output_len
5073d3b0591SJens Wiklander  *   additional[:add_len] = additional_input
5083d3b0591SJens Wiklander  * and entropy_input comes from calling ctx->f_entropy
5093d3b0591SJens Wiklander  * and with outputs
5103d3b0591SJens Wiklander  *   status = SUCCESS (this function does the reseed internally)
5113d3b0591SJens Wiklander  *   returned_bits = output[:output_len]
5123d3b0591SJens Wiklander  *   ctx contains new_working_state
5133d3b0591SJens Wiklander  */
514817466cbSJens Wiklander int mbedtls_ctr_drbg_random_with_add( void *p_rng,
515817466cbSJens Wiklander                               unsigned char *output, size_t output_len,
516817466cbSJens Wiklander                               const unsigned char *additional, size_t add_len )
517817466cbSJens Wiklander {
518817466cbSJens Wiklander     int ret = 0;
519817466cbSJens Wiklander     mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
520817466cbSJens Wiklander     unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
521817466cbSJens Wiklander     unsigned char *p = output;
522817466cbSJens Wiklander     unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE];
523817466cbSJens Wiklander     int i;
524817466cbSJens Wiklander     size_t use_len;
525817466cbSJens Wiklander 
526817466cbSJens Wiklander     if( output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST )
527817466cbSJens Wiklander         return( MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG );
528817466cbSJens Wiklander 
529817466cbSJens Wiklander     if( add_len > MBEDTLS_CTR_DRBG_MAX_INPUT )
530817466cbSJens Wiklander         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
531817466cbSJens Wiklander 
532817466cbSJens Wiklander     memset( add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN );
533817466cbSJens Wiklander 
534817466cbSJens Wiklander     if( ctx->reseed_counter > ctx->reseed_interval ||
535817466cbSJens Wiklander         ctx->prediction_resistance )
536817466cbSJens Wiklander     {
537817466cbSJens Wiklander         if( ( ret = mbedtls_ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 )
5383d3b0591SJens Wiklander         {
539817466cbSJens Wiklander             return( ret );
5403d3b0591SJens Wiklander         }
541817466cbSJens Wiklander         add_len = 0;
542817466cbSJens Wiklander     }
543817466cbSJens Wiklander 
544817466cbSJens Wiklander     if( add_len > 0 )
545817466cbSJens Wiklander     {
5463d3b0591SJens Wiklander         if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 )
5473d3b0591SJens Wiklander             goto exit;
5483d3b0591SJens Wiklander         if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
5493d3b0591SJens Wiklander             goto exit;
550817466cbSJens Wiklander     }
551817466cbSJens Wiklander 
552817466cbSJens Wiklander     while( output_len > 0 )
553817466cbSJens Wiklander     {
554817466cbSJens Wiklander         /*
555817466cbSJens Wiklander          * Increase counter
556817466cbSJens Wiklander          */
557817466cbSJens Wiklander         for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- )
558817466cbSJens Wiklander             if( ++ctx->counter[i - 1] != 0 )
559817466cbSJens Wiklander                 break;
560817466cbSJens Wiklander 
561817466cbSJens Wiklander         /*
562817466cbSJens Wiklander          * Crypt counter block
563817466cbSJens Wiklander          */
56411fa71b9SJerome Forissier         if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT,
56511fa71b9SJerome Forissier                                            ctx->counter, tmp ) ) != 0 )
56611fa71b9SJerome Forissier         {
5673d3b0591SJens Wiklander             goto exit;
56811fa71b9SJerome Forissier         }
569817466cbSJens Wiklander 
57011fa71b9SJerome Forissier         use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE )
57111fa71b9SJerome Forissier             ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len;
572817466cbSJens Wiklander         /*
573817466cbSJens Wiklander          * Copy random block to destination
574817466cbSJens Wiklander          */
575817466cbSJens Wiklander         memcpy( p, tmp, use_len );
576817466cbSJens Wiklander         p += use_len;
577817466cbSJens Wiklander         output_len -= use_len;
578817466cbSJens Wiklander     }
579817466cbSJens Wiklander 
5803d3b0591SJens Wiklander     if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
5813d3b0591SJens Wiklander         goto exit;
582817466cbSJens Wiklander 
583817466cbSJens Wiklander     ctx->reseed_counter++;
584817466cbSJens Wiklander 
5853d3b0591SJens Wiklander exit:
5863d3b0591SJens Wiklander     mbedtls_platform_zeroize( add_input, sizeof( add_input ) );
5873d3b0591SJens Wiklander     mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
5885b25c76aSJerome Forissier     return( ret );
589817466cbSJens Wiklander }
590817466cbSJens Wiklander 
59111fa71b9SJerome Forissier int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output,
59211fa71b9SJerome Forissier                              size_t output_len )
593817466cbSJens Wiklander {
59411fa71b9SJerome Forissier     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
595817466cbSJens Wiklander     mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
596817466cbSJens Wiklander 
597817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
598817466cbSJens Wiklander     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
599817466cbSJens Wiklander         return( ret );
600817466cbSJens Wiklander #endif
601817466cbSJens Wiklander 
602817466cbSJens Wiklander     ret = mbedtls_ctr_drbg_random_with_add( ctx, output, output_len, NULL, 0 );
603817466cbSJens Wiklander 
604817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
605817466cbSJens Wiklander     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
606817466cbSJens Wiklander         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
607817466cbSJens Wiklander #endif
608817466cbSJens Wiklander 
609817466cbSJens Wiklander     return( ret );
610817466cbSJens Wiklander }
611817466cbSJens Wiklander 
612817466cbSJens Wiklander #if defined(MBEDTLS_FS_IO)
61311fa71b9SJerome Forissier int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx,
61411fa71b9SJerome Forissier                                       const char *path )
615817466cbSJens Wiklander {
616817466cbSJens Wiklander     int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
617817466cbSJens Wiklander     FILE *f;
618817466cbSJens Wiklander     unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ];
619817466cbSJens Wiklander 
620817466cbSJens Wiklander     if( ( f = fopen( path, "wb" ) ) == NULL )
621817466cbSJens Wiklander         return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR );
622817466cbSJens Wiklander 
62311fa71b9SJerome Forissier     if( ( ret = mbedtls_ctr_drbg_random( ctx, buf,
62411fa71b9SJerome Forissier                                          MBEDTLS_CTR_DRBG_MAX_INPUT ) ) != 0 )
625817466cbSJens Wiklander         goto exit;
626817466cbSJens Wiklander 
62711fa71b9SJerome Forissier     if( fwrite( buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f ) !=
62811fa71b9SJerome Forissier         MBEDTLS_CTR_DRBG_MAX_INPUT )
62911fa71b9SJerome Forissier     {
630817466cbSJens Wiklander         ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
63111fa71b9SJerome Forissier     }
6323d3b0591SJens Wiklander     else
63311fa71b9SJerome Forissier     {
634817466cbSJens Wiklander         ret = 0;
63511fa71b9SJerome Forissier     }
636817466cbSJens Wiklander 
637817466cbSJens Wiklander exit:
6383d3b0591SJens Wiklander     mbedtls_platform_zeroize( buf, sizeof( buf ) );
6393d3b0591SJens Wiklander 
640817466cbSJens Wiklander     fclose( f );
641817466cbSJens Wiklander     return( ret );
642817466cbSJens Wiklander }
643817466cbSJens Wiklander 
64411fa71b9SJerome Forissier int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx,
64511fa71b9SJerome Forissier                                        const char *path )
646817466cbSJens Wiklander {
6473d3b0591SJens Wiklander     int ret = 0;
6483d3b0591SJens Wiklander     FILE *f = NULL;
649817466cbSJens Wiklander     size_t n;
650817466cbSJens Wiklander     unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ];
6513d3b0591SJens Wiklander     unsigned char c;
652817466cbSJens Wiklander 
653817466cbSJens Wiklander     if( ( f = fopen( path, "rb" ) ) == NULL )
654817466cbSJens Wiklander         return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR );
655817466cbSJens Wiklander 
6563d3b0591SJens Wiklander     n = fread( buf, 1, sizeof( buf ), f );
6573d3b0591SJens Wiklander     if( fread( &c, 1, 1, f ) != 0 )
658817466cbSJens Wiklander     {
6593d3b0591SJens Wiklander         ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
6603d3b0591SJens Wiklander         goto exit;
661817466cbSJens Wiklander     }
6623d3b0591SJens Wiklander     if( n == 0 || ferror( f ) )
663817466cbSJens Wiklander     {
6643d3b0591SJens Wiklander         ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
6653d3b0591SJens Wiklander         goto exit;
666817466cbSJens Wiklander     }
667817466cbSJens Wiklander     fclose( f );
6683d3b0591SJens Wiklander     f = NULL;
669817466cbSJens Wiklander 
6703d3b0591SJens Wiklander     ret = mbedtls_ctr_drbg_update_ret( ctx, buf, n );
671817466cbSJens Wiklander 
6723d3b0591SJens Wiklander exit:
6733d3b0591SJens Wiklander     mbedtls_platform_zeroize( buf, sizeof( buf ) );
6743d3b0591SJens Wiklander     if( f != NULL )
6753d3b0591SJens Wiklander         fclose( f );
6763d3b0591SJens Wiklander     if( ret != 0 )
6773d3b0591SJens Wiklander         return( ret );
678817466cbSJens Wiklander     return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) );
679817466cbSJens Wiklander }
680817466cbSJens Wiklander #endif /* MBEDTLS_FS_IO */
681817466cbSJens Wiklander 
682817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
683817466cbSJens Wiklander 
6847901324dSJerome Forissier /* The CTR_DRBG NIST test vectors used here are available at
6857901324dSJerome Forissier  * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Algorithm-Validation-Program/documents/drbg/drbgtestvectors.zip
6867901324dSJerome Forissier  *
6877901324dSJerome Forissier  * The parameters used to derive the test data are:
6887901324dSJerome Forissier  *
6897901324dSJerome Forissier  * [AES-128 use df]
6907901324dSJerome Forissier  * [PredictionResistance = True/False]
6917901324dSJerome Forissier  * [EntropyInputLen = 128]
6927901324dSJerome Forissier  * [NonceLen = 64]
6937901324dSJerome Forissier  * [PersonalizationStringLen = 128]
6947901324dSJerome Forissier  * [AdditionalInputLen = 0]
6957901324dSJerome Forissier  * [ReturnedBitsLen = 512]
6967901324dSJerome Forissier  *
6977901324dSJerome Forissier  * [AES-256 use df]
6987901324dSJerome Forissier  * [PredictionResistance = True/False]
6997901324dSJerome Forissier  * [EntropyInputLen = 256]
7007901324dSJerome Forissier  * [NonceLen = 128]
7017901324dSJerome Forissier  * [PersonalizationStringLen = 256]
7027901324dSJerome Forissier  * [AdditionalInputLen = 0]
7037901324dSJerome Forissier  * [ReturnedBitsLen = 512]
7047901324dSJerome Forissier  *
7057901324dSJerome Forissier  */
706817466cbSJens Wiklander 
70711fa71b9SJerome Forissier #if defined(MBEDTLS_CTR_DRBG_USE_128_BIT_KEY)
7087901324dSJerome Forissier static const unsigned char entropy_source_pr[] =
7097901324dSJerome Forissier     { 0x04, 0xd9, 0x49, 0xa6, 0xdc, 0xe8, 0x6e, 0xbb,
7107901324dSJerome Forissier       0xf1, 0x08, 0x77, 0x2b, 0x9e, 0x08, 0xca, 0x92,
7117901324dSJerome Forissier       0x65, 0x16, 0xda, 0x99, 0xa2, 0x59, 0xf3, 0xe8,
7127901324dSJerome Forissier       0x38, 0x7e, 0x3f, 0x6b, 0x51, 0x70, 0x7b, 0x20,
7137901324dSJerome Forissier       0xec, 0x53, 0xd0, 0x66, 0xc3, 0x0f, 0xe3, 0xb0,
7147901324dSJerome Forissier       0xe0, 0x86, 0xa6, 0xaa, 0x5f, 0x72, 0x2f, 0xad,
7157901324dSJerome Forissier       0xf7, 0xef, 0x06, 0xb8, 0xd6, 0x9c, 0x9d, 0xe8 };
71611fa71b9SJerome Forissier 
7177901324dSJerome Forissier static const unsigned char entropy_source_nopr[] =
7187901324dSJerome Forissier     { 0x07, 0x0d, 0x59, 0x63, 0x98, 0x73, 0xa5, 0x45,
7197901324dSJerome Forissier       0x27, 0x38, 0x22, 0x7b, 0x76, 0x85, 0xd1, 0xa9,
7207901324dSJerome Forissier       0x74, 0x18, 0x1f, 0x3c, 0x22, 0xf6, 0x49, 0x20,
7217901324dSJerome Forissier       0x4a, 0x47, 0xc2, 0xf3, 0x85, 0x16, 0xb4, 0x6f,
7227901324dSJerome Forissier       0x00, 0x2e, 0x71, 0xda, 0xed, 0x16, 0x9b, 0x5c };
7237901324dSJerome Forissier 
7247901324dSJerome Forissier static const unsigned char pers_pr[] =
7257901324dSJerome Forissier     { 0xbf, 0xa4, 0x9a, 0x8f, 0x7b, 0xd8, 0xb1, 0x7a,
7267901324dSJerome Forissier       0x9d, 0xfa, 0x45, 0xed, 0x21, 0x52, 0xb3, 0xad };
7277901324dSJerome Forissier 
7287901324dSJerome Forissier static const unsigned char pers_nopr[] =
7297901324dSJerome Forissier     { 0x4e, 0x61, 0x79, 0xd4, 0xc2, 0x72, 0xa1, 0x4c,
7307901324dSJerome Forissier       0xf1, 0x3d, 0xf6, 0x5e, 0xa3, 0xa6, 0xe5, 0x0f };
7317901324dSJerome Forissier 
7327901324dSJerome Forissier static const unsigned char result_pr[] =
7337901324dSJerome Forissier     { 0xc9, 0x0a, 0xaf, 0x85, 0x89, 0x71, 0x44, 0x66,
7347901324dSJerome Forissier       0x4f, 0x25, 0x0b, 0x2b, 0xde, 0xd8, 0xfa, 0xff,
7357901324dSJerome Forissier       0x52, 0x5a, 0x1b, 0x32, 0x5e, 0x41, 0x7a, 0x10,
7367901324dSJerome Forissier       0x1f, 0xef, 0x1e, 0x62, 0x23, 0xe9, 0x20, 0x30,
7377901324dSJerome Forissier       0xc9, 0x0d, 0xad, 0x69, 0xb4, 0x9c, 0x5b, 0xf4,
7387901324dSJerome Forissier       0x87, 0x42, 0xd5, 0xae, 0x5e, 0x5e, 0x43, 0xcc,
7397901324dSJerome Forissier       0xd9, 0xfd, 0x0b, 0x93, 0x4a, 0xe3, 0xd4, 0x06,
7407901324dSJerome Forissier       0x37, 0x36, 0x0f, 0x3f, 0x72, 0x82, 0x0c, 0xcf };
7417901324dSJerome Forissier 
7427901324dSJerome Forissier static const unsigned char result_nopr[] =
7437901324dSJerome Forissier     { 0x31, 0xc9, 0x91, 0x09, 0xf8, 0xc5, 0x10, 0x13,
7447901324dSJerome Forissier       0x3c, 0xd3, 0x96, 0xf9, 0xbc, 0x2c, 0x12, 0xc0,
7457901324dSJerome Forissier       0x7c, 0xc1, 0x61, 0x5f, 0xa3, 0x09, 0x99, 0xaf,
7467901324dSJerome Forissier       0xd7, 0xf2, 0x36, 0xfd, 0x40, 0x1a, 0x8b, 0xf2,
7477901324dSJerome Forissier       0x33, 0x38, 0xee, 0x1d, 0x03, 0x5f, 0x83, 0xb7,
7487901324dSJerome Forissier       0xa2, 0x53, 0xdc, 0xee, 0x18, 0xfc, 0xa7, 0xf2,
7497901324dSJerome Forissier       0xee, 0x96, 0xc6, 0xc2, 0xcd, 0x0c, 0xff, 0x02,
7507901324dSJerome Forissier       0x76, 0x70, 0x69, 0xaa, 0x69, 0xd1, 0x3b, 0xe8 };
75111fa71b9SJerome Forissier #else /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
752817466cbSJens Wiklander 
7537901324dSJerome Forissier static const unsigned char entropy_source_pr[] =
7547901324dSJerome Forissier     { 0xca, 0x58, 0xfd, 0xf2, 0xb9, 0x77, 0xcb, 0x49,
7557901324dSJerome Forissier       0xd4, 0xe0, 0x5b, 0xe2, 0x39, 0x50, 0xd9, 0x8a,
7567901324dSJerome Forissier       0x6a, 0xb3, 0xc5, 0x2f, 0xdf, 0x74, 0xd5, 0x85,
7577901324dSJerome Forissier       0x8f, 0xd1, 0xba, 0x64, 0x54, 0x7b, 0xdb, 0x1e,
7587901324dSJerome Forissier       0xc5, 0xea, 0x24, 0xc0, 0xfa, 0x0c, 0x90, 0x15,
7597901324dSJerome Forissier       0x09, 0x20, 0x92, 0x42, 0x32, 0x36, 0x45, 0x45,
7607901324dSJerome Forissier       0x7d, 0x20, 0x76, 0x6b, 0xcf, 0xa2, 0x15, 0xc8,
7617901324dSJerome Forissier       0x2f, 0x9f, 0xbc, 0x88, 0x3f, 0x80, 0xd1, 0x2c,
7627901324dSJerome Forissier       0xb7, 0x16, 0xd1, 0x80, 0x9e, 0xe1, 0xc9, 0xb3,
7637901324dSJerome Forissier       0x88, 0x1b, 0x21, 0x45, 0xef, 0xa1, 0x7f, 0xce,
7647901324dSJerome Forissier       0xc8, 0x92, 0x35, 0x55, 0x2a, 0xd9, 0x1d, 0x8e,
7657901324dSJerome Forissier       0x12, 0x38, 0xac, 0x01, 0x4e, 0x38, 0x18, 0x76,
7667901324dSJerome Forissier       0x9c, 0xf2, 0xb6, 0xd4, 0x13, 0xb6, 0x2c, 0x77,
7677901324dSJerome Forissier       0xc0, 0xe7, 0xe6, 0x0c, 0x47, 0x44, 0x95, 0xbe };
7687901324dSJerome Forissier 
7697901324dSJerome Forissier static const unsigned char entropy_source_nopr[] =
7707901324dSJerome Forissier     { 0x4c, 0xfb, 0x21, 0x86, 0x73, 0x34, 0x6d, 0x9d,
7717901324dSJerome Forissier       0x50, 0xc9, 0x22, 0xe4, 0x9b, 0x0d, 0xfc, 0xd0,
7727901324dSJerome Forissier       0x90, 0xad, 0xf0, 0x4f, 0x5c, 0x3b, 0xa4, 0x73,
7737901324dSJerome Forissier       0x27, 0xdf, 0xcd, 0x6f, 0xa6, 0x3a, 0x78, 0x5c,
7747901324dSJerome Forissier       0x01, 0x69, 0x62, 0xa7, 0xfd, 0x27, 0x87, 0xa2,
7757901324dSJerome Forissier       0x4b, 0xf6, 0xbe, 0x47, 0xef, 0x37, 0x83, 0xf1,
7767901324dSJerome Forissier       0xb7, 0xec, 0x46, 0x07, 0x23, 0x63, 0x83, 0x4a,
7777901324dSJerome Forissier       0x1b, 0x01, 0x33, 0xf2, 0xc2, 0x38, 0x91, 0xdb,
7787901324dSJerome Forissier       0x4f, 0x11, 0xa6, 0x86, 0x51, 0xf2, 0x3e, 0x3a,
7797901324dSJerome Forissier       0x8b, 0x1f, 0xdc, 0x03, 0xb1, 0x92, 0xc7, 0xe7 };
7807901324dSJerome Forissier 
7817901324dSJerome Forissier static const unsigned char pers_pr[] =
7827901324dSJerome Forissier     { 0x5a, 0x70, 0x95, 0xe9, 0x81, 0x40, 0x52, 0x33,
7837901324dSJerome Forissier       0x91, 0x53, 0x7e, 0x75, 0xd6, 0x19, 0x9d, 0x1e,
7847901324dSJerome Forissier       0xad, 0x0d, 0xc6, 0xa7, 0xde, 0x6c, 0x1f, 0xe0,
7857901324dSJerome Forissier       0xea, 0x18, 0x33, 0xa8, 0x7e, 0x06, 0x20, 0xe9 };
7867901324dSJerome Forissier 
7877901324dSJerome Forissier static const unsigned char pers_nopr[] =
7887901324dSJerome Forissier     { 0x88, 0xee, 0xb8, 0xe0, 0xe8, 0x3b, 0xf3, 0x29,
7897901324dSJerome Forissier       0x4b, 0xda, 0xcd, 0x60, 0x99, 0xeb, 0xe4, 0xbf,
7907901324dSJerome Forissier       0x55, 0xec, 0xd9, 0x11, 0x3f, 0x71, 0xe5, 0xeb,
7917901324dSJerome Forissier       0xcb, 0x45, 0x75, 0xf3, 0xd6, 0xa6, 0x8a, 0x6b };
7927901324dSJerome Forissier 
7937901324dSJerome Forissier static const unsigned char result_pr[] =
7947901324dSJerome Forissier     { 0xce, 0x2f, 0xdb, 0xb6, 0xd9, 0xb7, 0x39, 0x85,
7957901324dSJerome Forissier       0x04, 0xc5, 0xc0, 0x42, 0xc2, 0x31, 0xc6, 0x1d,
7967901324dSJerome Forissier       0x9b, 0x5a, 0x59, 0xf8, 0x7e, 0x0d, 0xcc, 0x62,
7977901324dSJerome Forissier       0x7b, 0x65, 0x11, 0x55, 0x10, 0xeb, 0x9e, 0x3d,
7987901324dSJerome Forissier       0xa4, 0xfb, 0x1c, 0x6a, 0x18, 0xc0, 0x74, 0xdb,
7997901324dSJerome Forissier       0xdd, 0xe7, 0x02, 0x23, 0x63, 0x21, 0xd0, 0x39,
8007901324dSJerome Forissier       0xf9, 0xa7, 0xc4, 0x52, 0x84, 0x3b, 0x49, 0x40,
8017901324dSJerome Forissier       0x72, 0x2b, 0xb0, 0x6c, 0x9c, 0xdb, 0xc3, 0x43 };
8027901324dSJerome Forissier 
8037901324dSJerome Forissier static const unsigned char result_nopr[] =
8047901324dSJerome Forissier     { 0xa5, 0x51, 0x80, 0xa1, 0x90, 0xbe, 0xf3, 0xad,
8057901324dSJerome Forissier       0xaf, 0x28, 0xf6, 0xb7, 0x95, 0xe9, 0xf1, 0xf3,
8067901324dSJerome Forissier       0xd6, 0xdf, 0xa1, 0xb2, 0x7d, 0xd0, 0x46, 0x7b,
8077901324dSJerome Forissier       0x0c, 0x75, 0xf5, 0xfa, 0x93, 0x1e, 0x97, 0x14,
8087901324dSJerome Forissier       0x75, 0xb2, 0x7c, 0xae, 0x03, 0xa2, 0x96, 0x54,
8097901324dSJerome Forissier       0xe2, 0xf4, 0x09, 0x66, 0xea, 0x33, 0x64, 0x30,
8107901324dSJerome Forissier       0x40, 0xd1, 0x40, 0x0f, 0xe6, 0x77, 0x87, 0x3a,
8117901324dSJerome Forissier       0xf8, 0x09, 0x7c, 0x1f, 0xe9, 0xf0, 0x02, 0x98 };
81211fa71b9SJerome Forissier #endif /* MBEDTLS_CTR_DRBG_USE_128_BIT_KEY */
813817466cbSJens Wiklander 
814817466cbSJens Wiklander static size_t test_offset;
815817466cbSJens Wiklander static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf,
816817466cbSJens Wiklander                                        size_t len )
817817466cbSJens Wiklander {
818817466cbSJens Wiklander     const unsigned char *p = data;
819817466cbSJens Wiklander     memcpy( buf, p + test_offset, len );
820817466cbSJens Wiklander     test_offset += len;
821817466cbSJens Wiklander     return( 0 );
822817466cbSJens Wiklander }
823817466cbSJens Wiklander 
824817466cbSJens Wiklander #define CHK( c )    if( (c) != 0 )                          \
825817466cbSJens Wiklander                     {                                       \
826817466cbSJens Wiklander                         if( verbose != 0 )                  \
827817466cbSJens Wiklander                             mbedtls_printf( "failed\n" );  \
828817466cbSJens Wiklander                         return( 1 );                        \
829817466cbSJens Wiklander                     }
830817466cbSJens Wiklander 
831*039e02dfSJerome Forissier #define SELF_TEST_OUTPUT_DISCARD_LENGTH 64
8327901324dSJerome Forissier 
833817466cbSJens Wiklander /*
834817466cbSJens Wiklander  * Checkup routine
835817466cbSJens Wiklander  */
836817466cbSJens Wiklander int mbedtls_ctr_drbg_self_test( int verbose )
837817466cbSJens Wiklander {
838817466cbSJens Wiklander     mbedtls_ctr_drbg_context ctx;
8397901324dSJerome Forissier     unsigned char buf[ sizeof( result_pr ) ];
840817466cbSJens Wiklander 
841817466cbSJens Wiklander     mbedtls_ctr_drbg_init( &ctx );
842817466cbSJens Wiklander 
843817466cbSJens Wiklander     /*
844817466cbSJens Wiklander      * Based on a NIST CTR_DRBG test vector (PR = True)
845817466cbSJens Wiklander      */
846817466cbSJens Wiklander     if( verbose != 0 )
847817466cbSJens Wiklander         mbedtls_printf( "  CTR_DRBG (PR = TRUE) : " );
848817466cbSJens Wiklander 
849817466cbSJens Wiklander     test_offset = 0;
8507901324dSJerome Forissier     mbedtls_ctr_drbg_set_entropy_len( &ctx, MBEDTLS_CTR_DRBG_KEYSIZE );
8517901324dSJerome Forissier     mbedtls_ctr_drbg_set_nonce_len( &ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2 );
8525b25c76aSJerome Forissier     CHK( mbedtls_ctr_drbg_seed( &ctx,
8535b25c76aSJerome Forissier                                 ctr_drbg_self_test_entropy,
8545b25c76aSJerome Forissier                                 (void *) entropy_source_pr,
8557901324dSJerome Forissier                                 pers_pr, MBEDTLS_CTR_DRBG_KEYSIZE ) );
856817466cbSJens Wiklander     mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON );
857*039e02dfSJerome Forissier     CHK( mbedtls_ctr_drbg_random( &ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH ) );
8587901324dSJerome Forissier     CHK( mbedtls_ctr_drbg_random( &ctx, buf, sizeof( result_pr ) ) );
8597901324dSJerome Forissier     CHK( memcmp( buf, result_pr, sizeof( result_pr ) ) );
860817466cbSJens Wiklander 
861817466cbSJens Wiklander     mbedtls_ctr_drbg_free( &ctx );
862817466cbSJens Wiklander 
863817466cbSJens Wiklander     if( verbose != 0 )
864817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
865817466cbSJens Wiklander 
866817466cbSJens Wiklander     /*
867817466cbSJens Wiklander      * Based on a NIST CTR_DRBG test vector (PR = FALSE)
868817466cbSJens Wiklander      */
869817466cbSJens Wiklander     if( verbose != 0 )
870817466cbSJens Wiklander         mbedtls_printf( "  CTR_DRBG (PR = FALSE): " );
871817466cbSJens Wiklander 
872817466cbSJens Wiklander     mbedtls_ctr_drbg_init( &ctx );
873817466cbSJens Wiklander 
874817466cbSJens Wiklander     test_offset = 0;
8757901324dSJerome Forissier     mbedtls_ctr_drbg_set_entropy_len( &ctx, MBEDTLS_CTR_DRBG_KEYSIZE);
8767901324dSJerome Forissier     mbedtls_ctr_drbg_set_nonce_len( &ctx, MBEDTLS_CTR_DRBG_KEYSIZE / 2 );
8775b25c76aSJerome Forissier     CHK( mbedtls_ctr_drbg_seed( &ctx,
8785b25c76aSJerome Forissier                                 ctr_drbg_self_test_entropy,
8795b25c76aSJerome Forissier                                 (void *) entropy_source_nopr,
8807901324dSJerome Forissier                                 pers_nopr, MBEDTLS_CTR_DRBG_KEYSIZE ) );
881817466cbSJens Wiklander     CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) );
882*039e02dfSJerome Forissier     CHK( mbedtls_ctr_drbg_random( &ctx, buf, SELF_TEST_OUTPUT_DISCARD_LENGTH ) );
8837901324dSJerome Forissier     CHK( mbedtls_ctr_drbg_random( &ctx, buf, sizeof( result_nopr ) ) );
8847901324dSJerome Forissier     CHK( memcmp( buf, result_nopr, sizeof( result_nopr ) ) );
885817466cbSJens Wiklander 
886817466cbSJens Wiklander     mbedtls_ctr_drbg_free( &ctx );
887817466cbSJens Wiklander 
888817466cbSJens Wiklander     if( verbose != 0 )
889817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
890817466cbSJens Wiklander 
891817466cbSJens Wiklander     if( verbose != 0 )
892817466cbSJens Wiklander             mbedtls_printf( "\n" );
893817466cbSJens Wiklander 
894817466cbSJens Wiklander     return( 0 );
895817466cbSJens Wiklander }
896817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
897817466cbSJens Wiklander 
898817466cbSJens Wiklander #endif /* MBEDTLS_CTR_DRBG_C */
899