summaryrefslogtreecommitdiff
path: root/third_party/srtp/crypto/ae_xfm/xfm.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/srtp/crypto/ae_xfm/xfm.c')
-rw-r--r--third_party/srtp/crypto/ae_xfm/xfm.c570
1 files changed, 570 insertions, 0 deletions
diff --git a/third_party/srtp/crypto/ae_xfm/xfm.c b/third_party/srtp/crypto/ae_xfm/xfm.c
new file mode 100644
index 00000000..f149d461
--- /dev/null
+++ b/third_party/srtp/crypto/ae_xfm/xfm.c
@@ -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, 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, 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, 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, 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;
+}