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
57err_status_t
58aes_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
131err_status_t
132aes_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
217err_status_t
218aes_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
328err_status_t
329aes_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
463cryptoalg_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
472cryptoalg_t cryptoalg = &cryptoalg_ctx;
473
474#define NULL_TAG_LEN 12
475
476err_status_t
477null_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
531err_status_t
532null_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
578cryptoalg_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
587cryptoalg_t null_cryptoalg = &null_cryptoalg_ctx;
588
589int
590cryptoalg_get_id(cryptoalg_t c) {
591  if (c == cryptoalg)
592    return 1;
593  return 0;
594}
595
596cryptoalg_t
597cryptoalg_find_by_id(int id) {
598  switch(id) {
599  case 1:
600    return cryptoalg;
601  default:
602    break;
603  }
604  return 0;
605}
606