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