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: 2009-2012 Aleksey Kravchenko
4             *
5             * Permission is hereby granted, free of charge, to any person obtaining a
6             * copy of this software and associated documentation files (the "Software"),
7             * to deal in the Software without restriction, including without limitation
8             * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9             * and/or sell copies of the Software, and to permit persons to whom the
10             * Software is furnished to do so.
11             *
12             * This program is distributed in the hope that it will be useful, but
13             * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14             * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
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
25             #include "byte_order.h"
26             #include "whirlpool.h"
27              
28             /**
29             * Initialize context before calculaing hash.
30             *
31             * @param ctx context to initialize
32             */
33 2           void rhash_whirlpool_init(struct whirlpool_ctx* ctx)
34             {
35 2           ctx->length = 0;
36 2           memset(ctx->hash, 0, sizeof(ctx->hash));
37 2           }
38              
39             /* Algorithm S-Box */
40             extern uint64_t rhash_whirlpool_sbox[8][256];
41              
42             #define WHIRLPOOL_OP(src, shift) ( \
43             rhash_whirlpool_sbox[0][(int)(src[ shift & 7] >> 56) ] ^ \
44             rhash_whirlpool_sbox[1][(int)(src[(shift + 7) & 7] >> 48) & 0xff] ^ \
45             rhash_whirlpool_sbox[2][(int)(src[(shift + 6) & 7] >> 40) & 0xff] ^ \
46             rhash_whirlpool_sbox[3][(int)(src[(shift + 5) & 7] >> 32) & 0xff] ^ \
47             rhash_whirlpool_sbox[4][(int)(src[(shift + 4) & 7] >> 24) & 0xff] ^ \
48             rhash_whirlpool_sbox[5][(int)(src[(shift + 3) & 7] >> 16) & 0xff] ^ \
49             rhash_whirlpool_sbox[6][(int)(src[(shift + 2) & 7] >> 8) & 0xff] ^ \
50             rhash_whirlpool_sbox[7][(int)(src[(shift + 1) & 7] ) & 0xff])
51              
52             /**
53             * The core transformation. Process a 512-bit block.
54             *
55             * @param hash algorithm state
56             * @param block the message block to process
57             */
58 2           static void rhash_whirlpool_process_block(uint64_t *hash, uint64_t* p_block)
59             {
60             int i; /* loop counter */
61             uint64_t K[2][8]; /* key */
62             uint64_t state[2][8]; /* state */
63              
64             /* alternating binary flags */
65 2           unsigned int m = 0;
66              
67             /* the number of rounds of the internal dedicated block cipher */
68 2           const int number_of_rounds = 10;
69              
70             /* array used in the rounds */
71             static const uint64_t rc[10] = {
72             I64(0x1823c6e887b8014f),
73             I64(0x36a6d2f5796f9152),
74             I64(0x60bc9b8ea30c7b35),
75             I64(0x1de0d7c22e4bfe57),
76             I64(0x157737e59ff04ada),
77             I64(0x58c9290ab1a06b85),
78             I64(0xbd5d10f4cb3e0567),
79             I64(0xe427418ba77d95d8),
80             I64(0xfbee7c66dd17479e),
81             I64(0xca2dbf07ad5a8333)
82             };
83              
84             /* map the message buffer to a block */
85 18 100         for (i = 0; i < 8; i++) {
86             /* store K^0 and xor it with the intermediate hash state */
87 16           K[0][i] = hash[i];
88 16           state[0][i] = be2me_64(p_block[i]) ^ hash[i];
89 16           hash[i] = state[0][i];
90             }
91              
92             /* iterate over algorithm rounds */
93 22 100         for (i = 0; i < number_of_rounds; i++)
94             {
95             /* compute K^i from K^{i-1} */
96 20           K[m ^ 1][0] = WHIRLPOOL_OP(K[m], 0) ^ rc[i];
97 20           K[m ^ 1][1] = WHIRLPOOL_OP(K[m], 1);
98 20           K[m ^ 1][2] = WHIRLPOOL_OP(K[m], 2);
99 20           K[m ^ 1][3] = WHIRLPOOL_OP(K[m], 3);
100 20           K[m ^ 1][4] = WHIRLPOOL_OP(K[m], 4);
101 20           K[m ^ 1][5] = WHIRLPOOL_OP(K[m], 5);
102 20           K[m ^ 1][6] = WHIRLPOOL_OP(K[m], 6);
103 20           K[m ^ 1][7] = WHIRLPOOL_OP(K[m], 7);
104              
105             /* apply the i-th round transformation */
106 20           state[m ^ 1][0] = WHIRLPOOL_OP(state[m], 0) ^ K[m ^ 1][0];
107 20           state[m ^ 1][1] = WHIRLPOOL_OP(state[m], 1) ^ K[m ^ 1][1];
108 20           state[m ^ 1][2] = WHIRLPOOL_OP(state[m], 2) ^ K[m ^ 1][2];
109 20           state[m ^ 1][3] = WHIRLPOOL_OP(state[m], 3) ^ K[m ^ 1][3];
110 20           state[m ^ 1][4] = WHIRLPOOL_OP(state[m], 4) ^ K[m ^ 1][4];
111 20           state[m ^ 1][5] = WHIRLPOOL_OP(state[m], 5) ^ K[m ^ 1][5];
112 20           state[m ^ 1][6] = WHIRLPOOL_OP(state[m], 6) ^ K[m ^ 1][6];
113 20           state[m ^ 1][7] = WHIRLPOOL_OP(state[m], 7) ^ K[m ^ 1][7];
114              
115 20           m = m ^ 1;
116             }
117              
118             /* apply the Miyaguchi-Preneel compression function */
119 2           hash[0] ^= state[0][0];
120 2           hash[1] ^= state[0][1];
121 2           hash[2] ^= state[0][2];
122 2           hash[3] ^= state[0][3];
123 2           hash[4] ^= state[0][4];
124 2           hash[5] ^= state[0][5];
125 2           hash[6] ^= state[0][6];
126 2           hash[7] ^= state[0][7];
127 2           }
128              
129             /**
130             * Calculate message hash.
131             * Can be called repeatedly with chunks of the message to be hashed.
132             *
133             * @param ctx the algorithm context containing current hashing state
134             * @param msg message chunk
135             * @param size length of the message chunk
136             */
137 2           void rhash_whirlpool_update(whirlpool_ctx *ctx, const unsigned char* msg, size_t size)
138             {
139 2           unsigned index = (unsigned)ctx->length & 63;
140             unsigned left;
141 2           ctx->length += size;
142              
143             /* fill partial block */
144 2 50         if (index) {
145 0           left = whirlpool_block_size - index;
146 0           memcpy(ctx->message + index, msg, (size < left ? size : left));
147 0 0         if (size < left) return;
148              
149             /* process partial block */
150 0           rhash_whirlpool_process_block(ctx->hash, (uint64_t*)ctx->message);
151 0           msg += left;
152 0           size -= left;
153             }
154 2 50         while (size >= whirlpool_block_size) {
155             uint64_t* aligned_message_block;
156 0 0         if (IS_ALIGNED_64(msg)) {
157             /* the most common case is processing of an already aligned message
158             without copying it */
159 0           aligned_message_block = (uint64_t*)msg;
160             } else {
161 0           memcpy(ctx->message, msg, whirlpool_block_size);
162 0           aligned_message_block = (uint64_t*)ctx->message;
163             }
164              
165 0           rhash_whirlpool_process_block(ctx->hash, aligned_message_block);
166 0           msg += whirlpool_block_size;
167 0           size -= whirlpool_block_size;
168             }
169 2 50         if (size) {
170             /* save leftovers */
171 2           memcpy(ctx->message, msg, size);
172             }
173             }
174              
175             /**
176             * Store calculated hash into the given array.
177             *
178             * @param ctx the algorithm context containing current hashing state
179             * @param result calculated hash in binary form
180             */
181 2           void rhash_whirlpool_final(whirlpool_ctx *ctx, unsigned char* result)
182             {
183 2           unsigned index = (unsigned)ctx->length & 63;
184 2           uint64_t* msg64 = (uint64_t*)ctx->message;
185              
186             /* pad message and run for last block */
187 2           ctx->message[index++] = 0x80;
188              
189             /* if no room left in the message to store 256-bit message length */
190 2 50         if (index > 32) {
191             /* then pad the rest with zeros and process it */
192 0 0         while (index < 64) {
193 0           ctx->message[index++] = 0;
194             }
195 0           rhash_whirlpool_process_block(ctx->hash, msg64);
196 0           index = 0;
197             }
198             /* due to optimization actually only 64-bit of message length are stored */
199 110 100         while (index < 56) {
200 108           ctx->message[index++] = 0;
201             }
202 2           msg64[7] = be2me_64(ctx->length << 3);
203 2           rhash_whirlpool_process_block(ctx->hash, msg64);
204              
205             /* save result hash */
206 2           be64_copy(result, 0, ctx->hash, 64);
207 2           }