PolarSSL v1.2.11
entropy.c
Go to the documentation of this file.
1 /*
2  * Entropy accumulator implementation
3  *
4  * Copyright (C) 2006-2011, 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 #include "polarssl/config.h"
27 
28 #if defined(POLARSSL_ENTROPY_C)
29 
30 #include "polarssl/entropy.h"
31 #include "polarssl/entropy_poll.h"
32 
33 #if defined(POLARSSL_FS_IO)
34 #include <stdio.h>
35 #endif
36 
37 #if defined(POLARSSL_HAVEGE_C)
38 #include "polarssl/havege.h"
39 #endif
40 
41 #define ENTROPY_MAX_LOOP 256
43 void entropy_init( entropy_context *ctx )
44 {
45  memset( ctx, 0, sizeof(entropy_context) );
46 
47  sha4_starts( &ctx->accumulator, 0 );
48 #if defined(POLARSSL_HAVEGE_C)
49  havege_init( &ctx->havege_data );
50 #endif
51 
52 #if !defined(POLARSSL_NO_DEFAULT_ENTROPY_SOURCES)
53 #if !defined(POLARSSL_NO_PLATFORM_ENTROPY)
56 #endif
57 #if defined(POLARSSL_TIMING_C)
59 #endif
60 #if defined(POLARSSL_HAVEGE_C)
61  entropy_add_source( ctx, havege_poll, &ctx->havege_data,
63 #endif
64 #endif /* POLARSSL_NO_DEFAULT_ENTROPY_SOURCES */
65 }
66 
68  f_source_ptr f_source, void *p_source,
69  size_t threshold )
70 {
71  int index = ctx->source_count;
72 
73  if( index >= ENTROPY_MAX_SOURCES )
75 
76  ctx->source[index].f_source = f_source;
77  ctx->source[index].p_source = p_source;
78  ctx->source[index].threshold = threshold;
79 
80  ctx->source_count++;
81 
82  return( 0 );
83 }
84 
85 /*
86  * Entropy accumulator update
87  */
88 static int entropy_update( entropy_context *ctx, unsigned char source_id,
89  const unsigned char *data, size_t len )
90 {
91  unsigned char header[2];
92  unsigned char tmp[ENTROPY_BLOCK_SIZE];
93  size_t use_len = len;
94  const unsigned char *p = data;
95 
96  if( use_len > ENTROPY_BLOCK_SIZE )
97  {
98  sha4( data, len, tmp, 0 );
99 
100  p = tmp;
101  use_len = ENTROPY_BLOCK_SIZE;
102  }
103 
104  header[0] = source_id;
105  header[1] = use_len & 0xFF;
106 
107  sha4_update( &ctx->accumulator, header, 2 );
108  sha4_update( &ctx->accumulator, p, use_len );
109 
110  return( 0 );
111 }
112 
114  const unsigned char *data, size_t len )
115 {
116  return entropy_update( ctx, ENTROPY_SOURCE_MANUAL, data, len );
117 }
118 
119 /*
120  * Run through the different sources to add entropy to our accumulator
121  */
123 {
124  int ret, i;
125  unsigned char buf[ENTROPY_MAX_GATHER];
126  size_t olen;
127 
128  if( ctx->source_count == 0 )
130 
131  /*
132  * Run through our entropy sources
133  */
134  for( i = 0; i < ctx->source_count; i++ )
135  {
136  olen = 0;
137  if ( ( ret = ctx->source[i].f_source( ctx->source[i].p_source,
138  buf, ENTROPY_MAX_GATHER, &olen ) ) != 0 )
139  {
140  return( ret );
141  }
142 
143  /*
144  * Add if we actually gathered something
145  */
146  if( olen > 0 )
147  {
148  entropy_update( ctx, (unsigned char) i, buf, olen );
149  ctx->source[i].size += olen;
150  }
151  }
152 
153  return( 0 );
154 }
155 
156 int entropy_func( void *data, unsigned char *output, size_t len )
157 {
158  int ret, count = 0, i, reached;
159  entropy_context *ctx = (entropy_context *) data;
160  unsigned char buf[ENTROPY_BLOCK_SIZE];
161 
162  if( len > ENTROPY_BLOCK_SIZE )
164 
165  /*
166  * Always gather extra entropy before a call
167  */
168  do
169  {
170  if( count++ > ENTROPY_MAX_LOOP )
172 
173  if( ( ret = entropy_gather( ctx ) ) != 0 )
174  return( ret );
175 
176  reached = 0;
177 
178  for( i = 0; i < ctx->source_count; i++ )
179  if( ctx->source[i].size >= ctx->source[i].threshold )
180  reached++;
181  }
182  while( reached != ctx->source_count );
183 
184  memset( buf, 0, ENTROPY_BLOCK_SIZE );
185 
186  sha4_finish( &ctx->accumulator, buf );
187 
188  /*
189  * Reset accumulator and counters and recycle existing entropy
190  */
191  memset( &ctx->accumulator, 0, sizeof( sha4_context ) );
192  sha4_starts( &ctx->accumulator, 0 );
194 
195  /*
196  * Perform second SHA-512 on entropy
197  */
198  sha4( buf, ENTROPY_BLOCK_SIZE, buf, 0 );
199 
200  for( i = 0; i < ctx->source_count; i++ )
201  ctx->source[i].size = 0;
202 
203  memcpy( output, buf, len );
204 
205  return( 0 );
206 }
207 
208 #if defined(POLARSSL_FS_IO)
209 int entropy_write_seed_file( entropy_context *ctx, const char *path )
210 {
212  FILE *f;
213  unsigned char buf[ENTROPY_BLOCK_SIZE];
214 
215  if( ( f = fopen( path, "wb" ) ) == NULL )
217 
218  if( ( ret = entropy_func( ctx, buf, ENTROPY_BLOCK_SIZE ) ) != 0 )
219  goto exit;
220 
221  if( fwrite( buf, 1, ENTROPY_BLOCK_SIZE, f ) != ENTROPY_BLOCK_SIZE )
222  {
224  goto exit;
225  }
226 
227  ret = 0;
228 
229 exit:
230  fclose( f );
231  return( ret );
232 }
233 
234 int entropy_update_seed_file( entropy_context *ctx, const char *path )
235 {
236  FILE *f;
237  size_t n;
238  unsigned char buf[ ENTROPY_MAX_SEED_SIZE ];
239 
240  if( ( f = fopen( path, "rb" ) ) == NULL )
242 
243  fseek( f, 0, SEEK_END );
244  n = (size_t) ftell( f );
245  fseek( f, 0, SEEK_SET );
246 
247  if( n > ENTROPY_MAX_SEED_SIZE )
249 
250  if( fread( buf, 1, n, f ) != n )
251  {
252  fclose( f );
254  }
255 
256  fclose( f );
257 
258  entropy_update_manual( ctx, buf, n );
259 
260  return( entropy_write_seed_file( ctx, path ) );
261 }
262 #endif /* POLARSSL_FS_IO */
263 
264 #endif
int entropy_add_source(entropy_context *ctx, f_source_ptr f_source, void *p_source, size_t threshold)
Adds an entropy source to poll.
#define ENTROPY_MIN_PLATFORM
Minimum for platform source.
Definition: entropy_poll.h:41
int entropy_update_manual(entropy_context *ctx, const unsigned char *data, size_t len)
Add data to the accumulator manually.
#define POLARSSL_ERR_ENTROPY_MAX_SOURCES
No more sources can be added.
Definition: entropy.h:40
Configuration options (set of defines)
int entropy_gather(entropy_context *ctx)
Trigger an extra gather poll for the accumulator.
#define ENTROPY_MIN_HARDCLOCK
Minimum for hardclock()
Definition: entropy_poll.h:43
Entropy context structure.
Definition: entropy.h:86
int source_count
Definition: entropy.h:89
#define ENTROPY_MAX_GATHER
Maximum amount requested from entropy sources.
Definition: entropy.h:46
void * p_source
The callback data pointer.
Definition: entropy.h:77
Platform-specific and custom entropy polling functions.
Entropy accumulator implementation.
#define ENTROPY_SOURCE_MANUAL
Definition: entropy.h:52
source_state source[ENTROPY_MAX_SOURCES]
Definition: entropy.h:90
#define ENTROPY_BLOCK_SIZE
Block size of entropy accumulator (SHA-512)
Definition: entropy.h:49
void sha4_starts(sha4_context *ctx, int is384)
SHA-512 context setup.
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:42
size_t size
Amount received.
Definition: entropy.h:78
f_source_ptr f_source
The entropy source callback.
Definition: entropy.h:76
void sha4_update(sha4_context *ctx, const unsigned char *input, size_t ilen)
SHA-512 process buffer.
#define ENTROPY_MAX_SEED_SIZE
Maximum size of seed we read from seed file.
Definition: entropy.h:51
HAVEGE: HArdware Volatile Entropy Gathering and Expansion.
sha4_context accumulator
Definition: entropy.h:88
int platform_entropy_poll(void *data, unsigned char *output, size_t len, size_t *olen)
Platform-specific entropy poll callback.
#define ENTROPY_MAX_SOURCES
Maximum number of sources supported.
Definition: entropy.h:45
void havege_init(havege_state *hs)
HAVEGE initialization.
void sha4(const unsigned char *input, size_t ilen, unsigned char output[64], int is384)
Output = SHA-512( input buffer )
size_t threshold
Minimum level required before release.
Definition: entropy.h:79
#define POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED
No sources have been added to poll.
Definition: entropy.h:41
SHA-512 context structure.
Definition: sha4.h:51
int entropy_update_seed_file(entropy_context *ctx, const char *path)
Read and update a seed file.
#define POLARSSL_ERR_ENTROPY_FILE_IO_ERROR
Read/write error in file.
Definition: entropy.h:42
void sha4_finish(sha4_context *ctx, unsigned char output[64])
SHA-512 final digest.
#define POLARSSL_ERR_ENTROPY_SOURCE_FAILED
Critical entropy source failure.
Definition: entropy.h:39
int(* f_source_ptr)(void *, unsigned char *, size_t, size_t *)
Entropy poll callback pointer.
Definition: entropy.h:69
int hardclock_poll(void *data, unsigned char *output, size_t len, size_t *olen)
hardclock-based entropy poll callback
int entropy_func(void *data, unsigned char *output, size_t len)
Retrieve entropy from the accumulator (Max ENTROPY_BLOCK_SIZE)