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