]> git.zerfleddert.de Git - proxmark3-svn/blame - common/hmac_drbg.c
REM: "hf legic writeraw" has been removed.
[proxmark3-svn] / common / hmac_drbg.c
CommitLineData
0de8e387 1/*
2 * HMAC_DRBG implementation (NIST SP 800-90)
3 *
4 * Copyright (C) 2014, ARM Limited, All Rights Reserved
5 *
6 * This file is part of mbed TLS (https://tls.mbed.org)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23/*
24 * The NIST SP 800-90A DRBGs are described in the following publication.
25 * http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
26 * References below are based on rev. 1 (January 2012).
27 */
28
29#if !defined(MBEDTLS_CONFIG_FILE)
30#include "mbedtls/config.h"
31#else
32#include MBEDTLS_CONFIG_FILE
33#endif
34
35#if defined(MBEDTLS_HMAC_DRBG_C)
36
37#include "mbedtls/hmac_drbg.h"
38
39#include <string.h>
40
41#if defined(MBEDTLS_FS_IO)
42#include <stdio.h>
43#endif
44
45#if defined(MBEDTLS_SELF_TEST)
46#if defined(MBEDTLS_PLATFORM_C)
47#include "mbedtls/platform.h"
48#else
49#include <stdio.h>
50#define mbedtls_printf printf
51#endif /* MBEDTLS_SELF_TEST */
52#endif /* MBEDTLS_PLATFORM_C */
53
54/* Implementation that should never be optimized out by the compiler */
55static void mbedtls_zeroize( void *v, size_t n ) {
56 volatile unsigned char *p = v; while( n-- ) *p++ = 0;
57}
58
59/*
60 * HMAC_DRBG context initialization
61 */
62void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx )
63{
64 memset( ctx, 0, sizeof( mbedtls_hmac_drbg_context ) );
65
66#if defined(MBEDTLS_THREADING_C)
67 mbedtls_mutex_init( &ctx->mutex );
68#endif
69}
70
71/*
72 * HMAC_DRBG update, using optional additional data (10.1.2.2)
73 */
74void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx,
75 const unsigned char *additional, size_t add_len )
76{
77 size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info );
78 unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1;
79 unsigned char sep[1];
80 unsigned char K[MBEDTLS_MD_MAX_SIZE];
81
82 for( sep[0] = 0; sep[0] < rounds; sep[0]++ )
83 {
84 /* Step 1 or 4 */
85 mbedtls_md_hmac_reset( &ctx->md_ctx );
86 mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
87 mbedtls_md_hmac_update( &ctx->md_ctx, sep, 1 );
88 if( rounds == 2 )
89 mbedtls_md_hmac_update( &ctx->md_ctx, additional, add_len );
90 mbedtls_md_hmac_finish( &ctx->md_ctx, K );
91
92 /* Step 2 or 5 */
93 mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len );
94 mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
95 mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V );
96 }
97}
98
99/*
100 * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA)
101 */
102int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx,
103 const mbedtls_md_info_t * md_info,
104 const unsigned char *data, size_t data_len )
105{
106 int ret;
107
108 if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
109 return( ret );
110
111 /*
112 * Set initial working state.
113 * Use the V memory location, which is currently all 0, to initialize the
114 * MD context with an all-zero key. Then set V to its initial value.
115 */
116 mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, mbedtls_md_get_size( md_info ) );
117 memset( ctx->V, 0x01, mbedtls_md_get_size( md_info ) );
118
119 mbedtls_hmac_drbg_update( ctx, data, data_len );
120
121 return( 0 );
122}
123
124/*
125 * HMAC_DRBG reseeding: 10.1.2.4 (arabic) + 9.2 (Roman)
126 */
127int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx,
128 const unsigned char *additional, size_t len )
129{
130 unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT];
131 size_t seedlen;
132
133 /* III. Check input length */
134 if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT ||
135 ctx->entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT )
136 {
137 return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG );
138 }
139
140 memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT );
141
142 /* IV. Gather entropy_len bytes of entropy for the seed */
143 if( ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) != 0 )
144 return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED );
145
146 seedlen = ctx->entropy_len;
147
148 /* 1. Concatenate entropy and additional data if any */
149 if( additional != NULL && len != 0 )
150 {
151 memcpy( seed + seedlen, additional, len );
152 seedlen += len;
153 }
154
155 /* 2. Update state */
156 mbedtls_hmac_drbg_update( ctx, seed, seedlen );
157
158 /* 3. Reset reseed_counter */
159 ctx->reseed_counter = 1;
160
161 /* 4. Done */
162 return( 0 );
163}
164
165/*
166 * HMAC_DRBG initialisation (10.1.2.3 + 9.1)
167 */
168int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx,
169 const mbedtls_md_info_t * md_info,
170 int (*f_entropy)(void *, unsigned char *, size_t),
171 void *p_entropy,
172 const unsigned char *custom,
173 size_t len )
174{
175 int ret;
176 size_t entropy_len, md_size;
177
178 if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 )
179 return( ret );
180
181 md_size = mbedtls_md_get_size( md_info );
182
183 /*
184 * Set initial working state.
185 * Use the V memory location, which is currently all 0, to initialize the
186 * MD context with an all-zero key. Then set V to its initial value.
187 */
188 mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size );
189 memset( ctx->V, 0x01, md_size );
190
191 ctx->f_entropy = f_entropy;
192 ctx->p_entropy = p_entropy;
193
194 ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL;
195
196 /*
197 * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by
198 * each hash function, then according to SP800-90A rev1 10.1 table 2,
199 * min_entropy_len (in bits) is security_strength.
200 *
201 * (This also matches the sizes used in the NIST test vectors.)
202 */
203 entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */
204 md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */
205 32; /* better (256+) -> 256 bits */
206
207 /*
208 * For initialisation, use more entropy to emulate a nonce
209 * (Again, matches test vectors.)
210 */
211 ctx->entropy_len = entropy_len * 3 / 2;
212
213 if( ( ret = mbedtls_hmac_drbg_reseed( ctx, custom, len ) ) != 0 )
214 return( ret );
215
216 ctx->entropy_len = entropy_len;
217
218 return( 0 );
219}
220
221/*
222 * Set prediction resistance
223 */
224void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx,
225 int resistance )
226{
227 ctx->prediction_resistance = resistance;
228}
229
230/*
231 * Set entropy length grabbed for reseeds
232 */
233void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len )
234{
235 ctx->entropy_len = len;
236}
237
238/*
239 * Set reseed interval
240 */
241void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, int interval )
242{
243 ctx->reseed_interval = interval;
244}
245
246/*
247 * HMAC_DRBG random function with optional additional data:
248 * 10.1.2.5 (arabic) + 9.3 (Roman)
249 */
250int mbedtls_hmac_drbg_random_with_add( void *p_rng,
251 unsigned char *output, size_t out_len,
252 const unsigned char *additional, size_t add_len )
253{
254 int ret;
255 mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng;
256 size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info );
257 size_t left = out_len;
258 unsigned char *out = output;
259
260 /* II. Check request length */
261 if( out_len > MBEDTLS_HMAC_DRBG_MAX_REQUEST )
262 return( MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG );
263
264 /* III. Check input length */
265 if( add_len > MBEDTLS_HMAC_DRBG_MAX_INPUT )
266 return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG );
267
268 /* 1. (aka VII and IX) Check reseed counter and PR */
269 if( ctx->f_entropy != NULL && /* For no-reseeding instances */
270 ( ctx->prediction_resistance == MBEDTLS_HMAC_DRBG_PR_ON ||
271 ctx->reseed_counter > ctx->reseed_interval ) )
272 {
273 if( ( ret = mbedtls_hmac_drbg_reseed( ctx, additional, add_len ) ) != 0 )
274 return( ret );
275
276 add_len = 0; /* VII.4 */
277 }
278
279 /* 2. Use additional data if any */
280 if( additional != NULL && add_len != 0 )
281 mbedtls_hmac_drbg_update( ctx, additional, add_len );
282
283 /* 3, 4, 5. Generate bytes */
284 while( left != 0 )
285 {
286 size_t use_len = left > md_len ? md_len : left;
287
288 mbedtls_md_hmac_reset( &ctx->md_ctx );
289 mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
290 mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V );
291
292 memcpy( out, ctx->V, use_len );
293 out += use_len;
294 left -= use_len;
295 }
296
297 /* 6. Update */
298 mbedtls_hmac_drbg_update( ctx, additional, add_len );
299
300 /* 7. Update reseed counter */
301 ctx->reseed_counter++;
302
303 /* 8. Done */
304 return( 0 );
305}
306
307/*
308 * HMAC_DRBG random function
309 */
310int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len )
311{
312 int ret;
313 mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng;
314
315#if defined(MBEDTLS_THREADING_C)
316 if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
317 return( ret );
318#endif
319
320 ret = mbedtls_hmac_drbg_random_with_add( ctx, output, out_len, NULL, 0 );
321
322#if defined(MBEDTLS_THREADING_C)
323 if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
324 return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
325#endif
326
327 return( ret );
328}
329
330/*
331 * Free an HMAC_DRBG context
332 */
333void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx )
334{
335 if( ctx == NULL )
336 return;
337
338#if defined(MBEDTLS_THREADING_C)
339 mbedtls_mutex_free( &ctx->mutex );
340#endif
341 mbedtls_md_free( &ctx->md_ctx );
342 mbedtls_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) );
343}
344
345#if defined(MBEDTLS_FS_IO)
346int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path )
347{
348 int ret;
349 FILE *f;
350 unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ];
351
352 if( ( f = fopen( path, "wb" ) ) == NULL )
353 return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR );
354
355 if( ( ret = mbedtls_hmac_drbg_random( ctx, buf, sizeof( buf ) ) ) != 0 )
356 goto exit;
357
358 if( fwrite( buf, 1, sizeof( buf ), f ) != sizeof( buf ) )
359 {
360 ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR;
361 goto exit;
362 }
363
364 ret = 0;
365
366exit:
367 fclose( f );
368 return( ret );
369}
370
371int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path )
372{
373 FILE *f;
374 size_t n;
375 unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ];
376
377 if( ( f = fopen( path, "rb" ) ) == NULL )
378 return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR );
379
380 fseek( f, 0, SEEK_END );
381 n = (size_t) ftell( f );
382 fseek( f, 0, SEEK_SET );
383
384 if( n > MBEDTLS_HMAC_DRBG_MAX_INPUT )
385 {
386 fclose( f );
387 return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG );
388 }
389
390 if( fread( buf, 1, n, f ) != n )
391 {
392 fclose( f );
393 return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR );
394 }
395
396 fclose( f );
397
398 mbedtls_hmac_drbg_update( ctx, buf, n );
399
400 return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) );
401}
402#endif /* MBEDTLS_FS_IO */
403
404
405#if defined(MBEDTLS_SELF_TEST)
406
407#if !defined(MBEDTLS_SHA1_C)
408/* Dummy checkup routine */
409int mbedtls_hmac_drbg_self_test( int verbose )
410{
411
412 if( verbose != 0 )
413 mbedtls_printf( "\n" );
414
415 return( 0 );
416}
417#else
418
419#define OUTPUT_LEN 80
420
421/* From a NIST PR=true test vector */
422static const unsigned char entropy_pr[] = {
423 0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f,
424 0xf7, 0x3e, 0x9c, 0x5b, 0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11,
425 0x48, 0xa5, 0x84, 0xfe, 0x69, 0xab, 0x5a, 0xee, 0x42, 0xaa, 0x4d, 0x42,
426 0x17, 0x60, 0x99, 0xd4, 0x5e, 0x13, 0x97, 0xdc, 0x40, 0x4d, 0x86, 0xa3,
427 0x7b, 0xf5, 0x59, 0x54, 0x75, 0x69, 0x51, 0xe4 };
428static const unsigned char result_pr[OUTPUT_LEN] = {
429 0x9a, 0x00, 0xa2, 0xd0, 0x0e, 0xd5, 0x9b, 0xfe, 0x31, 0xec, 0xb1, 0x39,
430 0x9b, 0x60, 0x81, 0x48, 0xd1, 0x96, 0x9d, 0x25, 0x0d, 0x3c, 0x1e, 0x94,
431 0x10, 0x10, 0x98, 0x12, 0x93, 0x25, 0xca, 0xb8, 0xfc, 0xcc, 0x2d, 0x54,
432 0x73, 0x19, 0x70, 0xc0, 0x10, 0x7a, 0xa4, 0x89, 0x25, 0x19, 0x95, 0x5e,
433 0x4b, 0xc6, 0x00, 0x1d, 0x7f, 0x4e, 0x6a, 0x2b, 0xf8, 0xa3, 0x01, 0xab,
434 0x46, 0x05, 0x5c, 0x09, 0xa6, 0x71, 0x88, 0xf1, 0xa7, 0x40, 0xee, 0xf3,
435 0xe1, 0x5c, 0x02, 0x9b, 0x44, 0xaf, 0x03, 0x44 };
436
437/* From a NIST PR=false test vector */
438static const unsigned char entropy_nopr[] = {
439 0x79, 0x34, 0x9b, 0xbf, 0x7c, 0xdd, 0xa5, 0x79, 0x95, 0x57, 0x86, 0x66,
440 0x21, 0xc9, 0x13, 0x83, 0x11, 0x46, 0x73, 0x3a, 0xbf, 0x8c, 0x35, 0xc8,
441 0xc7, 0x21, 0x5b, 0x5b, 0x96, 0xc4, 0x8e, 0x9b, 0x33, 0x8c, 0x74, 0xe3,
442 0xe9, 0x9d, 0xfe, 0xdf };
443static const unsigned char result_nopr[OUTPUT_LEN] = {
444 0xc6, 0xa1, 0x6a, 0xb8, 0xd4, 0x20, 0x70, 0x6f, 0x0f, 0x34, 0xab, 0x7f,
445 0xec, 0x5a, 0xdc, 0xa9, 0xd8, 0xca, 0x3a, 0x13, 0x3e, 0x15, 0x9c, 0xa6,
446 0xac, 0x43, 0xc6, 0xf8, 0xa2, 0xbe, 0x22, 0x83, 0x4a, 0x4c, 0x0a, 0x0a,
447 0xff, 0xb1, 0x0d, 0x71, 0x94, 0xf1, 0xc1, 0xa5, 0xcf, 0x73, 0x22, 0xec,
448 0x1a, 0xe0, 0x96, 0x4e, 0xd4, 0xbf, 0x12, 0x27, 0x46, 0xe0, 0x87, 0xfd,
449 0xb5, 0xb3, 0xe9, 0x1b, 0x34, 0x93, 0xd5, 0xbb, 0x98, 0xfa, 0xed, 0x49,
450 0xe8, 0x5f, 0x13, 0x0f, 0xc8, 0xa4, 0x59, 0xb7 };
451
452/* "Entropy" from buffer */
453static size_t test_offset;
454static int hmac_drbg_self_test_entropy( void *data,
455 unsigned char *buf, size_t len )
456{
457 const unsigned char *p = data;
458 memcpy( buf, p + test_offset, len );
459 test_offset += len;
460 return( 0 );
461}
462
463#define CHK( c ) if( (c) != 0 ) \
464 { \
465 if( verbose != 0 ) \
466 mbedtls_printf( "failed\n" ); \
467 return( 1 ); \
468 }
469
470/*
471 * Checkup routine for HMAC_DRBG with SHA-1
472 */
473int mbedtls_hmac_drbg_self_test( int verbose )
474{
475 mbedtls_hmac_drbg_context ctx;
476 unsigned char buf[OUTPUT_LEN];
477 const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 );
478
479 mbedtls_hmac_drbg_init( &ctx );
480
481 /*
482 * PR = True
483 */
484 if( verbose != 0 )
485 mbedtls_printf( " HMAC_DRBG (PR = True) : " );
486
487 test_offset = 0;
488 CHK( mbedtls_hmac_drbg_seed( &ctx, md_info,
489 hmac_drbg_self_test_entropy, (void *) entropy_pr,
490 NULL, 0 ) );
491 mbedtls_hmac_drbg_set_prediction_resistance( &ctx, MBEDTLS_HMAC_DRBG_PR_ON );
492 CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
493 CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
494 CHK( memcmp( buf, result_pr, OUTPUT_LEN ) );
495 mbedtls_hmac_drbg_free( &ctx );
496
497 mbedtls_hmac_drbg_free( &ctx );
498
499 if( verbose != 0 )
500 mbedtls_printf( "passed\n" );
501
502 /*
503 * PR = False
504 */
505 if( verbose != 0 )
506 mbedtls_printf( " HMAC_DRBG (PR = False) : " );
507
508 mbedtls_hmac_drbg_init( &ctx );
509
510 test_offset = 0;
511 CHK( mbedtls_hmac_drbg_seed( &ctx, md_info,
512 hmac_drbg_self_test_entropy, (void *) entropy_nopr,
513 NULL, 0 ) );
514 CHK( mbedtls_hmac_drbg_reseed( &ctx, NULL, 0 ) );
515 CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
516 CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) );
517 CHK( memcmp( buf, result_nopr, OUTPUT_LEN ) );
518 mbedtls_hmac_drbg_free( &ctx );
519
520 mbedtls_hmac_drbg_free( &ctx );
521
522 if( verbose != 0 )
523 mbedtls_printf( "passed\n" );
524
525 if( verbose != 0 )
526 mbedtls_printf( "\n" );
527
528 return( 0 );
529}
530#endif /* MBEDTLS_SHA1_C */
531#endif /* MBEDTLS_SELF_TEST */
532
533#endif /* MBEDTLS_HMAC_DRBG_C */
Impressum, Datenschutz