Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ctr_drbg.c Source File

ctr_drbg.c

00001 /*
00002  *  CTR_DRBG implementation based on AES-256 (NIST SP 800-90)
00003  *
00004  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
00005  *  SPDX-License-Identifier: Apache-2.0
00006  *
00007  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
00008  *  not use this file except in compliance with the License.
00009  *  You may obtain a copy of the License at
00010  *
00011  *  http://www.apache.org/licenses/LICENSE-2.0
00012  *
00013  *  Unless required by applicable law or agreed to in writing, software
00014  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
00015  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00016  *  See the License for the specific language governing permissions and
00017  *  limitations under the License.
00018  *
00019  *  This file is part of mbed TLS (https://tls.mbed.org)
00020  */
00021 /*
00022  *  The NIST SP 800-90 DRBGs are described in the following publication.
00023  *
00024  *  http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
00025  */
00026 
00027 #if !defined(MBEDTLS_CONFIG_FILE)
00028 #include "mbedtls/config.h"
00029 #else
00030 #include MBEDTLS_CONFIG_FILE
00031 #endif
00032 
00033 #if defined(MBEDTLS_CTR_DRBG_C)
00034 
00035 #include "mbedtls/ctr_drbg.h"
00036 #include "mbedtls/platform_util.h"
00037 
00038 #include <string.h>
00039 
00040 #if defined(MBEDTLS_FS_IO)
00041 #include <stdio.h>
00042 #endif
00043 
00044 #if defined(MBEDTLS_SELF_TEST)
00045 #if defined(MBEDTLS_PLATFORM_C)
00046 #include "mbedtls/platform.h"
00047 #else
00048 #include <stdio.h>
00049 #define mbedtls_printf printf
00050 #endif /* MBEDTLS_PLATFORM_C */
00051 #endif /* MBEDTLS_SELF_TEST */
00052 
00053 /*
00054  * CTR_DRBG context initialization
00055  */
00056 void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx )
00057 {
00058     memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) );
00059 
00060 #if defined(MBEDTLS_THREADING_C)
00061     mbedtls_mutex_init( &ctx->mutex );
00062 #endif
00063 }
00064 
00065 /*
00066  * Non-public function wrapped by mbedtls_ctr_drbg_seed(). Necessary to allow
00067  * NIST tests to succeed (which require known length fixed entropy)
00068  */
00069 /* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
00070  * mbedtls_ctr_drbg_seed_entropy_len(ctx, f_entropy, p_entropy,
00071  *                                   custom, len, entropy_len)
00072  * implements
00073  * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
00074  *                      security_strength) -> initial_working_state
00075  * with inputs
00076  *   custom[:len] = nonce || personalization_string
00077  * where entropy_input comes from f_entropy for entropy_len bytes
00078  * and with outputs
00079  *   ctx = initial_working_state
00080  */
00081 int mbedtls_ctr_drbg_seed_entropy_len(
00082                    mbedtls_ctr_drbg_context *ctx,
00083                    int (*f_entropy)(void *, unsigned char *, size_t),
00084                    void *p_entropy,
00085                    const unsigned char *custom,
00086                    size_t len,
00087                    size_t entropy_len )
00088 {
00089     int ret;
00090     unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
00091 
00092     memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE );
00093 
00094     mbedtls_aes_init( &ctx->aes_ctx  );
00095 
00096     ctx->f_entropy  = f_entropy;
00097     ctx->p_entropy  = p_entropy;
00098 
00099     ctx->entropy_len  = entropy_len;
00100     ctx->reseed_interval  = MBEDTLS_CTR_DRBG_RESEED_INTERVAL;
00101 
00102     /*
00103      * Initialize with an empty key
00104      */
00105     if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx , key,
00106                                         MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
00107     {
00108         return( ret );
00109     }
00110 
00111     if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 )
00112     {
00113         return( ret );
00114     }
00115     return( 0 );
00116 }
00117 
00118 int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx,
00119                    int (*f_entropy)(void *, unsigned char *, size_t),
00120                    void *p_entropy,
00121                    const unsigned char *custom,
00122                    size_t len )
00123 {
00124     return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy,
00125                                                custom, len,
00126                                                MBEDTLS_CTR_DRBG_ENTROPY_LEN ) );
00127 }
00128 
00129 void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx )
00130 {
00131     if( ctx == NULL )
00132         return;
00133 
00134 #if defined(MBEDTLS_THREADING_C)
00135     mbedtls_mutex_free( &ctx->mutex );
00136 #endif
00137     mbedtls_aes_free( &ctx->aes_ctx  );
00138     mbedtls_platform_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) );
00139 }
00140 
00141 void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx,
00142                                                  int resistance )
00143 {
00144     ctx->prediction_resistance  = resistance;
00145 }
00146 
00147 void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx,
00148                                        size_t len )
00149 {
00150     ctx->entropy_len  = len;
00151 }
00152 
00153 void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx,
00154                                            int interval )
00155 {
00156     ctx->reseed_interval  = interval;
00157 }
00158 
00159 static int block_cipher_df( unsigned char *output,
00160                             const unsigned char *data, size_t data_len )
00161 {
00162     unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
00163                       MBEDTLS_CTR_DRBG_BLOCKSIZE + 16];
00164     unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
00165     unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE];
00166     unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE];
00167     unsigned char *p, *iv;
00168     mbedtls_aes_context aes_ctx;
00169     int ret = 0;
00170 
00171     int i, j;
00172     size_t buf_len, use_len;
00173 
00174     if( data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
00175         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
00176 
00177     memset( buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +
00178             MBEDTLS_CTR_DRBG_BLOCKSIZE + 16 );
00179     mbedtls_aes_init( &aes_ctx );
00180 
00181     /*
00182      * Construct IV (16 bytes) and S in buffer
00183      * IV = Counter (in 32-bits) padded to 16 with zeroes
00184      * S = Length input string (in 32-bits) || Length of output (in 32-bits) ||
00185      *     data || 0x80
00186      *     (Total is padded to a multiple of 16-bytes with zeroes)
00187      */
00188     p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE;
00189     *p++ = ( data_len >> 24 ) & 0xff;
00190     *p++ = ( data_len >> 16 ) & 0xff;
00191     *p++ = ( data_len >> 8  ) & 0xff;
00192     *p++ = ( data_len       ) & 0xff;
00193     p += 3;
00194     *p++ = MBEDTLS_CTR_DRBG_SEEDLEN;
00195     memcpy( p, data, data_len );
00196     p[data_len] = 0x80;
00197 
00198     buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1;
00199 
00200     for( i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++ )
00201         key[i] = i;
00202 
00203     if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, key,
00204                                         MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
00205     {
00206         goto exit;
00207     }
00208 
00209     /*
00210      * Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data
00211      */
00212     for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
00213     {
00214         p = buf;
00215         memset( chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE );
00216         use_len = buf_len;
00217 
00218         while( use_len > 0 )
00219         {
00220             for( i = 0; i < MBEDTLS_CTR_DRBG_BLOCKSIZE; i++ )
00221                 chain[i] ^= p[i];
00222             p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
00223             use_len -= ( use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE ) ?
00224                        MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len;
00225 
00226             if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT,
00227                                                chain, chain ) ) != 0 )
00228             {
00229                 goto exit;
00230             }
00231         }
00232 
00233         memcpy( tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE );
00234 
00235         /*
00236          * Update IV
00237          */
00238         buf[3]++;
00239     }
00240 
00241     /*
00242      * Do final encryption with reduced data
00243      */
00244     if( ( ret = mbedtls_aes_setkey_enc( &aes_ctx, tmp,
00245                                         MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
00246     {
00247         goto exit;
00248     }
00249     iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE;
00250     p = output;
00251 
00252     for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
00253     {
00254         if( ( ret = mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT,
00255                                            iv, iv ) ) != 0 )
00256         {
00257             goto exit;
00258         }
00259         memcpy( p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE );
00260         p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
00261     }
00262 exit:
00263     mbedtls_aes_free( &aes_ctx );
00264     /*
00265     * tidy up the stack
00266     */
00267     mbedtls_platform_zeroize( buf, sizeof( buf ) );
00268     mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
00269     mbedtls_platform_zeroize( key, sizeof( key ) );
00270     mbedtls_platform_zeroize( chain, sizeof( chain ) );
00271     if( 0 != ret )
00272     {
00273         /*
00274         * wipe partial seed from memory
00275         */
00276         mbedtls_platform_zeroize( output, MBEDTLS_CTR_DRBG_SEEDLEN );
00277     }
00278 
00279     return( ret );
00280 }
00281 
00282 /* CTR_DRBG_Update (SP 800-90A &sect;10.2.1.2)
00283  * ctr_drbg_update_internal(ctx, provided_data)
00284  * implements
00285  * CTR_DRBG_Update(provided_data, Key, V)
00286  * with inputs and outputs
00287  *   ctx->aes_ctx = Key
00288  *   ctx->counter = V
00289  */
00290 static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx,
00291                           const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] )
00292 {
00293     unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN];
00294     unsigned char *p = tmp;
00295     int i, j;
00296     int ret = 0;
00297 
00298     memset( tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN );
00299 
00300     for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE )
00301     {
00302         /*
00303          * Increase counter
00304          */
00305         for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- )
00306             if( ++ctx->counter [i - 1] != 0 )
00307                 break;
00308 
00309         /*
00310          * Crypt counter block
00311          */
00312         if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx , MBEDTLS_AES_ENCRYPT,
00313                                            ctx->counter , p ) ) != 0 )
00314         {
00315             goto exit;
00316         }
00317 
00318         p += MBEDTLS_CTR_DRBG_BLOCKSIZE;
00319     }
00320 
00321     for( i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++ )
00322         tmp[i] ^= data[i];
00323 
00324     /*
00325      * Update key and counter
00326      */
00327     if( ( ret = mbedtls_aes_setkey_enc( &ctx->aes_ctx , tmp,
00328                                         MBEDTLS_CTR_DRBG_KEYBITS ) ) != 0 )
00329     {
00330         goto exit;
00331     }
00332     memcpy( ctx->counter , tmp + MBEDTLS_CTR_DRBG_KEYSIZE,
00333             MBEDTLS_CTR_DRBG_BLOCKSIZE );
00334 
00335 exit:
00336     mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
00337     return( ret );
00338 }
00339 
00340 /* CTR_DRBG_Instantiate with derivation function (SP 800-90A &sect;10.2.1.3.2)
00341  * mbedtls_ctr_drbg_update(ctx, additional, add_len)
00342  * implements
00343  * CTR_DRBG_Instantiate(entropy_input, nonce, personalization_string,
00344  *                      security_strength) -> initial_working_state
00345  * with inputs
00346  *   ctx->counter = all-bits-0
00347  *   ctx->aes_ctx = context from all-bits-0 key
00348  *   additional[:add_len] = entropy_input || nonce || personalization_string
00349  * and with outputs
00350  *   ctx = initial_working_state
00351  */
00352 int mbedtls_ctr_drbg_update_ret( mbedtls_ctr_drbg_context *ctx,
00353                                  const unsigned char *additional,
00354                                  size_t add_len )
00355 {
00356     unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
00357     int ret;
00358 
00359     if( add_len == 0 )
00360         return( 0 );
00361 
00362     if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 )
00363         goto exit;
00364     if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
00365         goto exit;
00366 
00367 exit:
00368     mbedtls_platform_zeroize( add_input, sizeof( add_input ) );
00369     return( ret );
00370 }
00371 
00372 #if !defined(MBEDTLS_DEPRECATED_REMOVED)
00373 void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx,
00374                               const unsigned char *additional,
00375                               size_t add_len )
00376 {
00377     /* MAX_INPUT would be more logical here, but we have to match
00378      * block_cipher_df()'s limits since we can't propagate errors */
00379     if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT )
00380         add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT;
00381     (void) mbedtls_ctr_drbg_update_ret( ctx, additional, add_len );
00382 }
00383 #endif /* MBEDTLS_DEPRECATED_REMOVED */
00384 
00385 /* CTR_DRBG_Reseed with derivation function (SP 800-90A &sect;10.2.1.4.2)
00386  * mbedtls_ctr_drbg_reseed(ctx, additional, len)
00387  * implements
00388  * CTR_DRBG_Reseed(working_state, entropy_input, additional_input)
00389  *                -> new_working_state
00390  * with inputs
00391  *   ctx contains working_state
00392  *   additional[:len] = additional_input
00393  * and entropy_input comes from calling ctx->f_entropy
00394  * and with output
00395  *   ctx contains new_working_state
00396  */
00397 int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx,
00398                      const unsigned char *additional, size_t len )
00399 {
00400     unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT];
00401     size_t seedlen = 0;
00402     int ret;
00403 
00404     if( ctx->entropy_len  > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ||
00405         len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len  )
00406         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
00407 
00408     memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT );
00409 
00410     /*
00411      * Gather entropy_len bytes of entropy to seed state
00412      */
00413     if( 0 != ctx->f_entropy ( ctx->p_entropy , seed,
00414                              ctx->entropy_len  ) )
00415     {
00416         return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
00417     }
00418 
00419     seedlen += ctx->entropy_len ;
00420 
00421     /*
00422      * Add additional data
00423      */
00424     if( additional && len )
00425     {
00426         memcpy( seed + seedlen, additional, len );
00427         seedlen += len;
00428     }
00429 
00430     /*
00431      * Reduce to 384 bits
00432      */
00433     if( ( ret = block_cipher_df( seed, seed, seedlen ) ) != 0 )
00434         goto exit;
00435 
00436     /*
00437      * Update state
00438      */
00439     if( ( ret = ctr_drbg_update_internal( ctx, seed ) ) != 0 )
00440         goto exit;
00441     ctx->reseed_counter  = 1;
00442 
00443 exit:
00444     mbedtls_platform_zeroize( seed, sizeof( seed ) );
00445     return( ret );
00446 }
00447 
00448 /* CTR_DRBG_Generate with derivation function (SP 800-90A &sect;10.2.1.5.2)
00449  * mbedtls_ctr_drbg_random_with_add(ctx, output, output_len, additional, add_len)
00450  * implements
00451  * CTR_DRBG_Reseed(working_state, entropy_input, additional[:add_len])
00452  *                -> working_state_after_reseed
00453  *                if required, then
00454  * CTR_DRBG_Generate(working_state_after_reseed,
00455  *                   requested_number_of_bits, additional_input)
00456  *                -> status, returned_bits, new_working_state
00457  * with inputs
00458  *   ctx contains working_state
00459  *   requested_number_of_bits = 8 * output_len
00460  *   additional[:add_len] = additional_input
00461  * and entropy_input comes from calling ctx->f_entropy
00462  * and with outputs
00463  *   status = SUCCESS (this function does the reseed internally)
00464  *   returned_bits = output[:output_len]
00465  *   ctx contains new_working_state
00466  */
00467 int mbedtls_ctr_drbg_random_with_add( void *p_rng,
00468                               unsigned char *output, size_t output_len,
00469                               const unsigned char *additional, size_t add_len )
00470 {
00471     int ret = 0;
00472     mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
00473     unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN];
00474     unsigned char *p = output;
00475     unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE];
00476     int i;
00477     size_t use_len;
00478 
00479     if( output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST )
00480         return( MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG );
00481 
00482     if( add_len > MBEDTLS_CTR_DRBG_MAX_INPUT )
00483         return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG );
00484 
00485     memset( add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN );
00486 
00487     if( ctx->reseed_counter  > ctx->reseed_interval  ||
00488         ctx->prediction_resistance  )
00489     {
00490         if( ( ret = mbedtls_ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 )
00491         {
00492             return( ret );
00493         }
00494         add_len = 0;
00495     }
00496 
00497     if( add_len > 0 )
00498     {
00499         if( ( ret = block_cipher_df( add_input, additional, add_len ) ) != 0 )
00500             goto exit;
00501         if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
00502             goto exit;
00503     }
00504 
00505     while( output_len > 0 )
00506     {
00507         /*
00508          * Increase counter
00509          */
00510         for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- )
00511             if( ++ctx->counter [i - 1] != 0 )
00512                 break;
00513 
00514         /*
00515          * Crypt counter block
00516          */
00517         if( ( ret = mbedtls_aes_crypt_ecb( &ctx->aes_ctx , MBEDTLS_AES_ENCRYPT,
00518                                            ctx->counter , tmp ) ) != 0 )
00519         {
00520             goto exit;
00521         }
00522 
00523         use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE )
00524             ? MBEDTLS_CTR_DRBG_BLOCKSIZE : output_len;
00525         /*
00526          * Copy random block to destination
00527          */
00528         memcpy( p, tmp, use_len );
00529         p += use_len;
00530         output_len -= use_len;
00531     }
00532 
00533     if( ( ret = ctr_drbg_update_internal( ctx, add_input ) ) != 0 )
00534         goto exit;
00535 
00536     ctx->reseed_counter ++;
00537 
00538 exit:
00539     mbedtls_platform_zeroize( add_input, sizeof( add_input ) );
00540     mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
00541     return( 0 );
00542 }
00543 
00544 int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output,
00545                              size_t output_len )
00546 {
00547     int ret;
00548     mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng;
00549 
00550 #if defined(MBEDTLS_THREADING_C)
00551     if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
00552         return( ret );
00553 #endif
00554 
00555     ret = mbedtls_ctr_drbg_random_with_add( ctx, output, output_len, NULL, 0 );
00556 
00557 #if defined(MBEDTLS_THREADING_C)
00558     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
00559         return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
00560 #endif
00561 
00562     return( ret );
00563 }
00564 
00565 #if defined(MBEDTLS_FS_IO)
00566 int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx,
00567                                       const char *path )
00568 {
00569     int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
00570     FILE *f;
00571     unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ];
00572 
00573     if( ( f = fopen( path, "wb" ) ) == NULL )
00574         return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR );
00575 
00576     if( ( ret = mbedtls_ctr_drbg_random( ctx, buf,
00577                                          MBEDTLS_CTR_DRBG_MAX_INPUT ) ) != 0 )
00578         goto exit;
00579 
00580     if( fwrite( buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f ) !=
00581         MBEDTLS_CTR_DRBG_MAX_INPUT )
00582     {
00583         ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
00584     }
00585     else
00586     {
00587         ret = 0;
00588     }
00589 
00590 exit:
00591     mbedtls_platform_zeroize( buf, sizeof( buf ) );
00592 
00593     fclose( f );
00594     return( ret );
00595 }
00596 
00597 int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx,
00598                                        const char *path )
00599 {
00600     int ret = 0;
00601     FILE *f = NULL;
00602     size_t n;
00603     unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ];
00604     unsigned char c;
00605 
00606     if( ( f = fopen( path, "rb" ) ) == NULL )
00607         return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR );
00608 
00609     n = fread( buf, 1, sizeof( buf ), f );
00610     if( fread( &c, 1, 1, f ) != 0 )
00611     {
00612         ret = MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG;
00613         goto exit;
00614     }
00615     if( n == 0 || ferror( f ) )
00616     {
00617         ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR;
00618         goto exit;
00619     }
00620     fclose( f );
00621     f = NULL;
00622 
00623     ret = mbedtls_ctr_drbg_update_ret( ctx, buf, n );
00624 
00625 exit:
00626     mbedtls_platform_zeroize( buf, sizeof( buf ) );
00627     if( f != NULL )
00628         fclose( f );
00629     if( ret != 0 )
00630         return( ret );
00631     return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) );
00632 }
00633 #endif /* MBEDTLS_FS_IO */
00634 
00635 #if defined(MBEDTLS_SELF_TEST)
00636 
00637 static const unsigned char entropy_source_pr[96] =
00638     { 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16,
00639       0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02,
00640       0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b,
00641       0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb,
00642       0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9,
00643       0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95,
00644       0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63,
00645       0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3,
00646       0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31,
00647       0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4,
00648       0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56,
00649       0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 };
00650 
00651 static const unsigned char entropy_source_nopr[64] =
00652     { 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14,
00653       0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe,
00654       0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d,
00655       0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20,
00656       0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9,
00657       0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46,
00658       0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e,
00659       0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e };
00660 
00661 static const unsigned char nonce_pers_pr[16] =
00662     { 0xd2, 0x54, 0xfc, 0xff, 0x02, 0x1e, 0x69, 0xd2,
00663       0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c };
00664 
00665 static const unsigned char nonce_pers_nopr[16] =
00666     { 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5,
00667       0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f };
00668 
00669 static const unsigned char result_pr[16] =
00670     { 0x34, 0x01, 0x16, 0x56, 0xb4, 0x29, 0x00, 0x8f,
00671       0x35, 0x63, 0xec, 0xb5, 0xf2, 0x59, 0x07, 0x23 };
00672 
00673 static const unsigned char result_nopr[16] =
00674     { 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88,
00675       0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f };
00676 
00677 static size_t test_offset;
00678 static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf,
00679                                        size_t len )
00680 {
00681     const unsigned char *p = data;
00682     memcpy( buf, p + test_offset, len );
00683     test_offset += len;
00684     return( 0 );
00685 }
00686 
00687 #define CHK( c )    if( (c) != 0 )                          \
00688                     {                                       \
00689                         if( verbose != 0 )                  \
00690                             mbedtls_printf( "failed\n" );  \
00691                         return( 1 );                        \
00692                     }
00693 
00694 /*
00695  * Checkup routine
00696  */
00697 int mbedtls_ctr_drbg_self_test( int verbose )
00698 {
00699     mbedtls_ctr_drbg_context ctx;
00700     unsigned char buf[16];
00701 
00702     mbedtls_ctr_drbg_init( &ctx );
00703 
00704     /*
00705      * Based on a NIST CTR_DRBG test vector (PR = True)
00706      */
00707     if( verbose != 0 )
00708         mbedtls_printf( "  CTR_DRBG (PR = TRUE) : " );
00709 
00710     test_offset = 0;
00711     CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
00712                          (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) );
00713     mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON );
00714     CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
00715     CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
00716     CHK( memcmp( buf, result_pr, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
00717 
00718     mbedtls_ctr_drbg_free( &ctx );
00719 
00720     if( verbose != 0 )
00721         mbedtls_printf( "passed\n" );
00722 
00723     /*
00724      * Based on a NIST CTR_DRBG test vector (PR = FALSE)
00725      */
00726     if( verbose != 0 )
00727         mbedtls_printf( "  CTR_DRBG (PR = FALSE): " );
00728 
00729     mbedtls_ctr_drbg_init( &ctx );
00730 
00731     test_offset = 0;
00732     CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy,
00733                      (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) );
00734     CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
00735     CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) );
00736     CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) );
00737     CHK( memcmp( buf, result_nopr, 16 ) );
00738 
00739     mbedtls_ctr_drbg_free( &ctx );
00740 
00741     if( verbose != 0 )
00742         mbedtls_printf( "passed\n" );
00743 
00744     if( verbose != 0 )
00745             mbedtls_printf( "\n" );
00746 
00747     return( 0 );
00748 }
00749 #endif /* MBEDTLS_SELF_TEST */
00750 
00751 #endif /* MBEDTLS_CTR_DRBG_C */