Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbedtls by
entropy.c
00001 /* 00002 * Entropy accumulator implementation 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 #if !defined(MBEDTLS_CONFIG_FILE) 00023 #include "mbedtls/config.h" 00024 #else 00025 #include MBEDTLS_CONFIG_FILE 00026 #endif 00027 00028 #if defined(MBEDTLS_ENTROPY_C) 00029 00030 #include "mbedtls/entropy.h" 00031 #include "mbedtls/entropy_poll.h" 00032 00033 #include <string.h> 00034 00035 #if defined(MBEDTLS_FS_IO) 00036 #include <stdio.h> 00037 #endif 00038 00039 #if defined(MBEDTLS_SELF_TEST) 00040 #if defined(MBEDTLS_PLATFORM_C) 00041 #include "mbedtls/platform.h" 00042 #else 00043 #include <stdio.h> 00044 #define mbedtls_printf printf 00045 #endif /* MBEDTLS_PLATFORM_C */ 00046 #endif /* MBEDTLS_SELF_TEST */ 00047 00048 #if defined(MBEDTLS_HAVEGE_C) 00049 #include "mbedtls/havege.h" 00050 #endif 00051 00052 /* Implementation that should never be optimized out by the compiler */ 00053 static void mbedtls_zeroize( void *v, size_t n ) { 00054 volatile unsigned char *p = v; while( n-- ) *p++ = 0; 00055 } 00056 00057 #define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ 00058 00059 void mbedtls_entropy_init( mbedtls_entropy_context *ctx ) 00060 { 00061 memset( ctx, 0, sizeof(mbedtls_entropy_context) ); 00062 00063 #if defined(MBEDTLS_THREADING_C) 00064 mbedtls_mutex_init( &ctx->mutex ); 00065 #endif 00066 00067 #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) 00068 mbedtls_sha512_starts( &ctx->accumulator, 0 ); 00069 #else 00070 mbedtls_sha256_starts( &ctx->accumulator, 0 ); 00071 #endif 00072 #if defined(MBEDTLS_HAVEGE_C) 00073 mbedtls_havege_init( &ctx->havege_data ); 00074 #endif 00075 00076 #if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) 00077 #if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) 00078 mbedtls_entropy_add_source( ctx, mbedtls_platform_entropy_poll, NULL, 00079 MBEDTLS_ENTROPY_MIN_PLATFORM, 00080 MBEDTLS_ENTROPY_SOURCE_STRONG ); 00081 #endif 00082 #if defined(MBEDTLS_TIMING_C) 00083 mbedtls_entropy_add_source( ctx, mbedtls_hardclock_poll, NULL, 00084 MBEDTLS_ENTROPY_MIN_HARDCLOCK, 00085 MBEDTLS_ENTROPY_SOURCE_WEAK ); 00086 #endif 00087 #if defined(MBEDTLS_HAVEGE_C) 00088 mbedtls_entropy_add_source( ctx, mbedtls_havege_poll, &ctx->havege_data, 00089 MBEDTLS_ENTROPY_MIN_HAVEGE, 00090 MBEDTLS_ENTROPY_SOURCE_STRONG ); 00091 #endif 00092 #if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) 00093 mbedtls_entropy_add_source( ctx, mbedtls_hardware_poll, NULL, 00094 MBEDTLS_ENTROPY_MIN_HARDWARE, 00095 MBEDTLS_ENTROPY_SOURCE_STRONG ); 00096 #endif 00097 #endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */ 00098 } 00099 00100 void mbedtls_entropy_free( mbedtls_entropy_context *ctx ) 00101 { 00102 #if defined(MBEDTLS_HAVEGE_C) 00103 mbedtls_havege_free( &ctx->havege_data ); 00104 #endif 00105 #if defined(MBEDTLS_THREADING_C) 00106 mbedtls_mutex_free( &ctx->mutex ); 00107 #endif 00108 mbedtls_zeroize( ctx, sizeof( mbedtls_entropy_context ) ); 00109 } 00110 00111 int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx, 00112 mbedtls_entropy_f_source_ptr f_source, void *p_source, 00113 size_t threshold, int strong ) 00114 { 00115 int index, ret = 0; 00116 00117 #if defined(MBEDTLS_THREADING_C) 00118 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) 00119 return( ret ); 00120 #endif 00121 00122 index = ctx->source_count; 00123 if( index >= MBEDTLS_ENTROPY_MAX_SOURCES ) 00124 { 00125 ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES; 00126 goto exit; 00127 } 00128 00129 ctx->source[index].f_source = f_source; 00130 ctx->source[index].p_source = p_source; 00131 ctx->source[index].threshold = threshold; 00132 ctx->source[index].strong = strong; 00133 00134 ctx->source_count++; 00135 00136 exit: 00137 #if defined(MBEDTLS_THREADING_C) 00138 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) 00139 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); 00140 #endif 00141 00142 return( ret ); 00143 } 00144 00145 /* 00146 * Entropy accumulator update 00147 */ 00148 static int entropy_update( mbedtls_entropy_context *ctx, unsigned char source_id, 00149 const unsigned char *data, size_t len ) 00150 { 00151 unsigned char header[2]; 00152 unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE]; 00153 size_t use_len = len; 00154 const unsigned char *p = data; 00155 00156 if( use_len > MBEDTLS_ENTROPY_BLOCK_SIZE ) 00157 { 00158 #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) 00159 mbedtls_sha512( data, len, tmp, 0 ); 00160 #else 00161 mbedtls_sha256( data, len, tmp, 0 ); 00162 #endif 00163 p = tmp; 00164 use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; 00165 } 00166 00167 header[0] = source_id; 00168 header[1] = use_len & 0xFF; 00169 00170 #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) 00171 mbedtls_sha512_update( &ctx->accumulator, header, 2 ); 00172 mbedtls_sha512_update( &ctx->accumulator, p, use_len ); 00173 #else 00174 mbedtls_sha256_update( &ctx->accumulator, header, 2 ); 00175 mbedtls_sha256_update( &ctx->accumulator, p, use_len ); 00176 #endif 00177 00178 return( 0 ); 00179 } 00180 00181 int mbedtls_entropy_update_manual( mbedtls_entropy_context *ctx, 00182 const unsigned char *data, size_t len ) 00183 { 00184 int ret; 00185 00186 #if defined(MBEDTLS_THREADING_C) 00187 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) 00188 return( ret ); 00189 #endif 00190 00191 ret = entropy_update( ctx, MBEDTLS_ENTROPY_SOURCE_MANUAL, data, len ); 00192 00193 #if defined(MBEDTLS_THREADING_C) 00194 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) 00195 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); 00196 #endif 00197 00198 return( ret ); 00199 } 00200 00201 /* 00202 * Run through the different sources to add entropy to our accumulator 00203 */ 00204 static int entropy_gather_internal( mbedtls_entropy_context *ctx ) 00205 { 00206 int ret, i, have_one_strong = 0; 00207 unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER]; 00208 size_t olen; 00209 00210 if( ctx->source_count == 0 ) 00211 return( MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED ); 00212 00213 /* 00214 * Run through our entropy sources 00215 */ 00216 for( i = 0; i < ctx->source_count; i++ ) 00217 { 00218 if( ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG ) 00219 have_one_strong = 1; 00220 00221 olen = 0; 00222 if( ( ret = ctx->source[i].f_source( ctx->source[i].p_source, 00223 buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen ) ) != 0 ) 00224 { 00225 return( ret ); 00226 } 00227 00228 /* 00229 * Add if we actually gathered something 00230 */ 00231 if( olen > 0 ) 00232 { 00233 entropy_update( ctx, (unsigned char) i, buf, olen ); 00234 ctx->source[i].size += olen; 00235 } 00236 } 00237 00238 if( have_one_strong == 0 ) 00239 return( MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE ); 00240 00241 return( 0 ); 00242 } 00243 00244 /* 00245 * Thread-safe wrapper for entropy_gather_internal() 00246 */ 00247 int mbedtls_entropy_gather( mbedtls_entropy_context *ctx ) 00248 { 00249 int ret; 00250 00251 #if defined(MBEDTLS_THREADING_C) 00252 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) 00253 return( ret ); 00254 #endif 00255 00256 ret = entropy_gather_internal( ctx ); 00257 00258 #if defined(MBEDTLS_THREADING_C) 00259 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) 00260 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); 00261 #endif 00262 00263 return( ret ); 00264 } 00265 00266 int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ) 00267 { 00268 int ret, count = 0, i, done; 00269 mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data; 00270 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 00271 00272 if( len > MBEDTLS_ENTROPY_BLOCK_SIZE ) 00273 return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); 00274 00275 #if defined(MBEDTLS_THREADING_C) 00276 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) 00277 return( ret ); 00278 #endif 00279 00280 /* 00281 * Always gather extra entropy before a call 00282 */ 00283 do 00284 { 00285 if( count++ > ENTROPY_MAX_LOOP ) 00286 { 00287 ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; 00288 goto exit; 00289 } 00290 00291 if( ( ret = entropy_gather_internal( ctx ) ) != 0 ) 00292 goto exit; 00293 00294 done = 1; 00295 for( i = 0; i < ctx->source_count; i++ ) 00296 if( ctx->source[i].size < ctx->source[i].threshold ) 00297 done = 0; 00298 } 00299 while( ! done ); 00300 00301 memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); 00302 00303 #if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) 00304 mbedtls_sha512_finish( &ctx->accumulator, buf ); 00305 00306 /* 00307 * Reset accumulator and counters and recycle existing entropy 00308 */ 00309 memset( &ctx->accumulator, 0, sizeof( mbedtls_sha512_context ) ); 00310 mbedtls_sha512_starts( &ctx->accumulator, 0 ); 00311 mbedtls_sha512_update( &ctx->accumulator, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); 00312 00313 /* 00314 * Perform second SHA-512 on entropy 00315 */ 00316 mbedtls_sha512( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf, 0 ); 00317 #else /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */ 00318 mbedtls_sha256_finish( &ctx->accumulator, buf ); 00319 00320 /* 00321 * Reset accumulator and counters and recycle existing entropy 00322 */ 00323 memset( &ctx->accumulator, 0, sizeof( mbedtls_sha256_context ) ); 00324 mbedtls_sha256_starts( &ctx->accumulator, 0 ); 00325 mbedtls_sha256_update( &ctx->accumulator, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); 00326 00327 /* 00328 * Perform second SHA-256 on entropy 00329 */ 00330 mbedtls_sha256( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf, 0 ); 00331 #endif /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */ 00332 00333 for( i = 0; i < ctx->source_count; i++ ) 00334 ctx->source[i].size = 0; 00335 00336 memcpy( output, buf, len ); 00337 00338 ret = 0; 00339 00340 exit: 00341 #if defined(MBEDTLS_THREADING_C) 00342 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) 00343 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); 00344 #endif 00345 00346 return( ret ); 00347 } 00348 00349 #if defined(MBEDTLS_FS_IO) 00350 int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path ) 00351 { 00352 int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; 00353 FILE *f; 00354 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; 00355 00356 if( ( f = fopen( path, "wb" ) ) == NULL ) 00357 return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); 00358 00359 if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) 00360 goto exit; 00361 00362 if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != MBEDTLS_ENTROPY_BLOCK_SIZE ) 00363 { 00364 ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; 00365 goto exit; 00366 } 00367 00368 ret = 0; 00369 00370 exit: 00371 fclose( f ); 00372 return( ret ); 00373 } 00374 00375 int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path ) 00376 { 00377 FILE *f; 00378 size_t n; 00379 unsigned char buf[ MBEDTLS_ENTROPY_MAX_SEED_SIZE ]; 00380 00381 if( ( f = fopen( path, "rb" ) ) == NULL ) 00382 return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); 00383 00384 fseek( f, 0, SEEK_END ); 00385 n = (size_t) ftell( f ); 00386 fseek( f, 0, SEEK_SET ); 00387 00388 if( n > MBEDTLS_ENTROPY_MAX_SEED_SIZE ) 00389 n = MBEDTLS_ENTROPY_MAX_SEED_SIZE; 00390 00391 if( fread( buf, 1, n, f ) != n ) 00392 { 00393 fclose( f ); 00394 return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); 00395 } 00396 00397 fclose( f ); 00398 00399 mbedtls_entropy_update_manual( ctx, buf, n ); 00400 00401 return( mbedtls_entropy_write_seed_file( ctx, path ) ); 00402 } 00403 #endif /* MBEDTLS_FS_IO */ 00404 00405 #if defined(MBEDTLS_SELF_TEST) 00406 /* 00407 * Dummy source function 00408 */ 00409 static int entropy_dummy_source( void *data, unsigned char *output, 00410 size_t len, size_t *olen ) 00411 { 00412 ((void) data); 00413 00414 memset( output, 0x2a, len ); 00415 *olen = len; 00416 00417 return( 0 ); 00418 } 00419 00420 /* 00421 * The actual entropy quality is hard to test, but we can at least 00422 * test that the functions don't cause errors and write the correct 00423 * amount of data to buffers. 00424 */ 00425 int mbedtls_entropy_self_test( int verbose ) 00426 { 00427 int ret = 0; 00428 mbedtls_entropy_context ctx; 00429 unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; 00430 unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; 00431 size_t i, j; 00432 00433 if( verbose != 0 ) 00434 mbedtls_printf( " ENTROPY test: " ); 00435 00436 mbedtls_entropy_init( &ctx ); 00437 00438 /* First do a gather to make sure we have default sources */ 00439 if( ( ret = mbedtls_entropy_gather( &ctx ) ) != 0 ) 00440 goto cleanup; 00441 00442 ret = mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL, 16, 00443 MBEDTLS_ENTROPY_SOURCE_WEAK ); 00444 if( ret != 0 ) 00445 goto cleanup; 00446 00447 if( ( ret = mbedtls_entropy_update_manual( &ctx, buf, sizeof buf ) ) != 0 ) 00448 goto cleanup; 00449 00450 /* 00451 * To test that mbedtls_entropy_func writes correct number of bytes: 00452 * - use the whole buffer and rely on ASan to detect overruns 00453 * - collect entropy 8 times and OR the result in an accumulator: 00454 * any byte should then be 0 with probably 2^(-64), so requiring 00455 * each of the 32 or 64 bytes to be non-zero has a false failure rate 00456 * of at most 2^(-58) which is acceptable. 00457 */ 00458 for( i = 0; i < 8; i++ ) 00459 { 00460 if( ( ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ) ) != 0 ) 00461 goto cleanup; 00462 00463 for( j = 0; j < sizeof( buf ); j++ ) 00464 acc[j] |= buf[j]; 00465 } 00466 00467 for( j = 0; j < sizeof( buf ); j++ ) 00468 { 00469 if( acc[j] == 0 ) 00470 { 00471 ret = 1; 00472 goto cleanup; 00473 } 00474 } 00475 00476 cleanup: 00477 mbedtls_entropy_free( &ctx ); 00478 00479 if( verbose != 0 ) 00480 { 00481 if( ret != 0 ) 00482 mbedtls_printf( "failed\n" ); 00483 else 00484 mbedtls_printf( "passed\n" ); 00485 00486 mbedtls_printf( "\n" ); 00487 } 00488 00489 return( ret != 0 ); 00490 } 00491 #endif /* MBEDTLS_SELF_TEST */ 00492 00493 #endif /* MBEDTLS_ENTROPY_C */
Generated on Tue Jul 12 2022 12:52:43 by
