diff options
Diffstat (limited to 'netwerk/srtp/src/crypto/ae_xfm/xfm.c')
-rw-r--r-- | netwerk/srtp/src/crypto/ae_xfm/xfm.c | 605 |
1 files changed, 605 insertions, 0 deletions
diff --git a/netwerk/srtp/src/crypto/ae_xfm/xfm.c b/netwerk/srtp/src/crypto/ae_xfm/xfm.c new file mode 100644 index 000000000..c3c08d9c7 --- /dev/null +++ b/netwerk/srtp/src/crypto/ae_xfm/xfm.c @@ -0,0 +1,605 @@ +/* + * xfm.c + * + * Crypto transform implementation + * + * David A. McGrew + * Cisco Systems, Inc. + */ +/* + * + * Copyright (c) 2001-2006, Cisco Systems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * Neither the name of the Cisco Systems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "cryptoalg.h" +#include "aes_cbc.h" +#include "hmac.h" +#include "crypto_kernel.h" /* for crypto_get_random() */ + +#define KEY_LEN 16 +#define ENC_KEY_LEN 16 +#define MAC_KEY_LEN 16 +#define IV_LEN 16 +#define TAG_LEN 12 +#define MAX_EXPAND 27 + +err_status_t +aes_128_cbc_hmac_sha1_96_func(void *key, + void *clear, + unsigned clear_len, + void *iv, + void *opaque, + unsigned *opaque_len, + void *auth_tag) { + aes_cbc_ctx_t aes_ctx; + hmac_ctx_t hmac_ctx; + unsigned char enc_key[ENC_KEY_LEN]; + unsigned char mac_key[MAC_KEY_LEN]; + err_status_t status; + + /* check if we're doing authentication only */ + if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { + + /* perform authentication only */ + + } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { + + /* + * bad parameter - we expect either all three pointers to be NULL, + * or none of those pointers to be NULL + */ + return err_status_fail; + + } else { + + /* derive encryption and authentication keys from the input key */ + status = hmac_init(&hmac_ctx, key, KEY_LEN); + if (status) return status; + status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key); + if (status) return status; + + status = hmac_init(&hmac_ctx, key, KEY_LEN); + if (status) return status; + status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key); + if (status) return status; + + + /* perform encryption and authentication */ + + /* set aes key */ + status = aes_cbc_context_init(&aes_ctx, key, ENC_KEY_LEN, direction_encrypt); + if (status) return status; + + /* set iv */ + status = crypto_get_random(iv, IV_LEN); + if (status) return status; + status = aes_cbc_set_iv(&aes_ctx, iv); + + /* encrypt the opaque data */ + status = aes_cbc_nist_encrypt(&aes_ctx, opaque, opaque_len); + if (status) return status; + + /* authenticate clear and opaque data */ + status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN); + if (status) return status; + + status = hmac_start(&hmac_ctx); + if (status) return status; + + status = hmac_update(&hmac_ctx, clear, clear_len); + if (status) return status; + + status = hmac_compute(&hmac_ctx, opaque, *opaque_len, TAG_LEN, auth_tag); + if (status) return status; + + } + + return err_status_ok; +} + +err_status_t +aes_128_cbc_hmac_sha1_96_inv(void *key, + void *clear, + unsigned clear_len, + void *iv, + void *opaque, + unsigned *opaque_len, + void *auth_tag) { + aes_cbc_ctx_t aes_ctx; + hmac_ctx_t hmac_ctx; + unsigned char enc_key[ENC_KEY_LEN]; + unsigned char mac_key[MAC_KEY_LEN]; + unsigned char tmp_tag[TAG_LEN]; + unsigned char *tag = auth_tag; + err_status_t status; + int i; + + /* check if we're doing authentication only */ + if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { + + /* perform authentication only */ + + } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { + + /* + * bad parameter - we expect either all three pointers to be NULL, + * or none of those pointers to be NULL + */ + return err_status_fail; + + } else { + + /* derive encryption and authentication keys from the input key */ + status = hmac_init(&hmac_ctx, key, KEY_LEN); + if (status) return status; + status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key); + if (status) return status; + + status = hmac_init(&hmac_ctx, key, KEY_LEN); + if (status) return status; + status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key); + if (status) return status; + + /* perform encryption and authentication */ + + /* set aes key */ + status = aes_cbc_context_init(&aes_ctx, key, ENC_KEY_LEN, direction_decrypt); + if (status) return status; + + /* set iv */ + status = rand_source_get_octet_string(iv, IV_LEN); + if (status) return status; + status = aes_cbc_set_iv(&aes_ctx, iv); + + /* encrypt the opaque data */ + status = aes_cbc_nist_decrypt(&aes_ctx, opaque, opaque_len); + if (status) return status; + + /* authenticate clear and opaque data */ + status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN); + if (status) return status; + + status = hmac_start(&hmac_ctx); + if (status) return status; + + status = hmac_update(&hmac_ctx, clear, clear_len); + if (status) return status; + + status = hmac_compute(&hmac_ctx, opaque, *opaque_len, TAG_LEN, tmp_tag); + if (status) return status; + + /* compare the computed tag with the one provided as input */ + for (i=0; i < TAG_LEN; i++) + if (tmp_tag[i] != tag[i]) + return err_status_auth_fail; + + } + + return err_status_ok; +} + + +#define ENC 1 + +#define DEBUG 0 + +err_status_t +aes_128_cbc_hmac_sha1_96_enc(void *key, + const void *clear, + unsigned clear_len, + void *iv, + void *opaque, + unsigned *opaque_len) { + aes_cbc_ctx_t aes_ctx; + hmac_ctx_t hmac_ctx; + unsigned char enc_key[ENC_KEY_LEN]; + unsigned char mac_key[MAC_KEY_LEN]; + unsigned char *auth_tag; + err_status_t status; + + /* check if we're doing authentication only */ + if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { + + /* perform authentication only */ + + } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { + + /* + * bad parameter - we expect either all three pointers to be NULL, + * or none of those pointers to be NULL + */ + return err_status_fail; + + } else { + +#if DEBUG + printf("ENC using key %s\n", octet_string_hex_string(key, KEY_LEN)); +#endif + + /* derive encryption and authentication keys from the input key */ + status = hmac_init(&hmac_ctx, key, KEY_LEN); + if (status) return status; + status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key); + if (status) return status; + + status = hmac_init(&hmac_ctx, key, KEY_LEN); + if (status) return status; + status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key); + if (status) return status; + + + /* perform encryption and authentication */ + + /* set aes key */ + status = aes_cbc_context_init(&aes_ctx, key, ENC_KEY_LEN, direction_encrypt); + if (status) return status; + + /* set iv */ + status = rand_source_get_octet_string(iv, IV_LEN); + if (status) return status; + status = aes_cbc_set_iv(&aes_ctx, iv); + if (status) return status; + +#if DEBUG + printf("plaintext len: %d\n", *opaque_len); + printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN)); + printf("plaintext: %s\n", octet_string_hex_string(opaque, *opaque_len)); +#endif + +#if ENC + /* encrypt the opaque data */ + status = aes_cbc_nist_encrypt(&aes_ctx, opaque, opaque_len); + if (status) return status; +#endif + +#if DEBUG + printf("ciphertext len: %d\n", *opaque_len); + printf("ciphertext: %s\n", octet_string_hex_string(opaque, *opaque_len)); +#endif + + /* + * authenticate clear and opaque data, then write the + * authentication tag to the location immediately following the + * ciphertext + */ + status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN); + if (status) return status; + + status = hmac_start(&hmac_ctx); + if (status) return status; + + status = hmac_update(&hmac_ctx, clear, clear_len); + if (status) return status; +#if DEBUG + printf("hmac input: %s\n", + octet_string_hex_string(clear, clear_len)); +#endif + auth_tag = (unsigned char *)opaque; + auth_tag += *opaque_len; + status = hmac_compute(&hmac_ctx, opaque, *opaque_len, TAG_LEN, auth_tag); + if (status) return status; +#if DEBUG + printf("hmac input: %s\n", + octet_string_hex_string(opaque, *opaque_len)); +#endif + /* bump up the opaque_len to reflect the authentication tag */ + *opaque_len += TAG_LEN; + +#if DEBUG + printf("prot data len: %d\n", *opaque_len); + printf("prot data: %s\n", octet_string_hex_string(opaque, *opaque_len)); +#endif + } + + return err_status_ok; +} + +err_status_t +aes_128_cbc_hmac_sha1_96_dec(void *key, + const void *clear, + unsigned clear_len, + void *iv, + void *opaque, + unsigned *opaque_len) { + aes_cbc_ctx_t aes_ctx; + hmac_ctx_t hmac_ctx; + unsigned char enc_key[ENC_KEY_LEN]; + unsigned char mac_key[MAC_KEY_LEN]; + unsigned char tmp_tag[TAG_LEN]; + unsigned char *auth_tag; + unsigned ciphertext_len; + err_status_t status; + int i; + + /* check if we're doing authentication only */ + if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { + + /* perform authentication only */ + + } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { + + /* + * bad parameter - we expect either all three pointers to be NULL, + * or none of those pointers to be NULL + */ + return err_status_fail; + + } else { +#if DEBUG + printf("DEC using key %s\n", octet_string_hex_string(key, KEY_LEN)); +#endif + + /* derive encryption and authentication keys from the input key */ + status = hmac_init(&hmac_ctx, key, KEY_LEN); + if (status) return status; + status = hmac_compute(&hmac_ctx, "ENC", 3, ENC_KEY_LEN, enc_key); + if (status) return status; + + status = hmac_init(&hmac_ctx, key, KEY_LEN); + if (status) return status; + status = hmac_compute(&hmac_ctx, "MAC", 3, MAC_KEY_LEN, mac_key); + if (status) return status; + +#if DEBUG + printf("prot data len: %d\n", *opaque_len); + printf("prot data: %s\n", octet_string_hex_string(opaque, *opaque_len)); +#endif + + /* + * set the protected data length to that of the ciphertext, by + * subtracting out the length of the authentication tag + */ + ciphertext_len = *opaque_len - TAG_LEN; + +#if DEBUG + printf("ciphertext len: %d\n", ciphertext_len); +#endif + /* verify the authentication tag */ + + /* + * compute the authentication tag for the clear and opaque data, + * and write it to a temporary location + */ + status = hmac_init(&hmac_ctx, mac_key, MAC_KEY_LEN); + if (status) return status; + + status = hmac_start(&hmac_ctx); + if (status) return status; + + status = hmac_update(&hmac_ctx, clear, clear_len); + if (status) return status; + +#if DEBUG + printf("hmac input: %s\n", + octet_string_hex_string(clear, clear_len)); +#endif + + status = hmac_compute(&hmac_ctx, opaque, ciphertext_len, TAG_LEN, tmp_tag); + if (status) return status; + +#if DEBUG + printf("hmac input: %s\n", + octet_string_hex_string(opaque, ciphertext_len)); +#endif + + /* + * compare the computed tag with the one provided as input (which + * immediately follows the ciphertext) + */ + auth_tag = (unsigned char *)opaque; + auth_tag += ciphertext_len; +#if DEBUG + printf("auth_tag: %s\n", octet_string_hex_string(auth_tag, TAG_LEN)); + printf("tmp_tag: %s\n", octet_string_hex_string(tmp_tag, TAG_LEN)); +#endif + for (i=0; i < TAG_LEN; i++) { + if (tmp_tag[i] != auth_tag[i]) + return err_status_auth_fail; + } + + /* bump down the opaque_len to reflect the authentication tag */ + *opaque_len -= TAG_LEN; + + /* decrypt the confidential data */ + status = aes_cbc_context_init(&aes_ctx, key, ENC_KEY_LEN, direction_decrypt); + if (status) return status; + status = aes_cbc_set_iv(&aes_ctx, iv); + if (status) return status; + +#if DEBUG + printf("ciphertext: %s\n", octet_string_hex_string(opaque, *opaque_len)); + printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN)); +#endif + +#if ENC + status = aes_cbc_nist_decrypt(&aes_ctx, opaque, &ciphertext_len); + if (status) return status; +#endif + +#if DEBUG + printf("plaintext len: %d\n", ciphertext_len); + printf("plaintext: %s\n", + octet_string_hex_string(opaque, ciphertext_len)); +#endif + + /* indicate the length of the plaintext */ + *opaque_len = ciphertext_len; + } + + return err_status_ok; +} + +cryptoalg_ctx_t cryptoalg_ctx = { + aes_128_cbc_hmac_sha1_96_enc, + aes_128_cbc_hmac_sha1_96_dec, + KEY_LEN, + IV_LEN, + TAG_LEN, + MAX_EXPAND, +}; + +cryptoalg_t cryptoalg = &cryptoalg_ctx; + +#define NULL_TAG_LEN 12 + +err_status_t +null_enc(void *key, + const void *clear, + unsigned clear_len, + void *iv, + void *opaque, + unsigned *opaque_len) { + int i; + unsigned char *auth_tag; + unsigned char *init_vec = iv; + + /* check if we're doing authentication only */ + if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { + + /* perform authentication only */ + + } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { + + /* + * bad parameter - we expect either all three pointers to be NULL, + * or none of those pointers to be NULL + */ + return err_status_fail; + + } else { + +#if DEBUG + printf("NULL ENC using key %s\n", octet_string_hex_string(key, KEY_LEN)); + printf("NULL_TAG_LEN: %d\n", NULL_TAG_LEN); + printf("plaintext len: %d\n", *opaque_len); +#endif + for (i=0; i < IV_LEN; i++) + init_vec[i] = i + (i * 16); +#if DEBUG + printf("iv: %s\n", + octet_string_hex_string(iv, IV_LEN)); + printf("plaintext: %s\n", + octet_string_hex_string(opaque, *opaque_len)); +#endif + auth_tag = opaque; + auth_tag += *opaque_len; + for (i=0; i < NULL_TAG_LEN; i++) + auth_tag[i] = i + (i * 16); + *opaque_len += NULL_TAG_LEN; +#if DEBUG + printf("protected data len: %d\n", *opaque_len); + printf("protected data: %s\n", + octet_string_hex_string(opaque, *opaque_len)); +#endif + + } + + return err_status_ok; +} + +err_status_t +null_dec(void *key, + const void *clear, + unsigned clear_len, + void *iv, + void *opaque, + unsigned *opaque_len) { + unsigned char *auth_tag; + + /* check if we're doing authentication only */ + if ((iv == NULL) && (opaque == NULL) && (opaque_len == NULL)) { + + /* perform authentication only */ + + } else if ((iv == NULL) || (opaque == NULL) || (opaque_len == NULL)) { + + /* + * bad parameter - we expect either all three pointers to be NULL, + * or none of those pointers to be NULL + */ + return err_status_fail; + + } else { + +#if DEBUG + printf("NULL DEC using key %s\n", octet_string_hex_string(key, KEY_LEN)); + + printf("protected data len: %d\n", *opaque_len); + printf("protected data: %s\n", + octet_string_hex_string(opaque, *opaque_len)); +#endif + auth_tag = opaque; + auth_tag += (*opaque_len - NULL_TAG_LEN); +#if DEBUG + printf("iv: %s\n", octet_string_hex_string(iv, IV_LEN)); +#endif + *opaque_len -= NULL_TAG_LEN; +#if DEBUG + printf("plaintext len: %d\n", *opaque_len); + printf("plaintext: %s\n", + octet_string_hex_string(opaque, *opaque_len)); +#endif + } + + return err_status_ok; +} + +cryptoalg_ctx_t null_cryptoalg_ctx = { + null_enc, + null_dec, + KEY_LEN, + IV_LEN, + NULL_TAG_LEN, + MAX_EXPAND, +}; + +cryptoalg_t null_cryptoalg = &null_cryptoalg_ctx; + +int +cryptoalg_get_id(cryptoalg_t c) { + if (c == cryptoalg) + return 1; + return 0; +} + +cryptoalg_t +cryptoalg_find_by_id(int id) { + switch(id) { + case 1: + return cryptoalg; + default: + break; + } + return 0; +} |