clarify comment
[openssl.git] / fips / rand / fips_drbg_hash.c
1 /* fips/rand/fips_drbg_hash.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 #define OPENSSL_FIPSAPI
55
56 #include <stdlib.h>
57 #include <string.h>
58 #include <openssl/crypto.h>
59 #include <openssl/fips.h>
60 #include <openssl/fips_rand.h>
61 #include "fips_rand_lcl.h"
62
63 /* This is Hash_df from SP 800-90 10.4.1 */
64
65 static int hash_df(DRBG_CTX *dctx, unsigned char *out,
66                         const unsigned char *in1, size_t in1len,
67                         const unsigned char *in2, size_t in2len,
68                         const unsigned char *in3, size_t in3len,
69                         const unsigned char *in4, size_t in4len)
70         {
71         EVP_MD_CTX *mctx = &dctx->d.hash.mctx;
72         unsigned char *vtmp = dctx->d.hash.vtmp;
73         unsigned char tmp[6];
74         /* Standard only ever needs seedlen bytes which is always less than
75          * maximum permitted so no need to check length.
76          */
77         size_t outlen = dctx->seedlen;
78         tmp[0] = 1;
79         tmp[1] = ((outlen * 8) >> 24) & 0xff;
80         tmp[2] = ((outlen * 8) >> 16) & 0xff;
81         tmp[3] = ((outlen * 8) >> 8) & 0xff;
82         tmp[4] = (outlen * 8) & 0xff;
83         if (!in1)
84                 {
85                 tmp[5] = (unsigned char)in1len;
86                 in1 = tmp + 5;
87                 in1len = 1;
88                 }
89         for (;;)
90                 {
91                 if (!FIPS_digestinit(mctx, dctx->d.hash.md))
92                         return 0;
93                 if (!FIPS_digestupdate(mctx, tmp, 5))
94                         return 0;
95                 if (in1 && !FIPS_digestupdate(mctx, in1, in1len))
96                         return 0;
97                 if (in2 && !FIPS_digestupdate(mctx, in2, in2len))
98                         return 0;
99                 if (in3 && !FIPS_digestupdate(mctx, in3, in3len))
100                         return 0;
101                 if (in4 && !FIPS_digestupdate(mctx, in4, in4len))
102                         return 0;
103                 if (outlen < dctx->blocklength)
104                         {
105                         if (!FIPS_digestfinal(mctx, vtmp, NULL))
106                                 return 0;
107                         memcpy(out, vtmp, outlen);
108                         OPENSSL_cleanse(vtmp, dctx->blocklength);
109                         return 1;
110                         }
111                 else if(!FIPS_digestfinal(mctx, out, NULL))
112                         return 0;
113
114                 outlen -= dctx->blocklength;
115                 if (outlen == 0)
116                         return 1;
117                 tmp[0]++;
118                 out += dctx->blocklength;
119                 }
120         }
121
122
123 /* Add an unsigned buffer to the buf value, storing the result in buf. For
124  * this algorithm the length of input never exceeds the seed length.
125  */
126
127 static void ctx_add_buf(DRBG_CTX *dctx, unsigned char *buf,
128                                 unsigned char *in, size_t inlen)
129         {
130         size_t i = inlen;
131         const unsigned char *q;
132         unsigned char c, *p;
133         p = buf + dctx->seedlen;
134         q = in + inlen;
135
136         OPENSSL_assert(i <= dctx->seedlen);
137
138         /* Special case: zero length, just increment buffer */
139         if (i)
140                 c = 0;
141         else 
142                 c = 1;
143
144         while (i)
145                 {
146                 int r;
147                 p--;
148                 q--;
149                 r = *p + *q + c;
150                 /* Carry */
151                 if (r > 0xff)
152                         c = 1;
153                 else
154                         c = 0;
155                 *p = r & 0xff;
156                 i--;
157                 }
158
159         i = dctx->seedlen - inlen;
160
161         /* If not adding whole buffer handle final carries */
162         if (c && i)
163                 {
164                 do
165                         {
166                         p--;
167                         c = *p;
168                         c++;
169                         *p = c;
170                         if(c)
171                                 return;
172                         } while(i--);
173                 }
174         }
175
176 /* Finalise and add hash to V */
177         
178 static int ctx_add_md(DRBG_CTX *dctx)
179         {
180         if (!FIPS_digestfinal(&dctx->d.hash.mctx, dctx->d.hash.vtmp, NULL))
181                         return 0;
182         ctx_add_buf(dctx, dctx->d.hash.V, dctx->d.hash.vtmp, dctx->blocklength);
183         return 1;
184         }
185
186 static int hash_gen(DRBG_CTX *dctx, unsigned char *out, size_t outlen)
187         {
188         DRBG_HASH_CTX *hctx = &dctx->d.hash;
189         if (outlen == 0)
190                 return 1;
191         memcpy(hctx->vtmp, hctx->V, dctx->seedlen);
192         for(;;)
193                 {
194                 FIPS_digestinit(&hctx->mctx, hctx->md);
195                 FIPS_digestupdate(&hctx->mctx, hctx->vtmp, dctx->seedlen);
196                 if (!(dctx->flags & DRBG_FLAG_TEST) && !dctx->lb_valid)
197                         {
198                         FIPS_digestfinal(&hctx->mctx, dctx->lb, NULL);
199                         dctx->lb_valid = 1;
200                         }
201                 else if (outlen < dctx->blocklength)
202                         {
203                         FIPS_digestfinal(&hctx->mctx, hctx->vtmp, NULL);
204                         if (!fips_drbg_cprng_test(dctx, hctx->vtmp))
205                                 return 0;
206                         memcpy(out, hctx->vtmp, outlen);
207                         return 1;
208                         }
209                 else
210                         {
211                         FIPS_digestfinal(&hctx->mctx, out, NULL);
212                         if (!fips_drbg_cprng_test(dctx, out))
213                                 return 0;
214                         outlen -= dctx->blocklength;
215                         if (outlen == 0)
216                                 return 1;
217                         out += dctx->blocklength;
218                         }
219                 ctx_add_buf(dctx, hctx->vtmp, NULL, 0);
220                 }
221         }
222
223 static int drbg_hash_instantiate(DRBG_CTX *dctx,
224                                 const unsigned char *ent, size_t ent_len,
225                                 const unsigned char *nonce, size_t nonce_len,
226                                 const unsigned char *pstr, size_t pstr_len)
227         {
228         DRBG_HASH_CTX *hctx = &dctx->d.hash;
229         if (!hash_df(dctx, hctx->V, 
230                         ent, ent_len, nonce, nonce_len, pstr, pstr_len,
231                         NULL, 0))
232                 return 0;
233         if (!hash_df(dctx, hctx->C, 
234                         NULL, 0, hctx->V, dctx->seedlen,
235                         NULL, 0, NULL, 0))
236                 return 0;
237
238 #ifdef HASH_DRBG_TRACE
239         fprintf(stderr, "V+C after instantiate:\n");
240         hexprint(stderr, hctx->V, dctx->seedlen);
241         hexprint(stderr, hctx->C, dctx->seedlen);
242 #endif
243         return 1;
244         }
245
246         
247 static int drbg_hash_reseed(DRBG_CTX *dctx,
248                                 const unsigned char *ent, size_t ent_len,
249                                 const unsigned char *adin, size_t adin_len)
250         {
251         DRBG_HASH_CTX *hctx = &dctx->d.hash;
252         /* V about to be updated so use C as output instead */
253         if (!hash_df(dctx, hctx->C,
254                         NULL, 1, hctx->V, dctx->seedlen,
255                         ent, ent_len, adin, adin_len))
256                 return 0;
257         memcpy(hctx->V, hctx->C, dctx->seedlen);
258         if (!hash_df(dctx, hctx->C, NULL, 0,
259                         hctx->V, dctx->seedlen, NULL, 0, NULL, 0))
260                 return 0;
261 #ifdef HASH_DRBG_TRACE
262         fprintf(stderr, "V+C after reseed:\n");
263         hexprint(stderr, hctx->V, dctx->seedlen);
264         hexprint(stderr, hctx->C, dctx->seedlen);
265 #endif
266         return 1;
267         }
268
269 static int drbg_hash_generate(DRBG_CTX *dctx,
270                                 unsigned char *out, size_t outlen,
271                                 const unsigned char *adin, size_t adin_len)
272         {
273         DRBG_HASH_CTX *hctx = &dctx->d.hash;
274         EVP_MD_CTX *mctx = &hctx->mctx;
275         unsigned char tmp[4];
276         if (adin && adin_len)
277                 {
278                 tmp[0] = 2;
279                 if (!FIPS_digestinit(mctx, hctx->md))
280                         return 0;
281                 if (!EVP_DigestUpdate(mctx, tmp, 1))
282                         return 0;
283                 if (!EVP_DigestUpdate(mctx, hctx->V, dctx->seedlen))
284                         return 0;
285                 if (!EVP_DigestUpdate(mctx, adin, adin_len))
286                         return 0;
287                 if (!ctx_add_md(dctx))
288                         return 0;
289                 }
290         if (!hash_gen(dctx, out, outlen))
291                 return 0;
292
293         tmp[0] = 3;
294         if (!FIPS_digestinit(mctx, hctx->md))
295                 return 0;
296         if (!EVP_DigestUpdate(mctx, tmp, 1))
297                 return 0;
298         if (!EVP_DigestUpdate(mctx, hctx->V, dctx->seedlen))
299                 return 0;
300
301         if (!ctx_add_md(dctx))
302                 return 0;
303
304         ctx_add_buf(dctx, hctx->V, hctx->C, dctx->seedlen);
305
306         tmp[0] = (dctx->reseed_counter >> 24) & 0xff;
307         tmp[1] = (dctx->reseed_counter >> 16) & 0xff;
308         tmp[2] = (dctx->reseed_counter >> 8) & 0xff;
309         tmp[3] = dctx->reseed_counter & 0xff;
310         ctx_add_buf(dctx, hctx->V, tmp, 4);
311 #ifdef HASH_DRBG_TRACE
312         fprintf(stderr, "V+C after generate:\n");
313         hexprint(stderr, hctx->V, dctx->seedlen);
314         hexprint(stderr, hctx->C, dctx->seedlen);
315 #endif
316         return 1;
317         }
318
319 static int drbg_hash_uninstantiate(DRBG_CTX *dctx)
320         {
321         EVP_MD_CTX_cleanup(&dctx->d.hash.mctx);
322         OPENSSL_cleanse(&dctx->d.hash, sizeof(DRBG_HASH_CTX));
323         return 1;
324         }
325
326 int fips_drbg_hash_init(DRBG_CTX *dctx)
327         {
328         const EVP_MD *md;
329         DRBG_HASH_CTX *hctx = &dctx->d.hash;
330         md = FIPS_get_digestbynid(dctx->type);
331         if (!md)
332                 return -2;
333         switch (dctx->type)
334                 {
335                 case NID_sha1:
336                 dctx->strength = 128;
337                 break;
338
339                 case NID_sha224:
340                 dctx->strength = 192;
341                 break;
342
343                 default:
344                 dctx->strength = 256;
345                 break;
346                 }
347
348         dctx->instantiate = drbg_hash_instantiate;
349         dctx->reseed = drbg_hash_reseed;
350         dctx->generate = drbg_hash_generate;
351         dctx->uninstantiate = drbg_hash_uninstantiate;
352
353         dctx->d.hash.md = md;
354         EVP_MD_CTX_init(&hctx->mctx);
355
356         /* These are taken from SP 800-90 10.1 table 2 */
357
358         dctx->blocklength = M_EVP_MD_size(md);
359         if (dctx->blocklength > 32)
360                 dctx->seedlen = 111;
361         else
362                 dctx->seedlen = 55;
363
364
365         dctx->min_entropy = dctx->strength / 8;
366         dctx->max_entropy = DRBG_MAX_LENGTH;
367
368         dctx->min_nonce = dctx->min_entropy / 2;
369         dctx->max_nonce = DRBG_MAX_LENGTH;
370
371         dctx->max_pers = DRBG_MAX_LENGTH;
372         dctx->max_adin = DRBG_MAX_LENGTH;
373
374         dctx->max_request = 1<<16;
375         dctx->reseed_interval = 1<<24;
376
377         return 1;
378         }