insert nonsensical useragent for sourceshit, so it won't try to show its idiotic...
[syren.git] / src / libpolarssl / entropy.c
blob6e93f31143c2902e27fda9eee24aba007bb6579c
1 /*
2 * Entropy accumulator implementation
4 * Copyright (C) 2006-2014, Brainspark B.V.
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
9 * All rights reserved.
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.
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.
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.
26 #if !defined(POLARSSL_CONFIG_FILE)
27 #include "config.h"
28 #else
29 #include POLARSSL_CONFIG_FILE
30 #endif
32 #if defined(POLARSSL_ENTROPY_C)
34 #include "entropy.h"
35 #include "entropy_poll.h"
37 #if defined(POLARSSL_FS_IO)
38 #include <stdio.h>
39 #endif
41 #if defined(POLARSSL_HAVEGE_C)
42 #include "havege.h"
43 #endif
45 #define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */
47 void entropy_init( entropy_context *ctx )
49 memset( ctx, 0, sizeof(entropy_context) );
51 #if defined(POLARSSL_THREADING_C)
52 polarssl_mutex_init( &ctx->mutex );
53 #endif
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
64 #if !defined(POLARSSL_NO_DEFAULT_ENTROPY_SOURCES)
65 #if !defined(POLARSSL_NO_PLATFORM_ENTROPY)
66 entropy_add_source( ctx, platform_entropy_poll, NULL,
67 ENTROPY_MIN_PLATFORM );
68 #endif
69 #if defined(POLARSSL_TIMING_C)
70 entropy_add_source( ctx, hardclock_poll, NULL, ENTROPY_MIN_HARDCLOCK );
71 #endif
72 #if defined(POLARSSL_HAVEGE_C)
73 entropy_add_source( ctx, havege_poll, &ctx->havege_data,
74 ENTROPY_MIN_HAVEGE );
75 #endif
76 #endif /* POLARSSL_NO_DEFAULT_ENTROPY_SOURCES */
79 void entropy_free( entropy_context *ctx )
81 ((void) ctx);
82 #if defined(POLARSSL_THREADING_C)
83 polarssl_mutex_free( &ctx->mutex );
84 #endif
87 int entropy_add_source( entropy_context *ctx,
88 f_source_ptr f_source, void *p_source,
89 size_t threshold )
91 int index, ret = 0;
93 #if defined(POLARSSL_THREADING_C)
94 if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
95 return( ret );
96 #endif
98 index = ctx->source_count;
99 if( index >= ENTROPY_MAX_SOURCES )
101 ret = POLARSSL_ERR_ENTROPY_MAX_SOURCES;
102 goto exit;
105 ctx->source[index].f_source = f_source;
106 ctx->source[index].p_source = p_source;
107 ctx->source[index].threshold = threshold;
109 ctx->source_count++;
111 exit:
112 #if defined(POLARSSL_THREADING_C)
113 if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
114 return( POLARSSL_ERR_THREADING_MUTEX_ERROR );
115 #endif
117 return( ret );
121 * Entropy accumulator update
123 static int entropy_update( entropy_context *ctx, unsigned char source_id,
124 const unsigned char *data, size_t len )
126 unsigned char header[2];
127 unsigned char tmp[ENTROPY_BLOCK_SIZE];
128 size_t use_len = len;
129 const unsigned char *p = data;
131 if( use_len > ENTROPY_BLOCK_SIZE )
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;
142 header[0] = source_id;
143 header[1] = use_len & 0xFF;
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
153 return( 0 );
156 int entropy_update_manual( entropy_context *ctx,
157 const unsigned char *data, size_t len )
159 int ret;
161 #if defined(POLARSSL_THREADING_C)
162 if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
163 return( ret );
164 #endif
166 ret = entropy_update( ctx, ENTROPY_SOURCE_MANUAL, data, len );
168 #if defined(POLARSSL_THREADING_C)
169 if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
170 return( POLARSSL_ERR_THREADING_MUTEX_ERROR );
171 #endif
173 return ( ret );
177 * Run through the different sources to add entropy to our accumulator
179 static int entropy_gather_internal( entropy_context *ctx )
181 int ret, i;
182 unsigned char buf[ENTROPY_MAX_GATHER];
183 size_t olen;
185 if( ctx->source_count == 0 )
186 return( POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED );
189 * Run through our entropy sources
191 for( i = 0; i < ctx->source_count; i++ )
193 olen = 0;
194 if ( ( ret = ctx->source[i].f_source( ctx->source[i].p_source,
195 buf, ENTROPY_MAX_GATHER, &olen ) ) != 0 )
197 return( ret );
201 * Add if we actually gathered something
203 if( olen > 0 )
205 entropy_update( ctx, (unsigned char) i, buf, olen );
206 ctx->source[i].size += olen;
210 return( 0 );
214 * Thread-safe wrapper for entropy_gather_internal()
216 int entropy_gather( entropy_context *ctx )
218 int ret;
220 #if defined(POLARSSL_THREADING_C)
221 if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
222 return( ret );
223 #endif
225 ret = entropy_gather_internal( ctx );
227 #if defined(POLARSSL_THREADING_C)
228 if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
229 return( POLARSSL_ERR_THREADING_MUTEX_ERROR );
230 #endif
232 return( ret );
235 int entropy_func( void *data, unsigned char *output, size_t len )
237 int ret, count = 0, i, reached;
238 entropy_context *ctx = (entropy_context *) data;
239 unsigned char buf[ENTROPY_BLOCK_SIZE];
241 if( len > ENTROPY_BLOCK_SIZE )
242 return( POLARSSL_ERR_ENTROPY_SOURCE_FAILED );
244 #if defined(POLARSSL_THREADING_C)
245 if( ( ret = polarssl_mutex_lock( &ctx->mutex ) ) != 0 )
246 return( ret );
247 #endif
250 * Always gather extra entropy before a call
254 if( count++ > ENTROPY_MAX_LOOP )
256 ret = POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
257 goto exit;
260 if( ( ret = entropy_gather_internal( ctx ) ) != 0 )
261 goto exit;
263 reached = 0;
265 for( i = 0; i < ctx->source_count; i++ )
266 if( ctx->source[i].size >= ctx->source[i].threshold )
267 reached++;
269 while( reached != ctx->source_count );
271 memset( buf, 0, ENTROPY_BLOCK_SIZE );
273 #if defined(POLARSSL_ENTROPY_SHA512_ACCUMULATOR)
274 sha512_finish( &ctx->accumulator, buf );
277 * Reset accumulator and counters and recycle existing entropy
279 memset( &ctx->accumulator, 0, sizeof( sha512_context ) );
280 sha512_starts( &ctx->accumulator, 0 );
281 sha512_update( &ctx->accumulator, buf, ENTROPY_BLOCK_SIZE );
284 * Perform second SHA-512 on entropy
286 sha512( buf, ENTROPY_BLOCK_SIZE, buf, 0 );
287 #else /* POLARSSL_ENTROPY_SHA512_ACCUMULATOR */
288 sha256_finish( &ctx->accumulator, buf );
291 * Reset accumulator and counters and recycle existing entropy
293 memset( &ctx->accumulator, 0, sizeof( sha256_context ) );
294 sha256_starts( &ctx->accumulator, 0 );
295 sha256_update( &ctx->accumulator, buf, ENTROPY_BLOCK_SIZE );
298 * Perform second SHA-256 on entropy
300 sha256( buf, ENTROPY_BLOCK_SIZE, buf, 0 );
301 #endif /* POLARSSL_ENTROPY_SHA512_ACCUMULATOR */
303 for( i = 0; i < ctx->source_count; i++ )
304 ctx->source[i].size = 0;
306 memcpy( output, buf, len );
308 ret = 0;
310 exit:
311 #if defined(POLARSSL_THREADING_C)
312 if( polarssl_mutex_unlock( &ctx->mutex ) != 0 )
313 return( POLARSSL_ERR_THREADING_MUTEX_ERROR );
314 #endif
316 return( ret );
319 #if defined(POLARSSL_FS_IO)
320 int entropy_write_seed_file( entropy_context *ctx, const char *path )
322 int ret = POLARSSL_ERR_ENTROPY_FILE_IO_ERROR;
323 FILE *f;
324 unsigned char buf[ENTROPY_BLOCK_SIZE];
326 if( ( f = fopen( path, "wb" ) ) == NULL )
327 return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR );
329 if( ( ret = entropy_func( ctx, buf, ENTROPY_BLOCK_SIZE ) ) != 0 )
330 goto exit;
332 if( fwrite( buf, 1, ENTROPY_BLOCK_SIZE, f ) != ENTROPY_BLOCK_SIZE )
334 ret = POLARSSL_ERR_ENTROPY_FILE_IO_ERROR;
335 goto exit;
338 ret = 0;
340 exit:
341 fclose( f );
342 return( ret );
345 int entropy_update_seed_file( entropy_context *ctx, const char *path )
347 FILE *f;
348 size_t n;
349 unsigned char buf[ ENTROPY_MAX_SEED_SIZE ];
351 if( ( f = fopen( path, "rb" ) ) == NULL )
352 return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR );
354 fseek( f, 0, SEEK_END );
355 n = (size_t) ftell( f );
356 fseek( f, 0, SEEK_SET );
358 if( n > ENTROPY_MAX_SEED_SIZE )
359 n = ENTROPY_MAX_SEED_SIZE;
361 if( fread( buf, 1, n, f ) != n )
363 fclose( f );
364 return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR );
367 fclose( f );
369 entropy_update_manual( ctx, buf, n );
371 return( entropy_write_seed_file( ctx, path ) );
373 #endif /* POLARSSL_FS_IO */
375 #endif /* POLARSSL_ENTROPY_C */