clarify comment
[openssl.git] / fips / rand / fips_drbg_hmac.c
1 /* fips/rand/fips_drbg_hmac.c */
2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3  * project.
4  */
5 /* ====================================================================
6  * Copyright (c) 2011 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer. 
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  */
53
54 #include <stdlib.h>
55 #include <string.h>
56 #include <openssl/crypto.h>
57 #include <openssl/evp.h>
58 #include <openssl/hmac.h>
59 #include <openssl/aes.h>
60 #include <openssl/fips.h>
61 #include <openssl/fips_rand.h>
62 #include "fips_rand_lcl.h"
63
64 static int drbg_hmac_update(DRBG_CTX *dctx,
65                                 const unsigned char *in1, size_t in1len,
66                                 const unsigned char *in2, size_t in2len,
67                                 const unsigned char *in3, size_t in3len
68                         )
69         {
70         static unsigned char c0 = 0, c1 = 1;
71         DRBG_HMAC_CTX *hmac = &dctx->d.hmac;
72         HMAC_CTX *hctx = &hmac->hctx;
73
74         if (!HMAC_Init_ex(hctx, hmac->K, dctx->blocklength, hmac->md, NULL))
75                 return 0;
76         if (!HMAC_Update(hctx, hmac->V, dctx->blocklength))
77                 return 0;
78         if (!HMAC_Update(hctx, &c0, 1))
79                 return 0;
80         if (in1len && !HMAC_Update(hctx, in1, in1len))
81                 return 0;
82         if (in2len && !HMAC_Update(hctx, in2, in2len))
83                 return 0;
84         if (in3len && !HMAC_Update(hctx, in3, in3len))
85                 return 0;
86
87         if (!HMAC_Final(hctx, hmac->K, NULL))
88                 return 0;
89
90         if (!HMAC_Init_ex(hctx, hmac->K, dctx->blocklength, hmac->md, NULL))
91                 return 0;
92         if (!HMAC_Update(hctx, hmac->V, dctx->blocklength))
93                 return 0;
94
95         if (!HMAC_Final(hctx, hmac->V, NULL))
96                 return 0;
97
98         if (!in1len && !in2len && !in3len)
99                 return 1;
100
101         if (!HMAC_Init_ex(hctx, hmac->K, dctx->blocklength, hmac->md, NULL))
102                 return 0;
103         if (!HMAC_Update(hctx, hmac->V, dctx->blocklength))
104                 return 0;
105         if (!HMAC_Update(hctx, &c1, 1))
106                 return 0;
107         if (in1len && !HMAC_Update(hctx, in1, in1len))
108                 return 0;
109         if (in2len && !HMAC_Update(hctx, in2, in2len))
110                 return 0;
111         if (in3len && !HMAC_Update(hctx, in3, in3len))
112                 return 0;
113
114         if (!HMAC_Final(hctx, hmac->K, NULL))
115                 return 0;
116
117         if (!HMAC_Init_ex(hctx, hmac->K, dctx->blocklength, hmac->md, NULL))
118                 return 0;
119         if (!HMAC_Update(hctx, hmac->V, dctx->blocklength))
120                 return 0;
121
122         if (!HMAC_Final(hctx, hmac->V, NULL))
123                 return 0;
124
125         return 1;
126
127         }
128
129 static int drbg_hmac_instantiate(DRBG_CTX *dctx,
130                                 const unsigned char *ent, size_t ent_len,
131                                 const unsigned char *nonce, size_t nonce_len,
132                                 const unsigned char *pstr, size_t pstr_len)
133         {
134         DRBG_HMAC_CTX *hmac = &dctx->d.hmac;
135         memset(hmac->K, 0, dctx->blocklength);
136         memset(hmac->V, 1, dctx->blocklength);
137         if (!drbg_hmac_update(dctx,
138                         ent, ent_len, nonce, nonce_len, pstr, pstr_len))
139                 return 0;
140
141 #ifdef HMAC_DRBG_TRACE
142         fprintf(stderr, "K+V after instantiate:\n");
143         hexprint(stderr, hmac->K, hmac->blocklength);
144         hexprint(stderr, hmac->V, hmac->blocklength);
145 #endif
146         return 1;
147         }
148
149 static int drbg_hmac_reseed(DRBG_CTX *dctx,
150                                 const unsigned char *ent, size_t ent_len,
151                                 const unsigned char *adin, size_t adin_len)
152         {
153         if (!drbg_hmac_update(dctx,
154                         ent, ent_len, adin, adin_len, NULL, 0))
155                 return 0;
156
157 #ifdef HMAC_DRBG_TRACE
158         {
159                 DRBG_HMAC_CTX *hmac = &dctx->d.hmac;
160                 fprintf(stderr, "K+V after reseed:\n");
161                 hexprint(stderr, hmac->K, hmac->blocklength);
162                 hexprint(stderr, hmac->V, hmac->blocklength);
163         }
164 #endif
165         return 1;
166         }
167
168 static int drbg_hmac_generate(DRBG_CTX *dctx,
169                                 unsigned char *out, size_t outlen,
170                                 const unsigned char *adin, size_t adin_len)
171         {
172         DRBG_HMAC_CTX *hmac = &dctx->d.hmac;
173         HMAC_CTX *hctx = &hmac->hctx;
174         const unsigned char *Vtmp = hmac->V;
175         if (adin_len && !drbg_hmac_update(dctx, adin, adin_len,
176                                                 NULL, 0, NULL, 0))
177                 return 0;
178         for (;;)
179                 {
180                 if (!HMAC_Init_ex(hctx, hmac->K, dctx->blocklength,
181                                                         hmac->md, NULL))
182                         return 0;
183                 if (!HMAC_Update(hctx, Vtmp, dctx->blocklength))
184                         return 0;
185                 if (!(dctx->flags & DRBG_FLAG_TEST) && !dctx->lb_valid)
186                         {
187                         if (!HMAC_Final(hctx, dctx->lb, NULL))
188                                 return 0;
189                         dctx->lb_valid = 1;
190                         Vtmp = dctx->lb;
191                         continue;
192                         }
193                 else if (outlen > dctx->blocklength)
194                         {
195                         if (!HMAC_Final(hctx, out, NULL))
196                                 return 0;
197                         if (!fips_drbg_cprng_test(dctx, out))
198                                 return 0;
199                         Vtmp = out;
200                         }
201                 else
202                         {
203                         if (!HMAC_Final(hctx, hmac->V, NULL))
204                                 return 0;
205                         if (!fips_drbg_cprng_test(dctx, hmac->V))
206                                 return 0;
207                         memcpy(out, hmac->V, outlen);
208                         break;
209                         }
210                 out += dctx->blocklength;
211                 outlen -= dctx->blocklength;
212                 }
213         if (!drbg_hmac_update(dctx, adin, adin_len, NULL, 0, NULL, 0))
214                 return 0;
215
216         return 1;
217         }
218
219 static int drbg_hmac_uninstantiate(DRBG_CTX *dctx)
220         {
221         HMAC_CTX_cleanup(&dctx->d.hmac.hctx);
222         OPENSSL_cleanse(&dctx->d.hmac, sizeof(DRBG_HMAC_CTX));
223         return 1;
224         }
225
226 int fips_drbg_hmac_init(DRBG_CTX *dctx)
227         {
228         const EVP_MD *md = NULL;
229         DRBG_HMAC_CTX *hctx = &dctx->d.hmac;
230         dctx->strength = 256;
231         switch (dctx->type)
232                 {
233                 case NID_hmacWithSHA1:
234                 md = EVP_sha1();
235                 dctx->strength = 128;
236                 break;
237
238                 case NID_hmacWithSHA224:
239                 md = EVP_sha224();
240                 dctx->strength = 192;
241                 break;
242
243                 case NID_hmacWithSHA256:
244                 md = EVP_sha256();
245                 break;
246
247                 case NID_hmacWithSHA384:
248                 md = EVP_sha384();
249                 break;
250
251                 case NID_hmacWithSHA512:
252                 md = EVP_sha512();
253                 break;
254
255                 default:
256                 dctx->strength = 0;
257                 return -2;
258                 }
259         dctx->instantiate = drbg_hmac_instantiate;
260         dctx->reseed = drbg_hmac_reseed;
261         dctx->generate = drbg_hmac_generate;
262         dctx->uninstantiate = drbg_hmac_uninstantiate;
263         HMAC_CTX_init(&hctx->hctx);
264         hctx->md = md;
265         dctx->blocklength = M_EVP_MD_size(md);
266         dctx->seedlen = M_EVP_MD_size(md);
267
268         dctx->min_entropy = dctx->strength / 8;
269         dctx->max_entropy = DRBG_MAX_LENGTH;
270
271         dctx->min_nonce = dctx->min_entropy / 2;
272         dctx->max_nonce = DRBG_MAX_LENGTH;
273
274         dctx->max_pers = DRBG_MAX_LENGTH;
275         dctx->max_adin = DRBG_MAX_LENGTH;
276
277         dctx->max_request = 1<<16;
278         dctx->reseed_interval = 1<<24;
279
280         return 1;
281         }