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 #include "tomcrypt.h" 13 14 /** 15 @file chc.c 16 CHC support. (Tom St Denis) 17 */ 18 19 #ifdef CHC_HASH 20 21 #define UNDEFED_HASH -17 22 23 /* chc settings */ 24 static int cipher_idx=UNDEFED_HASH, /* which cipher */ 25 cipher_blocksize; /* blocksize of cipher */ 26 27 28 const struct ltc_hash_descriptor chc_desc = { 29 "chc_hash", 12, 0, 0, { 0 }, 0, 30 &chc_init, 31 &chc_process, 32 &chc_done, 33 &chc_test, 34 NULL 35 }; 36 37 /** 38 Initialize the CHC state with a given cipher 39 @param cipher The index of the cipher you wish to bind 40 @return CRYPT_OK if successful 41 */ 42 int chc_register(int cipher) 43 { 44 int err, kl, idx; 45 46 if ((err = cipher_is_valid(cipher)) != CRYPT_OK) { 47 return err; 48 } 49 50 /* will it be valid? */ 51 kl = cipher_descriptor[cipher].block_length; 52 53 /* must be >64 bit block */ 54 if (kl <= 8) { 55 return CRYPT_INVALID_CIPHER; 56 } 57 58 /* can we use the ideal keysize? */ 59 if ((err = cipher_descriptor[cipher].keysize(&kl)) != CRYPT_OK) { 60 return err; 61 } 62 /* we require that key size == block size be a valid choice */ 63 if (kl != cipher_descriptor[cipher].block_length) { 64 return CRYPT_INVALID_CIPHER; 65 } 66 67 /* determine if chc_hash has been register_hash'ed already */ 68 if ((err = hash_is_valid(idx = find_hash("chc_hash"))) != CRYPT_OK) { 69 return err; 70 } 71 72 /* store into descriptor */ 73 hash_descriptor[idx].hashsize = 74 hash_descriptor[idx].blocksize = cipher_descriptor[cipher].block_length; 75 76 /* store the idx and block size */ 77 cipher_idx = cipher; 78 cipher_blocksize = cipher_descriptor[cipher].block_length; 79 return CRYPT_OK; 80 } 81 82 /** 83 Initialize the hash state 84 @param md The hash state you wish to initialize 85 @return CRYPT_OK if successful 86 */ 87 int chc_init(hash_state *md) 88 { 89 symmetric_key *key; 90 unsigned char buf[MAXBLOCKSIZE]; 91 int err; 92 93 LTC_ARGCHK(md != NULL); 94 95 /* is the cipher valid? */ 96 if ((err = cipher_is_valid(cipher_idx)) != CRYPT_OK) { 97 return err; 98 } 99 100 if (cipher_blocksize != cipher_descriptor[cipher_idx].block_length) { 101 return CRYPT_INVALID_CIPHER; 102 } 103 104 if ((key = XMALLOC(sizeof(*key))) == NULL) { 105 return CRYPT_MEM; 106 } 107 108 /* zero key and what not */ 109 zeromem(buf, cipher_blocksize); 110 if ((err = cipher_descriptor[cipher_idx].setup(buf, cipher_blocksize, 0, key)) != CRYPT_OK) { 111 XFREE(key); 112 return err; 113 } 114 115 /* encrypt zero block */ 116 cipher_descriptor[cipher_idx].ecb_encrypt(buf, md->chc.state, key); 117 118 /* zero other members */ 119 md->chc.length = 0; 120 md->chc.curlen = 0; 121 zeromem(md->chc.buf, sizeof(md->chc.buf)); 122 XFREE(key); 123 return CRYPT_OK; 124 } 125 126 /* 127 key <= state 128 T0,T1 <= block 129 T0 <= encrypt T0 130 state <= state xor T0 xor T1 131 */ 132 static int chc_compress(hash_state *md, unsigned char *buf) 133 { 134 unsigned char T[2][MAXBLOCKSIZE]; 135 symmetric_key *key; 136 int err, x; 137 138 if ((key = XMALLOC(sizeof(*key))) == NULL) { 139 return CRYPT_MEM; 140 } 141 if ((err = cipher_descriptor[cipher_idx].setup(md->chc.state, cipher_blocksize, 0, key)) != CRYPT_OK) { 142 XFREE(key); 143 return err; 144 } 145 XMEMCPY(T[1], buf, cipher_blocksize); 146 cipher_descriptor[cipher_idx].ecb_encrypt(buf, T[0], key); 147 for (x = 0; x < cipher_blocksize; x++) { 148 md->chc.state[x] ^= T[0][x] ^ T[1][x]; 149 } 150 XFREE(key); 151 #ifdef LTC_CLEAN_STACK 152 zeromem(T, sizeof(T)); 153 zeromem(&key, sizeof(key)); 154 #endif 155 return CRYPT_OK; 156 } 157 158 /* function for processing blocks */ 159 int _chc_process(hash_state * md, const unsigned char *buf, unsigned long len); 160 HASH_PROCESS(_chc_process, chc_compress, chc, (unsigned long)cipher_blocksize) 161 162 /** 163 Process a block of memory though the hash 164 @param md The hash state 165 @param in The data to hash 166 @param inlen The length of the data (octets) 167 @return CRYPT_OK if successful 168 */ 169 int chc_process(hash_state * md, const unsigned char *in, unsigned long inlen) 170 { 171 int err; 172 173 LTC_ARGCHK(md != NULL); 174 LTC_ARGCHK(in != NULL); 175 176 /* is the cipher valid? */ 177 if ((err = cipher_is_valid(cipher_idx)) != CRYPT_OK) { 178 return err; 179 } 180 if (cipher_blocksize != cipher_descriptor[cipher_idx].block_length) { 181 return CRYPT_INVALID_CIPHER; 182 } 183 184 return _chc_process(md, in, inlen); 185 } 186 187 /** 188 Terminate the hash to get the digest 189 @param md The hash state 190 @param out [out] The destination of the hash (length of the block size of the block cipher) 191 @return CRYPT_OK if successful 192 */ 193 int chc_done(hash_state *md, unsigned char *out) 194 { 195 int err; 196 197 LTC_ARGCHK(md != NULL); 198 LTC_ARGCHK(out != NULL); 199 200 /* is the cipher valid? */ 201 if ((err = cipher_is_valid(cipher_idx)) != CRYPT_OK) { 202 return err; 203 } 204 if (cipher_blocksize != cipher_descriptor[cipher_idx].block_length) { 205 return CRYPT_INVALID_CIPHER; 206 } 207 208 if (md->chc.curlen >= sizeof(md->chc.buf)) { 209 return CRYPT_INVALID_ARG; 210 } 211 212 /* increase the length of the message */ 213 md->chc.length += md->chc.curlen * 8; 214 215 /* append the '1' bit */ 216 md->chc.buf[md->chc.curlen++] = (unsigned char)0x80; 217 218 /* if the length is currently above l-8 bytes we append zeros 219 * then compress. Then we can fall back to padding zeros and length 220 * encoding like normal. 221 */ 222 if (md->chc.curlen > (unsigned long)(cipher_blocksize - 8)) { 223 while (md->chc.curlen < (unsigned long)cipher_blocksize) { 224 md->chc.buf[md->chc.curlen++] = (unsigned char)0; 225 } 226 chc_compress(md, md->chc.buf); 227 md->chc.curlen = 0; 228 } 229 230 /* pad upto l-8 bytes of zeroes */ 231 while (md->chc.curlen < (unsigned long)(cipher_blocksize - 8)) { 232 md->chc.buf[md->chc.curlen++] = (unsigned char)0; 233 } 234 235 /* store length */ 236 STORE64L(md->chc.length, md->chc.buf+(cipher_blocksize-8)); 237 chc_compress(md, md->chc.buf); 238 239 /* copy output */ 240 XMEMCPY(out, md->chc.state, cipher_blocksize); 241 242 #ifdef LTC_CLEAN_STACK 243 zeromem(md, sizeof(hash_state)); 244 #endif 245 return CRYPT_OK; 246 } 247 248 /** 249 Self-test the hash 250 @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled 251 */ 252 int chc_test(void) 253 { 254 static const struct { 255 unsigned char *msg, 256 md[MAXBLOCKSIZE]; 257 int len; 258 } tests[] = { 259 { 260 (unsigned char *)"hello world", 261 { 0xcf, 0x57, 0x9d, 0xc3, 0x0a, 0x0e, 0xea, 0x61, 262 0x0d, 0x54, 0x47, 0xc4, 0x3c, 0x06, 0xf5, 0x4e }, 263 16 264 } 265 }; 266 int x, oldhashidx, idx; 267 unsigned char out[MAXBLOCKSIZE]; 268 hash_state md; 269 270 /* AES can be under rijndael or aes... try to find it */ 271 if ((idx = find_cipher("aes")) == -1) { 272 if ((idx = find_cipher("rijndael")) == -1) { 273 return CRYPT_NOP; 274 } 275 } 276 oldhashidx = cipher_idx; 277 chc_register(idx); 278 279 for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { 280 chc_init(&md); 281 chc_process(&md, tests[x].msg, strlen((char *)tests[x].msg)); 282 chc_done(&md, out); 283 if (XMEMCMP(out, tests[x].md, tests[x].len)) { 284 return CRYPT_FAIL_TESTVECTOR; 285 } 286 } 287 if (oldhashidx != UNDEFED_HASH) { 288 chc_register(oldhashidx); 289 } 290 291 return CRYPT_OK; 292 } 293 294 #endif 295 296 /* $Source: /cvs/libtom/libtomcrypt/src/hashes/chc/chc.c,v $ */ 297 /* $Revision: 1.6 $ */ 298 /* $Date: 2006/11/01 09:28:17 $ */ 299