Index: pjproject/trunk/third_party/srtp/srtp/srtp.c
===================================================================
--- pjproject/trunk/third_party/srtp/srtp/srtp.c	(revision 2353)
+++ pjproject/trunk/third_party/srtp/srtp/srtp.c	(revision 5261)
@@ -45,6 +45,9 @@
 
 #include "srtp_priv.h"
-#include "aes_icm.h"         /* aes_icm is used in the KDF  */
+#include "ekt.h"             /* for SRTP Encrypted Key Transport */
 #include "alloc.h"           /* for crypto_alloc()          */
+#ifdef OPENSSL
+#include "aes_gcm_ossl.h"    /* for AES GCM mode  */
+#endif
 
 #ifndef SRTP_KERNEL
@@ -58,7 +61,4 @@
 
 
-extern cipher_type_t aes_icm;
-extern auth_type_t   tmmhv2;
-
 /* the debug module for srtp */
 
@@ -72,5 +72,69 @@
 #define octets_in_rtcp_header  8
 #define uint32s_in_rtcp_header 2
-
+#define octets_in_rtp_extn_hdr 4
+
+static err_status_t
+srtp_validate_rtp_header(void *rtp_hdr, int *pkt_octet_len) {
+  srtp_hdr_t *hdr = (srtp_hdr_t *)rtp_hdr;
+
+  /* Check RTP header length */
+  int rtp_header_len = octets_in_rtp_header + 4 * hdr->cc;
+  if (hdr->x == 1)
+    rtp_header_len += octets_in_rtp_extn_hdr;
+
+  if (*pkt_octet_len < rtp_header_len)
+    return err_status_bad_param;
+
+  /* Verifing profile length. */
+  if (hdr->x == 1) {
+    srtp_hdr_xtnd_t *xtn_hdr =
+      (srtp_hdr_xtnd_t *)((uint32_t *)hdr + uint32s_in_rtp_header + hdr->cc);
+    int profile_len = ntohs(xtn_hdr->length);
+    rtp_header_len += profile_len * 4;
+    /* profile length counts the number of 32-bit words */
+    if (*pkt_octet_len < rtp_header_len)
+      return err_status_bad_param;
+  }
+  return err_status_ok;
+}
+
+const char *srtp_get_version_string ()
+{
+    /*
+     * Simply return the autotools generated string
+     */
+    return SRTP_VER_STRING;
+}
+
+unsigned int srtp_get_version ()
+{
+    unsigned int major = 0, minor = 0, micro = 0;
+    unsigned int rv = 0;
+    int parse_rv;
+
+    /*
+     * Parse the autotools generated version 
+     */
+    parse_rv = sscanf(SRTP_VERSION, "%u.%u.%u", &major, &minor, &micro);
+    if (parse_rv != 3) {
+	/*
+	 * We're expected to parse all 3 version levels.
+	 * If not, then this must not be an official release.
+	 * Return all zeros on the version
+	 */
+	return (0);
+    }
+
+    /* 
+     * We allow 8 bits for the major and minor, while
+     * allowing 16 bits for the micro.  16 bits for the micro
+     * may be beneficial for a continuous delivery model 
+     * in the future.
+     */
+    rv |= (major & 0xFF) << 24;
+    rv |= (minor & 0xFF) << 16;
+    rv |= micro & 0xFF;
+    return rv;
+}
 
 err_status_t
@@ -97,5 +161,6 @@
   stat = crypto_kernel_alloc_cipher(p->rtp.cipher_type, 
 				    &str->rtp_cipher, 
-				    p->rtp.cipher_key_len); 
+				    p->rtp.cipher_key_len,
+				    p->rtp.auth_tag_len); 
   if (stat) {
     crypto_free(str);
@@ -129,5 +194,6 @@
   stat = crypto_kernel_alloc_cipher(p->rtcp.cipher_type, 
 				    &str->rtcp_cipher, 
-				    p->rtcp.cipher_key_len); 
+				    p->rtcp.cipher_key_len, 
+				    p->rtcp.auth_tag_len); 
   if (stat) {
     auth_dealloc(str->rtp_auth);
@@ -152,4 +218,16 @@
   }  
 
+  /* allocate ekt data associated with stream */
+  stat = ekt_alloc(&str->ekt, p->ekt);
+  if (stat) {
+    auth_dealloc(str->rtcp_auth);
+    cipher_dealloc(str->rtcp_cipher);
+    auth_dealloc(str->rtp_auth);
+    cipher_dealloc(str->rtp_cipher);
+    crypto_free(str->limit);
+    crypto_free(str);
+   return stat;    
+  }
+
   return err_status_ok;
 }
@@ -218,4 +296,17 @@
       return status;
   }
+
+  status = rdbx_dealloc(&stream->rtp_rdbx);
+  if (status)
+    return status;
+
+  /* DAM - need to deallocate EKT here */
+
+  /*
+   * zeroize the salt value
+   */
+  memset(stream->salt, 0, SRTP_AEAD_SALT_LEN);
+  memset(stream->c_salt, 0, SRTP_AEAD_SALT_LEN);
+
   
   /* deallocate srtp stream context */
@@ -257,10 +348,20 @@
   /* set key limit to point to that of the template */
   status = key_limit_clone(stream_template->limit, &str->limit);
-  if (status) 
+  if (status) { 
+    crypto_free(*str_ptr);
+    *str_ptr = NULL;
     return status;
+  }
 
   /* initialize replay databases */
-  rdbx_init(&str->rtp_rdbx);
+  status = rdbx_init(&str->rtp_rdbx,
+		     rdbx_get_window_size(&stream_template->rtp_rdbx));
+  if (status) {
+    crypto_free(*str_ptr);
+    *str_ptr = NULL;
+    return status;
+  }
   rdb_init(&str->rtcp_rdb);
+  str->allow_repeat_tx = stream_template->allow_repeat_tx;
   
   /* set ssrc to that provided */
@@ -271,4 +372,11 @@
   str->rtp_services  = stream_template->rtp_services;
   str->rtcp_services = stream_template->rtcp_services;
+
+  /* set pointer to EKT data associated with stream */
+  str->ekt = stream_template->ekt;
+
+  /* Copy the salt values */
+  memcpy(str->salt, stream_template->salt, SRTP_AEAD_SALT_LEN);
+  memcpy(str->c_salt, stream_template->c_salt, SRTP_AEAD_SALT_LEN);
 
   /* defensive coding */
@@ -284,5 +392,6 @@
  * srtp_kdf_t is a key derivation context
  *
- * srtp_kdf_init(&kdf, k) initializes kdf with the key k
+ * srtp_kdf_init(&kdf, cipher_id, k, keylen) initializes kdf to use cipher
+ * described by cipher_id, with the master key k with length in octets keylen.
  * 
  * srtp_kdf_generate(&kdf, l, kl, keylen) derives the key
@@ -291,5 +400,5 @@
  * should be called once for each subkey that is derived.
  *
- * srtp_kdf_clear(&kdf) zeroizes the kdf state
+ * srtp_kdf_clear(&kdf) zeroizes and deallocates the kdf state
  */
 
@@ -310,11 +419,20 @@
 
 typedef struct { 
-  aes_icm_ctx_t c;    /* cipher used for key derivation  */  
+  cipher_t *cipher;    /* cipher used for key derivation  */  
 } srtp_kdf_t;
 
 err_status_t
-srtp_kdf_init(srtp_kdf_t *kdf, const uint8_t key[30]) {
-
-  aes_icm_context_init(&kdf->c, key);
+srtp_kdf_init(srtp_kdf_t *kdf, cipher_type_id_t cipher_id, const uint8_t *key, int length) {
+
+  err_status_t stat;
+  stat = crypto_kernel_alloc_cipher(cipher_id, &kdf->cipher, length, 0);
+  if (stat)
+    return stat;
+
+  stat = cipher_init(kdf->cipher, key);
+  if (stat) {
+    cipher_dealloc(kdf->cipher);
+    return stat;
+  }
 
   return err_status_ok;
@@ -323,7 +441,8 @@
 err_status_t
 srtp_kdf_generate(srtp_kdf_t *kdf, srtp_prf_label label,
-		  uint8_t *key, int length) {
+		  uint8_t *key, unsigned int length) {
 
   v128_t nonce;
+  err_status_t status;
   
   /* set eigth octet of nonce to <label>, set the rest of it to zero */
@@ -331,8 +450,13 @@
   nonce.v8[7] = label;
  
-  aes_icm_set_iv(&kdf->c, &nonce);  
+  status = cipher_set_iv(kdf->cipher, &nonce, direction_encrypt);
+  if (status)
+    return status;
   
   /* generate keystream output */
-  aes_icm_output(&kdf->c, key, length);
+  octet_string_set_to_zero(key, length);
+  status = cipher_encrypt(kdf->cipher, key, &length);
+  if (status)
+    return status;
 
   return err_status_ok;
@@ -341,7 +465,9 @@
 err_status_t
 srtp_kdf_clear(srtp_kdf_t *kdf) {
-  
-  /* zeroize aes context */
-  octet_string_set_to_zero((uint8_t *)kdf, sizeof(srtp_kdf_t));
+  err_status_t status;
+  status = cipher_dealloc(kdf->cipher);
+  if (status)
+    return status;
+  kdf->cipher = NULL;
 
   return err_status_ok;  
@@ -354,4 +480,31 @@
 #define MAX_SRTP_KEY_LEN 256
 
+
+/* Get the base key length corresponding to a given combined key+salt
+ * length for the given cipher.
+ * Assumption is that for AES-ICM a key length < 30 is Ismacryp using
+ * AES-128 and short salts; everything else uses a salt length of 14.
+ * TODO: key and salt lengths should be separate fields in the policy.  */
+static inline int base_key_length(const cipher_type_t *cipher, int key_length)
+{
+  switch (cipher->id) {
+  case AES_128_ICM:
+  case AES_192_ICM:
+  case AES_256_ICM:
+    /* The legacy modes are derived from
+     * the configured key length on the policy */
+    return key_length - 14;
+    break;
+  case AES_128_GCM:
+    return 16;
+    break;
+  case AES_256_GCM:
+    return 32;
+    break;
+  default:
+    return key_length;
+    break;
+  }
+}
 
 err_status_t
@@ -360,32 +513,47 @@
   srtp_kdf_t kdf;
   uint8_t tmp_key[MAX_SRTP_KEY_LEN];
-  
+  int kdf_keylen = 30, rtp_keylen, rtcp_keylen;
+  int rtp_base_key_len, rtp_salt_len;
+  int rtcp_base_key_len, rtcp_salt_len;
+
+  /* If RTP or RTCP have a key length > AES-128, assume matching kdf. */
+  /* TODO: kdf algorithm, master key length, and master salt length should
+   * be part of srtp_policy_t. */
+  rtp_keylen = cipher_get_key_length(srtp->rtp_cipher);
+  rtcp_keylen = cipher_get_key_length(srtp->rtcp_cipher);
+  rtp_base_key_len = base_key_length(srtp->rtp_cipher->type, rtp_keylen);
+  rtp_salt_len = rtp_keylen - rtp_base_key_len;
+
+  if (rtp_keylen > kdf_keylen) {
+    kdf_keylen = 46;  /* AES-CTR mode is always used for KDF */
+  }
+
+  if (rtcp_keylen > kdf_keylen) {
+    kdf_keylen = 46;  /* AES-CTR mode is always used for KDF */
+  }
+
+  debug_print(mod_srtp, "srtp key len: %d", rtp_keylen);
+  debug_print(mod_srtp, "srtcp key len: %d", rtcp_keylen);
+  debug_print(mod_srtp, "base key len: %d", rtp_base_key_len);
+  debug_print(mod_srtp, "kdf key len: %d", kdf_keylen);
+  debug_print(mod_srtp, "rtp salt len: %d", rtp_salt_len);
+
+  /* 
+   * Make sure the key given to us is 'zero' appended.  GCM
+   * mode uses a shorter master SALT (96 bits), but still relies on 
+   * the legacy CTR mode KDF, which uses a 112 bit master SALT.
+   */
+  memset(tmp_key, 0x0, MAX_SRTP_KEY_LEN);
+  memcpy(tmp_key, key, (rtp_base_key_len + rtp_salt_len));
+
   /* initialize KDF state     */
-  srtp_kdf_init(&kdf, (const uint8_t *)key);
+  stat = srtp_kdf_init(&kdf, AES_ICM, (const uint8_t *)tmp_key, kdf_keylen);
+  if (stat) {
+    return err_status_init_fail;
+  }
   
   /* generate encryption key  */
-  srtp_kdf_generate(&kdf, label_rtp_encryption, 
-		    tmp_key, cipher_get_key_length(srtp->rtp_cipher));
-  /* 
-   * if the cipher in the srtp context is aes_icm, then we need
-   * to generate the salt value
-   */
-  if (srtp->rtp_cipher->type == &aes_icm) {
-    /* FIX!!! this is really the cipher key length; rest is salt */
-    int base_key_len = 16;
-    int salt_len = cipher_get_key_length(srtp->rtp_cipher) - base_key_len;
-    
-    debug_print(mod_srtp, "found aes_icm, generating salt", NULL);
-
-    /* generate encryption salt, put after encryption key */
-    srtp_kdf_generate(&kdf, label_rtp_salt, 
-		      tmp_key + base_key_len, salt_len);
-  }
-  debug_print(mod_srtp, "cipher key: %s", 
-	      octet_string_hex_string(tmp_key, 
-		      cipher_get_key_length(srtp->rtp_cipher)));  
-
-  /* initialize cipher */
-  stat = cipher_init(srtp->rtp_cipher, tmp_key, direction_any);
+  stat = srtp_kdf_generate(&kdf, label_rtp_encryption, 
+			   tmp_key, rtp_base_key_len);
   if (stat) {
     /* zeroize temp buffer */
@@ -393,8 +561,45 @@
     return err_status_init_fail;
   }
+  debug_print(mod_srtp, "cipher key: %s", 
+	      octet_string_hex_string(tmp_key, rtp_base_key_len));
+
+  /* 
+   * if the cipher in the srtp context uses a salt, then we need
+   * to generate the salt value
+   */
+  if (rtp_salt_len > 0) {
+    debug_print(mod_srtp, "found rtp_salt_len > 0, generating salt", NULL);
+
+    /* generate encryption salt, put after encryption key */
+    stat = srtp_kdf_generate(&kdf, label_rtp_salt, 
+			     tmp_key + rtp_base_key_len, rtp_salt_len);
+    if (stat) {
+      /* zeroize temp buffer */
+      octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+      return err_status_init_fail;
+    }
+    memcpy(srtp->salt, tmp_key + rtp_base_key_len, SRTP_AEAD_SALT_LEN);
+  }
+  if (rtp_salt_len > 0) {
+    debug_print(mod_srtp, "cipher salt: %s",
+		octet_string_hex_string(tmp_key + rtp_base_key_len, rtp_salt_len));
+  }
+
+  /* initialize cipher */
+  stat = cipher_init(srtp->rtp_cipher, tmp_key);
+  if (stat) {
+    /* zeroize temp buffer */
+    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+    return err_status_init_fail;
+  }
 
   /* generate authentication key */
-  srtp_kdf_generate(&kdf, label_rtp_msg_auth,
-		    tmp_key, auth_get_key_length(srtp->rtp_auth));
+  stat = srtp_kdf_generate(&kdf, label_rtp_msg_auth,
+			   tmp_key, auth_get_key_length(srtp->rtp_auth));
+  if (stat) {
+    /* zeroize temp buffer */
+    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+    return err_status_init_fail;
+  }
   debug_print(mod_srtp, "auth key:   %s",
 	      octet_string_hex_string(tmp_key, 
@@ -413,28 +618,11 @@
    */
 
+  rtcp_base_key_len = base_key_length(srtp->rtcp_cipher->type, rtcp_keylen);
+  rtcp_salt_len = rtcp_keylen - rtcp_base_key_len;
+  debug_print(mod_srtp, "rtcp salt len: %d", rtcp_salt_len);
+  
   /* generate encryption key  */
-  srtp_kdf_generate(&kdf, label_rtcp_encryption, 
-		    tmp_key, cipher_get_key_length(srtp->rtcp_cipher));
-  /* 
-   * if the cipher in the srtp context is aes_icm, then we need
-   * to generate the salt value
-   */
-  if (srtp->rtcp_cipher->type == &aes_icm) {
-    /* FIX!!! this is really the cipher key length; rest is salt */
-    int base_key_len = 16;
-    int salt_len = cipher_get_key_length(srtp->rtcp_cipher) - base_key_len;
-
-    debug_print(mod_srtp, "found aes_icm, generating rtcp salt", NULL);
-
-    /* generate encryption salt, put after encryption key */
-    srtp_kdf_generate(&kdf, label_rtcp_salt, 
-		      tmp_key + base_key_len, salt_len);
-  }
-  debug_print(mod_srtp, "rtcp cipher key: %s", 
-	      octet_string_hex_string(tmp_key, 
-		   cipher_get_key_length(srtp->rtcp_cipher)));  
-
-  /* initialize cipher */
-  stat = cipher_init(srtp->rtcp_cipher, tmp_key, direction_any);
+  stat = srtp_kdf_generate(&kdf, label_rtcp_encryption, 
+			   tmp_key, rtcp_base_key_len);
   if (stat) {
     /* zeroize temp buffer */
@@ -443,7 +631,46 @@
   }
 
+  /* 
+   * if the cipher in the srtp context uses a salt, then we need
+   * to generate the salt value
+   */
+  if (rtcp_salt_len > 0) {
+    debug_print(mod_srtp, "found rtcp_salt_len > 0, generating rtcp salt",
+		NULL);
+
+    /* generate encryption salt, put after encryption key */
+    stat = srtp_kdf_generate(&kdf, label_rtcp_salt, 
+			     tmp_key + rtcp_base_key_len, rtcp_salt_len);
+    if (stat) {
+      /* zeroize temp buffer */
+      octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+      return err_status_init_fail;
+    }
+    memcpy(srtp->c_salt, tmp_key + rtcp_base_key_len, SRTP_AEAD_SALT_LEN);
+  }
+  debug_print(mod_srtp, "rtcp cipher key: %s", 
+	      octet_string_hex_string(tmp_key, rtcp_base_key_len));  
+  if (rtcp_salt_len > 0) {
+    debug_print(mod_srtp, "rtcp cipher salt: %s",
+		octet_string_hex_string(tmp_key + rtcp_base_key_len, rtcp_salt_len));
+  }
+
+  /* initialize cipher */
+  stat = cipher_init(srtp->rtcp_cipher, tmp_key);
+  if (stat) {
+    /* zeroize temp buffer */
+    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+    return err_status_init_fail;
+  }
+
   /* generate authentication key */
-  srtp_kdf_generate(&kdf, label_rtcp_msg_auth,
-		    tmp_key, auth_get_key_length(srtp->rtcp_auth));
+  stat = srtp_kdf_generate(&kdf, label_rtcp_msg_auth,
+			   tmp_key, auth_get_key_length(srtp->rtcp_auth));
+  if (stat) {
+    /* zeroize temp buffer */
+    octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);
+    return err_status_init_fail;
+  }
+
   debug_print(mod_srtp, "rtcp auth key:   %s",
 	      octet_string_hex_string(tmp_key, 
@@ -459,6 +686,8 @@
 
   /* clear memory then return */
-  srtp_kdf_clear(&kdf);
+  stat = srtp_kdf_clear(&kdf);
   octet_string_set_to_zero(tmp_key, MAX_SRTP_KEY_LEN);  
+  if (stat)
+    return err_status_init_fail;
 
   return err_status_ok;
@@ -474,5 +703,16 @@
 
    /* initialize replay database */
-   rdbx_init(&srtp->rtp_rdbx);
+   /* window size MUST be at least 64.  MAY be larger.  Values more than
+    * 2^15 aren't meaningful due to how extended sequence numbers are
+    * calculated.   Let a window size of 0 imply the default value. */
+
+   if (p->window_size != 0 && (p->window_size < 64 || p->window_size >= 0x8000))
+     return err_status_bad_param;
+
+   if (p->window_size != 0)
+     err = rdbx_init(&srtp->rtp_rdbx, p->window_size);
+   else
+     err = rdbx_init(&srtp->rtp_rdbx, 128);
+   if (err) return err;
 
    /* initialize key limit to maximum value */
@@ -484,5 +724,5 @@
 }
 #else
-   key_limit_set(srtp->limit, PJ_UINT64(0xffffffffffff));
+   key_limit_set(srtp->limit, 0xffffffffffffLL);
 #endif
 
@@ -504,9 +744,30 @@
    rdb_init(&srtp->rtcp_rdb);
 
+   /* initialize allow_repeat_tx */
+   /* guard against uninitialized memory: allow only 0 or 1 here */
+   if (p->allow_repeat_tx != 0 && p->allow_repeat_tx != 1) {
+     rdbx_dealloc(&srtp->rtp_rdbx);
+     return err_status_bad_param;
+   }
+   srtp->allow_repeat_tx = p->allow_repeat_tx;
+
    /* DAM - no RTCP key limit at present */
 
    /* initialize keys */
    err = srtp_stream_init_keys(srtp, p->key);
-   if (err) return err;
+   if (err) {
+     rdbx_dealloc(&srtp->rtp_rdbx);
+     return err;
+   }
+
+   /* 
+    * if EKT is in use, then initialize the EKT data associated with
+    * the stream
+    */
+   err = ekt_stream_init_from_policy(srtp->ekt, p->ekt);
+   if (err) {
+     rdbx_dealloc(&srtp->rtp_rdbx);
+     return err;
+   }
 
    return err_status_ok;  
@@ -569,4 +830,365 @@
  }
 
+/*
+ * AEAD uses a new IV formation method.  This function implements
+ * section 9.1 from draft-ietf-avtcore-srtp-aes-gcm-07.txt.  The
+ * calculation is defined as, where (+) is the xor operation:
+ *
+ *
+ *              0  0  0  0  0  0  0  0  0  0  1  1
+ *              0  1  2  3  4  5  6  7  8  9  0  1
+ *            +--+--+--+--+--+--+--+--+--+--+--+--+
+ *            |00|00|    SSRC   |     ROC   | SEQ |---+
+ *            +--+--+--+--+--+--+--+--+--+--+--+--+   |
+ *                                                    |
+ *            +--+--+--+--+--+--+--+--+--+--+--+--+   |
+ *            |         Encryption Salt           |->(+)
+ *            +--+--+--+--+--+--+--+--+--+--+--+--+   |
+ *                                                    |
+ *            +--+--+--+--+--+--+--+--+--+--+--+--+   |
+ *            |       Initialization Vector       |<--+
+ *            +--+--+--+--+--+--+--+--+--+--+--+--+*
+ *
+ * Input:  *stream - pointer to SRTP stream context, used to retrieve
+ *                   the SALT 
+ *         *iv     - Pointer to receive the calculated IV
+ *         *seq    - The ROC and SEQ value to use for the
+ *                   IV calculation.
+ *         *hdr    - The RTP header, used to get the SSRC value
+ *
+ */
+static void srtp_calc_aead_iv(srtp_stream_ctx_t *stream, v128_t *iv, 
+	                      xtd_seq_num_t *seq, srtp_hdr_t *hdr)
+{
+    v128_t	in;
+    v128_t	salt;
+
+#ifdef NO_64BIT_MATH
+    uint32_t local_roc = ((high32(*seq) << 16) |
+                         (low32(*seq) >> 16));
+    uint16_t local_seq = (uint16_t) (low32(*seq));
+#else
+    uint32_t local_roc = (uint32_t)(*seq >> 16);
+    uint16_t local_seq = (uint16_t) *seq;
+#endif
+
+    memset(&in, 0, sizeof(v128_t));
+    memset(&salt, 0, sizeof(v128_t));
+
+    in.v16[5] = htons(local_seq);
+    local_roc = htonl(local_roc);
+    memcpy(&in.v16[3], &local_roc, sizeof(local_roc));
+
+    /*
+     * Copy in the RTP SSRC value
+     */
+    memcpy(&in.v8[2], &hdr->ssrc, 4);
+    debug_print(mod_srtp, "Pre-salted RTP IV = %s\n", v128_hex_string(&in));
+
+    /*
+     * Get the SALT value from the context
+     */
+    memcpy(salt.v8, stream->salt, SRTP_AEAD_SALT_LEN);
+    debug_print(mod_srtp, "RTP SALT = %s\n", v128_hex_string(&salt));
+
+    /*
+     * Finally, apply tyhe SALT to the input
+     */
+    v128_xor(iv, &in, &salt);
+}
+
+
+/*
+ * This function handles outgoing SRTP packets while in AEAD mode,
+ * which currently supports AES-GCM encryption.  All packets are
+ * encrypted and authenticated.
+ */
+static err_status_t
+srtp_protect_aead (srtp_ctx_t *ctx, srtp_stream_ctx_t *stream, 
+	           void *rtp_hdr, unsigned int *pkt_octet_len)
+{
+    srtp_hdr_t *hdr = (srtp_hdr_t*)rtp_hdr;
+    uint32_t *enc_start;        /* pointer to start of encrypted portion  */
+    int enc_octet_len = 0; /* number of octets in encrypted portion  */
+    xtd_seq_num_t est;          /* estimated xtd_seq_num_t of *hdr        */
+    int delta;                  /* delta of local pkt idx and that in hdr */
+    err_status_t status;
+    int tag_len;
+    v128_t iv;
+    unsigned int aad_len;
+
+    debug_print(mod_srtp, "function srtp_protect_aead", NULL);
+
+    /*
+     * update the key usage limit, and check it to make sure that we
+     * didn't just hit either the soft limit or the hard limit, and call
+     * the event handler if we hit either.
+     */
+    switch (key_limit_update(stream->limit)) {
+    case key_event_normal:
+        break;
+    case key_event_hard_limit:
+        srtp_handle_event(ctx, stream, event_key_hard_limit);
+        return err_status_key_expired;
+    case key_event_soft_limit:
+    default:
+        srtp_handle_event(ctx, stream, event_key_soft_limit);
+        break;
+    }
+
+    /* get tag length from stream */
+    tag_len = auth_get_tag_length(stream->rtp_auth);
+
+    /*
+     * find starting point for encryption and length of data to be
+     * encrypted - the encrypted portion starts after the rtp header
+     * extension, if present; otherwise, it starts after the last csrc,
+     * if any are present
+     */
+     enc_start = (uint32_t*)hdr + uint32s_in_rtp_header + hdr->cc;
+     if (hdr->x == 1) {
+         srtp_hdr_xtnd_t *xtn_hdr = (srtp_hdr_xtnd_t*)enc_start;
+         enc_start += (ntohs(xtn_hdr->length) + 1);
+     }
+     if (!((uint8_t*)enc_start <= (uint8_t*)hdr + *pkt_octet_len))
+         return err_status_parse_err;
+     enc_octet_len = (int)(*pkt_octet_len -
+                                    ((uint8_t*)enc_start - (uint8_t*)hdr));
+     if (enc_octet_len < 0) return err_status_parse_err;
+
+    /*
+     * estimate the packet index using the start of the replay window
+     * and the sequence number from the header
+     */
+    delta = rdbx_estimate_index(&stream->rtp_rdbx, &est, ntohs(hdr->seq));
+    status = rdbx_check(&stream->rtp_rdbx, delta);
+    if (status) {
+	if (status != err_status_replay_fail || !stream->allow_repeat_tx) {
+	    return status;  /* we've been asked to reuse an index */
+	}
+    } else {
+	rdbx_add_index(&stream->rtp_rdbx, delta);
+    }
+
+#ifdef NO_64BIT_MATH
+    debug_print2(mod_srtp, "estimated packet index: %08x%08x",
+                 high32(est), low32(est));
+#else
+    debug_print(mod_srtp, "estimated packet index: %016llx", est);
+#endif
+
+    /*
+     * AEAD uses a new IV formation method
+     */
+    srtp_calc_aead_iv(stream, &iv, &est, hdr);
+    status = cipher_set_iv(stream->rtp_cipher, &iv, direction_encrypt);
+    if (status) {
+        return err_status_cipher_fail;
+    }
+
+    /* shift est, put into network byte order */
+#ifdef NO_64BIT_MATH
+    est = be64_to_cpu(make64((high32(est) << 16) |
+                             (low32(est) >> 16),
+                             low32(est) << 16));
+#else
+    est = be64_to_cpu(est << 16);
+#endif
+
+    /*
+     * Set the AAD over the RTP header 
+     */
+    aad_len = (uint8_t *)enc_start - (uint8_t *)hdr;
+    status = cipher_set_aad(stream->rtp_cipher, (uint8_t*)hdr, aad_len);
+    if (status) {
+        return ( err_status_cipher_fail);
+    }
+
+    /* Encrypt the payload  */
+    status = cipher_encrypt(stream->rtp_cipher,
+                            (uint8_t*)enc_start, (unsigned int *)&enc_octet_len);
+    if (status) {
+        return err_status_cipher_fail;
+    }
+    /*
+     * If we're doing GCM, we need to get the tag
+     * and append that to the output
+     */
+    status = cipher_get_tag(stream->rtp_cipher, 
+                            (uint8_t*)enc_start+enc_octet_len, &tag_len);
+    if (status) {
+	return ( err_status_cipher_fail);
+    }
+
+    /* increase the packet length by the length of the auth tag */
+    *pkt_octet_len += tag_len;
+
+    return err_status_ok;
+}
+
+
+/*
+ * This function handles incoming SRTP packets while in AEAD mode,
+ * which currently supports AES-GCM encryption.  All packets are
+ * encrypted and authenticated.  Note, the auth tag is at the end
+ * of the packet stream and is automatically checked by GCM
+ * when decrypting the payload.
+ */
+static err_status_t
+srtp_unprotect_aead (srtp_ctx_t *ctx, srtp_stream_ctx_t *stream, int delta, 
+	             xtd_seq_num_t est, void *srtp_hdr, unsigned int *pkt_octet_len)
+{
+    srtp_hdr_t *hdr = (srtp_hdr_t*)srtp_hdr;
+    uint32_t *enc_start;        /* pointer to start of encrypted portion  */
+    unsigned int enc_octet_len = 0; /* number of octets in encrypted portion */
+    v128_t iv;
+    err_status_t status;
+    int tag_len;
+    unsigned int aad_len;
+
+    debug_print(mod_srtp, "function srtp_unprotect_aead", NULL);
+
+#ifdef NO_64BIT_MATH
+    debug_print2(mod_srtp, "estimated u_packet index: %08x%08x", high32(est), low32(est));
+#else
+    debug_print(mod_srtp, "estimated u_packet index: %016llx", est);
+#endif
+
+    /* get tag length from stream */
+    tag_len = auth_get_tag_length(stream->rtp_auth);
+
+    /*
+     * AEAD uses a new IV formation method 
+     */
+    srtp_calc_aead_iv(stream, &iv, &est, hdr);
+    status = cipher_set_iv(stream->rtp_cipher, &iv, direction_decrypt);
+    if (status) {
+        return err_status_cipher_fail;
+    }
+
+    /*
+     * find starting point for decryption and length of data to be
+     * decrypted - the encrypted portion starts after the rtp header
+     * extension, if present; otherwise, it starts after the last csrc,
+     * if any are present
+     */
+    enc_start = (uint32_t*)hdr + uint32s_in_rtp_header + hdr->cc;
+    if (hdr->x == 1) {
+        srtp_hdr_xtnd_t *xtn_hdr = (srtp_hdr_xtnd_t*)enc_start;
+        enc_start += (ntohs(xtn_hdr->length) + 1);
+    }
+    if (!((uint8_t*)enc_start <= (uint8_t*)hdr + (*pkt_octet_len - tag_len)))
+        return err_status_parse_err;
+    /*
+     * We pass the tag down to the cipher when doing GCM mode 
+     */
+    enc_octet_len = (unsigned int)(*pkt_octet_len - 
+                                   ((uint8_t*)enc_start - (uint8_t*)hdr));
+
+    /*
+     * Sanity check the encrypted payload length against
+     * the tag size.  It must always be at least as large
+     * as the tag length.
+     */
+    if (enc_octet_len < (unsigned int) tag_len) {
+        return err_status_cipher_fail;
+    }
+
+    /*
+     * update the key usage limit, and check it to make sure that we
+     * didn't just hit either the soft limit or the hard limit, and call
+     * the event handler if we hit either.
+     */
+    switch (key_limit_update(stream->limit)) {
+    case key_event_normal:
+        break;
+    case key_event_soft_limit:
+        srtp_handle_event(ctx, stream, event_key_soft_limit);
+        break;
+    case key_event_hard_limit:
+        srtp_handle_event(ctx, stream, event_key_hard_limit);
+        return err_status_key_expired;
+    default:
+        break;
+    }
+
+    /*
+     * Set the AAD for AES-GCM, which is the RTP header
+     */
+    aad_len = (uint8_t *)enc_start - (uint8_t *)hdr;
+    status = cipher_set_aad(stream->rtp_cipher, (uint8_t*)hdr, aad_len);
+    if (status) {
+        return ( err_status_cipher_fail);
+    }
+
+    /* Decrypt the ciphertext.  This also checks the auth tag based 
+     * on the AAD we just specified above */
+    status = cipher_decrypt(stream->rtp_cipher,
+                            (uint8_t*)enc_start, &enc_octet_len);
+    if (status) {
+        return status;
+    }
+
+    /*
+     * verify that stream is for received traffic - this check will
+     * detect SSRC collisions, since a stream that appears in both
+     * srtp_protect() and srtp_unprotect() will fail this test in one of
+     * those functions.
+     *
+     * we do this check *after* the authentication check, so that the
+     * latter check will catch any attempts to fool us into thinking
+     * that we've got a collision
+     */
+    if (stream->direction != dir_srtp_receiver) {
+        if (stream->direction == dir_unknown) {
+            stream->direction = dir_srtp_receiver;
+        } else {
+            srtp_handle_event(ctx, stream, event_ssrc_collision);
+        }
+    }
+
+    /*
+     * if the stream is a 'provisional' one, in which the template context
+     * is used, then we need to allocate a new stream at this point, since
+     * the authentication passed
+     */
+    if (stream == ctx->stream_template) {
+        srtp_stream_ctx_t *new_stream;
+
+        /*
+         * allocate and initialize a new stream
+         *
+         * note that we indicate failure if we can't allocate the new
+         * stream, and some implementations will want to not return
+         * failure here
+         */
+        status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream);
+        if (status) {
+            return status;
+        }
+
+        /* add new stream to the head of the stream_list */
+        new_stream->next = ctx->stream_list;
+        ctx->stream_list = new_stream;
+
+        /* set stream (the pointer used in this function) */
+        stream = new_stream;
+    }
+
+    /*
+     * the message authentication function passed, so add the packet
+     * index into the replay database
+     */
+    rdbx_add_index(&stream->rtp_rdbx, delta);
+
+    /* decrease the packet length by the length of the auth tag */
+    *pkt_octet_len -= tag_len;
+
+    return err_status_ok;
+}
+
+
+
+
  err_status_t
  srtp_protect(srtp_ctx_t *ctx, void *rtp_hdr, int *pkt_octet_len) {
@@ -574,5 +1196,5 @@
    uint32_t *enc_start;        /* pointer to start of encrypted portion  */
    uint32_t *auth_start;       /* pointer to start of auth. portion      */
-   unsigned enc_octet_len = 0; /* number of octets in encrypted portion  */
+   int enc_octet_len = 0; /* number of octets in encrypted portion  */
    xtd_seq_num_t est;          /* estimated xtd_seq_num_t of *hdr        */
    int delta;                  /* delta of local pkt idx and that in hdr */
@@ -586,4 +1208,9 @@
 
   /* we assume the hdr is 32-bit aligned to start */
+
+  /* Verify RTP header */
+  status = srtp_validate_rtp_header(rtp_hdr, pkt_octet_len);
+  if (status)
+    return status;
 
    /* check the packet length - it must at least contain a full header */
@@ -630,5 +1257,5 @@
     * those functions.
     */
-   if (stream->direction != dir_srtp_sender) {
+  if (stream->direction != dir_srtp_sender) {
      if (stream->direction == dir_unknown) {
        stream->direction = dir_srtp_sender;
@@ -636,5 +1263,14 @@
        srtp_handle_event(ctx, stream, event_ssrc_collision);
      }
-   }
+  }
+
+   /*
+    * Check if this is an AEAD stream (GCM mode).  If so, then dispatch
+    * the request to our AEAD handler.
+    */
+  if (stream->rtp_cipher->algorithm == AES_128_GCM ||
+      stream->rtp_cipher->algorithm == AES_256_GCM) {
+      return srtp_protect_aead(ctx, stream, rtp_hdr, (unsigned int*)pkt_octet_len);
+  }
 
   /* 
@@ -673,6 +1309,9 @@
        enc_start += (ntohs(xtn_hdr->length) + 1);
      }
-     enc_octet_len = (unsigned int)(*pkt_octet_len 
-				    - ((enc_start - (uint32_t *)hdr) << 2));
+     if (!((uint8_t*)enc_start <= (uint8_t*)hdr + *pkt_octet_len))
+       return err_status_parse_err;
+     enc_octet_len = (int)(*pkt_octet_len -
+                                    ((uint8_t*)enc_start - (uint8_t*)hdr));
+     if (enc_octet_len < 0) return err_status_parse_err;
    } else {
      enc_start = NULL;
@@ -698,7 +1337,10 @@
    delta = rdbx_estimate_index(&stream->rtp_rdbx, &est, ntohs(hdr->seq));
    status = rdbx_check(&stream->rtp_rdbx, delta);
-   if (status)
-     return status;  /* we've been asked to reuse an index */
-   rdbx_add_index(&stream->rtp_rdbx, delta);
+   if (status) {
+     if (status != err_status_replay_fail || !stream->allow_repeat_tx)
+       return status;  /* we've been asked to reuse an index */
+   }
+   else
+     rdbx_add_index(&stream->rtp_rdbx, delta);
 
 #ifdef NO_64BIT_MATH
@@ -712,5 +1354,6 @@
     * if we're using rindael counter mode, set nonce and seq 
     */
-   if (stream->rtp_cipher->type == &aes_icm) {
+   if (stream->rtp_cipher->type->id == AES_ICM ||
+       stream->rtp_cipher->type->id == AES_256_ICM) {
      v128_t iv;
 
@@ -723,5 +1366,5 @@
      iv.v64[1] = be64_to_cpu(est << 16);
 #endif
-     status = cipher_set_iv(stream->rtp_cipher, &iv);
+     status = cipher_set_iv(stream->rtp_cipher, &iv, direction_encrypt);
 
    } else {  
@@ -736,5 +1379,5 @@
 #endif
      iv.v64[1] = be64_to_cpu(est);
-     status = cipher_set_iv(stream->rtp_cipher, &iv);
+     status = cipher_set_iv(stream->rtp_cipher, &iv, direction_encrypt);
    }
    if (status)
@@ -769,5 +1412,5 @@
   if (enc_start) {
     status = cipher_encrypt(stream->rtp_cipher, 
-			    (uint8_t *)enc_start, &enc_octet_len);
+			    (uint8_t *)enc_start, (unsigned int*)&enc_octet_len);
     if (status)
       return err_status_cipher_fail;
@@ -814,5 +1457,5 @@
   uint32_t *enc_start;      /* pointer to start of encrypted portion  */
   uint32_t *auth_start;     /* pointer to start of auth. portion      */
-  unsigned enc_octet_len = 0;/* number of octets in encrypted portion */
+  unsigned int enc_octet_len = 0;/* number of octets in encrypted portion */
   uint8_t *auth_tag = NULL; /* location of auth_tag within packet     */
   xtd_seq_num_t est;        /* estimated xtd_seq_num_t of *hdr        */
@@ -827,4 +1470,9 @@
 
   /* we assume the hdr is 32-bit aligned to start */
+
+  /* Verify RTP header */
+  status = srtp_validate_rtp_header(srtp_hdr, pkt_octet_len);
+  if (status)
+    return status;
 
   /* check the packet length - it must at least contain a full header */
@@ -882,4 +1530,13 @@
 #endif
 
+  /*
+   * Check if this is an AEAD stream (GCM mode).  If so, then dispatch
+   * the request to our AEAD handler.
+   */
+  if (stream->rtp_cipher->algorithm == AES_128_GCM ||
+      stream->rtp_cipher->algorithm == AES_256_GCM) {
+      return srtp_unprotect_aead(ctx, stream, delta, est, srtp_hdr, (unsigned int*)pkt_octet_len);
+  }
+
   /* get tag length from stream */
   tag_len = auth_get_tag_length(stream->rtp_auth); 
@@ -889,5 +1546,6 @@
    * happen to be using
    */
-  if (stream->rtp_cipher->type == &aes_icm) {
+  if (stream->rtp_cipher->type->id == AES_ICM ||
+      stream->rtp_cipher->type->id == AES_256_ICM) {
 
     /* aes counter mode */
@@ -900,5 +1558,5 @@
     iv.v64[1] = be64_to_cpu(est << 16);
 #endif
-    status = aes_icm_set_iv((aes_icm_ctx_t*)stream->rtp_cipher->state, &iv);
+    status = cipher_set_iv(stream->rtp_cipher, &iv, direction_decrypt);
   } else {  
     
@@ -911,5 +1569,5 @@
 #endif
     iv.v64[1] = be64_to_cpu(est);
-    status = cipher_set_iv(stream->rtp_cipher, &iv);
+    status = cipher_set_iv(stream->rtp_cipher, &iv, direction_decrypt);
   }
   if (status)
@@ -939,6 +1597,8 @@
       enc_start += (ntohs(xtn_hdr->length) + 1);
     }  
-    enc_octet_len = (uint32_t)(*pkt_octet_len - tag_len 
-			       - ((enc_start - (uint32_t *)hdr) << 2));
+    if (!((uint8_t*)enc_start <= (uint8_t*)hdr + (*pkt_octet_len - tag_len)))
+      return err_status_parse_err;
+    enc_octet_len = (uint32_t)(*pkt_octet_len - tag_len -
+                               ((uint8_t*)enc_start - (uint8_t*)hdr));
   } else {
     enc_start = NULL;
@@ -1021,7 +1681,7 @@
   }
 
-  /* if we're encrypting, add keystream into ciphertext */
+  /* if we're decrypting, add keystream into ciphertext */
   if (enc_start) {
-    status = cipher_encrypt(stream->rtp_cipher, 
+    status = cipher_decrypt(stream->rtp_cipher, 
 			    (uint8_t *)enc_start, &enc_octet_len);
     if (status)
@@ -1104,11 +1764,17 @@
 
 err_status_t
-srtp_deinit() {
+srtp_shutdown() {
   err_status_t status;
 
+  /* shut down crypto kernel */
   status = crypto_kernel_shutdown();
-
-  return status;
-}
+  if (status) 
+    return status;
+
+  /* shutting down crypto kernel frees the srtp debug module as well */
+
+  return err_status_ok;
+}
+
 
 /* 
@@ -1190,4 +1856,7 @@
     if (status)
       return status;
+    status = rdbx_dealloc(&session->stream_template->rtp_rdbx);
+    if (status)
+      return status;
     crypto_free(session->stream_template);
   }
@@ -1282,4 +1951,5 @@
   ctx->stream_template = NULL;
   ctx->stream_list = NULL;
+  ctx->user_data = NULL;
   while (policy != NULL) {    
 
@@ -1318,5 +1988,9 @@
 
   /* remove stream from the list */
-  last_stream->next = stream->next;
+  if (last_stream == stream)
+    /* stream was first in list */
+    session->stream_list = stream->next;
+  else
+    last_stream->next = stream->next;
 
   /* deallocate the stream */
@@ -1346,5 +2020,5 @@
 crypto_policy_set_rtp_default(crypto_policy_t *p) {
 
-  p->cipher_type     = AES_128_ICM;           
+  p->cipher_type     = AES_ICM;           
   p->cipher_key_len  = 30;                /* default 128 bits per RFC 3711 */
   p->auth_type       = HMAC_SHA1;             
@@ -1358,5 +2032,5 @@
 crypto_policy_set_rtcp_default(crypto_policy_t *p) {
 
-  p->cipher_type     = AES_128_ICM;           
+  p->cipher_type     = AES_ICM;           
   p->cipher_key_len  = 30;                 /* default 128 bits per RFC 3711 */
   p->auth_type       = HMAC_SHA1;             
@@ -1371,10 +2045,10 @@
 
   /*
-   * corresponds to draft-ietf-mmusic-sdescriptions-12.txt
+   * corresponds to RFC 4568
    *
    * note that this crypto policy is intended for SRTP, but not SRTCP
    */
 
-  p->cipher_type     = AES_128_ICM;           
+  p->cipher_type     = AES_ICM;           
   p->cipher_key_len  = 30;                /* 128 bit key, 112 bit salt */
   p->auth_type       = HMAC_SHA1;             
@@ -1390,10 +2064,10 @@
 
   /*
-   * corresponds to draft-ietf-mmusic-sdescriptions-12.txt
+   * corresponds to RFC 4568
    *
    * note that this crypto policy is intended for SRTP, but not SRTCP
    */
 
-  p->cipher_type     = AES_128_ICM;           
+  p->cipher_type     = AES_ICM;           
   p->cipher_key_len  = 30;                /* 128 bit key, 112 bit salt */
   p->auth_type       = NULL_AUTH;             
@@ -1409,5 +2083,5 @@
 
   /*
-   * corresponds to draft-ietf-mmusic-sdescriptions-12.txt
+   * corresponds to RFC 4568
    */
 
@@ -1422,7 +2096,521 @@
 
 
+void
+crypto_policy_set_aes_cm_256_hmac_sha1_80(crypto_policy_t *p) {
+
+  /*
+   * corresponds to draft-ietf-avt-big-aes-03.txt
+   */
+
+  p->cipher_type     = AES_ICM;           
+  p->cipher_key_len  = 46;
+  p->auth_type       = HMAC_SHA1;             
+  p->auth_key_len    = 20;                /* default 160 bits per RFC 3711 */
+  p->auth_tag_len    = 10;                /* default 80 bits per RFC 3711 */
+  p->sec_serv        = sec_serv_conf_and_auth;
+}
+
+
+void
+crypto_policy_set_aes_cm_256_hmac_sha1_32(crypto_policy_t *p) {
+
+  /*
+   * corresponds to draft-ietf-avt-big-aes-03.txt
+   *
+   * note that this crypto policy is intended for SRTP, but not SRTCP
+   */
+
+  p->cipher_type     = AES_ICM;           
+  p->cipher_key_len  = 46;
+  p->auth_type       = HMAC_SHA1;             
+  p->auth_key_len    = 20;                /* default 160 bits per RFC 3711 */
+  p->auth_tag_len    = 4;                 /* default 80 bits per RFC 3711 */
+  p->sec_serv        = sec_serv_conf_and_auth;
+}
+
+/*
+ * AES-256 with no authentication.
+ */
+void
+crypto_policy_set_aes_cm_256_null_auth (crypto_policy_t *p)
+{
+    p->cipher_type     = AES_ICM;
+    p->cipher_key_len  = 46;
+    p->auth_type       = NULL_AUTH;
+    p->auth_key_len    = 0;
+    p->auth_tag_len    = 0;
+    p->sec_serv        = sec_serv_conf;
+}
+
+#ifdef OPENSSL
+/*
+ * AES-128 GCM mode with 8 octet auth tag. 
+ */
+void
+crypto_policy_set_aes_gcm_128_8_auth(crypto_policy_t *p) {
+  p->cipher_type     = AES_128_GCM;           
+  p->cipher_key_len  = AES_128_GCM_KEYSIZE_WSALT; 
+  p->auth_type       = NULL_AUTH; /* GCM handles the auth for us */            
+  p->auth_key_len    = 0; 
+  p->auth_tag_len    = 8;   /* 8 octet tag length */
+  p->sec_serv        = sec_serv_conf_and_auth;
+}
+
+/*
+ * AES-256 GCM mode with 8 octet auth tag. 
+ */
+void
+crypto_policy_set_aes_gcm_256_8_auth(crypto_policy_t *p) {
+  p->cipher_type     = AES_256_GCM;           
+  p->cipher_key_len  = AES_256_GCM_KEYSIZE_WSALT; 
+  p->auth_type       = NULL_AUTH; /* GCM handles the auth for us */ 
+  p->auth_key_len    = 0; 
+  p->auth_tag_len    = 8;   /* 8 octet tag length */
+  p->sec_serv        = sec_serv_conf_and_auth;
+}
+
+/*
+ * AES-128 GCM mode with 8 octet auth tag, no RTCP encryption. 
+ */
+void
+crypto_policy_set_aes_gcm_128_8_only_auth(crypto_policy_t *p) {
+  p->cipher_type     = AES_128_GCM;           
+  p->cipher_key_len  = AES_128_GCM_KEYSIZE_WSALT; 
+  p->auth_type       = NULL_AUTH; /* GCM handles the auth for us */ 
+  p->auth_key_len    = 0; 
+  p->auth_tag_len    = 8;   /* 8 octet tag length */
+  p->sec_serv        = sec_serv_auth;  /* This only applies to RTCP */
+}
+
+/*
+ * AES-256 GCM mode with 8 octet auth tag, no RTCP encryption. 
+ */
+void
+crypto_policy_set_aes_gcm_256_8_only_auth(crypto_policy_t *p) {
+  p->cipher_type     = AES_256_GCM;           
+  p->cipher_key_len  = AES_256_GCM_KEYSIZE_WSALT; 
+  p->auth_type       = NULL_AUTH; /* GCM handles the auth for us */ 
+  p->auth_key_len    = 0; 
+  p->auth_tag_len    = 8;   /* 8 octet tag length */
+  p->sec_serv        = sec_serv_auth;  /* This only applies to RTCP */
+}
+
+/*
+ * AES-128 GCM mode with 16 octet auth tag. 
+ */
+void
+crypto_policy_set_aes_gcm_128_16_auth(crypto_policy_t *p) {
+  p->cipher_type     = AES_128_GCM;           
+  p->cipher_key_len  = AES_128_GCM_KEYSIZE_WSALT; 
+  p->auth_type       = NULL_AUTH; /* GCM handles the auth for us */            
+  p->auth_key_len    = 0; 
+  p->auth_tag_len    = 16;   /* 16 octet tag length */
+  p->sec_serv        = sec_serv_conf_and_auth;
+}
+
+/*
+ * AES-256 GCM mode with 16 octet auth tag. 
+ */
+void
+crypto_policy_set_aes_gcm_256_16_auth(crypto_policy_t *p) {
+  p->cipher_type     = AES_256_GCM;           
+  p->cipher_key_len  = AES_256_GCM_KEYSIZE_WSALT; 
+  p->auth_type       = NULL_AUTH; /* GCM handles the auth for us */ 
+  p->auth_key_len    = 0; 
+  p->auth_tag_len    = 16;   /* 16 octet tag length */
+  p->sec_serv        = sec_serv_conf_and_auth;
+}
+
+#endif
+
 /* 
  * secure rtcp functions
  */
+
+/*
+ * AEAD uses a new IV formation method.  This function implements
+ * section 10.1 from draft-ietf-avtcore-srtp-aes-gcm-07.txt.  The
+ * calculation is defined as, where (+) is the xor operation:
+ *
+ *                0  1  2  3  4  5  6  7  8  9 10 11
+ *               +--+--+--+--+--+--+--+--+--+--+--+--+
+ *               |00|00|    SSRC   |00|00|0+SRTCP Idx|---+
+ *               +--+--+--+--+--+--+--+--+--+--+--+--+   |
+ *                                                       |
+ *               +--+--+--+--+--+--+--+--+--+--+--+--+   |
+ *               |         Encryption Salt           |->(+)
+ *               +--+--+--+--+--+--+--+--+--+--+--+--+   |
+ *                                                       |
+ *               +--+--+--+--+--+--+--+--+--+--+--+--+   |
+ *               |       Initialization Vector       |<--+
+ *               +--+--+--+--+--+--+--+--+--+--+--+--+*
+ *
+ * Input:  *stream - pointer to SRTP stream context, used to retrieve
+ *                   the SALT 
+ *         *iv     - Pointer to recieve the calculated IV
+ *         seq_num - The SEQ value to use for the IV calculation.
+ *         *hdr    - The RTP header, used to get the SSRC value
+ *
+ */
+static void srtp_calc_aead_iv_srtcp(srtp_stream_ctx_t *stream, v128_t *iv, 
+                                    uint32_t seq_num, srtcp_hdr_t *hdr)
+{
+    v128_t	in;
+    v128_t	salt;
+
+    memset(&in, 0, sizeof(v128_t));
+    memset(&salt, 0, sizeof(v128_t));
+
+    in.v16[0] = 0;
+    memcpy(&in.v16[1], &hdr->ssrc, 4); /* still in network order! */
+    in.v16[3] = 0;
+    in.v32[2] = 0x7FFFFFFF & htonl(seq_num); /* bit 32 is suppose to be zero */
+
+    debug_print(mod_srtp, "Pre-salted RTCP IV = %s\n", v128_hex_string(&in));
+
+    /*
+     * Get the SALT value from the context
+     */
+    memcpy(salt.v8, stream->c_salt, 12);
+    debug_print(mod_srtp, "RTCP SALT = %s\n", v128_hex_string(&salt));
+
+    /*
+     * Finally, apply the SALT to the input
+     */
+    v128_xor(iv, &in, &salt);
+}
+
+/*
+ * This code handles AEAD ciphers for outgoing RTCP.  We currently support
+ * AES-GCM mode with 128 or 256 bit keys. 
+ */
+static err_status_t
+srtp_protect_rtcp_aead (srtp_t ctx, srtp_stream_ctx_t *stream, 
+                        void *rtcp_hdr, unsigned int *pkt_octet_len)
+{
+    srtcp_hdr_t *hdr = (srtcp_hdr_t*)rtcp_hdr;
+    uint32_t *enc_start;        /* pointer to start of encrypted portion  */
+    uint32_t *trailer;          /* pointer to start of trailer            */
+    unsigned int enc_octet_len = 0; /* number of octets in encrypted portion */
+    uint8_t *auth_tag = NULL;   /* location of auth_tag within packet     */
+    err_status_t status;
+    int tag_len;
+    uint32_t seq_num;
+    v128_t iv;
+    uint32_t tseq;
+
+    /* get tag length from stream context */
+    tag_len = auth_get_tag_length(stream->rtcp_auth);
+
+    /*
+     * set encryption start and encryption length - if we're not
+     * providing confidentiality, set enc_start to NULL
+     */
+    enc_start = (uint32_t*)hdr + uint32s_in_rtcp_header;
+    enc_octet_len = *pkt_octet_len - octets_in_rtcp_header;
+
+    /* NOTE: hdr->length is not usable - it refers to only the first
+           RTCP report in the compound packet! */
+    /* NOTE: trailer is 32-bit aligned because RTCP 'packets' are always
+           multiples of 32-bits (RFC 3550 6.1) */
+    trailer = (uint32_t*)((char*)enc_start + enc_octet_len + tag_len);
+
+    if (stream->rtcp_services & sec_serv_conf) {
+        *trailer = htonl(SRTCP_E_BIT); /* set encrypt bit */
+    } else {
+        enc_start = NULL;
+        enc_octet_len = 0;
+        /* 0 is network-order independant */
+        *trailer = 0x00000000; /* set encrypt bit */
+    }
+
+    /*
+     * set the auth_tag pointer to the proper location, which is after
+     * the payload, but before the trailer
+     * (note that srtpc *always* provides authentication, unlike srtp)
+     */
+    /* Note: This would need to change for optional mikey data */
+    auth_tag = (uint8_t*)hdr + *pkt_octet_len;
+
+    /*
+     * check sequence number for overruns, and copy it into the packet
+     * if its value isn't too big
+     */
+    status = rdb_increment(&stream->rtcp_rdb);
+    if (status) {
+        return status;
+    }
+    seq_num = rdb_get_value(&stream->rtcp_rdb);
+    *trailer |= htonl(seq_num);
+    debug_print(mod_srtp, "srtcp index: %x", seq_num);
+
+    /*
+     * Calculating the IV and pass it down to the cipher 
+     */
+    srtp_calc_aead_iv_srtcp(stream, &iv, seq_num, hdr);
+    status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_encrypt);
+    if (status) {
+        return err_status_cipher_fail;
+    }
+
+    /*
+     * Set the AAD for GCM mode
+     */
+    if (enc_start) {
+	/*
+	 * If payload encryption is enabled, then the AAD consist of
+	 * the RTCP header and the seq# at the end of the packet
+	 */
+	status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)hdr, 
+                                octets_in_rtcp_header);
+	if (status) {
+	    return ( err_status_cipher_fail);
+	}
+    } else {
+	/*
+	 * Since payload encryption is not enabled, we must authenticate
+	 * the entire packet as described in section 10.3 in revision 07
+	 * of the draft.
+	 */
+	status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)hdr, 
+                                *pkt_octet_len);
+	if (status) {
+	    return ( err_status_cipher_fail);
+	}
+    }
+    /* 
+     * Process the sequence# as AAD
+     */
+    tseq = *trailer;
+    status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)&tseq, 
+                            sizeof(srtcp_trailer_t));
+    if (status) {
+        return ( err_status_cipher_fail);
+    }
+
+    /* if we're encrypting, exor keystream into the message */
+    if (enc_start) {
+        status = cipher_encrypt(stream->rtcp_cipher,
+                                (uint8_t*)enc_start, &enc_octet_len);
+        if (status) {
+            return err_status_cipher_fail;
+        }
+	/*
+	 * Get the tag and append that to the output
+	 */
+	status = cipher_get_tag(stream->rtcp_cipher, (uint8_t*)auth_tag, 
+                                &tag_len);
+	if (status) {
+	    return ( err_status_cipher_fail);
+	}
+	enc_octet_len += tag_len;
+    } else {
+	/*
+	 * Even though we're not encrypting the payload, we need
+	 * to run the cipher to get the auth tag.
+	 */
+	unsigned int nolen = 0;
+        status = cipher_encrypt(stream->rtcp_cipher, NULL, &nolen);
+        if (status) {
+            return err_status_cipher_fail;
+        }
+	/*
+	 * Get the tag and append that to the output
+	 */
+	status = cipher_get_tag(stream->rtcp_cipher, (uint8_t*)auth_tag, 
+                                &tag_len);
+	if (status) {
+	    return ( err_status_cipher_fail);
+	}
+	enc_octet_len += tag_len;
+    }
+
+    /* increase the packet length by the length of the auth tag and seq_num*/
+    *pkt_octet_len += (tag_len + sizeof(srtcp_trailer_t));
+
+    return err_status_ok;
+}
+
+/*
+ * This function handles incoming SRTCP packets while in AEAD mode,
+ * which currently supports AES-GCM encryption.  Note, the auth tag is 
+ * at the end of the packet stream and is automatically checked by GCM
+ * when decrypting the payload.
+ */
+static err_status_t
+srtp_unprotect_rtcp_aead (srtp_t ctx, srtp_stream_ctx_t *stream, 
+                          void *srtcp_hdr, unsigned int *pkt_octet_len)
+{
+    srtcp_hdr_t *hdr = (srtcp_hdr_t*)srtcp_hdr;
+    uint32_t *enc_start;        /* pointer to start of encrypted portion  */
+    uint32_t *trailer;          /* pointer to start of trailer            */
+    unsigned int enc_octet_len = 0; /* number of octets in encrypted portion */
+    uint8_t *auth_tag = NULL;   /* location of auth_tag within packet     */
+    err_status_t status;
+    int tag_len;
+    unsigned int tmp_len;
+    uint32_t seq_num;
+    v128_t iv;
+    uint32_t tseq;
+
+    /* get tag length from stream context */
+    tag_len = auth_get_tag_length(stream->rtcp_auth);
+
+    /*
+     * set encryption start, encryption length, and trailer
+     */
+    /* index & E (encryption) bit follow normal data.  hdr->len
+           is the number of words (32-bit) in the normal packet minus 1 */
+    /* This should point trailer to the word past the end of the
+           normal data. */
+    /* This would need to be modified for optional mikey data */
+    /*
+     * NOTE: trailer is 32-bit aligned because RTCP 'packets' are always
+     *	 multiples of 32-bits (RFC 3550 6.1)
+     */
+    trailer = (uint32_t*)((char*)hdr + *pkt_octet_len - sizeof(srtcp_trailer_t));
+    /*
+     * We pass the tag down to the cipher when doing GCM mode 
+     */
+    enc_octet_len = *pkt_octet_len - (octets_in_rtcp_header + 
+                                      sizeof(srtcp_trailer_t));
+    auth_tag = (uint8_t*)hdr + *pkt_octet_len - tag_len - sizeof(srtcp_trailer_t);
+
+    if (*((unsigned char*)trailer) & SRTCP_E_BYTE_BIT) {
+        enc_start = (uint32_t*)hdr + uint32s_in_rtcp_header;
+    } else {
+        enc_octet_len = 0;
+        enc_start = NULL; /* this indicates that there's no encryption */
+    }
+
+    /*
+     * check the sequence number for replays
+     */
+    /* this is easier than dealing with bitfield access */
+    seq_num = ntohl(*trailer) & SRTCP_INDEX_MASK;
+    debug_print(mod_srtp, "srtcp index: %x", seq_num);
+    status = rdb_check(&stream->rtcp_rdb, seq_num);
+    if (status) {
+        return status;
+    }
+
+    /*
+     * Calculate and set the IV
+     */
+    srtp_calc_aead_iv_srtcp(stream, &iv, seq_num, hdr);
+    status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_decrypt);
+    if (status) {
+        return err_status_cipher_fail;
+    }
+
+    /*
+     * Set the AAD for GCM mode
+     */
+    if (enc_start) {
+	/*
+	 * If payload encryption is enabled, then the AAD consist of
+	 * the RTCP header and the seq# at the end of the packet
+	 */
+	status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)hdr, 
+                                octets_in_rtcp_header);
+	if (status) {
+	    return ( err_status_cipher_fail);
+	}
+    } else {
+	/*
+	 * Since payload encryption is not enabled, we must authenticate
+	 * the entire packet as described in section 10.3 in revision 07
+	 * of the draft.
+	 */
+	status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)hdr, 
+			       (*pkt_octet_len - tag_len - sizeof(srtcp_trailer_t)));
+	if (status) {
+	    return ( err_status_cipher_fail);
+	}
+    }
+
+    /* 
+     * Process the sequence# as AAD 
+     */
+    tseq = *trailer;
+    status = cipher_set_aad(stream->rtcp_cipher, (uint8_t*)&tseq, 
+                            sizeof(srtcp_trailer_t));
+    if (status) {
+	return ( err_status_cipher_fail);
+    }
+
+    /* if we're decrypting, exor keystream into the message */
+    if (enc_start) {
+        status = cipher_decrypt(stream->rtcp_cipher,
+                                (uint8_t*)enc_start, &enc_octet_len);
+        if (status) {
+            return status;
+        }
+    } else {
+	/*
+	 * Still need to run the cipher to check the tag
+	 */
+	tmp_len = tag_len;
+        status = cipher_decrypt(stream->rtcp_cipher, (uint8_t*)auth_tag, 
+                                &tmp_len);
+        if (status) {
+            return status;
+        }
+    }
+
+    /* decrease the packet length by the length of the auth tag and seq_num*/
+    *pkt_octet_len -= (tag_len + sizeof(srtcp_trailer_t));
+
+    /*
+     * verify that stream is for received traffic - this check will
+     * detect SSRC collisions, since a stream that appears in both
+     * srtp_protect() and srtp_unprotect() will fail this test in one of
+     * those functions.
+     *
+     * we do this check *after* the authentication check, so that the
+     * latter check will catch any attempts to fool us into thinking
+     * that we've got a collision
+     */
+    if (stream->direction != dir_srtp_receiver) {
+        if (stream->direction == dir_unknown) {
+            stream->direction = dir_srtp_receiver;
+        } else {
+            srtp_handle_event(ctx, stream, event_ssrc_collision);
+        }
+    }
+
+    /*
+     * if the stream is a 'provisional' one, in which the template context
+     * is used, then we need to allocate a new stream at this point, since
+     * the authentication passed
+     */
+    if (stream == ctx->stream_template) {
+        srtp_stream_ctx_t *new_stream;
+
+        /*
+         * allocate and initialize a new stream
+         *
+         * note that we indicate failure if we can't allocate the new
+         * stream, and some implementations will want to not return
+         * failure here
+         */
+        status = srtp_stream_clone(ctx->stream_template, hdr->ssrc, &new_stream);
+        if (status) {
+            return status;
+        }
+
+        /* add new stream to the head of the stream_list */
+        new_stream->next = ctx->stream_list;
+        ctx->stream_list = new_stream;
+
+        /* set stream (the pointer used in this function) */
+        stream = new_stream;
+    }
+
+    /* we've passed the authentication check, so add seq_num to the rdb */
+    rdb_add_index(&stream->rtcp_rdb, seq_num);
+
+    return err_status_ok;
+}
 
 err_status_t 
@@ -1432,5 +2620,5 @@
   uint32_t *auth_start;     /* pointer to start of auth. portion      */
   uint32_t *trailer;        /* pointer to start of trailer            */
-  unsigned enc_octet_len = 0;/* number of octets in encrypted portion */
+  unsigned int enc_octet_len = 0;/* number of octets in encrypted portion */
   uint8_t *auth_tag = NULL; /* location of auth_tag within packet     */
   err_status_t status;   
@@ -1441,4 +2629,9 @@
 
   /* we assume the hdr is 32-bit aligned to start */
+
+  /* check the packet length - it must at least contain a full header */
+  if (*pkt_octet_len < octets_in_rtcp_header)
+    return err_status_bad_param;
+
   /*
    * look up ssrc in srtp_stream list, and process the packet with 
@@ -1485,4 +2678,13 @@
   }  
 
+  /*
+   * Check if this is an AEAD stream (GCM mode).  If so, then dispatch
+   * the request to our AEAD handler.
+   */
+  if (stream->rtp_cipher->algorithm == AES_128_GCM ||
+      stream->rtp_cipher->algorithm == AES_256_GCM) {
+      return srtp_protect_rtcp_aead(ctx, stream, rtcp_hdr, (unsigned int*)pkt_octet_len);
+  }
+
   /* get tag length from stream context */
   tag_len = auth_get_tag_length(stream->rtcp_auth); 
@@ -1519,4 +2721,8 @@
   auth_tag = (uint8_t *)hdr + *pkt_octet_len + sizeof(srtcp_trailer_t); 
 
+  /* perform EKT processing if needed */
+  ekt_write_data(stream->ekt, auth_tag, tag_len, pkt_octet_len, 
+		 rdbx_get_packet_index(&stream->rtp_rdbx));
+
   /* 
    * check sequence number for overruns, and copy it into the packet
@@ -1533,5 +2739,5 @@
    * if we're using rindael counter mode, set nonce and seq 
    */
-  if (stream->rtcp_cipher->type == &aes_icm) {
+  if (stream->rtcp_cipher->type->id == AES_ICM) {
     v128_t iv;
     
@@ -1540,5 +2746,5 @@
     iv.v32[2] = htonl(seq_num >> 16);
     iv.v32[3] = htonl(seq_num << 16);
-    status = aes_icm_set_iv((aes_icm_ctx_t*)stream->rtcp_cipher->state, &iv);
+    status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_encrypt);
 
   } else {  
@@ -1550,5 +2756,5 @@
     iv.v32[2] = 0;
     iv.v32[3] = htonl(seq_num);
-    status = cipher_set_iv(stream->rtcp_cipher, &iv);
+    status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_encrypt);
   }
   if (status)
@@ -1611,14 +2817,25 @@
   uint32_t *auth_start;     /* pointer to start of auth. portion      */
   uint32_t *trailer;        /* pointer to start of trailer            */
-  unsigned enc_octet_len = 0;/* number of octets in encrypted portion */
+  unsigned int enc_octet_len = 0;/* number of octets in encrypted portion */
   uint8_t *auth_tag = NULL; /* location of auth_tag within packet     */
   uint8_t tmp_tag[SRTP_MAX_TAG_LEN];
+  uint8_t tag_copy[SRTP_MAX_TAG_LEN];
   err_status_t status;   
+  unsigned int auth_len;
   int tag_len;
   srtp_stream_ctx_t *stream;
   int prefix_len;
   uint32_t seq_num;
+  int e_bit_in_packet;     /* whether the E-bit was found in the packet */
+  int sec_serv_confidentiality; /* whether confidentiality was requested */
 
   /* we assume the hdr is 32-bit aligned to start */
+
+  /* check that the length value is sane; we'll check again once we
+     know the tag length, but we at least want to know that it is
+     a positive value */
+  if (*pkt_octet_len < octets_in_rtcp_header + sizeof(srtcp_trailer_t))
+    return err_status_bad_param;
+
   /*
    * look up ssrc in srtp_stream list, and process the packet with 
@@ -1632,4 +2849,21 @@
     if (ctx->stream_template != NULL) {
       stream = ctx->stream_template;
+
+      /* 
+       * check to see if stream_template has an EKT data structure, in
+       * which case we initialize the template using the EKT policy
+       * referenced by that data (which consists of decrypting the
+       * master key from the EKT field)
+       *
+       * this function initializes a *provisional* stream, and this
+       * stream should not be accepted until and unless the packet
+       * passes its authentication check
+       */ 
+      if (stream->ekt != NULL) {
+	status = srtp_stream_init_from_ekt(stream, srtcp_hdr, *pkt_octet_len);
+	if (status)
+	  return status;
+      }
+
       debug_print(mod_srtp, "srtcp using provisional stream (SSRC: 0x%08x)", 
 		  hdr->ssrc);
@@ -1641,5 +2875,24 @@
   
   /* get tag length from stream context */
-  tag_len = auth_get_tag_length(stream->rtcp_auth); 
+  tag_len = auth_get_tag_length(stream->rtcp_auth);
+
+  /* check the packet length - it must contain at least a full RTCP
+     header, an auth tag (if applicable), and the SRTCP encrypted flag
+     and 31-bit index value */
+  if (*pkt_octet_len < (int) (octets_in_rtcp_header + tag_len + sizeof(srtcp_trailer_t))) {
+    return err_status_bad_param;
+  }
+
+  /*
+   * Check if this is an AEAD stream (GCM mode).  If so, then dispatch
+   * the request to our AEAD handler.
+   */
+  if (stream->rtp_cipher->algorithm == AES_128_GCM ||
+      stream->rtp_cipher->algorithm == AES_256_GCM) {
+      return srtp_unprotect_rtcp_aead(ctx, stream, srtcp_hdr, (unsigned int*)pkt_octet_len);
+  }
+
+  sec_serv_confidentiality = stream->rtcp_services == sec_serv_conf ||
+      stream->rtcp_services == sec_serv_conf_and_auth;
 
   /*
@@ -1658,6 +2911,11 @@
    */
   trailer = (uint32_t *) ((char *) hdr +
-		     *pkt_octet_len -(tag_len + sizeof(srtcp_trailer_t)));
-  if (*((unsigned char *) trailer) & SRTCP_E_BYTE_BIT) {
+      *pkt_octet_len -(tag_len + sizeof(srtcp_trailer_t)));
+  e_bit_in_packet =
+      (*((unsigned char *) trailer) & SRTCP_E_BYTE_BIT) == SRTCP_E_BYTE_BIT;
+  if (e_bit_in_packet != sec_serv_confidentiality) {
+    return err_status_cant_check;
+  }
+  if (sec_serv_confidentiality) {
     enc_start = (uint32_t *)hdr + uint32s_in_rtcp_header;  
   } else {
@@ -1671,5 +2929,21 @@
    */
   auth_start = (uint32_t *)hdr;
-  auth_tag = (uint8_t *)hdr + *pkt_octet_len - tag_len;
+  auth_len = *pkt_octet_len - tag_len;
+  auth_tag = (uint8_t *)hdr + auth_len;
+
+  /* 
+   * if EKT is in use, then we make a copy of the tag from the packet,
+   * and then zeroize the location of the base tag
+   *
+   * we first re-position the auth_tag pointer so that it points to
+   * the base tag
+   */
+  if (stream->ekt) {
+    auth_tag -= ekt_octets_after_base_tag(stream->ekt);
+    memcpy(tag_copy, auth_tag, tag_len);
+    octet_string_set_to_zero(auth_tag, tag_len);
+    auth_tag = tag_copy;
+    auth_len += tag_len;
+  }
 
   /* 
@@ -1686,5 +2960,5 @@
    * if we're using aes counter mode, set nonce and seq 
    */
-  if (stream->rtcp_cipher->type == &aes_icm) {
+  if (stream->rtcp_cipher->type->id == AES_ICM) {
     v128_t iv;
 
@@ -1693,5 +2967,5 @@
     iv.v32[2] = htonl(seq_num >> 16);
     iv.v32[3] = htonl(seq_num << 16);
-    status = aes_icm_set_iv((aes_icm_ctx_t*)stream->rtcp_cipher->state, &iv);
+    status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_decrypt);
 
   } else {  
@@ -1703,5 +2977,5 @@
     iv.v32[2] = 0;
     iv.v32[3] = htonl(seq_num);
-    status = cipher_set_iv(stream->rtcp_cipher, &iv);
+    status = cipher_set_iv(stream->rtcp_cipher, &iv, direction_decrypt);
 
   }
@@ -1714,6 +2988,5 @@
   /* run auth func over packet, put result into tmp_tag */
   status = auth_compute(stream->rtcp_auth, (uint8_t *)auth_start,  
-			*pkt_octet_len - tag_len,
-			tmp_tag);
+			auth_len, tmp_tag);
   debug_print(mod_srtp, "srtcp computed tag:       %s", 
 	      octet_string_hex_string(tmp_tag, tag_len));
@@ -1742,5 +3015,5 @@
   /* if we're decrypting, exor keystream into the message */
   if (enc_start) {
-    status = cipher_encrypt(stream->rtcp_cipher, 
+    status = cipher_decrypt(stream->rtcp_cipher, 
 			    (uint8_t *)enc_start, &enc_octet_len);
     if (status)
@@ -1748,6 +3021,12 @@
   }
 
-  /* decrease the packet length by the length of the auth tag and seq_num*/
+  /* decrease the packet length by the length of the auth tag and seq_num */
   *pkt_octet_len -= (tag_len + sizeof(srtcp_trailer_t));
+
+  /*
+   * if EKT is in effect, subtract the EKT data out of the packet
+   * length
+   */
+  *pkt_octet_len -= ekt_octets_after_base_tag(stream->ekt);
 
   /* 
@@ -1803,4 +3082,18 @@
 }
 
+
+/*
+ * user data within srtp_t context
+ */
+
+void
+srtp_set_user_data(srtp_t ctx, void *data) {
+  ctx->user_data = data;
+}
+
+void*
+srtp_get_user_data(srtp_t ctx) {
+  return ctx->user_data;
+}
 
 
@@ -1824,8 +3117,12 @@
     crypto_policy_set_null_cipher_hmac_sha1_80(policy);
     break;
+  case srtp_profile_aes256_cm_sha1_80:
+    crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
+    break;
+  case srtp_profile_aes256_cm_sha1_32:
+    crypto_policy_set_aes_cm_256_hmac_sha1_32(policy);
+    break;
     /* the following profiles are not (yet) supported */
   case srtp_profile_null_sha1_32:
-  case srtp_profile_aes256_cm_sha1_80:
-  case srtp_profile_aes256_cm_sha1_32:
   default:
     return err_status_bad_param;
@@ -1845,13 +3142,21 @@
     break;
   case srtp_profile_aes128_cm_sha1_32:
-    crypto_policy_set_aes_cm_128_hmac_sha1_32(policy);
+    /* We do not honor the 32-bit auth tag request since
+     * this is not compliant with RFC 3711 */
+    crypto_policy_set_aes_cm_128_hmac_sha1_80(policy);
     break;
   case srtp_profile_null_sha1_80:
     crypto_policy_set_null_cipher_hmac_sha1_80(policy);
     break;
+  case srtp_profile_aes256_cm_sha1_80:
+    crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
+    break;
+  case srtp_profile_aes256_cm_sha1_32:
+    /* We do not honor the 32-bit auth tag request since
+     * this is not compliant with RFC 3711 */
+    crypto_policy_set_aes_cm_256_hmac_sha1_80(policy);
+    break;
     /* the following profiles are not (yet) supported */
   case srtp_profile_null_sha1_32:
-  case srtp_profile_aes256_cm_sha1_80:
-  case srtp_profile_aes256_cm_sha1_32:
   default:
     return err_status_bad_param;
@@ -1882,8 +3187,12 @@
     return 16;
     break;
+  case srtp_profile_aes256_cm_sha1_80:
+    return 32;
+    break;
+  case srtp_profile_aes256_cm_sha1_32:
+    return 32;
+    break;
     /* the following profiles are not (yet) supported */
   case srtp_profile_null_sha1_32:
-  case srtp_profile_aes256_cm_sha1_80:
-  case srtp_profile_aes256_cm_sha1_32:
   default:
     return 0;  /* indicate error by returning a zero */
@@ -1904,8 +3213,12 @@
     return 14;
     break;
+  case srtp_profile_aes256_cm_sha1_80:
+    return 14;
+    break;
+  case srtp_profile_aes256_cm_sha1_32:
+    return 14;
+    break;
     /* the following profiles are not (yet) supported */
   case srtp_profile_null_sha1_32:
-  case srtp_profile_aes256_cm_sha1_80:
-  case srtp_profile_aes256_cm_sha1_32:
   default:
     return 0;  /* indicate error by returning a zero */
