comparison libtomcrypt/src/hashes/chc/chc.c @ 285:1b9e69c058d2

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