1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3 *
4 * LibTomCrypt is a library that provides various cryptographic
5 * algorithms in a highly modular and flexible manner.
6 *
7 * The library is free for all purposes without any express
8 * guarantee it works.
9 */
10
11 #include "tomcrypt_private.h"
12
13 /**
14 @file chc.c
15 CHC support. (Tom St Denis)
16 */
17
18 #ifdef LTC_CHC_HASH
19
20 #define UNDEFED_HASH -17
21
22 /* chc settings */
23 static int cipher_idx=UNDEFED_HASH, /* which cipher */
24 cipher_blocksize; /* blocksize of cipher */
25
26
27 const struct ltc_hash_descriptor chc_desc = {
28 "chc_hash", 12, 0, 0, { 0 }, 0,
29 &chc_init,
30 &chc_process,
31 &chc_done,
32 &chc_test,
33 NULL
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 */
chc_register(int cipher)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 */
chc_init(hash_state * md)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 */
chc_compress(hash_state * md,const unsigned char * buf)131 static int chc_compress(hash_state *md, const 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 XMEMCPY(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 #ifdef LTC_CLEAN_STACK
150 zeromem(T, sizeof(T));
151 zeromem(key, sizeof(*key));
152 #endif
153 XFREE(key);
154 return CRYPT_OK;
155 }
156
157 /**
158 Function for processing blocks
159 @param md The hash state
160 @param buf The data to hash
161 @param len The length of the data (octets)
162 @return CRYPT_OK if successful
163 */
164 static int _chc_process(hash_state * md, const unsigned char *in, unsigned long inlen);
165 static HASH_PROCESS(_chc_process, chc_compress, chc, (unsigned long)cipher_blocksize)
166
167 /**
168 Process a block of memory though the hash
169 @param md The hash state
170 @param in The data to hash
171 @param inlen The length of the data (octets)
172 @return CRYPT_OK if successful
173 */
chc_process(hash_state * md,const unsigned char * in,unsigned long inlen)174 int chc_process(hash_state * md, const unsigned char *in, unsigned long inlen)
175 {
176 int err;
177
178 LTC_ARGCHK(md != NULL);
179 LTC_ARGCHK(in != NULL);
180
181 /* is the cipher valid? */
182 if ((err = cipher_is_valid(cipher_idx)) != CRYPT_OK) {
183 return err;
184 }
185 if (cipher_blocksize != cipher_descriptor[cipher_idx]->block_length) {
186 return CRYPT_INVALID_CIPHER;
187 }
188
189 return _chc_process(md, in, inlen);
190 }
191
192 /**
193 Terminate the hash to get the digest
194 @param md The hash state
195 @param out [out] The destination of the hash (length of the block size of the block cipher)
196 @return CRYPT_OK if successful
197 */
chc_done(hash_state * md,unsigned char * out)198 int chc_done(hash_state *md, unsigned char *out)
199 {
200 int err;
201
202 LTC_ARGCHK(md != NULL);
203 LTC_ARGCHK(out != NULL);
204
205 /* is the cipher valid? */
206 if ((err = cipher_is_valid(cipher_idx)) != CRYPT_OK) {
207 return err;
208 }
209 if (cipher_blocksize != cipher_descriptor[cipher_idx]->block_length) {
210 return CRYPT_INVALID_CIPHER;
211 }
212
213 if (md->chc.curlen >= sizeof(md->chc.buf)) {
214 return CRYPT_INVALID_ARG;
215 }
216
217 /* increase the length of the message */
218 md->chc.length += md->chc.curlen * 8;
219
220 /* append the '1' bit */
221 md->chc.buf[md->chc.curlen++] = (unsigned char)0x80;
222
223 /* if the length is currently above l-8 bytes we append zeros
224 * then compress. Then we can fall back to padding zeros and length
225 * encoding like normal.
226 */
227 if (md->chc.curlen > (unsigned long)(cipher_blocksize - 8)) {
228 while (md->chc.curlen < (unsigned long)cipher_blocksize) {
229 md->chc.buf[md->chc.curlen++] = (unsigned char)0;
230 }
231 chc_compress(md, md->chc.buf);
232 md->chc.curlen = 0;
233 }
234
235 /* pad upto l-8 bytes of zeroes */
236 while (md->chc.curlen < (unsigned long)(cipher_blocksize - 8)) {
237 md->chc.buf[md->chc.curlen++] = (unsigned char)0;
238 }
239
240 /* store length */
241 STORE64L(md->chc.length, md->chc.buf+(cipher_blocksize-8));
242 chc_compress(md, md->chc.buf);
243
244 /* copy output */
245 XMEMCPY(out, md->chc.state, cipher_blocksize);
246
247 #ifdef LTC_CLEAN_STACK
248 zeromem(md, sizeof(hash_state));
249 #endif
250 return CRYPT_OK;
251 }
252
253 /**
254 Self-test the hash
255 @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
256 */
chc_test(void)257 int chc_test(void)
258 {
259 #ifndef LTC_TEST
260 return CRYPT_NOP;
261 #else
262 static const struct {
263 unsigned char *msg,
264 hash[MAXBLOCKSIZE];
265 int len;
266 } tests[] = {
267 {
268 (unsigned char *)"hello world",
269 { 0xcf, 0x57, 0x9d, 0xc3, 0x0a, 0x0e, 0xea, 0x61,
270 0x0d, 0x54, 0x47, 0xc4, 0x3c, 0x06, 0xf5, 0x4e },
271 16
272 }
273 };
274 int i, oldhashidx, idx;
275 unsigned char tmp[MAXBLOCKSIZE];
276 hash_state md;
277
278 /* AES can be under rijndael or aes... try to find it */
279 if ((idx = find_cipher("aes")) == -1) {
280 if ((idx = find_cipher("rijndael")) == -1) {
281 return CRYPT_NOP;
282 }
283 }
284 oldhashidx = cipher_idx;
285 chc_register(idx);
286
287 for (i = 0; i < (int)(sizeof(tests)/sizeof(tests[0])); i++) {
288 chc_init(&md);
289 chc_process(&md, tests[i].msg, strlen((char *)tests[i].msg));
290 chc_done(&md, tmp);
291 if (compare_testvector(tmp, tests[i].len, tests[i].hash, tests[i].len, "CHC", i)) {
292 return CRYPT_FAIL_TESTVECTOR;
293 }
294 }
295 if (oldhashidx != UNDEFED_HASH) {
296 chc_register(oldhashidx);
297 }
298
299 return CRYPT_OK;
300 #endif
301 }
302
303 #endif
304
305 /* ref: $Format:%D$ */
306 /* git commit: $Format:%H$ */
307 /* commit time: $Format:%ai$ */
308