• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 */
chc_register(int cipher)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 */
chc_init(hash_state * md)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 */
chc_compress(hash_state * md,unsigned char * buf)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 */
chc_process(hash_state * md,const unsigned char * in,unsigned long inlen)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 */
chc_done(hash_state * md,unsigned char * out)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 */
chc_test(void)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