1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3
4 /**
5 @file whirl.c
6 LTC_WHIRLPOOL (using their new sbox) hash function by Tom St Denis
7 */
8
9 #include "tomcrypt_private.h"
10
11 #ifdef LTC_WHIRLPOOL
12
13 const struct ltc_hash_descriptor whirlpool_desc =
14 {
15 "whirlpool",
16 11,
17 64,
18 64,
19
20 /* OID */
21 { 1, 0, 10118, 3, 0, 55 },
22 6,
23
24 &whirlpool_init,
25 &whirlpool_process,
26 &whirlpool_done,
27 &whirlpool_test,
28 NULL
29 };
30
31 /* the sboxes */
32 #define LTC_WHIRLTAB_C
33 #include "whirltab.c"
34
35 /* get a_{i,j} */
36 #define GB(a,i,j) ((a[(i) & 7] >> (8 * (j))) & 255)
37
38 /* shortcut macro to perform three functions at once */
39 #define theta_pi_gamma(a, i) \
40 (SB0(GB(a, i-0, 7)) ^ \
41 SB1(GB(a, i-1, 6)) ^ \
42 SB2(GB(a, i-2, 5)) ^ \
43 SB3(GB(a, i-3, 4)) ^ \
44 SB4(GB(a, i-4, 3)) ^ \
45 SB5(GB(a, i-5, 2)) ^ \
46 SB6(GB(a, i-6, 1)) ^ \
47 SB7(GB(a, i-7, 0)))
48
49 #ifdef LTC_CLEAN_STACK
ss_whirlpool_compress(hash_state * md,const unsigned char * buf)50 static int ss_whirlpool_compress(hash_state *md, const unsigned char *buf)
51 #else
52 static int s_whirlpool_compress(hash_state *md, const unsigned char *buf)
53 #endif
54 {
55 ulong64 K[2][8], T[3][8];
56 int x, y;
57
58 /* load the block/state */
59 for (x = 0; x < 8; x++) {
60 K[0][x] = md->whirlpool.state[x];
61
62 LOAD64H(T[0][x], buf + (8 * x));
63 T[2][x] = T[0][x];
64 T[0][x] ^= K[0][x];
65 }
66
67 /* do rounds 1..10 */
68 for (x = 0; x < 10; x += 2) {
69 /* odd round */
70 /* apply main transform to K[0] into K[1] */
71 for (y = 0; y < 8; y++) {
72 K[1][y] = theta_pi_gamma(K[0], y);
73 }
74 /* xor the constant */
75 K[1][0] ^= cont[x];
76
77 /* apply main transform to T[0] into T[1] */
78 for (y = 0; y < 8; y++) {
79 T[1][y] = theta_pi_gamma(T[0], y) ^ K[1][y];
80 }
81
82 /* even round */
83 /* apply main transform to K[1] into K[0] */
84 for (y = 0; y < 8; y++) {
85 K[0][y] = theta_pi_gamma(K[1], y);
86 }
87 /* xor the constant */
88 K[0][0] ^= cont[x+1];
89
90 /* apply main transform to T[1] into T[0] */
91 for (y = 0; y < 8; y++) {
92 T[0][y] = theta_pi_gamma(T[1], y) ^ K[0][y];
93 }
94 }
95
96 /* store state */
97 for (x = 0; x < 8; x++) {
98 md->whirlpool.state[x] ^= T[0][x] ^ T[2][x];
99 }
100
101 return CRYPT_OK;
102 }
103
104
105 #ifdef LTC_CLEAN_STACK
s_whirlpool_compress(hash_state * md,const unsigned char * buf)106 static int s_whirlpool_compress(hash_state *md, const unsigned char *buf)
107 {
108 int err;
109 err = ss_whirlpool_compress(md, buf);
110 burn_stack((5 * 8 * sizeof(ulong64)) + (2 * sizeof(int)));
111 return err;
112 }
113 #endif
114
115
116 /**
117 Initialize the hash state
118 @param md The hash state you wish to initialize
119 @return CRYPT_OK if successful
120 */
whirlpool_init(hash_state * md)121 int whirlpool_init(hash_state * md)
122 {
123 LTC_ARGCHK(md != NULL);
124 zeromem(&md->whirlpool, sizeof(md->whirlpool));
125 return CRYPT_OK;
126 }
127
128 /**
129 Process a block of memory though the hash
130 @param md The hash state
131 @param in The data to hash
132 @param inlen The length of the data (octets)
133 @return CRYPT_OK if successful
134 */
135 HASH_PROCESS(whirlpool_process, s_whirlpool_compress, whirlpool, 64)
136
137 /**
138 Terminate the hash to get the digest
139 @param md The hash state
140 @param out [out] The destination of the hash (64 bytes)
141 @return CRYPT_OK if successful
142 */
whirlpool_done(hash_state * md,unsigned char * out)143 int whirlpool_done(hash_state * md, unsigned char *out)
144 {
145 int i;
146
147 LTC_ARGCHK(md != NULL);
148 LTC_ARGCHK(out != NULL);
149
150 if (md->whirlpool.curlen >= sizeof(md->whirlpool.buf)) {
151 return CRYPT_INVALID_ARG;
152 }
153
154 /* increase the length of the message */
155 md->whirlpool.length += md->whirlpool.curlen * 8;
156
157 /* append the '1' bit */
158 md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0x80;
159
160 /* if the length is currently above 32 bytes we append zeros
161 * then compress. Then we can fall back to padding zeros and length
162 * encoding like normal.
163 */
164 if (md->whirlpool.curlen > 32) {
165 while (md->whirlpool.curlen < 64) {
166 md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0;
167 }
168 s_whirlpool_compress(md, md->whirlpool.buf);
169 md->whirlpool.curlen = 0;
170 }
171
172 /* pad upto 56 bytes of zeroes (should be 32 but we only support 64-bit lengths) */
173 while (md->whirlpool.curlen < 56) {
174 md->whirlpool.buf[md->whirlpool.curlen++] = (unsigned char)0;
175 }
176
177 /* store length */
178 STORE64H(md->whirlpool.length, md->whirlpool.buf+56);
179 s_whirlpool_compress(md, md->whirlpool.buf);
180
181 /* copy output */
182 for (i = 0; i < 8; i++) {
183 STORE64H(md->whirlpool.state[i], out+(8*i));
184 }
185 #ifdef LTC_CLEAN_STACK
186 zeromem(md, sizeof(*md));
187 #endif
188 return CRYPT_OK;
189 }
190
191 /**
192 Self-test the hash
193 @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
194 */
whirlpool_test(void)195 int whirlpool_test(void)
196 {
197 #ifndef LTC_TEST
198 return CRYPT_NOP;
199 #else
200 static const struct {
201 int len;
202 unsigned char msg[128], hash[64];
203 } tests[] = {
204
205 /* NULL Message */
206 {
207 0,
208 { 0x00 },
209 { 0x19, 0xFA, 0x61, 0xD7, 0x55, 0x22, 0xA4, 0x66, 0x9B, 0x44, 0xE3, 0x9C, 0x1D, 0x2E, 0x17, 0x26,
210 0xC5, 0x30, 0x23, 0x21, 0x30, 0xD4, 0x07, 0xF8, 0x9A, 0xFE, 0xE0, 0x96, 0x49, 0x97, 0xF7, 0xA7,
211 0x3E, 0x83, 0xBE, 0x69, 0x8B, 0x28, 0x8F, 0xEB, 0xCF, 0x88, 0xE3, 0xE0, 0x3C, 0x4F, 0x07, 0x57,
212 0xEA, 0x89, 0x64, 0xE5, 0x9B, 0x63, 0xD9, 0x37, 0x08, 0xB1, 0x38, 0xCC, 0x42, 0xA6, 0x6E, 0xB3 }
213 },
214
215
216 /* 448-bits of 0 bits */
217 {
218
219 56,
220 { 0x00 },
221 { 0x0B, 0x3F, 0x53, 0x78, 0xEB, 0xED, 0x2B, 0xF4, 0xD7, 0xBE, 0x3C, 0xFD, 0x81, 0x8C, 0x1B, 0x03,
222 0xB6, 0xBB, 0x03, 0xD3, 0x46, 0x94, 0x8B, 0x04, 0xF4, 0xF4, 0x0C, 0x72, 0x6F, 0x07, 0x58, 0x70,
223 0x2A, 0x0F, 0x1E, 0x22, 0x58, 0x80, 0xE3, 0x8D, 0xD5, 0xF6, 0xED, 0x6D, 0xE9, 0xB1, 0xE9, 0x61,
224 0xE4, 0x9F, 0xC1, 0x31, 0x8D, 0x7C, 0xB7, 0x48, 0x22, 0xF3, 0xD0, 0xE2, 0xE9, 0xA7, 0xE7, 0xB0 }
225 },
226
227 /* 520-bits of 0 bits */
228 {
229 65,
230 { 0x00 },
231 { 0x85, 0xE1, 0x24, 0xC4, 0x41, 0x5B, 0xCF, 0x43, 0x19, 0x54, 0x3E, 0x3A, 0x63, 0xFF, 0x57, 0x1D,
232 0x09, 0x35, 0x4C, 0xEE, 0xBE, 0xE1, 0xE3, 0x25, 0x30, 0x8C, 0x90, 0x69, 0xF4, 0x3E, 0x2A, 0xE4,
233 0xD0, 0xE5, 0x1D, 0x4E, 0xB1, 0xE8, 0x64, 0x28, 0x70, 0x19, 0x4E, 0x95, 0x30, 0xD8, 0xD8, 0xAF,
234 0x65, 0x89, 0xD1, 0xBF, 0x69, 0x49, 0xDD, 0xF9, 0x0A, 0x7F, 0x12, 0x08, 0x62, 0x37, 0x95, 0xB9 }
235 },
236
237 /* 512-bits, leading set */
238 {
239 64,
240 { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
244 { 0x10, 0x3E, 0x00, 0x55, 0xA9, 0xB0, 0x90, 0xE1, 0x1C, 0x8F, 0xDD, 0xEB, 0xBA, 0x06, 0xC0, 0x5A,
245 0xCE, 0x8B, 0x64, 0xB8, 0x96, 0x12, 0x8F, 0x6E, 0xED, 0x30, 0x71, 0xFC, 0xF3, 0xDC, 0x16, 0x94,
246 0x67, 0x78, 0xE0, 0x72, 0x23, 0x23, 0x3F, 0xD1, 0x80, 0xFC, 0x40, 0xCC, 0xDB, 0x84, 0x30, 0xA6,
247 0x40, 0xE3, 0x76, 0x34, 0x27, 0x1E, 0x65, 0x5C, 0xA1, 0x67, 0x4E, 0xBF, 0xF5, 0x07, 0xF8, 0xCB }
248 },
249
250 /* 512-bits, leading set of second byte */
251 {
252 64,
253 { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
255 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
257 { 0x35, 0x7B, 0x42, 0xEA, 0x79, 0xBC, 0x97, 0x86, 0x97, 0x5A, 0x3C, 0x44, 0x70, 0xAA, 0xB2, 0x3E,
258 0x62, 0x29, 0x79, 0x7B, 0xAD, 0xBD, 0x54, 0x36, 0x5B, 0x54, 0x96, 0xE5, 0x5D, 0x9D, 0xD7, 0x9F,
259 0xE9, 0x62, 0x4F, 0xB4, 0x22, 0x66, 0x93, 0x0A, 0x62, 0x8E, 0xD4, 0xDB, 0x08, 0xF9, 0xDD, 0x35,
260 0xEF, 0x1B, 0xE1, 0x04, 0x53, 0xFC, 0x18, 0xF4, 0x2C, 0x7F, 0x5E, 0x1F, 0x9B, 0xAE, 0x55, 0xE0 }
261 },
262
263 /* 512-bits, leading set of last byte */
264 {
265 64,
266 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
267 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
268 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 },
270 { 0x8B, 0x39, 0x04, 0xDD, 0x19, 0x81, 0x41, 0x26, 0xFD, 0x02, 0x74, 0xAB, 0x49, 0xC5, 0x97, 0xF6,
271 0xD7, 0x75, 0x33, 0x52, 0xA2, 0xDD, 0x91, 0xFD, 0x8F, 0x9F, 0x54, 0x05, 0x4C, 0x54, 0xBF, 0x0F,
272 0x06, 0xDB, 0x4F, 0xF7, 0x08, 0xA3, 0xA2, 0x8B, 0xC3, 0x7A, 0x92, 0x1E, 0xEE, 0x11, 0xED, 0x7B,
273 0x6A, 0x53, 0x79, 0x32, 0xCC, 0x5E, 0x94, 0xEE, 0x1E, 0xA6, 0x57, 0x60, 0x7E, 0x36, 0xC9, 0xF7 }
274 },
275
276 };
277
278 int i;
279 unsigned char tmp[64];
280 hash_state md;
281
282 for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
283 whirlpool_init(&md);
284 whirlpool_process(&md, (unsigned char *)tests[i].msg, tests[i].len);
285 whirlpool_done(&md, tmp);
286 if (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "WHIRLPOOL", i)) {
287 return CRYPT_FAIL_TESTVECTOR;
288 }
289 }
290 return CRYPT_OK;
291 #endif
292 }
293
294
295 #endif
296
297