1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3  *
4  * LibTomCrypt is a library that provides various cryptographic
5  * algorithms in a highly modular and flexible manner.
6  *
7  * The library is free for all purposes without any express
8  * guarantee it works.
9  */
10 
11 /**
12    @file whirl.c
13    LTC_WHIRLPOOL (using their new sbox) hash function by Tom St Denis
14 */
15 
16 #include "tomcrypt_private.h"
17 
18 #ifdef LTC_WHIRLPOOL
19 
20 const struct ltc_hash_descriptor whirlpool_desc =
21 {
22     "whirlpool",
23     11,
24     64,
25     64,
26 
27    /* OID */
28    { 1, 0, 10118, 3, 0, 55 },
29    6,
30 
31     &whirlpool_init,
32     &whirlpool_process,
33     &whirlpool_done,
34     &whirlpool_test,
35     NULL
36 };
37 
38 /* the sboxes */
39 #define __LTC_WHIRLTAB_C__
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
_whirlpool_compress(hash_state * md,const unsigned char * buf)57 static int _whirlpool_compress(hash_state *md, const unsigned char *buf)
58 #else
59 static int whirlpool_compress(hash_state *md, const 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
whirlpool_compress(hash_state * md,const unsigned char * buf)113 static int whirlpool_compress(hash_state *md, const 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 */
whirlpool_init(hash_state * md)128 int 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 */
142 HASH_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 */
whirlpool_done(hash_state * md,unsigned char * out)150 int 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 */
whirlpool_test(void)202 int  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 (compare_testvector(tmp, sizeof(tmp), tests[i].hash, sizeof(tests[i].hash), "WHIRLPOOL", i)) {
294          return CRYPT_FAIL_TESTVECTOR;
295       }
296   }
297   return CRYPT_OK;
298  #endif
299 }
300 
301 
302 #endif
303 
304 
305 /* ref:         $Format:%D$ */
306 /* git commit:  $Format:%H$ */
307 /* commit time: $Format:%ai$ */
308