/src/libgcrypt/cipher/hash-common.c
Line | Count | Source (jump to first uncovered line) |
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 "bufhelp.h" |
30 | | #include "hash-common.h" |
31 | | |
32 | | |
33 | | /* Run a selftest for hash algorithm ALGO. If the resulting digest |
34 | | matches EXPECT/EXPECTLEN and everything else is fine as well, |
35 | | return NULL. If an error occurs, return a static text string |
36 | | describing the error. |
37 | | |
38 | | DATAMODE controls what will be hashed according to this table: |
39 | | |
40 | | 0 - Hash the supplied DATA of DATALEN. |
41 | | 1 - Hash one million times a 'a'. DATA and DATALEN are ignored. |
42 | | |
43 | | */ |
44 | | const char * |
45 | | _gcry_hash_selftest_check_one (int algo, |
46 | | int datamode, const void *data, size_t datalen, |
47 | | const void *expect, size_t expectlen) |
48 | 0 | { |
49 | 0 | const char *result = NULL; |
50 | 0 | gcry_error_t err = 0; |
51 | 0 | gcry_md_hd_t hd; |
52 | 0 | unsigned char *digest; |
53 | 0 | char aaa[1000]; |
54 | 0 | int expect_xof = 0; |
55 | |
|
56 | 0 | if (_gcry_md_get_algo_dlen (algo) != expectlen) |
57 | 0 | expect_xof = 1; |
58 | |
|
59 | 0 | err = _gcry_md_open (&hd, algo, 0); |
60 | 0 | if (err) |
61 | 0 | return "gcry_md_open failed"; |
62 | | |
63 | 0 | switch (datamode) |
64 | 0 | { |
65 | 0 | case 0: |
66 | 0 | _gcry_md_write (hd, data, datalen); |
67 | 0 | break; |
68 | | |
69 | 0 | case 1: /* Hash one million times an "a". */ |
70 | 0 | { |
71 | 0 | int i; |
72 | | |
73 | | /* Write in odd size chunks so that we test the buffering. */ |
74 | 0 | memset (aaa, 'a', 1000); |
75 | 0 | for (i = 0; i < 1000; i++) |
76 | 0 | _gcry_md_write (hd, aaa, 1000); |
77 | 0 | } |
78 | 0 | break; |
79 | | |
80 | 0 | default: |
81 | 0 | result = "invalid DATAMODE"; |
82 | 0 | } |
83 | | |
84 | 0 | if (!result) |
85 | 0 | { |
86 | 0 | if (!expect_xof) |
87 | 0 | { |
88 | 0 | digest = _gcry_md_read (hd, algo); |
89 | |
|
90 | 0 | if ( memcmp (digest, expect, expectlen) ) |
91 | 0 | result = "digest mismatch"; |
92 | 0 | } |
93 | 0 | else |
94 | 0 | { |
95 | 0 | gcry_assert(expectlen <= sizeof(aaa)); |
96 | | |
97 | 0 | err = _gcry_md_extract (hd, algo, aaa, expectlen); |
98 | 0 | if (err) |
99 | 0 | result = "error extracting output from XOF"; |
100 | 0 | else if ( memcmp (aaa, expect, expectlen) ) |
101 | 0 | result = "digest mismatch"; |
102 | 0 | } |
103 | 0 | } |
104 | | |
105 | 0 | _gcry_md_close (hd); |
106 | |
|
107 | 0 | return result; |
108 | 0 | } |
109 | | |
110 | | |
111 | | /* Common function to write a chunk of data to the transform function |
112 | | of a hash algorithm. Note that the use of the term "block" does |
113 | | not imply a fixed size block. Note that we explicitly allow to use |
114 | | this function after the context has been finalized; the result does |
115 | | not have any meaning but writing after finalize is sometimes |
116 | | helpful to mitigate timing attacks. */ |
117 | | void |
118 | | _gcry_md_block_write (void *context, const void *inbuf_arg, size_t inlen) |
119 | 707k | { |
120 | 707k | const unsigned char *inbuf = inbuf_arg; |
121 | 707k | gcry_md_block_ctx_t *hd = context; |
122 | 707k | unsigned int stack_burn = 0; |
123 | 707k | unsigned int nburn; |
124 | 707k | const unsigned int blocksize_shift = hd->blocksize_shift; |
125 | 707k | const unsigned int blocksize = 1 << blocksize_shift; |
126 | 707k | size_t inblocks; |
127 | 707k | size_t copylen; |
128 | | |
129 | 707k | if (sizeof(hd->buf) < blocksize) |
130 | 0 | BUG(); |
131 | | |
132 | 707k | if (!hd->bwrite) |
133 | 0 | return; |
134 | | |
135 | 707k | if (hd->count > blocksize) |
136 | 0 | { |
137 | | /* This happens only when gcry_md_write is called after final. |
138 | | * Writing after final is used for mitigating timing attacks. */ |
139 | 0 | hd->count = 0; |
140 | 0 | } |
141 | | |
142 | 854k | while (hd->count) |
143 | 592k | { |
144 | 592k | if (hd->count == blocksize) /* Flush the buffer. */ |
145 | 53.8k | { |
146 | 53.8k | nburn = hd->bwrite (hd, hd->buf, 1); |
147 | 53.8k | stack_burn = nburn > stack_burn ? nburn : stack_burn; |
148 | 53.8k | hd->count = 0; |
149 | 53.8k | if (!++hd->nblocks) |
150 | 0 | hd->nblocks_high++; |
151 | 53.8k | } |
152 | 538k | else |
153 | 538k | { |
154 | 538k | copylen = inlen; |
155 | 538k | if (copylen > blocksize - hd->count) |
156 | 36.9k | copylen = blocksize - hd->count; |
157 | | |
158 | 538k | if (copylen == 0) |
159 | 445k | break; |
160 | | |
161 | 93.2k | buf_cpy (&hd->buf[hd->count], inbuf, copylen); |
162 | 93.2k | hd->count += copylen; |
163 | 93.2k | inbuf += copylen; |
164 | 93.2k | inlen -= copylen; |
165 | 93.2k | } |
166 | 592k | } |
167 | | |
168 | 707k | if (inlen == 0) |
169 | 471k | return; |
170 | | |
171 | 235k | if (inlen >= blocksize) |
172 | 92.0k | { |
173 | 92.0k | inblocks = inlen >> blocksize_shift; |
174 | 92.0k | nburn = hd->bwrite (hd, inbuf, inblocks); |
175 | 92.0k | stack_burn = nburn > stack_burn ? nburn : stack_burn; |
176 | 92.0k | hd->count = 0; |
177 | 92.0k | hd->nblocks_high += (hd->nblocks + inblocks < inblocks); |
178 | 92.0k | hd->nblocks += inblocks; |
179 | 92.0k | inlen -= inblocks << blocksize_shift; |
180 | 92.0k | inbuf += inblocks << blocksize_shift; |
181 | 92.0k | } |
182 | | |
183 | 235k | if (inlen) |
184 | 207k | { |
185 | 207k | buf_cpy (hd->buf, inbuf, inlen); |
186 | 207k | hd->count = inlen; |
187 | 207k | } |
188 | | |
189 | 235k | if (stack_burn > 0) |
190 | 51.7k | _gcry_burn_stack (stack_burn); |
191 | 235k | } |