Mercurial > dropbear
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 $ */ |