PolarSSL v1.3.9
entropy.c
Go to the documentation of this file.
1/*
2 * Entropy accumulator implementation
3 *
4 * Copyright (C) 2006-2014, Brainspark B.V.
5 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26#if !defined(POLARSSL_CONFIG_FILE)
27#include "polarssl/config.h"
28#else
29#include POLARSSL_CONFIG_FILE
30#endif
31
32#if defined(POLARSSL_ENTROPY_C)
33
34#include "polarssl/entropy.h"
36
37#if defined(POLARSSL_FS_IO)
38#include <stdio.h>
39#endif
40
41#if defined(POLARSSL_HAVEGE_C)
42#include "polarssl/havege.h"
43#endif
44
45/* Implementation that should never be optimized out by the compiler */
46static void polarssl_zeroize( void *v, size_t n ) {
47 volatile unsigned char *p = v; while( n-- ) *p++ = 0;
48}
49
50#define ENTROPY_MAX_LOOP 256
53{
54 memset( ctx, 0, sizeof(entropy_context) );
55
56#if defined(POLARSSL_THREADING_C)
57 polarssl_mutex_init( &ctx->mutex );
58#endif
59
60#if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
61 sha512_starts( &ctx->accumulator, 0 );
62#else
63 sha256_starts( &ctx->accumulator, 0 );
64#endif
65#if defined(POLARSSL_HAVEGE_C)
66 havege_init( &ctx->havege_data );
67#endif
68
69#if !defined(POLARSSL_NO_DEFAULT_ENTROPY_SOURCES)
70#if !defined(POLARSSL_NO_PLATFORM_ENTROPY)
73#endif
74#if defined(POLARSSL_TIMING_C)
76#endif
77#if defined(POLARSSL_HAVEGE_C)
80#endif
81#endif /* POLARSSL_NO_DEFAULT_ENTROPY_SOURCES */
82}
83
85{
86#if defined(POLARSSL_HAVEGE_C)
87 havege_free( &ctx->havege_data );
88#endif
89 polarssl_zeroize( ctx, sizeof( entropy_context ) );
90#if defined(POLARSSL_THREADING_C)
91 polarssl_mutex_free( &ctx->mutex );
92#endif
93}
94
96 f_source_ptr f_source, void *p_source,
97 size_t threshold )
98{
99 int index, ret = 0;
100
101#if defined(POLARSSL_THREADING_C)
102 if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
103 return( ret );
104#endif
105
106 index = ctx->source_count;
107 if( index >= ENTROPY_MAX_SOURCES )
108 {
110 goto exit;
111 }
112
113 ctx->source[index].f_source = f_source;
114 ctx->source[index].p_source = p_source;
115 ctx->source[index].threshold = threshold;
116
117 ctx->source_count++;
118
119exit:
120#if defined(POLARSSL_THREADING_C)
121 if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
123#endif
124
125 return( ret );
126}
127
128/*
129 * Entropy accumulator update
130 */
131static int entropy_update( entropy_context *ctx, unsigned char source_id,
132 const unsigned char *data, size_t len )
133{
134 unsigned char header[2];
135 unsigned char tmp[ENTROPY_BLOCK_SIZE];
136 size_t use_len = len;
137 const unsigned char *p = data;
138
139 if( use_len > ENTROPY_BLOCK_SIZE )
140 {
141#if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
142 sha512( data, len, tmp, 0 );
143#else
144 sha256( data, len, tmp, 0 );
145#endif
146 p = tmp;
147 use_len = ENTROPY_BLOCK_SIZE;
148 }
149
150 header[0] = source_id;
151 header[1] = use_len & 0xFF;
152
153#if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
154 sha512_update( &ctx->accumulator, header, 2 );
155 sha512_update( &ctx->accumulator, p, use_len );
156#else
157 sha256_update( &ctx->accumulator, header, 2 );
158 sha256_update( &ctx->accumulator, p, use_len );
159#endif
160
161 return( 0 );
162}
163
165 const unsigned char *data, size_t len )
166{
167 int ret;
168
169#if defined(POLARSSL_THREADING_C)
170 if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
171 return( ret );
172#endif
173
174 ret = entropy_update( ctx, ENTROPY_SOURCE_MANUAL, data, len );
175
176#if defined(POLARSSL_THREADING_C)
177 if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
179#endif
180
181 return( ret );
182}
183
184/*
185 * Run through the different sources to add entropy to our accumulator
186 */
187static int entropy_gather_internal( entropy_context *ctx )
188{
189 int ret, i;
190 unsigned char buf[ENTROPY_MAX_GATHER];
191 size_t olen;
192
193 if( ctx->source_count == 0 )
195
196 /*
197 * Run through our entropy sources
198 */
199 for( i = 0; i < ctx->source_count; i++ )
200 {
201 olen = 0;
202 if( ( ret = ctx->source[i].f_source( ctx->source[i].p_source,
203 buf, ENTROPY_MAX_GATHER, &olen ) ) != 0 )
204 {
205 return( ret );
206 }
207
208 /*
209 * Add if we actually gathered something
210 */
211 if( olen > 0 )
212 {
213 entropy_update( ctx, (unsigned char) i, buf, olen );
214 ctx->source[i].size += olen;
215 }
216 }
217
218 return( 0 );
219}
220
221/*
222 * Thread-safe wrapper for entropy_gather_internal()
223 */
225{
226 int ret;
227
228#if defined(POLARSSL_THREADING_C)
229 if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
230 return( ret );
231#endif
232
233 ret = entropy_gather_internal( ctx );
234
235#if defined(POLARSSL_THREADING_C)
236 if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
238#endif
239
240 return( ret );
241}
242
243int entropy_func( void *data, unsigned char *output, size_t len )
244{
245 int ret, count = 0, i, reached;
246 entropy_context *ctx = (entropy_context *) data;
247 unsigned char buf[ENTROPY_BLOCK_SIZE];
248
249 if( len > ENTROPY_BLOCK_SIZE )
251
252#if defined(POLARSSL_THREADING_C)
253 if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
254 return( ret );
255#endif
256
257 /*
258 * Always gather extra entropy before a call
259 */
260 do
261 {
262 if( count++ > ENTROPY_MAX_LOOP )
263 {
265 goto exit;
266 }
267
268 if( ( ret = entropy_gather_internal( ctx ) ) != 0 )
269 goto exit;
270
271 reached = 0;
272
273 for( i = 0; i < ctx->source_count; i++ )
274 if( ctx->source[i].size >= ctx->source[i].threshold )
275 reached++;
276 }
277 while( reached != ctx->source_count );
278
279 memset( buf, 0, ENTROPY_BLOCK_SIZE );
280
281#if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
282 sha512_finish( &ctx->accumulator, buf );
283
284 /*
285 * Reset accumulator and counters and recycle existing entropy
286 */
287 memset( &ctx->accumulator, 0, sizeof( sha512_context ) );
288 sha512_starts( &ctx->accumulator, 0 );
290
291 /*
292 * Perform second SHA-512 on entropy
293 */
294 sha512( buf, ENTROPY_BLOCK_SIZE, buf, 0 );
295#else /* POLARSSL_ENTROPY_SHA512_ACCUMULATOR */
296 sha256_finish( &ctx->accumulator, buf );
297
298 /*
299 * Reset accumulator and counters and recycle existing entropy
300 */
301 memset( &ctx->accumulator, 0, sizeof( sha256_context ) );
302 sha256_starts( &ctx->accumulator, 0 );
304
305 /*
306 * Perform second SHA-256 on entropy
307 */
308 sha256( buf, ENTROPY_BLOCK_SIZE, buf, 0 );
309#endif /* POLARSSL_ENTROPY_SHA512_ACCUMULATOR */
310
311 for( i = 0; i < ctx->source_count; i++ )
312 ctx->source[i].size = 0;
313
314 memcpy( output, buf, len );
315
316 ret = 0;
317
318exit:
319#if defined(POLARSSL_THREADING_C)
320 if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
322#endif
323
324 return( ret );
325}
326
327#if defined(POLARSSL_FS_IO)
328int entropy_write_seed_file( entropy_context *ctx, const char *path )
329{
331 FILE *f;
332 unsigned char buf[ENTROPY_BLOCK_SIZE];
333
334 if( ( f = fopen( path, "wb" ) ) == NULL )
336
337 if( ( ret = entropy_func( ctx, buf, ENTROPY_BLOCK_SIZE ) ) != 0 )
338 goto exit;
339
340 if( fwrite( buf, 1, ENTROPY_BLOCK_SIZE, f ) != ENTROPY_BLOCK_SIZE )
341 {
343 goto exit;
344 }
345
346 ret = 0;
347
348exit:
349 fclose( f );
350 return( ret );
351}
352
353int entropy_update_seed_file( entropy_context *ctx, const char *path )
354{
355 FILE *f;
356 size_t n;
357 unsigned char buf[ ENTROPY_MAX_SEED_SIZE ];
358
359 if( ( f = fopen( path, "rb" ) ) == NULL )
361
362 fseek( f, 0, SEEK_END );
363 n = (size_t) ftell( f );
364 fseek( f, 0, SEEK_SET );
365
366 if( n > ENTROPY_MAX_SEED_SIZE )
368
369 if( fread( buf, 1, n, f ) != n )
370 {
371 fclose( f );
373 }
374
375 fclose( f );
376
377 entropy_update_manual( ctx, buf, n );
378
379 return( entropy_write_seed_file( ctx, path ) );
380}
381#endif /* POLARSSL_FS_IO */
382
383#if defined(POLARSSL_SELF_TEST)
384
385#if defined(POLARSSL_PLATFORM_C)
386#include "polarssl/platform.h"
387#else
388#include <stdio.h>
389#define polarssl_printf printf
390#endif
391
392/*
393 * Dummy source function
394 */
395static int entropy_dummy_source( void *data, unsigned char *output,
396 size_t len, size_t *olen )
397{
398 ((void) data);
399
400 memset( output, 0x2a, len );
401 *olen = len;
402
403 return( 0 );
404}
405
406/*
407 * The actual entropy quality is hard to test, but we can at least
408 * test that the functions don't cause errors and write the correct
409 * amount of data to buffers.
410 */
411int entropy_self_test( int verbose )
412{
413 int ret = 0;
414 entropy_context ctx;
415 unsigned char buf[ENTROPY_BLOCK_SIZE] = { 0 };
416 unsigned char acc[ENTROPY_BLOCK_SIZE] = { 0 };
417 size_t i, j;
418
419 if( verbose != 0 )
420 polarssl_printf( " ENTROPY test: " );
421
422 entropy_init( &ctx );
423
424 ret = entropy_add_source( &ctx, entropy_dummy_source, NULL, 16 );
425 if( ret != 0 )
426 goto cleanup;
427
428 if( ( ret = entropy_gather( &ctx ) ) != 0 )
429 goto cleanup;
430
431 if( ( ret = entropy_update_manual( &ctx, buf, sizeof buf ) ) != 0 )
432 goto cleanup;
433
434 /*
435 * To test that entropy_func writes correct number of bytes:
436 * - use the whole buffer and rely on ASan to detect overruns
437 * - collect entropy 8 times and OR the result in an accumulator:
438 * any byte should then be 0 with probably 2^(-64), so requiring
439 * each of the 32 or 64 bytes to be non-zero has a false failure rate
440 * of at most 2^(-58) which is acceptable.
441 */
442 for( i = 0; i < 8; i++ )
443 {
444 if( ( ret = entropy_func( &ctx, buf, sizeof( buf ) ) ) != 0 )
445 goto cleanup;
446
447 for( j = 0; j < sizeof( buf ); j++ )
448 acc[j] |= buf[j];
449 }
450
451 for( j = 0; j < sizeof( buf ); j++ )
452 {
453 if( acc[j] == 0 )
454 {
455 ret = 1;
456 goto cleanup;
457 }
458 }
459
460cleanup:
461 entropy_free( &ctx );
462
463 if( verbose != 0 )
464 {
465 if( ret != 0 )
466 polarssl_printf( "failed\n" );
467 else
468 polarssl_printf( "passed\n" );
469
470 polarssl_printf( "\n" );
471 }
472
473 return( ret != 0 );
474}
475#endif /* POLARSSL_SELF_TEST */
476
477#endif /* POLARSSL_ENTROPY_C */
#define ENTROPY_MAX_SOURCES
Configuration options (set of defines)
Entropy accumulator implementation.
void entropy_init(entropy_context *ctx)
Initialize the context.
#define POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED
No sources have been added to poll.
Definition entropy.h:58
#define ENTROPY_MAX_SEED_SIZE
Maximum size of seed we read from seed file.
Definition entropy.h:85
int entropy_func(void *data, unsigned char *output, size_t len)
Retrieve entropy from the accumulator (Maximum length: ENTROPY_BLOCK_SIZE) (Thread-safe if POLARSSL_T...
#define POLARSSL_ERR_ENTROPY_FILE_IO_ERROR
Read/write error in file.
Definition entropy.h:59
int(* f_source_ptr)(void *data, unsigned char *output, size_t len, size_t *olen)
Entropy poll callback pointer.
Definition entropy.h:103
#define ENTROPY_BLOCK_SIZE
Block size of entropy accumulator (SHA-512)
Definition entropy.h:80
int entropy_update_manual(entropy_context *ctx, const unsigned char *data, size_t len)
Add data to the accumulator manually (Thread-safe if POLARSSL_THREADING_C is enabled)
int entropy_add_source(entropy_context *ctx, f_source_ptr f_source, void *p_source, size_t threshold)
Adds an entropy source to poll (Thread-safe if POLARSSL_THREADING_C is enabled)
int entropy_update_seed_file(entropy_context *ctx, const char *path)
Read and update a seed file.
#define ENTROPY_SOURCE_MANUAL
Definition entropy.h:86
#define POLARSSL_ERR_ENTROPY_MAX_SOURCES
No more sources can be added.
Definition entropy.h:57
#define POLARSSL_ERR_ENTROPY_SOURCE_FAILED
Critical entropy source failure.
Definition entropy.h:56
int entropy_gather(entropy_context *ctx)
Trigger an extra gather poll for the accumulator (Thread-safe if POLARSSL_THREADING_C is enabled)
#define ENTROPY_MAX_GATHER
Maximum amount requested from entropy sources.
Definition entropy.h:74
void entropy_free(entropy_context *ctx)
Free the data in the context.
int entropy_self_test(int verbose)
Checkup routine.
int entropy_write_seed_file(entropy_context *ctx, const char *path)
Write a seed file.
Platform-specific and custom entropy polling functions.
int hardclock_poll(void *data, unsigned char *output, size_t len, size_t *olen)
hardclock-based entropy poll callback
int platform_entropy_poll(void *data, unsigned char *output, size_t len, size_t *olen)
Platform-specific entropy poll callback.
#define ENTROPY_MIN_HARDCLOCK
Minimum for hardclock()
#define ENTROPY_MIN_HAVEGE
Minimum for HAVEGE
int havege_poll(void *data, unsigned char *output, size_t len, size_t *olen)
HAVEGE based entropy poll callback.
#define ENTROPY_MIN_PLATFORM
Minimum for platform source
HAVEGE: HArdware Volatile Entropy Gathering and Expansion.
void havege_init(havege_state *hs)
HAVEGE initialization.
void havege_free(havege_state *hs)
Clear HAVEGE state.
PolarSSL Platform abstraction layer.
void sha256_finish(sha256_context *ctx, unsigned char output[32])
SHA-256 final digest.
void sha256(const unsigned char *input, size_t ilen, unsigned char output[32], int is224)
Output = SHA-256( input buffer )
void sha256_update(sha256_context *ctx, const unsigned char *input, size_t ilen)
SHA-256 process buffer.
void sha256_starts(sha256_context *ctx, int is224)
SHA-256 context setup.
void sha512_starts(sha512_context *ctx, int is384)
SHA-512 context setup.
void sha512(const unsigned char *input, size_t ilen, unsigned char output[64], int is384)
Output = SHA-512( input buffer )
void sha512_finish(sha512_context *ctx, unsigned char output[64])
SHA-512 final digest.
void sha512_update(sha512_context *ctx, const unsigned char *input, size_t ilen)
SHA-512 process buffer.
Entropy context structure.
Definition entropy.h:122
source_state source[ENTROPY_MAX_SOURCES]
Definition entropy.h:129
sha512_context accumulator
Definition entropy.h:124
havege_state havege_data
Definition entropy.h:131
SHA-256 context structure.
Definition sha256.h:59
SHA-512 context structure.
Definition sha512.h:60
f_source_ptr f_source
The entropy source callback.
Definition entropy.h:111
void * p_source
The callback data pointer.
Definition entropy.h:112
size_t threshold
Minimum level required before release.
Definition entropy.h:114
size_t size
Amount received.
Definition entropy.h:113
#define polarssl_printf
int(* polarssl_mutex_init)(threading_mutex_t *mutex)
int(* polarssl_mutex_free)(threading_mutex_t *mutex)
int(* polarssl_mutex_unlock)(threading_mutex_t *mutex)
int(* polarssl_mutex_lock)(threading_mutex_t *mutex)
#define POLARSSL_ERR_THREADING_MUTEX_ERROR
Locking / unlocking / free failed with error code.
Definition threading.h:44