Mercurial > dropbear
comparison libtomcrypt/src/hashes/chc/chc.c @ 389:5ff8218bcee9
propagate from branch 'au.asn.ucc.matt.ltm.dropbear' (head 2af95f00ebd5bb7a28b3817db1218442c935388e)
to branch 'au.asn.ucc.matt.dropbear' (head ecd779509ef23a8cdf64888904fc9b31d78aa933)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 11 Jan 2007 03:14:55 +0000 |
parents | 0cbe8f6dbf9e |
children | f849a5ca2efc |
comparison
equal
deleted
inserted
replaced
388:fb54020f78e1 | 389:5ff8218bcee9 |
---|---|
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.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 $ */ |