Index: libsrtp/crypto/ae_xfm/xfm.c |
=================================================================== |
--- libsrtp/crypto/ae_xfm/xfm.c (revision 0) |
+++ libsrtp/crypto/ae_xfm/xfm.c (revision 0) |
@@ -0,0 +1,570 @@ |
+/* |
+ * xfm.c |
+ * |
+ * Crypto transform implementation |
+ * |
+ * David A. McGrew |
+ * Cisco Systems, Inc. |
+ */ |
+ |
+#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; |
+} |
Property changes on: libsrtp/crypto/ae_xfm/xfm.c |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |