]>
Commit | Line | Data |
---|---|---|
4f22f405 RS |
1 | /* |
2 | * Copyright 2005-2016 The OpenSSL Project Authors. All Rights Reserved. | |
3 | * | |
4 | * Licensed under the OpenSSL license (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
d1593e6b AP |
10 | /** |
11 | * The Whirlpool hashing function. | |
12 | * | |
13 | * <P> | |
14 | * <b>References</b> | |
15 | * | |
16 | * <P> | |
17 | * The Whirlpool algorithm was developed by | |
18 | * <a href="mailto:pbarreto@scopus.com.br">Paulo S. L. M. Barreto</a> and | |
19 | * <a href="mailto:vincent.rijmen@cryptomathic.com">Vincent Rijmen</a>. | |
20 | * | |
21 | * See | |
22 | * P.S.L.M. Barreto, V. Rijmen, | |
23 | * ``The Whirlpool hashing function,'' | |
24 | * NESSIE submission, 2000 (tweaked version, 2001), | |
25 | * <https://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/whirlpool.zip> | |
26 | * | |
27 | * Based on "@version 3.0 (2003.03.12)" by Paulo S.L.M. Barreto and | |
28 | * Vincent Rijmen. Lookup "reference implementations" on | |
29 | * <http://planeta.terra.com.br/informatica/paulobarreto/> | |
30 | * | |
31 | * ============================================================================= | |
32 | * | |
33 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS | |
34 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
35 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
36 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE | |
37 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
38 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
39 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | |
40 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
41 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |
42 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
43 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
44 | * | |
45 | */ | |
46 | ||
47 | /* | |
48 | * OpenSSL-specific implementation notes. | |
49 | * | |
50 | * WHIRLPOOL_Update as well as one-stroke WHIRLPOOL both expect | |
51 | * number of *bytes* as input length argument. Bit-oriented routine | |
52 | * as specified by authors is called WHIRLPOOL_BitUpdate[!] and | |
53 | * does not have one-stroke counterpart. | |
54 | * | |
55 | * WHIRLPOOL_BitUpdate implements byte-oriented loop, essentially | |
56 | * to serve WHIRLPOOL_Update. This is done for performance. | |
57 | * | |
58 | * Unlike authors' reference implementation, block processing | |
59 | * routine whirlpool_block is designed to operate on multi-block | |
0d4fb843 | 60 | * input. This is done for performance. |
d1593e6b AP |
61 | */ |
62 | ||
3ce2fdab | 63 | #include <openssl/crypto.h> |
d1593e6b AP |
64 | #include "wp_locl.h" |
65 | #include <string.h> | |
66 | ||
0f113f3e MC |
67 | int WHIRLPOOL_Init(WHIRLPOOL_CTX *c) |
68 | { | |
69 | memset(c, 0, sizeof(*c)); | |
70 | return (1); | |
71 | } | |
d1593e6b | 72 | |
0f113f3e MC |
73 | int WHIRLPOOL_Update(WHIRLPOOL_CTX *c, const void *_inp, size_t bytes) |
74 | { | |
75 | /* | |
76 | * Well, largest suitable chunk size actually is | |
77 | * (1<<(sizeof(size_t)*8-3))-64, but below number is large enough for not | |
78 | * to care about excessive calls to WHIRLPOOL_BitUpdate... | |
79 | */ | |
80 | size_t chunk = ((size_t)1) << (sizeof(size_t) * 8 - 4); | |
81 | const unsigned char *inp = _inp; | |
d1593e6b | 82 | |
0f113f3e MC |
83 | while (bytes >= chunk) { |
84 | WHIRLPOOL_BitUpdate(c, inp, chunk * 8); | |
85 | bytes -= chunk; | |
86 | inp += chunk; | |
87 | } | |
88 | if (bytes) | |
89 | WHIRLPOOL_BitUpdate(c, inp, bytes * 8); | |
137db78b | 90 | |
0f113f3e MC |
91 | return (1); |
92 | } | |
d1593e6b | 93 | |
0f113f3e MC |
94 | void WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c, const void *_inp, size_t bits) |
95 | { | |
96 | size_t n; | |
97 | unsigned int bitoff = c->bitoff, | |
98 | bitrem = bitoff % 8, inpgap = (8 - (unsigned int)bits % 8) & 7; | |
99 | const unsigned char *inp = _inp; | |
d1593e6b | 100 | |
0f113f3e MC |
101 | /* |
102 | * This 256-bit increment procedure relies on the size_t being natural | |
103 | * size of CPU register, so that we don't have to mask the value in order | |
104 | * to detect overflows. | |
105 | */ | |
106 | c->bitlen[0] += bits; | |
107 | if (c->bitlen[0] < bits) { /* overflow */ | |
108 | n = 1; | |
109 | do { | |
110 | c->bitlen[n]++; | |
111 | } while (c->bitlen[n] == 0 | |
112 | && ++n < (WHIRLPOOL_COUNTER / sizeof(size_t))); | |
113 | } | |
d1593e6b | 114 | #ifndef OPENSSL_SMALL_FOOTPRINT |
0f113f3e MC |
115 | reconsider: |
116 | if (inpgap == 0 && bitrem == 0) { /* byte-oriented loop */ | |
117 | while (bits) { | |
118 | if (bitoff == 0 && (n = bits / WHIRLPOOL_BBLOCK)) { | |
119 | whirlpool_block(c, inp, n); | |
120 | inp += n * WHIRLPOOL_BBLOCK / 8; | |
121 | bits %= WHIRLPOOL_BBLOCK; | |
122 | } else { | |
123 | unsigned int byteoff = bitoff / 8; | |
d1593e6b | 124 | |
0f113f3e MC |
125 | bitrem = WHIRLPOOL_BBLOCK - bitoff; /* re-use bitrem */ |
126 | if (bits >= bitrem) { | |
127 | bits -= bitrem; | |
128 | bitrem /= 8; | |
129 | memcpy(c->data + byteoff, inp, bitrem); | |
130 | inp += bitrem; | |
131 | whirlpool_block(c, c->data, 1); | |
132 | bitoff = 0; | |
133 | } else { | |
134 | memcpy(c->data + byteoff, inp, bits / 8); | |
135 | bitoff += (unsigned int)bits; | |
136 | bits = 0; | |
137 | } | |
138 | c->bitoff = bitoff; | |
139 | } | |
140 | } | |
141 | } else /* bit-oriented loop */ | |
d1593e6b | 142 | #endif |
0f113f3e | 143 | { |
50e735f9 MC |
144 | /*- |
145 | inp | |
146 | | | |
147 | +-------+-------+------- | |
148 | ||||||||||||||||||||| | |
149 | +-------+-------+------- | |
150 | +-------+-------+-------+-------+------- | |
151 | |||||||||||||| c->data | |
152 | +-------+-------+-------+-------+------- | |
153 | | | |
154 | c->bitoff/8 | |
155 | */ | |
0f113f3e MC |
156 | while (bits) { |
157 | unsigned int byteoff = bitoff / 8; | |
158 | unsigned char b; | |
d1593e6b AP |
159 | |
160 | #ifndef OPENSSL_SMALL_FOOTPRINT | |
0f113f3e MC |
161 | if (bitrem == inpgap) { |
162 | c->data[byteoff++] |= inp[0] & (0xff >> inpgap); | |
163 | inpgap = 8 - inpgap; | |
164 | bitoff += inpgap; | |
165 | bitrem = 0; /* bitoff%8 */ | |
166 | bits -= inpgap; | |
167 | inpgap = 0; /* bits%8 */ | |
168 | inp++; | |
169 | if (bitoff == WHIRLPOOL_BBLOCK) { | |
170 | whirlpool_block(c, c->data, 1); | |
171 | bitoff = 0; | |
172 | } | |
173 | c->bitoff = bitoff; | |
174 | goto reconsider; | |
175 | } else | |
d1593e6b | 176 | #endif |
0b20ad12 | 177 | if (bits > 8) { |
0f113f3e MC |
178 | b = ((inp[0] << inpgap) | (inp[1] >> (8 - inpgap))); |
179 | b &= 0xff; | |
180 | if (bitrem) | |
181 | c->data[byteoff++] |= b >> bitrem; | |
182 | else | |
183 | c->data[byteoff++] = b; | |
184 | bitoff += 8; | |
185 | bits -= 8; | |
186 | inp++; | |
187 | if (bitoff >= WHIRLPOOL_BBLOCK) { | |
188 | whirlpool_block(c, c->data, 1); | |
189 | byteoff = 0; | |
190 | bitoff %= WHIRLPOOL_BBLOCK; | |
191 | } | |
192 | if (bitrem) | |
193 | c->data[byteoff] = b << (8 - bitrem); | |
0b20ad12 | 194 | } else { /* remaining less than or equal to 8 bits */ |
0f113f3e MC |
195 | |
196 | b = (inp[0] << inpgap) & 0xff; | |
197 | if (bitrem) | |
198 | c->data[byteoff++] |= b >> bitrem; | |
199 | else | |
200 | c->data[byteoff++] = b; | |
201 | bitoff += (unsigned int)bits; | |
202 | if (bitoff == WHIRLPOOL_BBLOCK) { | |
203 | whirlpool_block(c, c->data, 1); | |
204 | byteoff = 0; | |
205 | bitoff %= WHIRLPOOL_BBLOCK; | |
206 | } | |
207 | if (bitrem) | |
208 | c->data[byteoff] = b << (8 - bitrem); | |
209 | bits = 0; | |
210 | } | |
211 | c->bitoff = bitoff; | |
212 | } | |
213 | } | |
214 | } | |
d1593e6b | 215 | |
0f113f3e MC |
216 | int WHIRLPOOL_Final(unsigned char *md, WHIRLPOOL_CTX *c) |
217 | { | |
218 | unsigned int bitoff = c->bitoff, byteoff = bitoff / 8; | |
219 | size_t i, j, v; | |
220 | unsigned char *p; | |
d1593e6b | 221 | |
0f113f3e MC |
222 | bitoff %= 8; |
223 | if (bitoff) | |
224 | c->data[byteoff] |= 0x80 >> bitoff; | |
225 | else | |
226 | c->data[byteoff] = 0x80; | |
227 | byteoff++; | |
d1593e6b | 228 | |
0f113f3e MC |
229 | /* pad with zeros */ |
230 | if (byteoff > (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) { | |
231 | if (byteoff < WHIRLPOOL_BBLOCK / 8) | |
232 | memset(&c->data[byteoff], 0, WHIRLPOOL_BBLOCK / 8 - byteoff); | |
233 | whirlpool_block(c, c->data, 1); | |
234 | byteoff = 0; | |
235 | } | |
236 | if (byteoff < (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER)) | |
237 | memset(&c->data[byteoff], 0, | |
238 | (WHIRLPOOL_BBLOCK / 8 - WHIRLPOOL_COUNTER) - byteoff); | |
239 | /* smash 256-bit c->bitlen in big-endian order */ | |
240 | p = &c->data[WHIRLPOOL_BBLOCK / 8 - 1]; /* last byte in c->data */ | |
241 | for (i = 0; i < WHIRLPOOL_COUNTER / sizeof(size_t); i++) | |
242 | for (v = c->bitlen[i], j = 0; j < sizeof(size_t); j++, v >>= 8) | |
243 | *p-- = (unsigned char)(v & 0xff); | |
d1593e6b | 244 | |
0f113f3e | 245 | whirlpool_block(c, c->data, 1); |
d1593e6b | 246 | |
0f113f3e MC |
247 | if (md) { |
248 | memcpy(md, c->H.c, WHIRLPOOL_DIGEST_LENGTH); | |
3ce2fdab | 249 | OPENSSL_cleanse(c, sizeof(*c)); |
0f113f3e MC |
250 | return (1); |
251 | } | |
252 | return (0); | |
253 | } | |
d1593e6b | 254 | |
0f113f3e MC |
255 | unsigned char *WHIRLPOOL(const void *inp, size_t bytes, unsigned char *md) |
256 | { | |
257 | WHIRLPOOL_CTX ctx; | |
258 | static unsigned char m[WHIRLPOOL_DIGEST_LENGTH]; | |
d1593e6b | 259 | |
0f113f3e MC |
260 | if (md == NULL) |
261 | md = m; | |
262 | WHIRLPOOL_Init(&ctx); | |
263 | WHIRLPOOL_Update(&ctx, inp, bytes); | |
264 | WHIRLPOOL_Final(md, &ctx); | |
265 | return (md); | |
266 | } |