File Coverage

_whirlpool.c
Criterion Covered Total %
statement 56 73 76.7
branch 10 20 50.0
condition n/a
subroutine n/a
pod n/a
total 66 93 70.9


line stmt bran cond sub pod time code
1             /* whirlpool.c - an implementation of the Whirlpool Hash Function.
2             *
3             * Copyright (c) 2009, Aleksey Kravchenko
4             *
5             * Permission to use, copy, modify, and/or distribute this software for any
6             * purpose with or without fee is hereby granted.
7             *
8             * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9             * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10             * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11             * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12             * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13             * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14             * PERFORMANCE OF THIS SOFTWARE.
15             *
16             * Documentation:
17             * P. S. L. M. Barreto, V. Rijmen, ``The Whirlpool hashing function,''
18             * NESSIE submission, 2000 (tweaked version, 2001)
19             *
20             * The algorithm is named after the Whirlpool Galaxy in Canes Venatici.
21             */
22              
23             #include
24             #include "byte_order.h"
25             #include "whirlpool.h"
26              
27             /**
28             * Initialize context before calculating hash.
29             *
30             * @param ctx context to initialize
31             */
32 2           void rhash_whirlpool_init(struct whirlpool_ctx* ctx)
33             {
34 2           ctx->length = 0;
35 2           memset(ctx->hash, 0, sizeof(ctx->hash));
36 2           }
37              
38             /* Algorithm S-Box */
39             extern uint64_t rhash_whirlpool_sbox[8][256];
40              
41             #define WHIRLPOOL_OP(src, shift) ( \
42             rhash_whirlpool_sbox[0][(int)(src[ shift & 7] >> 56) ] ^ \
43             rhash_whirlpool_sbox[1][(int)(src[(shift + 7) & 7] >> 48) & 0xff] ^ \
44             rhash_whirlpool_sbox[2][(int)(src[(shift + 6) & 7] >> 40) & 0xff] ^ \
45             rhash_whirlpool_sbox[3][(int)(src[(shift + 5) & 7] >> 32) & 0xff] ^ \
46             rhash_whirlpool_sbox[4][(int)(src[(shift + 4) & 7] >> 24) & 0xff] ^ \
47             rhash_whirlpool_sbox[5][(int)(src[(shift + 3) & 7] >> 16) & 0xff] ^ \
48             rhash_whirlpool_sbox[6][(int)(src[(shift + 2) & 7] >> 8) & 0xff] ^ \
49             rhash_whirlpool_sbox[7][(int)(src[(shift + 1) & 7] ) & 0xff])
50              
51             /**
52             * The core transformation. Process a 512-bit block.
53             *
54             * @param hash algorithm state
55             * @param block the message block to process
56             */
57 2           static void rhash_whirlpool_process_block(uint64_t* hash, uint64_t* p_block)
58             {
59             int i; /* loop counter */
60             uint64_t K[2][8]; /* key */
61             uint64_t state[2][8]; /* state */
62              
63             /* alternating binary flags */
64 2           unsigned int m = 0;
65              
66             /* the number of rounds of the internal dedicated block cipher */
67 2           const int number_of_rounds = 10;
68              
69             /* array used in the rounds */
70             static const uint64_t rc[10] = {
71             I64(0x1823c6e887b8014f),
72             I64(0x36a6d2f5796f9152),
73             I64(0x60bc9b8ea30c7b35),
74             I64(0x1de0d7c22e4bfe57),
75             I64(0x157737e59ff04ada),
76             I64(0x58c9290ab1a06b85),
77             I64(0xbd5d10f4cb3e0567),
78             I64(0xe427418ba77d95d8),
79             I64(0xfbee7c66dd17479e),
80             I64(0xca2dbf07ad5a8333)
81             };
82              
83             /* map the message buffer to a block */
84 18 100         for (i = 0; i < 8; i++) {
85             /* store K^0 and xor it with the intermediate hash state */
86 16           K[0][i] = hash[i];
87 16           state[0][i] = be2me_64(p_block[i]) ^ hash[i];
88 16           hash[i] = state[0][i];
89             }
90              
91             /* iterate over algorithm rounds */
92 22 100         for (i = 0; i < number_of_rounds; i++)
93             {
94             /* compute K^i from K^{i-1} */
95 20           K[m ^ 1][0] = WHIRLPOOL_OP(K[m], 0) ^ rc[i];
96 20           K[m ^ 1][1] = WHIRLPOOL_OP(K[m], 1);
97 20           K[m ^ 1][2] = WHIRLPOOL_OP(K[m], 2);
98 20           K[m ^ 1][3] = WHIRLPOOL_OP(K[m], 3);
99 20           K[m ^ 1][4] = WHIRLPOOL_OP(K[m], 4);
100 20           K[m ^ 1][5] = WHIRLPOOL_OP(K[m], 5);
101 20           K[m ^ 1][6] = WHIRLPOOL_OP(K[m], 6);
102 20           K[m ^ 1][7] = WHIRLPOOL_OP(K[m], 7);
103              
104             /* apply the i-th round transformation */
105 20           state[m ^ 1][0] = WHIRLPOOL_OP(state[m], 0) ^ K[m ^ 1][0];
106 20           state[m ^ 1][1] = WHIRLPOOL_OP(state[m], 1) ^ K[m ^ 1][1];
107 20           state[m ^ 1][2] = WHIRLPOOL_OP(state[m], 2) ^ K[m ^ 1][2];
108 20           state[m ^ 1][3] = WHIRLPOOL_OP(state[m], 3) ^ K[m ^ 1][3];
109 20           state[m ^ 1][4] = WHIRLPOOL_OP(state[m], 4) ^ K[m ^ 1][4];
110 20           state[m ^ 1][5] = WHIRLPOOL_OP(state[m], 5) ^ K[m ^ 1][5];
111 20           state[m ^ 1][6] = WHIRLPOOL_OP(state[m], 6) ^ K[m ^ 1][6];
112 20           state[m ^ 1][7] = WHIRLPOOL_OP(state[m], 7) ^ K[m ^ 1][7];
113              
114 20           m = m ^ 1;
115             }
116              
117             /* apply the Miyaguchi-Preneel compression function */
118 2           hash[0] ^= state[0][0];
119 2           hash[1] ^= state[0][1];
120 2           hash[2] ^= state[0][2];
121 2           hash[3] ^= state[0][3];
122 2           hash[4] ^= state[0][4];
123 2           hash[5] ^= state[0][5];
124 2           hash[6] ^= state[0][6];
125 2           hash[7] ^= state[0][7];
126 2           }
127              
128             /**
129             * Calculate message hash.
130             * Can be called repeatedly with chunks of the message to be hashed.
131             *
132             * @param ctx the algorithm context containing current hashing state
133             * @param msg message chunk
134             * @param size length of the message chunk
135             */
136 2           void rhash_whirlpool_update(whirlpool_ctx* ctx, const unsigned char* msg, size_t size)
137             {
138 2           unsigned index = (unsigned)ctx->length & 63;
139             unsigned left;
140 2           ctx->length += size;
141              
142             /* fill partial block */
143 2 50         if (index) {
144 0           left = whirlpool_block_size - index;
145 0           memcpy(ctx->message + index, msg, (size < left ? size : left));
146 0 0         if (size < left) return;
147              
148             /* process partial block */
149 0           rhash_whirlpool_process_block(ctx->hash, (uint64_t*)ctx->message);
150 0           msg += left;
151 0           size -= left;
152             }
153 2 50         while (size >= whirlpool_block_size) {
154             uint64_t* aligned_message_block;
155 0 0         if (IS_ALIGNED_64(msg)) {
156             /* the most common case is processing of an already aligned message
157             without copying it */
158 0           aligned_message_block = (uint64_t*)msg;
159             } else {
160 0           memcpy(ctx->message, msg, whirlpool_block_size);
161 0           aligned_message_block = (uint64_t*)ctx->message;
162             }
163              
164 0           rhash_whirlpool_process_block(ctx->hash, aligned_message_block);
165 0           msg += whirlpool_block_size;
166 0           size -= whirlpool_block_size;
167             }
168 2 50         if (size) {
169             /* save leftovers */
170 2           memcpy(ctx->message, msg, size);
171             }
172             }
173              
174             /**
175             * Store calculated hash into the given array.
176             *
177             * @param ctx the algorithm context containing current hashing state
178             * @param result calculated hash in binary form
179             */
180 2           void rhash_whirlpool_final(whirlpool_ctx* ctx, unsigned char* result)
181             {
182 2           unsigned index = (unsigned)ctx->length & 63;
183 2           uint64_t* msg64 = (uint64_t*)ctx->message;
184              
185             /* pad message and run for last block */
186 2           ctx->message[index++] = 0x80;
187              
188             /* if no room left in the message to store 256-bit message length */
189 2 50         if (index > 32) {
190             /* then pad the rest with zeros and process it */
191 0 0         while (index < 64) {
192 0           ctx->message[index++] = 0;
193             }
194 0           rhash_whirlpool_process_block(ctx->hash, msg64);
195 0           index = 0;
196             }
197             /* due to optimization actually only 64-bit of message length are stored */
198 110 100         while (index < 56) {
199 108           ctx->message[index++] = 0;
200             }
201 2           msg64[7] = be2me_64(ctx->length << 3);
202 2           rhash_whirlpool_process_block(ctx->hash, msg64);
203              
204             /* save result hash */
205 2           be64_copy(result, 0, ctx->hash, 64);
206 2           }