blob: 6aa1ba565b4538c263a3289f1594d1b9fe08f4fb [file] [log] [blame]
Manuel Pégourié-Gonnard490bdf32014-01-27 14:03:10 +01001/*
2 * HMAC_DRBG implementation (NIST SP 800-90)
3 *
4 * Copyright (C) 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/*
27 * The NIST SP 800-90 DRBGs are described in the following publication.
28 * http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf
29 */
30
31#include "polarssl/config.h"
32
33#if defined(POLARSSL_HMAC_DRBG_C)
34
35#include "polarssl/hmac_drbg.h"
36
37/*
38 * HMAC_DRBG update, using optional additional data
39 */
40void hmac_drbg_update( hmac_drbg_context *ctx,
41 const unsigned char *additional, size_t add_len )
42{
43 size_t md_len = ctx->md_ctx.md_info->size;
44 unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1;
45 unsigned char sep[1];
46
47 for( sep[0] = 0; sep[0] < rounds; sep[0]++ )
48 {
49 md_hmac_starts( &ctx->md_ctx, ctx->K, md_len );
50 md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
51 md_hmac_update( &ctx->md_ctx, sep, 1 );
52 if( rounds == 2 )
53 md_hmac_update( &ctx->md_ctx, additional, add_len );
54 md_hmac_finish( &ctx->md_ctx, ctx->K );
55
56 md_hmac_starts( &ctx->md_ctx, ctx->K, md_len );
57 md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
58 md_hmac_finish( &ctx->md_ctx, ctx->V );
59 }
60}
61
62/*
63 * Simplified HMAC_DRBG initialisation.
64 */
65int hmac_drbg_init( hmac_drbg_context *ctx,
66 const md_info_t * md_info,
67 const unsigned char *data, size_t data_len )
68{
69 int ret;
70
71 memset( ctx, 0, sizeof( hmac_drbg_context ) );
72
73 if( ( ret = md_init_ctx( &ctx->md_ctx, md_info ) ) != 0 )
74 return( ret );
75
76 memset( ctx->V, 0x01, md_info->size );
77 /* ctx->K is already 0 */
78
79 hmac_drbg_update( ctx, data, data_len );
80
81 return( 0 );
82}
83
84/*
85 * Simplified HMAC_DRBG random function
86 */
87int hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len )
88{
89 hmac_drbg_context *ctx = (hmac_drbg_context *) p_rng;
90 size_t md_len = ctx->md_ctx.md_info->size;
91 size_t left = out_len;
92 unsigned char *out = output;
93
94 while( left != 0 )
95 {
96 size_t use_len = left > md_len ? md_len : left;
97
98 md_hmac_starts( &ctx->md_ctx, ctx->K, md_len );
99 md_hmac_update( &ctx->md_ctx, ctx->V, md_len );
100 md_hmac_finish( &ctx->md_ctx, ctx->V );
101
102 memcpy( out, ctx->V, use_len );
103 out += use_len;
104 left -= use_len;
105 }
106
107 hmac_drbg_update( ctx, NULL, 0 );
108
109 return( 0 );
110}
111
112/*
113 * Free an HMAC_DRBG context
114 */
115void hmac_drbg_free( hmac_drbg_context *ctx )
116{
117 if( ctx == NULL )
118 return;
119
120 md_free_ctx( &ctx->md_ctx );
121
122 memset( ctx, 0, sizeof( hmac_drbg_context ) );
123}
124
125
126#if defined(POLARSSL_SELF_TEST)
127
128#include <stdio.h>
129
130/*
131 * Checkup routine
132 */
133int hmac_drbg_self_test( int verbose )
134{
135
136 if( verbose != 0 )
137 printf( "\n" );
138
139 return( 0 );
140}
141#endif /* POLARSSL_SELF_TEST */
142
143#endif /* POLARSSL_HMAC_DRBG_C */