PolarSSL v1.3.7
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"
35 #include "polarssl/entropy_poll.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 #define ENTROPY_MAX_LOOP 256
47 void entropy_init( entropy_context *ctx )
48 {
49  memset( ctx, 0, sizeof(entropy_context) );
50 
51 #if defined(POLARSSL_THREADING_C)
52  polarssl_mutex_init( &ctx->mutex );
53 #endif
54 
55 #if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
56  sha512_starts( &ctx->accumulator, 0 );
57 #else
58  sha256_starts( &ctx->accumulator, 0 );
59 #endif
60 #if defined(POLARSSL_HAVEGE_C)
61  havege_init( &ctx->havege_data );
62 #endif
63 
64 #if !defined(POLARSSL_NO_DEFAULT_ENTROPY_SOURCES)
65 #if !defined(POLARSSL_NO_PLATFORM_ENTROPY)
68 #endif
69 #if defined(POLARSSL_TIMING_C)
71 #endif
72 #if defined(POLARSSL_HAVEGE_C)
73  entropy_add_source( ctx, havege_poll, &ctx->havege_data,
75 #endif
76 #endif /* POLARSSL_NO_DEFAULT_ENTROPY_SOURCES */
77 }
78 
79 void entropy_free( entropy_context *ctx )
80 {
81  ((void) ctx);
82 #if defined(POLARSSL_THREADING_C)
83  polarssl_mutex_free( &ctx->mutex );
84 #endif
85 }
86 
88  f_source_ptr f_source, void *p_source,
89  size_t threshold )
90 {
91  int index, ret = 0;
92 
93 #if defined(POLARSSL_THREADING_C)
94  if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
95  return( ret );
96 #endif
97 
98  index = ctx->source_count;
99  if( index >= ENTROPY_MAX_SOURCES )
100  {
102  goto exit;
103  }
104 
105  ctx->source[index].f_source = f_source;
106  ctx->source[index].p_source = p_source;
107  ctx->source[index].threshold = threshold;
108 
109  ctx->source_count++;
110 
111 exit:
112 #if defined(POLARSSL_THREADING_C)
113  if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
115 #endif
116 
117  return( ret );
118 }
119 
120 /*
121  * Entropy accumulator update
122  */
123 static int entropy_update( entropy_context *ctx, unsigned char source_id,
124  const unsigned char *data, size_t len )
125 {
126  unsigned char header[2];
127  unsigned char tmp[ENTROPY_BLOCK_SIZE];
128  size_t use_len = len;
129  const unsigned char *p = data;
130 
131  if( use_len > ENTROPY_BLOCK_SIZE )
132  {
133 #if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
134  sha512( data, len, tmp, 0 );
135 #else
136  sha256( data, len, tmp, 0 );
137 #endif
138  p = tmp;
139  use_len = ENTROPY_BLOCK_SIZE;
140  }
141 
142  header[0] = source_id;
143  header[1] = use_len & 0xFF;
144 
145 #if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
146  sha512_update( &ctx->accumulator, header, 2 );
147  sha512_update( &ctx->accumulator, p, use_len );
148 #else
149  sha256_update( &ctx->accumulator, header, 2 );
150  sha256_update( &ctx->accumulator, p, use_len );
151 #endif
152 
153  return( 0 );
154 }
155 
157  const unsigned char *data, size_t len )
158 {
159  int ret;
160 
161 #if defined(POLARSSL_THREADING_C)
162  if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
163  return( ret );
164 #endif
165 
166  ret = entropy_update( ctx, ENTROPY_SOURCE_MANUAL, data, len );
167 
168 #if defined(POLARSSL_THREADING_C)
169  if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
171 #endif
172 
173  return ( ret );
174 }
175 
176 /*
177  * Run through the different sources to add entropy to our accumulator
178  */
179 static int entropy_gather_internal( entropy_context *ctx )
180 {
181  int ret, i;
182  unsigned char buf[ENTROPY_MAX_GATHER];
183  size_t olen;
184 
185  if( ctx->source_count == 0 )
187 
188  /*
189  * Run through our entropy sources
190  */
191  for( i = 0; i < ctx->source_count; i++ )
192  {
193  olen = 0;
194  if ( ( ret = ctx->source[i].f_source( ctx->source[i].p_source,
195  buf, ENTROPY_MAX_GATHER, &olen ) ) != 0 )
196  {
197  return( ret );
198  }
199 
200  /*
201  * Add if we actually gathered something
202  */
203  if( olen > 0 )
204  {
205  entropy_update( ctx, (unsigned char) i, buf, olen );
206  ctx->source[i].size += olen;
207  }
208  }
209 
210  return( 0 );
211 }
212 
213 /*
214  * Thread-safe wrapper for entropy_gather_internal()
215  */
217 {
218  int ret;
219 
220 #if defined(POLARSSL_THREADING_C)
221  if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
222  return( ret );
223 #endif
224 
225  ret = entropy_gather_internal( ctx );
226 
227 #if defined(POLARSSL_THREADING_C)
228  if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
230 #endif
231 
232  return( ret );
233 }
234 
235 int entropy_func( void *data, unsigned char *output, size_t len )
236 {
237  int ret, count = 0, i, reached;
238  entropy_context *ctx = (entropy_context *) data;
239  unsigned char buf[ENTROPY_BLOCK_SIZE];
240 
241  if( len > ENTROPY_BLOCK_SIZE )
243 
244 #if defined(POLARSSL_THREADING_C)
245  if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
246  return( ret );
247 #endif
248 
249  /*
250  * Always gather extra entropy before a call
251  */
252  do
253  {
254  if( count++ > ENTROPY_MAX_LOOP )
255  {
257  goto exit;
258  }
259 
260  if( ( ret = entropy_gather_internal( ctx ) ) != 0 )
261  goto exit;
262 
263  reached = 0;
264 
265  for( i = 0; i < ctx->source_count; i++ )
266  if( ctx->source[i].size >= ctx->source[i].threshold )
267  reached++;
268  }
269  while( reached != ctx->source_count );
270 
271  memset( buf, 0, ENTROPY_BLOCK_SIZE );
272 
273 #if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
274  sha512_finish( &ctx->accumulator, buf );
275 
276  /*
277  * Reset accumulator and counters and recycle existing entropy
278  */
279  memset( &ctx->accumulator, 0, sizeof( sha512_context ) );
280  sha512_starts( &ctx->accumulator, 0 );
282 
283  /*
284  * Perform second SHA-512 on entropy
285  */
286  sha512( buf, ENTROPY_BLOCK_SIZE, buf, 0 );
287 #else /* POLARSSL_ENTROPY_SHA512_ACCUMULATOR */
288  sha256_finish( &ctx->accumulator, buf );
289 
290  /*
291  * Reset accumulator and counters and recycle existing entropy
292  */
293  memset( &ctx->accumulator, 0, sizeof( sha256_context ) );
294  sha256_starts( &ctx->accumulator, 0 );
296 
297  /*
298  * Perform second SHA-256 on entropy
299  */
300  sha256( buf, ENTROPY_BLOCK_SIZE, buf, 0 );
301 #endif /* POLARSSL_ENTROPY_SHA512_ACCUMULATOR */
302 
303  for( i = 0; i < ctx->source_count; i++ )
304  ctx->source[i].size = 0;
305 
306  memcpy( output, buf, len );
307 
308  ret = 0;
309 
310 exit:
311 #if defined(POLARSSL_THREADING_C)
312  if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
314 #endif
315 
316  return( ret );
317 }
318 
319 #if defined(POLARSSL_FS_IO)
320 int entropy_write_seed_file( entropy_context *ctx, const char *path )
321 {
323  FILE *f;
324  unsigned char buf[ENTROPY_BLOCK_SIZE];
325 
326  if( ( f = fopen( path, "wb" ) ) == NULL )
328 
329  if( ( ret = entropy_func( ctx, buf, ENTROPY_BLOCK_SIZE ) ) != 0 )
330  goto exit;
331 
332  if( fwrite( buf, 1, ENTROPY_BLOCK_SIZE, f ) != ENTROPY_BLOCK_SIZE )
333  {
335  goto exit;
336  }
337 
338  ret = 0;
339 
340 exit:
341  fclose( f );
342  return( ret );
343 }
344 
345 int entropy_update_seed_file( entropy_context *ctx, const char *path )
346 {
347  FILE *f;
348  size_t n;
349  unsigned char buf[ ENTROPY_MAX_SEED_SIZE ];
350 
351  if( ( f = fopen( path, "rb" ) ) == NULL )
353 
354  fseek( f, 0, SEEK_END );
355  n = (size_t) ftell( f );
356  fseek( f, 0, SEEK_SET );
357 
358  if( n > ENTROPY_MAX_SEED_SIZE )
360 
361  if( fread( buf, 1, n, f ) != n )
362  {
363  fclose( f );
365  }
366 
367  fclose( f );
368 
369  entropy_update_manual( ctx, buf, n );
370 
371  return( entropy_write_seed_file( ctx, path ) );
372 }
373 #endif /* POLARSSL_FS_IO */
374 
375 #endif /* POLARSSL_ENTROPY_C */
int(* polarssl_mutex_lock)(threading_mutex_t *mutex)
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)
void sha256_update(sha256_context *ctx, const unsigned char *input, size_t ilen)
SHA-256 process buffer.
void sha256(const unsigned char *input, size_t ilen, unsigned char output[32], int is224)
Output = SHA-256( input buffer )
#define ENTROPY_MIN_PLATFORM
Minimum for platform source.
Definition: entropy_poll.h:45
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) ...
#define POLARSSL_ERR_ENTROPY_MAX_SOURCES
No more sources can be added.
Definition: entropy.h:57
sha512_context accumulator
Definition: entropy.h:124
Configuration options (set of defines)
int entropy_gather(entropy_context *ctx)
Trigger an extra gather poll for the accumulator (Thread-safe if POLARSSL_THREADING_C is enabled) ...
#define ENTROPY_MIN_HARDCLOCK
Minimum for hardclock()
Definition: entropy_poll.h:47
Entropy context structure.
Definition: entropy.h:121
int source_count
Definition: entropy.h:128
#define ENTROPY_MAX_GATHER
Maximum amount requested from entropy sources.
Definition: entropy.h:74
void * p_source
The callback data pointer.
Definition: entropy.h:112
Platform-specific and custom entropy polling functions.
Entropy accumulator implementation.
#define ENTROPY_SOURCE_MANUAL
Definition: entropy.h:86
int(* f_source_ptr)(void *data, unsigned char *output, size_t len, size_t *olen)
Entropy poll callback pointer.
Definition: entropy.h:103
source_state source[ENTROPY_MAX_SOURCES]
Definition: entropy.h:129
#define ENTROPY_BLOCK_SIZE
Block size of entropy accumulator (SHA-512)
Definition: entropy.h:80
int entropy_write_seed_file(entropy_context *ctx, const char *path)
Write a seed file.
#define ENTROPY_MIN_HAVEGE
Minimum for HAVEGE.
Definition: entropy_poll.h:46
size_t size
Amount received.
Definition: entropy.h:113
f_source_ptr f_source
The entropy source callback.
Definition: entropy.h:111
void sha256_starts(sha256_context *ctx, int is224)
SHA-256 context setup.
SHA-512 context structure.
Definition: sha512.h:59
#define ENTROPY_MAX_SEED_SIZE
Maximum size of seed we read from seed file.
Definition: entropy.h:85
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 )
HAVEGE: HArdware Volatile Entropy Gathering and Expansion.
int platform_entropy_poll(void *data, unsigned char *output, size_t len, size_t *olen)
Platform-specific entropy poll callback.
int(* polarssl_mutex_free)(threading_mutex_t *mutex)
#define ENTROPY_MAX_SOURCES
Maximum number of sources supported.
Definition: entropy.h:70
void sha512_finish(sha512_context *ctx, unsigned char output[64])
SHA-512 final digest.
void havege_init(havege_state *hs)
HAVEGE initialization.
size_t threshold
Minimum level required before release.
Definition: entropy.h:114
int(* polarssl_mutex_unlock)(threading_mutex_t *mutex)
#define POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED
No sources have been added to poll.
Definition: entropy.h:58
int(* polarssl_mutex_init)(threading_mutex_t *mutex)
#define POLARSSL_ERR_THREADING_MUTEX_ERROR
Locking / unlocking / free failed with error code.
Definition: threading.h:44
int entropy_update_seed_file(entropy_context *ctx, const char *path)
Read and update a seed file.
void sha256_finish(sha256_context *ctx, unsigned char output[32])
SHA-256 final digest.
#define POLARSSL_ERR_ENTROPY_FILE_IO_ERROR
Read/write error in file.
Definition: entropy.h:59
SHA-256 context structure.
Definition: sha256.h:58
#define POLARSSL_ERR_ENTROPY_SOURCE_FAILED
Critical entropy source failure.
Definition: entropy.h:56
int hardclock_poll(void *data, unsigned char *output, size_t len, size_t *olen)
hardclock-based entropy poll callback
void sha512_update(sha512_context *ctx, const unsigned char *input, size_t ilen)
SHA-512 process buffer.
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...
void entropy_free(entropy_context *ctx)
Free the data in the context.