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