OLD | NEW |
| (Empty) |
1 /* | |
2 * xfm.c | |
3 * | |
4 * Crypto transform implementation | |
5 * | |
6 * David A. McGrew | |
7 * Cisco Systems, Inc. | |
8 */ | |
9 /* | |
10 * | |
11 * Copyright (c) 2001-2006, Cisco Systems, Inc. | |
12 * All rights reserved. | |
13 * | |
14 * Redistribution and use in source and binary forms, with or without | |
15 * modification, are permitted provided that the following conditions | |
16 * are met: | |
17 * | |
18 * Redistributions of source code must retain the above copyright | |
19 * notice, this list of conditions and the following disclaimer. | |
20 * | |
21 * Redistributions in binary form must reproduce the above | |
22 * copyright notice, this list of conditions and the following | |
23 * disclaimer in the documentation and/or other materials provided | |
24 * with the distribution. | |
25 * | |
26 * Neither the name of the Cisco Systems, Inc. nor the names of its | |
27 * contributors may be used to endorse or promote products derived | |
28 * from this software without specific prior written permission. | |
29 * | |
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
31 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
33 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
34 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
35 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
36 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
37 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
41 * OF THE POSSIBILITY OF SUCH DAMAGE. | |
42 * | |
43 */ | |
44 | |
45 #include "cryptoalg.h" | |
46 #include "aes_cbc.h" | |
47 #include "hmac.h" | |
48 #include "crypto_kernel.h" /* for crypto_get_random() */ | |
49 | |
50 #define KEY_LEN 16 | |
51 #define ENC_KEY_LEN 16 | |
52 #define MAC_KEY_LEN 16 | |
53 #define IV_LEN 16 | |
54 #define TAG_LEN 12 | |
55 #define MAX_EXPAND 27 | |
56 | |
57 err_status_t | |
58 aes_128_cbc_hmac_sha1_96_func(void *key, | |
59 void *clear, | |
60 unsigned clear_len, | |
61 void *iv, | |
62 void *opaque, | |
63 unsigned *opaque_len, | |
64 void *auth_tag) { | |
65 aes_cbc_ctx_t aes_ctx; | |
66 hmac_ctx_t hmac_ctx; | |
67 unsigned char enc_key[ENC_KEY_LEN]; | |
68 unsigned char mac_key[MAC_KEY_LEN]; | |
69 err_status_t status; | |
70 | |
71 /* check if we're doing authentication only */ | |
72 if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { | |
73 | |
74 /* perform authentication only */ | |
75 | |
76 } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { | |
77 | |
78 /* | |
79 * bad parameter - we expect either all three pointers to be NULL, | |
80 * or none of those pointers to be NULL | |
81 */ | |
82 return err_status_fail; | |
83 | |
84 } else { | |
85 | |
86 /* derive encryption and authentication keys from the input key */ | |
87 status = hmac_init(&hmac_ctx, key, KEY_LEN); | |
88 if (status) return status; | |
89 status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key); | |
90 if (status) return status; | |
91 | |
92 status = hmac_init(&hmac_ctx, key, KEY_LEN); | |
93 if (status) return status; | |
94 status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key); | |
95 if (status) return status; | |
96 | |
97 | |
98 /* perform encryption and authentication */ | |
99 | |
100 /* set aes key */ | |
101 status = aes_cbc_context_init(&aes_ctx, key, ENC_KEY_LEN, direction_encrypt)
; | |
102 if (status) return status; | |
103 | |
104 /* set iv */ | |
105 status = crypto_get_random(iv, IV_LEN); | |
106 if (status) return status; | |
107 status = aes_cbc_set_iv(&aes_ctx, iv); | |
108 | |
109 /* encrypt the opaque data */ | |
110 status = aes_cbc_nist_encrypt(&aes_ctx, opaque, opaque_len); | |
111 if (status) return status; | |
112 | |
113 /* authenticate clear and opaque data */ | |
114 status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN); | |
115 if (status) return status; | |
116 | |
117 status = hmac_start(&hmac_ctx); | |
118 if (status) return status; | |
119 | |
120 status = hmac_update(&hmac_ctx, clear, clear_len); | |
121 if (status) return status; | |
122 | |
123 status = hmac_compute(&hmac_ctx, opaque, *opaque_len, TAG_LEN, auth_tag); | |
124 if (status) return status; | |
125 | |
126 } | |
127 | |
128 return err_status_ok; | |
129 } | |
130 | |
131 err_status_t | |
132 aes_128_cbc_hmac_sha1_96_inv(void *key, | |
133 void *clear, | |
134 unsigned clear_len, | |
135 void *iv, | |
136 void *opaque, | |
137 unsigned *opaque_len, | |
138 void *auth_tag) { | |
139 aes_cbc_ctx_t aes_ctx; | |
140 hmac_ctx_t hmac_ctx; | |
141 unsigned char enc_key[ENC_KEY_LEN]; | |
142 unsigned char mac_key[MAC_KEY_LEN]; | |
143 unsigned char tmp_tag[TAG_LEN]; | |
144 unsigned char *tag = auth_tag; | |
145 err_status_t status; | |
146 int i; | |
147 | |
148 /* check if we're doing authentication only */ | |
149 if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { | |
150 | |
151 /* perform authentication only */ | |
152 | |
153 } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { | |
154 | |
155 /* | |
156 * bad parameter - we expect either all three pointers to be NULL, | |
157 * or none of those pointers to be NULL | |
158 */ | |
159 return err_status_fail; | |
160 | |
161 } else { | |
162 | |
163 /* derive encryption and authentication keys from the input key */ | |
164 status = hmac_init(&hmac_ctx, key, KEY_LEN); | |
165 if (status) return status; | |
166 status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key); | |
167 if (status) return status; | |
168 | |
169 status = hmac_init(&hmac_ctx, key, KEY_LEN); | |
170 if (status) return status; | |
171 status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key); | |
172 if (status) return status; | |
173 | |
174 /* perform encryption and authentication */ | |
175 | |
176 /* set aes key */ | |
177 status = aes_cbc_context_init(&aes_ctx, key, ENC_KEY_LEN, direction_decrypt)
; | |
178 if (status) return status; | |
179 | |
180 /* set iv */ | |
181 status = rand_source_get_octet_string(iv, IV_LEN); | |
182 if (status) return status; | |
183 status = aes_cbc_set_iv(&aes_ctx, iv); | |
184 | |
185 /* encrypt the opaque data */ | |
186 status = aes_cbc_nist_decrypt(&aes_ctx, opaque, opaque_len); | |
187 if (status) return status; | |
188 | |
189 /* authenticate clear and opaque data */ | |
190 status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN); | |
191 if (status) return status; | |
192 | |
193 status = hmac_start(&hmac_ctx); | |
194 if (status) return status; | |
195 | |
196 status = hmac_update(&hmac_ctx, clear, clear_len); | |
197 if (status) return status; | |
198 | |
199 status = hmac_compute(&hmac_ctx, opaque, *opaque_len, TAG_LEN, tmp_tag); | |
200 if (status) return status; | |
201 | |
202 /* compare the computed tag with the one provided as input */ | |
203 for (i=0; i < TAG_LEN; i++) | |
204 if (tmp_tag[i] != tag[i]) | |
205 return err_status_auth_fail; | |
206 | |
207 } | |
208 | |
209 return err_status_ok; | |
210 } | |
211 | |
212 | |
213 #define ENC 1 | |
214 | |
215 #define DEBUG 0 | |
216 | |
217 err_status_t | |
218 aes_128_cbc_hmac_sha1_96_enc(void *key, | |
219 const void *clear, | |
220 unsigned clear_len, | |
221 void *iv, | |
222 void *opaque, | |
223 unsigned *opaque_len) { | |
224 aes_cbc_ctx_t aes_ctx; | |
225 hmac_ctx_t hmac_ctx; | |
226 unsigned char enc_key[ENC_KEY_LEN]; | |
227 unsigned char mac_key[MAC_KEY_LEN]; | |
228 unsigned char *auth_tag; | |
229 err_status_t status; | |
230 | |
231 /* check if we're doing authentication only */ | |
232 if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { | |
233 | |
234 /* perform authentication only */ | |
235 | |
236 } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { | |
237 | |
238 /* | |
239 * bad parameter - we expect either all three pointers to be NULL, | |
240 * or none of those pointers to be NULL | |
241 */ | |
242 return err_status_fail; | |
243 | |
244 } else { | |
245 | |
246 #if DEBUG | |
247 printf("ENC using key %s\n", octet_string_hex_string(key, KEY_LEN)); | |
248 #endif | |
249 | |
250 /* derive encryption and authentication keys from the input key */ | |
251 status = hmac_init(&hmac_ctx, key, KEY_LEN); | |
252 if (status) return status; | |
253 status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key); | |
254 if (status) return status; | |
255 | |
256 status = hmac_init(&hmac_ctx, key, KEY_LEN); | |
257 if (status) return status; | |
258 status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key); | |
259 if (status) return status; | |
260 | |
261 | |
262 /* perform encryption and authentication */ | |
263 | |
264 /* set aes key */ | |
265 status = aes_cbc_context_init(&aes_ctx, key, ENC_KEY_LEN, direction_encrypt)
; | |
266 if (status) return status; | |
267 | |
268 /* set iv */ | |
269 status = rand_source_get_octet_string(iv, IV_LEN); | |
270 if (status) return status; | |
271 status = aes_cbc_set_iv(&aes_ctx, iv); | |
272 if (status) return status; | |
273 | |
274 #if DEBUG | |
275 printf("plaintext len: %d\n", *opaque_len); | |
276 printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN)); | |
277 printf("plaintext: %s\n", octet_string_hex_string(opaque, *opaque_len)); | |
278 #endif | |
279 | |
280 #if ENC | |
281 /* encrypt the opaque data */ | |
282 status = aes_cbc_nist_encrypt(&aes_ctx, opaque, opaque_len); | |
283 if (status) return status; | |
284 #endif | |
285 | |
286 #if DEBUG | |
287 printf("ciphertext len: %d\n", *opaque_len); | |
288 printf("ciphertext: %s\n", octet_string_hex_string(opaque, *opaque_len)); | |
289 #endif | |
290 | |
291 /* | |
292 * authenticate clear and opaque data, then write the | |
293 * authentication tag to the location immediately following the | |
294 * ciphertext | |
295 */ | |
296 status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN); | |
297 if (status) return status; | |
298 | |
299 status = hmac_start(&hmac_ctx); | |
300 if (status) return status; | |
301 | |
302 status = hmac_update(&hmac_ctx, clear, clear_len); | |
303 if (status) return status; | |
304 #if DEBUG | |
305 printf("hmac input: %s\n", | |
306 octet_string_hex_string(clear, clear_len)); | |
307 #endif | |
308 auth_tag = (unsigned char *)opaque; | |
309 auth_tag += *opaque_len; | |
310 status = hmac_compute(&hmac_ctx, opaque, *opaque_len, TAG_LEN, auth_tag); | |
311 if (status) return status; | |
312 #if DEBUG | |
313 printf("hmac input: %s\n", | |
314 octet_string_hex_string(opaque, *opaque_len)); | |
315 #endif | |
316 /* bump up the opaque_len to reflect the authentication tag */ | |
317 *opaque_len += TAG_LEN; | |
318 | |
319 #if DEBUG | |
320 printf("prot data len: %d\n", *opaque_len); | |
321 printf("prot data: %s\n", octet_string_hex_string(opaque, *opaque_len)); | |
322 #endif | |
323 } | |
324 | |
325 return err_status_ok; | |
326 } | |
327 | |
328 err_status_t | |
329 aes_128_cbc_hmac_sha1_96_dec(void *key, | |
330 const void *clear, | |
331 unsigned clear_len, | |
332 void *iv, | |
333 void *opaque, | |
334 unsigned *opaque_len) { | |
335 aes_cbc_ctx_t aes_ctx; | |
336 hmac_ctx_t hmac_ctx; | |
337 unsigned char enc_key[ENC_KEY_LEN]; | |
338 unsigned char mac_key[MAC_KEY_LEN]; | |
339 unsigned char tmp_tag[TAG_LEN]; | |
340 unsigned char *auth_tag; | |
341 unsigned ciphertext_len; | |
342 err_status_t status; | |
343 int i; | |
344 | |
345 /* check if we're doing authentication only */ | |
346 if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { | |
347 | |
348 /* perform authentication only */ | |
349 | |
350 } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { | |
351 | |
352 /* | |
353 * bad parameter - we expect either all three pointers to be NULL, | |
354 * or none of those pointers to be NULL | |
355 */ | |
356 return err_status_fail; | |
357 | |
358 } else { | |
359 #if DEBUG | |
360 printf("DEC using key %s\n", octet_string_hex_string(key, KEY_LEN)); | |
361 #endif | |
362 | |
363 /* derive encryption and authentication keys from the input key */ | |
364 status = hmac_init(&hmac_ctx, key, KEY_LEN); | |
365 if (status) return status; | |
366 status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key); | |
367 if (status) return status; | |
368 | |
369 status = hmac_init(&hmac_ctx, key, KEY_LEN); | |
370 if (status) return status; | |
371 status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key); | |
372 if (status) return status; | |
373 | |
374 #if DEBUG | |
375 printf("prot data len: %d\n", *opaque_len); | |
376 printf("prot data: %s\n", octet_string_hex_string(opaque, *opaque_len)); | |
377 #endif | |
378 | |
379 /* | |
380 * set the protected data length to that of the ciphertext, by | |
381 * subtracting out the length of the authentication tag | |
382 */ | |
383 ciphertext_len = *opaque_len - TAG_LEN; | |
384 | |
385 #if DEBUG | |
386 printf("ciphertext len: %d\n", ciphertext_len); | |
387 #endif | |
388 /* verify the authentication tag */ | |
389 | |
390 /* | |
391 * compute the authentication tag for the clear and opaque data, | |
392 * and write it to a temporary location | |
393 */ | |
394 status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN); | |
395 if (status) return status; | |
396 | |
397 status = hmac_start(&hmac_ctx); | |
398 if (status) return status; | |
399 | |
400 status = hmac_update(&hmac_ctx, clear, clear_len); | |
401 if (status) return status; | |
402 | |
403 #if DEBUG | |
404 printf("hmac input: %s\n", | |
405 octet_string_hex_string(clear, clear_len)); | |
406 #endif | |
407 | |
408 status = hmac_compute(&hmac_ctx, opaque, ciphertext_len, TAG_LEN, tmp_tag); | |
409 if (status) return status; | |
410 | |
411 #if DEBUG | |
412 printf("hmac input: %s\n", | |
413 octet_string_hex_string(opaque, ciphertext_len)); | |
414 #endif | |
415 | |
416 /* | |
417 * compare the computed tag with the one provided as input (which | |
418 * immediately follows the ciphertext) | |
419 */ | |
420 auth_tag = (unsigned char *)opaque; | |
421 auth_tag += ciphertext_len; | |
422 #if DEBUG | |
423 printf("auth_tag: %s\n", octet_string_hex_string(auth_tag, TAG_LEN)); | |
424 printf("tmp_tag: %s\n", octet_string_hex_string(tmp_tag, TAG_LEN)); | |
425 #endif | |
426 for (i=0; i < TAG_LEN; i++) { | |
427 if (tmp_tag[i] != auth_tag[i]) | |
428 return err_status_auth_fail; | |
429 } | |
430 | |
431 /* bump down the opaque_len to reflect the authentication tag */ | |
432 *opaque_len -= TAG_LEN; | |
433 | |
434 /* decrypt the confidential data */ | |
435 status = aes_cbc_context_init(&aes_ctx, key, ENC_KEY_LEN, direction_decrypt)
; | |
436 if (status) return status; | |
437 status = aes_cbc_set_iv(&aes_ctx, iv); | |
438 if (status) return status; | |
439 | |
440 #if DEBUG | |
441 printf("ciphertext: %s\n", octet_string_hex_string(opaque, *opaque_len)); | |
442 printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN)); | |
443 #endif | |
444 | |
445 #if ENC | |
446 status = aes_cbc_nist_decrypt(&aes_ctx, opaque, &ciphertext_len); | |
447 if (status) return status; | |
448 #endif | |
449 | |
450 #if DEBUG | |
451 printf("plaintext len: %d\n", ciphertext_len); | |
452 printf("plaintext: %s\n", | |
453 octet_string_hex_string(opaque, ciphertext_len)); | |
454 #endif | |
455 | |
456 /* indicate the length of the plaintext */ | |
457 *opaque_len = ciphertext_len; | |
458 } | |
459 | |
460 return err_status_ok; | |
461 } | |
462 | |
463 cryptoalg_ctx_t cryptoalg_ctx = { | |
464 aes_128_cbc_hmac_sha1_96_enc, | |
465 aes_128_cbc_hmac_sha1_96_dec, | |
466 KEY_LEN, | |
467 IV_LEN, | |
468 TAG_LEN, | |
469 MAX_EXPAND, | |
470 }; | |
471 | |
472 cryptoalg_t cryptoalg = &cryptoalg_ctx; | |
473 | |
474 #define NULL_TAG_LEN 12 | |
475 | |
476 err_status_t | |
477 null_enc(void *key, | |
478 const void *clear, | |
479 unsigned clear_len, | |
480 void *iv, | |
481 void *opaque, | |
482 unsigned *opaque_len) { | |
483 int i; | |
484 unsigned char *auth_tag; | |
485 unsigned char *init_vec = iv; | |
486 | |
487 /* check if we're doing authentication only */ | |
488 if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { | |
489 | |
490 /* perform authentication only */ | |
491 | |
492 } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { | |
493 | |
494 /* | |
495 * bad parameter - we expect either all three pointers to be NULL, | |
496 * or none of those pointers to be NULL | |
497 */ | |
498 return err_status_fail; | |
499 | |
500 } else { | |
501 | |
502 #if DEBUG | |
503 printf("NULL ENC using key %s\n", octet_string_hex_string(key, KEY_LEN)); | |
504 printf("NULL_TAG_LEN: %d\n", NULL_TAG_LEN); | |
505 printf("plaintext len: %d\n", *opaque_len); | |
506 #endif | |
507 for (i=0; i < IV_LEN; i++) | |
508 init_vec[i] = i + (i * 16); | |
509 #if DEBUG | |
510 printf("iv: %s\n", | |
511 octet_string_hex_string(iv, IV_LEN)); | |
512 printf("plaintext: %s\n", | |
513 octet_string_hex_string(opaque, *opaque_len)); | |
514 #endif | |
515 auth_tag = opaque; | |
516 auth_tag += *opaque_len; | |
517 for (i=0; i < NULL_TAG_LEN; i++) | |
518 auth_tag[i] = i + (i * 16); | |
519 *opaque_len += NULL_TAG_LEN; | |
520 #if DEBUG | |
521 printf("protected data len: %d\n", *opaque_len); | |
522 printf("protected data: %s\n", | |
523 octet_string_hex_string(opaque, *opaque_len)); | |
524 #endif | |
525 | |
526 } | |
527 | |
528 return err_status_ok; | |
529 } | |
530 | |
531 err_status_t | |
532 null_dec(void *key, | |
533 const void *clear, | |
534 unsigned clear_len, | |
535 void *iv, | |
536 void *opaque, | |
537 unsigned *opaque_len) { | |
538 unsigned char *auth_tag; | |
539 | |
540 /* check if we're doing authentication only */ | |
541 if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { | |
542 | |
543 /* perform authentication only */ | |
544 | |
545 } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { | |
546 | |
547 /* | |
548 * bad parameter - we expect either all three pointers to be NULL, | |
549 * or none of those pointers to be NULL | |
550 */ | |
551 return err_status_fail; | |
552 | |
553 } else { | |
554 | |
555 #if DEBUG | |
556 printf("NULL DEC using key %s\n", octet_string_hex_string(key, KEY_LEN)); | |
557 | |
558 printf("protected data len: %d\n", *opaque_len); | |
559 printf("protected data: %s\n", | |
560 octet_string_hex_string(opaque, *opaque_len)); | |
561 #endif | |
562 auth_tag = opaque; | |
563 auth_tag += (*opaque_len - NULL_TAG_LEN); | |
564 #if DEBUG | |
565 printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN)); | |
566 #endif | |
567 *opaque_len -= NULL_TAG_LEN; | |
568 #if DEBUG | |
569 printf("plaintext len: %d\n", *opaque_len); | |
570 printf("plaintext: %s\n", | |
571 octet_string_hex_string(opaque, *opaque_len)); | |
572 #endif | |
573 } | |
574 | |
575 return err_status_ok; | |
576 } | |
577 | |
578 cryptoalg_ctx_t null_cryptoalg_ctx = { | |
579 null_enc, | |
580 null_dec, | |
581 KEY_LEN, | |
582 IV_LEN, | |
583 NULL_TAG_LEN, | |
584 MAX_EXPAND, | |
585 }; | |
586 | |
587 cryptoalg_t null_cryptoalg = &null_cryptoalg_ctx; | |
588 | |
589 int | |
590 cryptoalg_get_id(cryptoalg_t c) { | |
591 if (c == cryptoalg) | |
592 return 1; | |
593 return 0; | |
594 } | |
595 | |
596 cryptoalg_t | |
597 cryptoalg_find_by_id(int id) { | |
598 switch(id) { | |
599 case 1: | |
600 return cryptoalg; | |
601 default: | |
602 break; | |
603 } | |
604 return 0; | |
605 } | |
OLD | NEW |