/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 xof = 0; |
55 | |
|
56 | 0 | if (_gcry_md_get_algo_dlen (algo) == 0) |
57 | 0 | xof = 1; |
58 | 0 | else if (_gcry_md_get_algo_dlen (algo) != expectlen) |
59 | 0 | return "digest size does not match expected size"; |
60 | | |
61 | 0 | err = _gcry_md_open (&hd, algo, 0); |
62 | 0 | if (err) |
63 | 0 | return "gcry_md_open failed"; |
64 | | |
65 | 0 | switch (datamode) |
66 | 0 | { |
67 | 0 | case 0: |
68 | 0 | _gcry_md_write (hd, data, datalen); |
69 | 0 | break; |
70 | | |
71 | 0 | case 1: /* Hash one million times an "a". */ |
72 | 0 | { |
73 | 0 | int i; |
74 | | |
75 | | /* Write in odd size chunks so that we test the buffering. */ |
76 | 0 | memset (aaa, 'a', 1000); |
77 | 0 | for (i = 0; i < 1000; i++) |
78 | 0 | _gcry_md_write (hd, aaa, 1000); |
79 | 0 | } |
80 | 0 | break; |
81 | | |
82 | 0 | default: |
83 | 0 | result = "invalid DATAMODE"; |
84 | 0 | } |
85 | | |
86 | 0 | if (!result) |
87 | 0 | { |
88 | 0 | if (!xof) |
89 | 0 | { |
90 | 0 | digest = _gcry_md_read (hd, algo); |
91 | |
|
92 | 0 | if ( memcmp (digest, expect, expectlen) ) |
93 | 0 | result = "digest mismatch"; |
94 | 0 | } |
95 | 0 | else |
96 | 0 | { |
97 | 0 | gcry_assert(expectlen <= sizeof(aaa)); |
98 | | |
99 | 0 | err = _gcry_md_extract (hd, algo, aaa, expectlen); |
100 | 0 | if (err) |
101 | 0 | result = "error extracting output from XOF"; |
102 | 0 | else if ( memcmp (aaa, expect, expectlen) ) |
103 | 0 | result = "digest mismatch"; |
104 | 0 | } |
105 | 0 | } |
106 | | |
107 | 0 | _gcry_md_close (hd); |
108 | |
|
109 | 0 | return result; |
110 | 0 | } |
111 | | |
112 | | |
113 | | /* Common function to write a chunk of data to the transform function |
114 | | of a hash algorithm. Note that the use of the term "block" does |
115 | | not imply a fixed size block. Note that we explicitly allow to use |
116 | | this function after the context has been finalized; the result does |
117 | | not have any meaning but writing after finalize is sometimes |
118 | | helpful to mitigate timing attacks. */ |
119 | | void |
120 | | _gcry_md_block_write (void *context, const void *inbuf_arg, size_t inlen) |
121 | 135k | { |
122 | 135k | const unsigned char *inbuf = inbuf_arg; |
123 | 135k | gcry_md_block_ctx_t *hd = context; |
124 | 135k | unsigned int stack_burn = 0; |
125 | 135k | unsigned int nburn; |
126 | 135k | const unsigned int blocksize_shift = hd->blocksize_shift; |
127 | 135k | const unsigned int blocksize = 1 << blocksize_shift; |
128 | 135k | size_t inblocks; |
129 | 135k | size_t copylen; |
130 | | |
131 | 135k | if (sizeof(hd->buf) < blocksize) |
132 | 0 | BUG(); |
133 | | |
134 | 135k | if (!hd->bwrite) |
135 | 0 | return; |
136 | | |
137 | 135k | if (hd->count > blocksize) |
138 | 0 | { |
139 | | /* This happens only when gcry_md_write is called after final. |
140 | | * Writing after final is used for mitigating timing attacks. */ |
141 | 0 | hd->count = 0; |
142 | 0 | } |
143 | | |
144 | 151k | while (hd->count) |
145 | 18.6k | { |
146 | 18.6k | if (hd->count == blocksize) /* Flush the buffer. */ |
147 | 7.05k | { |
148 | 7.05k | nburn = hd->bwrite (hd, hd->buf, 1); |
149 | 7.05k | stack_burn = nburn > stack_burn ? nburn : stack_burn; |
150 | 7.05k | hd->count = 0; |
151 | 7.05k | if (!++hd->nblocks) |
152 | 0 | hd->nblocks_high++; |
153 | 7.05k | } |
154 | 11.6k | else |
155 | 11.6k | { |
156 | 11.6k | copylen = inlen; |
157 | 11.6k | if (copylen > blocksize - hd->count) |
158 | 6.93k | copylen = blocksize - hd->count; |
159 | | |
160 | 11.6k | if (copylen == 0) |
161 | 2.33k | break; |
162 | | |
163 | 9.26k | buf_cpy (&hd->buf[hd->count], inbuf, copylen); |
164 | 9.26k | hd->count += copylen; |
165 | 9.26k | inbuf += copylen; |
166 | 9.26k | inlen -= copylen; |
167 | 9.26k | } |
168 | 18.6k | } |
169 | | |
170 | 135k | if (inlen == 0) |
171 | 12.2k | return; |
172 | | |
173 | 123k | if (inlen >= blocksize) |
174 | 116k | { |
175 | 116k | inblocks = inlen >> blocksize_shift; |
176 | 116k | nburn = hd->bwrite (hd, inbuf, inblocks); |
177 | 116k | stack_burn = nburn > stack_burn ? nburn : stack_burn; |
178 | 116k | hd->count = 0; |
179 | 116k | hd->nblocks_high += (hd->nblocks + inblocks < inblocks); |
180 | 116k | hd->nblocks += inblocks; |
181 | 116k | inlen -= inblocks << blocksize_shift; |
182 | 116k | inbuf += inblocks << blocksize_shift; |
183 | 116k | } |
184 | | |
185 | 123k | if (inlen) |
186 | 112k | { |
187 | 112k | buf_cpy (hd->buf, inbuf, inlen); |
188 | 112k | hd->count = inlen; |
189 | 112k | } |
190 | | |
191 | 123k | if (stack_burn > 0) |
192 | 8.16k | _gcry_burn_stack (stack_burn); |
193 | 123k | } |