comparison libtomcrypt/src/hashes/chc/chc.c @ 391:00fcf5045160

propagate from branch 'au.asn.ucc.matt.ltc.dropbear' (head c1db4398d56c56c6d06ae1e20c1e0d04dbb598ed) to branch 'au.asn.ucc.matt.dropbear' (head d26d5eb2837f46b56a33fb0e7573aa0201abd4d5)
author Matt Johnston <matt@ucc.asn.au>
date Thu, 11 Jan 2007 04:29:08 +0000
parents 0cbe8f6dbf9e
children f849a5ca2efc
comparison
equal deleted inserted replaced
390:d8e44bef7917 391:00fcf5045160
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 $ */