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 (at) 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 21 const 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 57 static int _whirlpool_compress(hash_state *md, unsigned char *buf) 58 #else 59 static 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 113 static 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 */ 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 */ 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 */ 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 (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