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