Keccak: Add SHAKE Extendable-Output Functions
[libgcrypt.git] / cipher / hash-common.c
1 /* hash-common.c - Common code for hash algorithms
2  * Copyright (C) 2008 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #ifdef HAVE_STDINT_H
25 # include <stdint.h>
26 #endif
27
28 #include "g10lib.h"
29 #include "hash-common.h"
30
31
32 /* Run a selftest for hash algorithm ALGO.  If the resulting digest
33    matches EXPECT/EXPECTLEN and everything else is fine as well,
34    return NULL.  If an error occurs, return a static text string
35    describing the error.
36
37    DATAMODE controls what will be hashed according to this table:
38
39      0 - Hash the supplied DATA of DATALEN.
40      1 - Hash one million times a 'a'.  DATA and DATALEN are ignored.
41
42 */
43 const char *
44 _gcry_hash_selftest_check_one (int algo,
45                                int datamode, const void *data, size_t datalen,
46                                const void *expect, size_t expectlen)
47 {
48   const char *result = NULL;
49   gcry_error_t err = 0;
50   gcry_md_hd_t hd;
51   unsigned char *digest;
52   char aaa[1000];
53   int xof = 0;
54
55   if (_gcry_md_get_algo_dlen (algo) == 0)
56     xof = 1;
57   else if (_gcry_md_get_algo_dlen (algo) != expectlen)
58     return "digest size does not match expected size";
59
60   err = _gcry_md_open (&hd, algo, 0);
61   if (err)
62     return "gcry_md_open failed";
63
64   switch (datamode)
65     {
66     case 0:
67       _gcry_md_write (hd, data, datalen);
68       break;
69
70     case 1: /* Hash one million times an "a". */
71       {
72         int i;
73
74         /* Write in odd size chunks so that we test the buffering.  */
75         memset (aaa, 'a', 1000);
76         for (i = 0; i < 1000; i++)
77           _gcry_md_write (hd, aaa, 1000);
78       }
79       break;
80
81     default:
82       result = "invalid DATAMODE";
83     }
84
85   if (!result)
86     {
87       if (!xof)
88         {
89           digest = _gcry_md_read (hd, algo);
90
91           if ( memcmp (digest, expect, expectlen) )
92             result = "digest mismatch";
93         }
94       else
95         {
96           gcry_assert(expectlen <= sizeof(aaa));
97
98           err = _gcry_md_extract (hd, algo, aaa, expectlen);
99           if (err)
100             result = "error extracting output from XOF";
101           else if ( memcmp (aaa, expect, expectlen) )
102             result = "digest mismatch";
103         }
104     }
105
106   _gcry_md_close (hd);
107
108   return result;
109 }
110
111
112 /* Common function to write a chunk of data to the transform function
113    of a hash algorithm.  Note that the use of the term "block" does
114    not imply a fixed size block.  Note that we explicitly allow to use
115    this function after the context has been finalized; the result does
116    not have any meaning but writing after finalize is sometimes
117    helpful to mitigate timing attacks. */
118 void
119 _gcry_md_block_write (void *context, const void *inbuf_arg, size_t inlen)
120 {
121   const unsigned char *inbuf = inbuf_arg;
122   gcry_md_block_ctx_t *hd = context;
123   unsigned int stack_burn = 0;
124   const unsigned int blocksize = hd->blocksize;
125   size_t inblocks;
126
127   if (sizeof(hd->buf) < blocksize)
128     BUG();
129
130   if (!hd->bwrite)
131     return;
132
133   if (hd->count == blocksize)  /* Flush the buffer. */
134     {
135       stack_burn = hd->bwrite (hd, hd->buf, 1);
136       _gcry_burn_stack (stack_burn);
137       stack_burn = 0;
138       hd->count = 0;
139       if (!++hd->nblocks)
140         hd->nblocks_high++;
141     }
142   if (!inbuf)
143     return;
144
145   if (hd->count)
146     {
147       for (; inlen && hd->count < blocksize; inlen--)
148         hd->buf[hd->count++] = *inbuf++;
149       _gcry_md_block_write (hd, NULL, 0);
150       if (!inlen)
151         return;
152     }
153
154   if (inlen >= blocksize)
155     {
156       inblocks = inlen / blocksize;
157       stack_burn = hd->bwrite (hd, inbuf, inblocks);
158       hd->count = 0;
159       hd->nblocks_high += (hd->nblocks + inblocks < inblocks);
160       hd->nblocks += inblocks;
161       inlen -= inblocks * blocksize;
162       inbuf += inblocks * blocksize;
163     }
164   _gcry_burn_stack (stack_burn);
165   for (; inlen && hd->count < blocksize; inlen--)
166     hd->buf[hd->count++] = *inbuf++;
167 }