1 | /* |
2 | +----------------------------------------------------------------------+ |
3 | | PHP Version 5 | |
4 | +----------------------------------------------------------------------+ |
5 | | Copyright (c) 1997-2015 The PHP Group | |
6 | +----------------------------------------------------------------------+ |
7 | | This source file is subject to version 3.01 of the PHP license, | |
8 | | that is bundled with this package in the file LICENSE, and is | |
9 | | available through the world-wide-web at the following url: | |
10 | | http://www.php.net/license/3_01.txt | |
11 | | If you did not receive a copy of the PHP license and are unable to | |
12 | | obtain it through the world-wide-web, please send a note to | |
13 | | license@php.net so we can mail you a copy immediately. | |
14 | +----------------------------------------------------------------------+ |
15 | | Authors: Michael Wallner <mike@php.net> | |
16 | | Sara Golemon <pollita@php.net> | |
17 | +----------------------------------------------------------------------+ |
18 | */ |
19 | |
20 | /* $Id$ */ |
21 | |
22 | #include "php_hash.h" |
23 | |
24 | /* |
25 | * TODO: simplify Update and Final, those look ridiculously complex |
26 | * Mike, 2005-11-23 |
27 | */ |
28 | |
29 | #include "php_hash_whirlpool.h" |
30 | #include "php_hash_whirlpool_tables.h" |
31 | |
32 | #define DIGESTBYTES 64 |
33 | #define DIGESTBITS (8*DIGESTBYTES) /* 512 */ |
34 | |
35 | #define WBLOCKBYTES 64 |
36 | #define WBLOCKBITS (8*WBLOCKBYTES) /* 512 */ |
37 | |
38 | #define LENGTHBYTES 32 |
39 | #define LENGTHBITS (8*LENGTHBYTES) /* 256 */ |
40 | |
41 | static void WhirlpoolTransform(PHP_WHIRLPOOL_CTX *context) |
42 | { |
43 | int i, r; |
44 | php_hash_uint64 K[8]; /* the round key */ |
45 | php_hash_uint64 block[8]; /* mu(buffer) */ |
46 | php_hash_uint64 state[8]; /* the cipher state */ |
47 | php_hash_uint64 L[8]; |
48 | unsigned char *buffer = context->buffer.data; |
49 | |
50 | /* |
51 | * map the buffer to a block: |
52 | */ |
53 | for (i = 0; i < 8; i++, buffer += 8) { |
54 | block[i] = |
55 | (((php_hash_uint64)buffer[0] ) << 56) ^ |
56 | (((php_hash_uint64)buffer[1] & 0xffL) << 48) ^ |
57 | (((php_hash_uint64)buffer[2] & 0xffL) << 40) ^ |
58 | (((php_hash_uint64)buffer[3] & 0xffL) << 32) ^ |
59 | (((php_hash_uint64)buffer[4] & 0xffL) << 24) ^ |
60 | (((php_hash_uint64)buffer[5] & 0xffL) << 16) ^ |
61 | (((php_hash_uint64)buffer[6] & 0xffL) << 8) ^ |
62 | (((php_hash_uint64)buffer[7] & 0xffL) ); |
63 | } |
64 | /* |
65 | * compute and apply K^0 to the cipher state: |
66 | */ |
67 | state[0] = block[0] ^ (K[0] = context->state[0]); |
68 | state[1] = block[1] ^ (K[1] = context->state[1]); |
69 | state[2] = block[2] ^ (K[2] = context->state[2]); |
70 | state[3] = block[3] ^ (K[3] = context->state[3]); |
71 | state[4] = block[4] ^ (K[4] = context->state[4]); |
72 | state[5] = block[5] ^ (K[5] = context->state[5]); |
73 | state[6] = block[6] ^ (K[6] = context->state[6]); |
74 | state[7] = block[7] ^ (K[7] = context->state[7]); |
75 | /* |
76 | * iterate over all rounds: |
77 | */ |
78 | for (r = 1; r <= R; r++) { |
79 | /* |
80 | * compute K^r from K^{r-1}: |
81 | */ |
82 | L[0] = |
83 | C0[(int)(K[0] >> 56) ] ^ |
84 | C1[(int)(K[7] >> 48) & 0xff] ^ |
85 | C2[(int)(K[6] >> 40) & 0xff] ^ |
86 | C3[(int)(K[5] >> 32) & 0xff] ^ |
87 | C4[(int)(K[4] >> 24) & 0xff] ^ |
88 | C5[(int)(K[3] >> 16) & 0xff] ^ |
89 | C6[(int)(K[2] >> 8) & 0xff] ^ |
90 | C7[(int)(K[1] ) & 0xff] ^ |
91 | rc[r]; |
92 | L[1] = |
93 | C0[(int)(K[1] >> 56) ] ^ |
94 | C1[(int)(K[0] >> 48) & 0xff] ^ |
95 | C2[(int)(K[7] >> 40) & 0xff] ^ |
96 | C3[(int)(K[6] >> 32) & 0xff] ^ |
97 | C4[(int)(K[5] >> 24) & 0xff] ^ |
98 | C5[(int)(K[4] >> 16) & 0xff] ^ |
99 | C6[(int)(K[3] >> 8) & 0xff] ^ |
100 | C7[(int)(K[2] ) & 0xff]; |
101 | L[2] = |
102 | C0[(int)(K[2] >> 56) ] ^ |
103 | C1[(int)(K[1] >> 48) & 0xff] ^ |
104 | C2[(int)(K[0] >> 40) & 0xff] ^ |
105 | C3[(int)(K[7] >> 32) & 0xff] ^ |
106 | C4[(int)(K[6] >> 24) & 0xff] ^ |
107 | C5[(int)(K[5] >> 16) & 0xff] ^ |
108 | C6[(int)(K[4] >> 8) & 0xff] ^ |
109 | C7[(int)(K[3] ) & 0xff]; |
110 | L[3] = |
111 | C0[(int)(K[3] >> 56) ] ^ |
112 | C1[(int)(K[2] >> 48) & 0xff] ^ |
113 | C2[(int)(K[1] >> 40) & 0xff] ^ |
114 | C3[(int)(K[0] >> 32) & 0xff] ^ |
115 | C4[(int)(K[7] >> 24) & 0xff] ^ |
116 | C5[(int)(K[6] >> 16) & 0xff] ^ |
117 | C6[(int)(K[5] >> 8) & 0xff] ^ |
118 | C7[(int)(K[4] ) & 0xff]; |
119 | L[4] = |
120 | C0[(int)(K[4] >> 56) ] ^ |
121 | C1[(int)(K[3] >> 48) & 0xff] ^ |
122 | C2[(int)(K[2] >> 40) & 0xff] ^ |
123 | C3[(int)(K[1] >> 32) & 0xff] ^ |
124 | C4[(int)(K[0] >> 24) & 0xff] ^ |
125 | C5[(int)(K[7] >> 16) & 0xff] ^ |
126 | C6[(int)(K[6] >> 8) & 0xff] ^ |
127 | C7[(int)(K[5] ) & 0xff]; |
128 | L[5] = |
129 | C0[(int)(K[5] >> 56) ] ^ |
130 | C1[(int)(K[4] >> 48) & 0xff] ^ |
131 | C2[(int)(K[3] >> 40) & 0xff] ^ |
132 | C3[(int)(K[2] >> 32) & 0xff] ^ |
133 | C4[(int)(K[1] >> 24) & 0xff] ^ |
134 | C5[(int)(K[0] >> 16) & 0xff] ^ |
135 | C6[(int)(K[7] >> 8) & 0xff] ^ |
136 | C7[(int)(K[6] ) & 0xff]; |
137 | L[6] = |
138 | C0[(int)(K[6] >> 56) ] ^ |
139 | C1[(int)(K[5] >> 48) & 0xff] ^ |
140 | C2[(int)(K[4] >> 40) & 0xff] ^ |
141 | C3[(int)(K[3] >> 32) & 0xff] ^ |
142 | C4[(int)(K[2] >> 24) & 0xff] ^ |
143 | C5[(int)(K[1] >> 16) & 0xff] ^ |
144 | C6[(int)(K[0] >> 8) & 0xff] ^ |
145 | C7[(int)(K[7] ) & 0xff]; |
146 | L[7] = |
147 | C0[(int)(K[7] >> 56) ] ^ |
148 | C1[(int)(K[6] >> 48) & 0xff] ^ |
149 | C2[(int)(K[5] >> 40) & 0xff] ^ |
150 | C3[(int)(K[4] >> 32) & 0xff] ^ |
151 | C4[(int)(K[3] >> 24) & 0xff] ^ |
152 | C5[(int)(K[2] >> 16) & 0xff] ^ |
153 | C6[(int)(K[1] >> 8) & 0xff] ^ |
154 | C7[(int)(K[0] ) & 0xff]; |
155 | K[0] = L[0]; |
156 | K[1] = L[1]; |
157 | K[2] = L[2]; |
158 | K[3] = L[3]; |
159 | K[4] = L[4]; |
160 | K[5] = L[5]; |
161 | K[6] = L[6]; |
162 | K[7] = L[7]; |
163 | /* |
164 | * apply the r-th round transformation: |
165 | */ |
166 | L[0] = |
167 | C0[(int)(state[0] >> 56) ] ^ |
168 | C1[(int)(state[7] >> 48) & 0xff] ^ |
169 | C2[(int)(state[6] >> 40) & 0xff] ^ |
170 | C3[(int)(state[5] >> 32) & 0xff] ^ |
171 | C4[(int)(state[4] >> 24) & 0xff] ^ |
172 | C5[(int)(state[3] >> 16) & 0xff] ^ |
173 | C6[(int)(state[2] >> 8) & 0xff] ^ |
174 | C7[(int)(state[1] ) & 0xff] ^ |
175 | K[0]; |
176 | L[1] = |
177 | C0[(int)(state[1] >> 56) ] ^ |
178 | C1[(int)(state[0] >> 48) & 0xff] ^ |
179 | C2[(int)(state[7] >> 40) & 0xff] ^ |
180 | C3[(int)(state[6] >> 32) & 0xff] ^ |
181 | C4[(int)(state[5] >> 24) & 0xff] ^ |
182 | C5[(int)(state[4] >> 16) & 0xff] ^ |
183 | C6[(int)(state[3] >> 8) & 0xff] ^ |
184 | C7[(int)(state[2] ) & 0xff] ^ |
185 | K[1]; |
186 | L[2] = |
187 | C0[(int)(state[2] >> 56) ] ^ |
188 | C1[(int)(state[1] >> 48) & 0xff] ^ |
189 | C2[(int)(state[0] >> 40) & 0xff] ^ |
190 | C3[(int)(state[7] >> 32) & 0xff] ^ |
191 | C4[(int)(state[6] >> 24) & 0xff] ^ |
192 | C5[(int)(state[5] >> 16) & 0xff] ^ |
193 | C6[(int)(state[4] >> 8) & 0xff] ^ |
194 | C7[(int)(state[3] ) & 0xff] ^ |
195 | K[2]; |
196 | L[3] = |
197 | C0[(int)(state[3] >> 56) ] ^ |
198 | C1[(int)(state[2] >> 48) & 0xff] ^ |
199 | C2[(int)(state[1] >> 40) & 0xff] ^ |
200 | C3[(int)(state[0] >> 32) & 0xff] ^ |
201 | C4[(int)(state[7] >> 24) & 0xff] ^ |
202 | C5[(int)(state[6] >> 16) & 0xff] ^ |
203 | C6[(int)(state[5] >> 8) & 0xff] ^ |
204 | C7[(int)(state[4] ) & 0xff] ^ |
205 | K[3]; |
206 | L[4] = |
207 | C0[(int)(state[4] >> 56) ] ^ |
208 | C1[(int)(state[3] >> 48) & 0xff] ^ |
209 | C2[(int)(state[2] >> 40) & 0xff] ^ |
210 | C3[(int)(state[1] >> 32) & 0xff] ^ |
211 | C4[(int)(state[0] >> 24) & 0xff] ^ |
212 | C5[(int)(state[7] >> 16) & 0xff] ^ |
213 | C6[(int)(state[6] >> 8) & 0xff] ^ |
214 | C7[(int)(state[5] ) & 0xff] ^ |
215 | K[4]; |
216 | L[5] = |
217 | C0[(int)(state[5] >> 56) ] ^ |
218 | C1[(int)(state[4] >> 48) & 0xff] ^ |
219 | C2[(int)(state[3] >> 40) & 0xff] ^ |
220 | C3[(int)(state[2] >> 32) & 0xff] ^ |
221 | C4[(int)(state[1] >> 24) & 0xff] ^ |
222 | C5[(int)(state[0] >> 16) & 0xff] ^ |
223 | C6[(int)(state[7] >> 8) & 0xff] ^ |
224 | C7[(int)(state[6] ) & 0xff] ^ |
225 | K[5]; |
226 | L[6] = |
227 | C0[(int)(state[6] >> 56) ] ^ |
228 | C1[(int)(state[5] >> 48) & 0xff] ^ |
229 | C2[(int)(state[4] >> 40) & 0xff] ^ |
230 | C3[(int)(state[3] >> 32) & 0xff] ^ |
231 | C4[(int)(state[2] >> 24) & 0xff] ^ |
232 | C5[(int)(state[1] >> 16) & 0xff] ^ |
233 | C6[(int)(state[0] >> 8) & 0xff] ^ |
234 | C7[(int)(state[7] ) & 0xff] ^ |
235 | K[6]; |
236 | L[7] = |
237 | C0[(int)(state[7] >> 56) ] ^ |
238 | C1[(int)(state[6] >> 48) & 0xff] ^ |
239 | C2[(int)(state[5] >> 40) & 0xff] ^ |
240 | C3[(int)(state[4] >> 32) & 0xff] ^ |
241 | C4[(int)(state[3] >> 24) & 0xff] ^ |
242 | C5[(int)(state[2] >> 16) & 0xff] ^ |
243 | C6[(int)(state[1] >> 8) & 0xff] ^ |
244 | C7[(int)(state[0] ) & 0xff] ^ |
245 | K[7]; |
246 | state[0] = L[0]; |
247 | state[1] = L[1]; |
248 | state[2] = L[2]; |
249 | state[3] = L[3]; |
250 | state[4] = L[4]; |
251 | state[5] = L[5]; |
252 | state[6] = L[6]; |
253 | state[7] = L[7]; |
254 | } |
255 | /* |
256 | * apply the Miyaguchi-Preneel compression function: |
257 | */ |
258 | context->state[0] ^= state[0] ^ block[0]; |
259 | context->state[1] ^= state[1] ^ block[1]; |
260 | context->state[2] ^= state[2] ^ block[2]; |
261 | context->state[3] ^= state[3] ^ block[3]; |
262 | context->state[4] ^= state[4] ^ block[4]; |
263 | context->state[5] ^= state[5] ^ block[5]; |
264 | context->state[6] ^= state[6] ^ block[6]; |
265 | context->state[7] ^= state[7] ^ block[7]; |
266 | |
267 | memset(state, 0, sizeof(state)); |
268 | } |
269 | |
270 | PHP_HASH_API void PHP_WHIRLPOOLInit(PHP_WHIRLPOOL_CTX *context) |
271 | { |
272 | memset(context, 0, sizeof(*context)); |
273 | } |
274 | |
275 | PHP_HASH_API void PHP_WHIRLPOOLUpdate(PHP_WHIRLPOOL_CTX *context, const unsigned char *input, size_t len) |
276 | { |
277 | php_hash_uint64 sourceBits = len * 8; |
278 | int sourcePos = 0; /* index of leftmost source unsigned char containing data (1 to 8 bits). */ |
279 | int sourceGap = (8 - ((int)sourceBits & 7)) & 7; /* space on source[sourcePos]. */ |
280 | int bufferRem = context->buffer.bits & 7; /* occupied bits on buffer[bufferPos]. */ |
281 | const unsigned char *source = input; |
282 | unsigned char *buffer = context->buffer.data; |
283 | unsigned char *bitLength = context->bitlength; |
284 | int bufferBits = context->buffer.bits; |
285 | int bufferPos = context->buffer.pos; |
286 | php_hash_uint32 b, carry; |
287 | int i; |
288 | |
289 | /* |
290 | * tally the length of the added data: |
291 | */ |
292 | php_hash_uint64 value = sourceBits; |
293 | for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != L64(0)); i--) { |
294 | carry += bitLength[i] + ((php_hash_uint32)value & 0xff); |
295 | bitLength[i] = (unsigned char)carry; |
296 | carry >>= 8; |
297 | value >>= 8; |
298 | } |
299 | /* |
300 | * process data in chunks of 8 bits (a more efficient approach would be to take whole-word chunks): |
301 | */ |
302 | while (sourceBits > 8) { |
303 | /* N.B. at least source[sourcePos] and source[sourcePos+1] contain data. */ |
304 | /* |
305 | * take a byte from the source: |
306 | */ |
307 | b = ((source[sourcePos] << sourceGap) & 0xff) | |
308 | ((source[sourcePos + 1] & 0xff) >> (8 - sourceGap)); |
309 | /* |
310 | * process this byte: |
311 | */ |
312 | buffer[bufferPos++] |= (unsigned char)(b >> bufferRem); |
313 | bufferBits += 8 - bufferRem; /* bufferBits = 8*bufferPos; */ |
314 | if (bufferBits == DIGESTBITS) { |
315 | /* |
316 | * process data block: |
317 | */ |
318 | WhirlpoolTransform(context); |
319 | /* |
320 | * reset buffer: |
321 | */ |
322 | bufferBits = bufferPos = 0; |
323 | } |
324 | buffer[bufferPos] = (unsigned char) (b << (8 - bufferRem)); |
325 | bufferBits += bufferRem; |
326 | /* |
327 | * proceed to remaining data: |
328 | */ |
329 | sourceBits -= 8; |
330 | sourcePos++; |
331 | } |
332 | /* now 0 <= sourceBits <= 8; |
333 | * furthermore, all data (if any is left) is in source[sourcePos]. |
334 | */ |
335 | if (sourceBits > 0) { |
336 | b = (source[sourcePos] << sourceGap) & 0xff; /* bits are left-justified on b. */ |
337 | /* |
338 | * process the remaining bits: |
339 | */ |
340 | buffer[bufferPos] |= b >> bufferRem; |
341 | } else { |
342 | b = 0; |
343 | } |
344 | if (bufferRem + sourceBits < 8) { |
345 | /* |
346 | * all remaining data fits on buffer[bufferPos], |
347 | * and there still remains some space. |
348 | */ |
349 | bufferBits += (int) sourceBits; |
350 | } else { |
351 | /* |
352 | * buffer[bufferPos] is full: |
353 | */ |
354 | bufferPos++; |
355 | bufferBits += 8 - bufferRem; /* bufferBits = 8*bufferPos; */ |
356 | sourceBits -= 8 - bufferRem; |
357 | /* now 0 <= sourceBits < 8; |
358 | * furthermore, all data (if any is left) is in source[sourcePos]. |
359 | */ |
360 | if (bufferBits == DIGESTBITS) { |
361 | /* |
362 | * process data block: |
363 | */ |
364 | WhirlpoolTransform(context); |
365 | /* |
366 | * reset buffer: |
367 | */ |
368 | bufferBits = bufferPos = 0; |
369 | } |
370 | buffer[bufferPos] = (unsigned char) (b << (8 - bufferRem)); |
371 | bufferBits += (int)sourceBits; |
372 | } |
373 | context->buffer.bits = bufferBits; |
374 | context->buffer.pos = bufferPos; |
375 | } |
376 | |
377 | PHP_HASH_API void PHP_WHIRLPOOLFinal(unsigned char digest[64], PHP_WHIRLPOOL_CTX *context) |
378 | { |
379 | int i; |
380 | unsigned char *buffer = context->buffer.data; |
381 | unsigned char *bitLength = context->bitlength; |
382 | int bufferBits = context->buffer.bits; |
383 | int bufferPos = context->buffer.pos; |
384 | |
385 | /* |
386 | * append a '1'-bit: |
387 | */ |
388 | buffer[bufferPos] |= 0x80U >> (bufferBits & 7); |
389 | bufferPos++; /* all remaining bits on the current unsigned char are set to zero. */ |
390 | /* |
391 | * pad with zero bits to complete (N*WBLOCKBITS - LENGTHBITS) bits: |
392 | */ |
393 | if (bufferPos > WBLOCKBYTES - LENGTHBYTES) { |
394 | if (bufferPos < WBLOCKBYTES) { |
395 | memset(&buffer[bufferPos], 0, WBLOCKBYTES - bufferPos); |
396 | } |
397 | /* |
398 | * process data block: |
399 | */ |
400 | WhirlpoolTransform(context); |
401 | /* |
402 | * reset buffer: |
403 | */ |
404 | bufferPos = 0; |
405 | } |
406 | if (bufferPos < WBLOCKBYTES - LENGTHBYTES) { |
407 | memset(&buffer[bufferPos], 0, (WBLOCKBYTES - LENGTHBYTES) - bufferPos); |
408 | } |
409 | bufferPos = WBLOCKBYTES - LENGTHBYTES; |
410 | /* |
411 | * append bit length of hashed data: |
412 | */ |
413 | memcpy(&buffer[WBLOCKBYTES - LENGTHBYTES], bitLength, LENGTHBYTES); |
414 | /* |
415 | * process data block: |
416 | */ |
417 | WhirlpoolTransform(context); |
418 | /* |
419 | * return the completed message digest: |
420 | */ |
421 | for (i = 0; i < DIGESTBYTES/8; i++) { |
422 | digest[0] = (unsigned char)(context->state[i] >> 56); |
423 | digest[1] = (unsigned char)(context->state[i] >> 48); |
424 | digest[2] = (unsigned char)(context->state[i] >> 40); |
425 | digest[3] = (unsigned char)(context->state[i] >> 32); |
426 | digest[4] = (unsigned char)(context->state[i] >> 24); |
427 | digest[5] = (unsigned char)(context->state[i] >> 16); |
428 | digest[6] = (unsigned char)(context->state[i] >> 8); |
429 | digest[7] = (unsigned char)(context->state[i] ); |
430 | digest += 8; |
431 | } |
432 | |
433 | memset(context, 0, sizeof(*context)); |
434 | } |
435 | |
436 | const php_hash_ops php_hash_whirlpool_ops = { |
437 | (php_hash_init_func_t) PHP_WHIRLPOOLInit, |
438 | (php_hash_update_func_t) PHP_WHIRLPOOLUpdate, |
439 | (php_hash_final_func_t) PHP_WHIRLPOOLFinal, |
440 | (php_hash_copy_func_t) php_hash_copy, |
441 | 64, |
442 | 64, |
443 | sizeof(PHP_WHIRLPOOL_CTX) |
444 | }; |
445 | |
446 | /* |
447 | * Local variables: |
448 | * tab-width: 4 |
449 | * c-basic-offset: 4 |
450 | * End: |
451 | * vim600: sw=4 ts=4 fdm=marker |
452 | * vim<600: sw=4 ts=4 |
453 | */ |
454 | |