whirlpool.c
Go to the documentation of this file.
1 /**
2  * @file whirlpool.c
3  * @brief Whirlpool hash function
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2021 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * Whirlpool is a hash function that operates on messages less than 2^256 bits
30  * in length, and produces a message digest of 512 bits
31  *
32  * @author Oryx Embedded SARL (www.oryx-embedded.com)
33  * @version 2.0.2
34  **/
35 
36 //Switch to the appropriate trace level
37 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
38 
39 //Dependencies
40 #include "core/crypto.h"
41 #include "hash/whirlpool.h"
42 
43 //Check crypto library configuration
44 #if (WHIRLPOOL_SUPPORT == ENABLED)
45 
46 //Round function
47 #define RHO(b, a, n, c) \
48 { \
49  b = t[(a[n] >> 56) & 0xFF]; \
50  b ^= ROR64(t[(a[(n + 7) % 8] >> 48) & 0xFF], 8); \
51  b ^= ROR64(t[(a[(n + 6) % 8] >> 40) & 0xFF], 16); \
52  b ^= ROR64(t[(a[(n + 5) % 8] >> 32) & 0xFF], 24); \
53  b ^= ROR64(t[(a[(n + 4) % 8] >> 24) & 0xFF], 32); \
54  b ^= ROR64(t[(a[(n + 3) % 8] >> 16) & 0xFF], 40); \
55  b ^= ROR64(t[(a[(n + 2) % 8] >> 8) & 0xFF], 48); \
56  b ^= ROR64(t[a[(n + 1) % 8] & 0xFF], 56); \
57  b ^= c; \
58 }
59 
60 //Whirlpool padding
61 static const uint8_t padding[64] =
62 {
63  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
66  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
67 };
68 
69 //Whirlpool constants
70 static const uint64_t rc[10] =
71 {
72  0x1823C6E887B8014F,
73  0x36A6D2F5796F9152,
74  0x60BC9B8EA30C7B35,
75  0x1DE0D7C22E4BFE57,
76  0x157737E59FF04ADA,
77  0x58C9290AB1A06B85,
78  0xBD5D10F4CB3E0567,
79  0xE427418BA77D95D8,
80  0xFBEE7C66DD17479E,
81  0xCA2DBF07AD5A8333
82 };
83 
84 //Whirlpool look-up table
85 static const uint64_t t[256] =
86 {
87  0x18186018C07830D8, 0x23238C2305AF4626, 0xC6C63FC67EF991B8, 0xE8E887E8136FCDFB,
88  0x878726874CA113CB, 0xB8B8DAB8A9626D11, 0x0101040108050209, 0x4F4F214F426E9E0D,
89  0x3636D836ADEE6C9B, 0xA6A6A2A6590451FF, 0xD2D26FD2DEBDB90C, 0xF5F5F3F5FB06F70E,
90  0x7979F979EF80F296, 0x6F6FA16F5FCEDE30, 0x91917E91FCEF3F6D, 0x52525552AA07A4F8,
91  0x60609D6027FDC047, 0xBCBCCABC89766535, 0x9B9B569BACCD2B37, 0x8E8E028E048C018A,
92  0xA3A3B6A371155BD2, 0x0C0C300C603C186C, 0x7B7BF17BFF8AF684, 0x3535D435B5E16A80,
93  0x1D1D741DE8693AF5, 0xE0E0A7E05347DDB3, 0xD7D77BD7F6ACB321, 0xC2C22FC25EED999C,
94  0x2E2EB82E6D965C43, 0x4B4B314B627A9629, 0xFEFEDFFEA321E15D, 0x575741578216AED5,
95  0x15155415A8412ABD, 0x7777C1779FB6EEE8, 0x3737DC37A5EB6E92, 0xE5E5B3E57B56D79E,
96  0x9F9F469F8CD92313, 0xF0F0E7F0D317FD23, 0x4A4A354A6A7F9420, 0xDADA4FDA9E95A944,
97  0x58587D58FA25B0A2, 0xC9C903C906CA8FCF, 0x2929A429558D527C, 0x0A0A280A5022145A,
98  0xB1B1FEB1E14F7F50, 0xA0A0BAA0691A5DC9, 0x6B6BB16B7FDAD614, 0x85852E855CAB17D9,
99  0xBDBDCEBD8173673C, 0x5D5D695DD234BA8F, 0x1010401080502090, 0xF4F4F7F4F303F507,
100  0xCBCB0BCB16C08BDD, 0x3E3EF83EEDC67CD3, 0x0505140528110A2D, 0x676781671FE6CE78,
101  0xE4E4B7E47353D597, 0x27279C2725BB4E02, 0x4141194132588273, 0x8B8B168B2C9D0BA7,
102  0xA7A7A6A7510153F6, 0x7D7DE97DCF94FAB2, 0x95956E95DCFB3749, 0xD8D847D88E9FAD56,
103  0xFBFBCBFB8B30EB70, 0xEEEE9FEE2371C1CD, 0x7C7CED7CC791F8BB, 0x6666856617E3CC71,
104  0xDDDD53DDA68EA77B, 0x17175C17B84B2EAF, 0x4747014702468E45, 0x9E9E429E84DC211A,
105  0xCACA0FCA1EC589D4, 0x2D2DB42D75995A58, 0xBFBFC6BF9179632E, 0x07071C07381B0E3F,
106  0xADAD8EAD012347AC, 0x5A5A755AEA2FB4B0, 0x838336836CB51BEF, 0x3333CC3385FF66B6,
107  0x636391633FF2C65C, 0x02020802100A0412, 0xAAAA92AA39384993, 0x7171D971AFA8E2DE,
108  0xC8C807C80ECF8DC6, 0x19196419C87D32D1, 0x494939497270923B, 0xD9D943D9869AAF5F,
109  0xF2F2EFF2C31DF931, 0xE3E3ABE34B48DBA8, 0x5B5B715BE22AB6B9, 0x88881A8834920DBC,
110  0x9A9A529AA4C8293E, 0x262698262DBE4C0B, 0x3232C8328DFA64BF, 0xB0B0FAB0E94A7D59,
111  0xE9E983E91B6ACFF2, 0x0F0F3C0F78331E77, 0xD5D573D5E6A6B733, 0x80803A8074BA1DF4,
112  0xBEBEC2BE997C6127, 0xCDCD13CD26DE87EB, 0x3434D034BDE46889, 0x48483D487A759032,
113  0xFFFFDBFFAB24E354, 0x7A7AF57AF78FF48D, 0x90907A90F4EA3D64, 0x5F5F615FC23EBE9D,
114  0x202080201DA0403D, 0x6868BD6867D5D00F, 0x1A1A681AD07234CA, 0xAEAE82AE192C41B7,
115  0xB4B4EAB4C95E757D, 0x54544D549A19A8CE, 0x93937693ECE53B7F, 0x222288220DAA442F,
116  0x64648D6407E9C863, 0xF1F1E3F1DB12FF2A, 0x7373D173BFA2E6CC, 0x12124812905A2482,
117  0x40401D403A5D807A, 0x0808200840281048, 0xC3C32BC356E89B95, 0xECEC97EC337BC5DF,
118  0xDBDB4BDB9690AB4D, 0xA1A1BEA1611F5FC0, 0x8D8D0E8D1C830791, 0x3D3DF43DF5C97AC8,
119  0x97976697CCF1335B, 0x0000000000000000, 0xCFCF1BCF36D483F9, 0x2B2BAC2B4587566E,
120  0x7676C57697B3ECE1, 0x8282328264B019E6, 0xD6D67FD6FEA9B128, 0x1B1B6C1BD87736C3,
121  0xB5B5EEB5C15B7774, 0xAFAF86AF112943BE, 0x6A6AB56A77DFD41D, 0x50505D50BA0DA0EA,
122  0x45450945124C8A57, 0xF3F3EBF3CB18FB38, 0x3030C0309DF060AD, 0xEFEF9BEF2B74C3C4,
123  0x3F3FFC3FE5C37EDA, 0x55554955921CAAC7, 0xA2A2B2A2791059DB, 0xEAEA8FEA0365C9E9,
124  0x656589650FECCA6A, 0xBABAD2BAB9686903, 0x2F2FBC2F65935E4A, 0xC0C027C04EE79D8E,
125  0xDEDE5FDEBE81A160, 0x1C1C701CE06C38FC, 0xFDFDD3FDBB2EE746, 0x4D4D294D52649A1F,
126  0x92927292E4E03976, 0x7575C9758FBCEAFA, 0x06061806301E0C36, 0x8A8A128A249809AE,
127  0xB2B2F2B2F940794B, 0xE6E6BFE66359D185, 0x0E0E380E70361C7E, 0x1F1F7C1FF8633EE7,
128  0x6262956237F7C455, 0xD4D477D4EEA3B53A, 0xA8A89AA829324D81, 0x96966296C4F43152,
129  0xF9F9C3F99B3AEF62, 0xC5C533C566F697A3, 0x2525942535B14A10, 0x59597959F220B2AB,
130  0x84842A8454AE15D0, 0x7272D572B7A7E4C5, 0x3939E439D5DD72EC, 0x4C4C2D4C5A619816,
131  0x5E5E655ECA3BBC94, 0x7878FD78E785F09F, 0x3838E038DDD870E5, 0x8C8C0A8C14860598,
132  0xD1D163D1C6B2BF17, 0xA5A5AEA5410B57E4, 0xE2E2AFE2434DD9A1, 0x616199612FF8C24E,
133  0xB3B3F6B3F1457B42, 0x2121842115A54234, 0x9C9C4A9C94D62508, 0x1E1E781EF0663CEE,
134  0x4343114322528661, 0xC7C73BC776FC93B1, 0xFCFCD7FCB32BE54F, 0x0404100420140824,
135  0x51515951B208A2E3, 0x99995E99BCC72F25, 0x6D6DA96D4FC4DA22, 0x0D0D340D68391A65,
136  0xFAFACFFA8335E979, 0xDFDF5BDFB684A369, 0x7E7EE57ED79BFCA9, 0x242490243DB44819,
137  0x3B3BEC3BC5D776FE, 0xABAB96AB313D4B9A, 0xCECE1FCE3ED181F0, 0x1111441188552299,
138  0x8F8F068F0C890383, 0x4E4E254E4A6B9C04, 0xB7B7E6B7D1517366, 0xEBEB8BEB0B60CBE0,
139  0x3C3CF03CFDCC78C1, 0x81813E817CBF1FFD, 0x94946A94D4FE3540, 0xF7F7FBF7EB0CF31C,
140  0xB9B9DEB9A1676F18, 0x13134C13985F268B, 0x2C2CB02C7D9C5851, 0xD3D36BD3D6B8BB05,
141  0xE7E7BBE76B5CD38C, 0x6E6EA56E57CBDC39, 0xC4C437C46EF395AA, 0x03030C03180F061B,
142  0x565645568A13ACDC, 0x44440D441A49885E, 0x7F7FE17FDF9EFEA0, 0xA9A99EA921374F88,
143  0x2A2AA82A4D825467, 0xBBBBD6BBB16D6B0A, 0xC1C123C146E29F87, 0x53535153A202A6F1,
144  0xDCDC57DCAE8BA572, 0x0B0B2C0B58271653, 0x9D9D4E9D9CD32701, 0x6C6CAD6C47C1D82B,
145  0x3131C43195F562A4, 0x7474CD7487B9E8F3, 0xF6F6FFF6E309F115, 0x464605460A438C4C,
146  0xACAC8AAC092645A5, 0x89891E893C970FB5, 0x14145014A04428B4, 0xE1E1A3E15B42DFBA,
147  0x16165816B04E2CA6, 0x3A3AE83ACDD274F7, 0x6969B9696FD0D206, 0x09092409482D1241,
148  0x7070DD70A7ADE0D7, 0xB6B6E2B6D954716F, 0xD0D067D0CEB7BD1E, 0xEDED93ED3B7EC7D6,
149  0xCCCC17CC2EDB85E2, 0x424215422A578468, 0x98985A98B4C22D2C, 0xA4A4AAA4490E55ED,
150  0x2828A0285D885075, 0x5C5C6D5CDA31B886, 0xF8F8C7F8933FED6B, 0x8686228644A411C2
151 };
152 
153 //Whirlpool object identifier (1.0.10118.3.0.55)
154 const uint8_t whirlpoolOid[6] = {0x28, 0xCF, 0x06, 0x03, 0x00, 0x37};
155 
156 //Common interface for hash algorithms
158 {
159  "Whirlpool",
160  whirlpoolOid,
161  sizeof(whirlpoolOid),
162  sizeof(WhirlpoolContext),
166  TRUE,
171  NULL
172 };
173 
174 
175 /**
176  * @brief Digest a message using Whirlpool
177  * @param[in] data Pointer to the message being hashed
178  * @param[in] length Length of the message
179  * @param[out] digest Pointer to the calculated digest
180  * @return Error code
181  **/
182 
183 error_t whirlpoolCompute(const void *data, size_t length, uint8_t *digest)
184 {
185  error_t error;
186  WhirlpoolContext *context;
187 
188  //Allocate a memory buffer to hold the Whirlpool context
189  context = cryptoAllocMem(sizeof(WhirlpoolContext));
190 
191  //Successful memory allocation?
192  if(context != NULL)
193  {
194  //Initialize the Whirlpool context
195  whirlpoolInit(context);
196  //Digest the message
197  whirlpoolUpdate(context, data, length);
198  //Finalize the Whirlpool message digest
199  whirlpoolFinal(context, digest);
200 
201  //Free previously allocated memory
202  cryptoFreeMem(context);
203 
204  //Successful processing
205  error = NO_ERROR;
206  }
207  else
208  {
209  //Failed to allocate memory
210  error = ERROR_OUT_OF_MEMORY;
211  }
212 
213  //Return status code
214  return error;
215 }
216 
217 
218 /**
219  * @brief Initialize Whirlpool message digest context
220  * @param[in] context Pointer to the Whirlpool context to initialize
221  **/
222 
224 {
225  uint_t i;
226 
227  //Set initial hash value
228  for(i = 0; i < 8; i++)
229  {
230  context->h[i] = 0;
231  }
232 
233  //Number of bytes in the buffer
234  context->size = 0;
235  //Total length of the message
236  context->totalSize = 0;
237 }
238 
239 
240 /**
241  * @brief Update the Whirlpool context with a portion of the message being hashed
242  * @param[in] context Pointer to the Whirlpool context
243  * @param[in] data Pointer to the buffer being hashed
244  * @param[in] length Length of the buffer
245  **/
246 
247 void whirlpoolUpdate(WhirlpoolContext *context, const void *data, size_t length)
248 {
249  size_t n;
250 
251  //Process the incoming data
252  while(length > 0)
253  {
254  //The buffer can hold at most 64 bytes
255  n = MIN(length, 64 - context->size);
256 
257  //Copy the data to the buffer
258  osMemcpy(context->buffer + context->size, data, n);
259 
260  //Update the Whirlpool context
261  context->size += n;
262  context->totalSize += n;
263  //Advance the data pointer
264  data = (uint8_t *) data + n;
265  //Remaining bytes to process
266  length -= n;
267 
268  //Process message in 8-word blocks
269  if(context->size == 64)
270  {
271  //Transform the 8-word block
272  whirlpoolProcessBlock(context);
273  //Empty the buffer
274  context->size = 0;
275  }
276  }
277 }
278 
279 
280 /**
281  * @brief Finish the Whirlpool message digest
282  * @param[in] context Pointer to the Whirlpool context
283  * @param[out] digest Calculated digest (optional parameter)
284  **/
285 
286 void whirlpoolFinal(WhirlpoolContext *context, uint8_t *digest)
287 {
288  uint_t i;
289  size_t paddingSize;
290  uint64_t totalSize;
291 
292  //Length of the original message (before padding)
293  totalSize = context->totalSize * 8;
294 
295  //Pad the message so that its length is congruent to 32 modulo 64
296  if(context->size < 32)
297  paddingSize = 32 - context->size;
298  else
299  paddingSize = 64 + 32 - context->size;
300 
301  //Append padding
302  whirlpoolUpdate(context, padding, paddingSize);
303 
304  //Append the length of the original message
305  context->x[4] = 0;
306  context->x[5] = 0;
307  context->x[6] = 0;
308  context->x[7] = htobe64(totalSize);
309 
310  //Calculate the message digest
311  whirlpoolProcessBlock(context);
312 
313  //Convert from host byte order to big-endian byte order
314  for(i = 0; i < 8; i++)
315  {
316  context->h[i] = htobe64(context->h[i]);
317  }
318 
319  //Copy the resulting digest
320  if(digest != NULL)
321  {
322  osMemcpy(digest, context->digest, WHIRLPOOL_DIGEST_SIZE);
323  }
324 }
325 
326 
327 /**
328  * @brief Process message in 16-word blocks
329  * @param[in] context Pointer to the Whirlpool context
330  **/
331 
333 {
334  uint_t i;
335 
336  uint64_t *x = context->x;
337  uint64_t *k = context->k;
338  uint64_t *l = context->l;
339  uint64_t *state = context->state;
340 
341  //Convert from big-endian byte order to host byte order
342  for(i = 0; i < 8; i++)
343  {
344  x[i] = betoh64(x[i]);
345  }
346 
347  k[0] = context->h[0];
348  k[1] = context->h[1];
349  k[2] = context->h[2];
350  k[3] = context->h[3];
351  k[4] = context->h[4];
352  k[5] = context->h[5];
353  k[6] = context->h[6];
354  k[7] = context->h[7];
355 
356  state[0] = x[0] ^ k[0];
357  state[1] = x[1] ^ k[1];
358  state[2] = x[2] ^ k[2];
359  state[3] = x[3] ^ k[3];
360  state[4] = x[4] ^ k[4];
361  state[5] = x[5] ^ k[5];
362  state[6] = x[6] ^ k[6];
363  state[7] = x[7] ^ k[7];
364 
365  //Iterate over all rounds
366  for(i = 0; i < 10; i++)
367  {
368  //Key schedule
369  RHO(l[0], k, 0, rc[i]);
370  RHO(l[1], k, 1, 0);
371  RHO(l[2], k, 2, 0);
372  RHO(l[3], k, 3, 0);
373  RHO(l[4], k, 4, 0);
374  RHO(l[5], k, 5, 0);
375  RHO(l[6], k, 6, 0);
376  RHO(l[7], k, 7, 0);
377 
378  k[0] = l[0];
379  k[1] = l[1];
380  k[2] = l[2];
381  k[3] = l[3];
382  k[4] = l[4];
383  k[5] = l[5];
384  k[6] = l[6];
385  k[7] = l[7];
386 
387  //Apply the round function
388  RHO(l[0], state, 0, k[0]);
389  RHO(l[1], state, 1, k[1]);
390  RHO(l[2], state, 2, k[2]);
391  RHO(l[3], state, 3, k[3]);
392  RHO(l[4], state, 4, k[4]);
393  RHO(l[5], state, 5, k[5]);
394  RHO(l[6], state, 6, k[6]);
395  RHO(l[7], state, 7, k[7]);
396 
397  state[0] = l[0];
398  state[1] = l[1];
399  state[2] = l[2];
400  state[3] = l[3];
401  state[4] = l[4];
402  state[5] = l[5];
403  state[6] = l[6];
404  state[7] = l[7];
405  }
406 
407  //Update the hash value
408  context->h[0] ^= state[0] ^ x[0];
409  context->h[1] ^= state[1] ^ x[1];
410  context->h[2] ^= state[2] ^ x[2];
411  context->h[3] ^= state[3] ^ x[3];
412  context->h[4] ^= state[4] ^ x[4];
413  context->h[5] ^= state[5] ^ x[5];
414  context->h[6] ^= state[6] ^ x[6];
415  context->h[7] ^= state[7] ^ x[7];
416 }
417 
418 #endif
uint8_t length
Definition: coap_common.h:191
void whirlpoolUpdate(WhirlpoolContext *context, const void *data, size_t length)
Update the Whirlpool context with a portion of the message being hashed.
Definition: whirlpool.c:247
uint64_t k[8]
Definition: whirlpool.h:71
#define WHIRLPOOL_MIN_PAD_SIZE
Definition: whirlpool.h:42
void(* HashAlgoInit)(void *context)
Definition: crypto.h:1042
uint8_t data[]
Definition: ethernet.h:210
#define WHIRLPOOL_BLOCK_SIZE
Definition: whirlpool.h:38
uint8_t digest[64]
Definition: whirlpool.h:63
uint64_t h[8]
Definition: whirlpool.h:62
#define TRUE
Definition: os_port.h:50
#define RHO(b, a, n, c)
Definition: whirlpool.c:47
uint8_t buffer[64]
Definition: whirlpool.h:68
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
const HashAlgo whirlpoolHashAlgo
Definition: whirlpool.c:157
void whirlpoolProcessBlock(WhirlpoolContext *context)
Process message in 16-word blocks.
Definition: whirlpool.c:332
void(* HashAlgoUpdate)(void *context, const void *data, size_t length)
Definition: crypto.h:1043
uint64_t totalSize
Definition: whirlpool.h:76
uint64_t l[8]
Definition: whirlpool.h:72
uint8_t t
Definition: llmnr_common.h:81
void whirlpoolInit(WhirlpoolContext *context)
Initialize Whirlpool message digest context.
Definition: whirlpool.c:223
#define osMemcpy(dest, src, length)
Definition: os_port.h:134
error_t
Error codes.
Definition: error.h:43
uint64_t x[8]
Definition: whirlpool.h:67
General definitions for cryptographic algorithms.
#define htobe64(value)
Definition: cpu_endian.h:447
#define MIN(a, b)
Definition: os_port.h:62
uint64_t state[8]
Definition: whirlpool.h:73
void whirlpoolFinal(WhirlpoolContext *context, uint8_t *digest)
Finish the Whirlpool message digest.
Definition: whirlpool.c:286
const uint8_t whirlpoolOid[6]
Definition: whirlpool.c:154
Whirlpool algorithm context.
Definition: whirlpool.h:59
void(* HashAlgoFinal)(void *context, uint8_t *digest)
Definition: crypto.h:1044
uint8_t l
Definition: ndp.h:410
uint8_t n
#define betoh64(value)
Definition: cpu_endian.h:455
#define cryptoFreeMem(p)
Definition: crypto.h:644
uint32_t totalSize
#define cryptoAllocMem(size)
Definition: crypto.h:639
Common interface for hash algorithms.
Definition: crypto.h:1077
Whirlpool hash function.
error_t whirlpoolCompute(const void *data, size_t length, uint8_t *digest)
Digest a message using Whirlpool.
Definition: whirlpool.c:183
unsigned int uint_t
Definition: compiler_port.h:45
#define WHIRLPOOL_DIGEST_SIZE
Definition: whirlpool.h:40
error_t(* HashAlgoCompute)(const void *data, size_t length, uint8_t *digest)
Definition: crypto.h:1041
@ NO_ERROR
Success.
Definition: error.h:44