Ticket #61: imported libsrtp into third_party directory (backported from srtp branch)

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1730 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/third_party/srtp/test/dtls_srtp_driver.c b/third_party/srtp/test/dtls_srtp_driver.c
new file mode 100644
index 0000000..a8eddc0
--- /dev/null
+++ b/third_party/srtp/test/dtls_srtp_driver.c
@@ -0,0 +1,245 @@
+/*
+ * dtls_srtp_driver.c
+ *
+ * test driver for DTLS-SRTP functions
+ *
+ * David McGrew
+ * Cisco Systems, Inc.
+ */
+/*
+ *	
+ * Copyright (c) 2001-2006 Cisco Systems, Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ * 
+ *   Neither the name of the Cisco Systems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>    /* for printf()          */
+#include "getopt_s.h" /* for local getopt()    */
+#include "srtp_priv.h"
+
+err_status_t 
+test_dtls_srtp();
+
+srtp_hdr_t *
+srtp_create_test_packet(int pkt_octet_len, uint32_t ssrc);
+
+void
+usage(char *prog_name) {
+  printf("usage: %s [ -t ][ -c ][ -v ][-d <debug_module> ]* [ -l ]\n"
+         "  -d <mod>   turn on debugging module <mod>\n"
+         "  -l         list debugging modules\n", prog_name);
+  exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+  unsigned do_list_mods      = 0;
+  char q;
+  err_status_t err;
+
+  printf("dtls_srtp_driver\n");
+
+  /* initialize srtp library */
+  err = srtp_init();
+  if (err) {
+    printf("error: srtp init failed with error code %d\n", err);
+    exit(1);
+  }
+
+  /* process input arguments */
+  while (1) {
+    q = getopt_s(argc, argv, "ld:");
+    if (q == -1) 
+      break;
+    switch (q) {
+    case 'l':
+      do_list_mods = 1;
+      break;
+    case 'd':
+      err = crypto_kernel_set_debug_module(optarg_s, 1);
+      if (err) {
+        printf("error: set debug module (%s) failed\n", optarg_s);
+        exit(1);
+      }  
+      break;
+    default:
+      usage(argv[0]);
+    }    
+  }
+
+  if (do_list_mods) {
+    err = crypto_kernel_list_debug_modules();
+    if (err) {
+      printf("error: list of debug modules failed\n");
+      exit(1);
+    }
+  }
+
+  printf("testing dtls_srtp...");
+  err = test_dtls_srtp();
+  if (err) {
+    printf("\nerror (code %d)\n", err);
+    exit(1);
+  }
+  printf("passed\n");
+  
+  return 0;
+}
+
+
+err_status_t
+test_dtls_srtp() {
+  srtp_hdr_t *test_packet;
+  int test_packet_len = 80;
+  srtp_t s;
+  srtp_policy_t policy;
+  uint8_t key[SRTP_MAX_KEY_LEN];
+  uint8_t salt[SRTP_MAX_KEY_LEN];
+  unsigned int key_len, salt_len;
+  srtp_profile_t profile;
+  err_status_t err;
+
+  /* create a 'null' SRTP session */
+  err = srtp_create(&s, NULL);
+  if (err) 
+    return err;
+
+  /* 
+   * verify that packet-processing functions behave properly - we
+   * expect that these functions will return err_status_no_ctx
+   */
+  test_packet = srtp_create_test_packet(80, 0xa5a5a5a5);
+  if (test_packet == NULL) 
+    return err_status_alloc_fail;
+  err = srtp_protect(s, test_packet, &test_packet_len);
+  if (err != err_status_no_ctx) {
+    printf("wrong return value from srtp_protect() (got code %d)\n", 
+	   err);
+    return err_status_fail;
+  }
+  err = srtp_unprotect(s, test_packet, &test_packet_len);
+  if (err != err_status_no_ctx) {
+    printf("wrong return value from srtp_unprotect() (got code %d)\n", 
+	   err);
+    return err_status_fail;
+  }
+  err = srtp_protect_rtcp(s, test_packet, &test_packet_len);
+  if (err != err_status_no_ctx) {
+    printf("wrong return value from srtp_protect_rtcp() (got code %d)\n", 
+	   err);
+    return err_status_fail;
+  }
+  err = srtp_unprotect_rtcp(s, test_packet, &test_packet_len);
+  if (err != err_status_no_ctx) {
+    printf("wrong return value from srtp_unprotect_rtcp() (got code %d)\n", 
+	   err);
+    return err_status_fail;
+  }
+
+
+  /* 
+   * set keys to known values for testing
+   */
+  profile = srtp_profile_aes128_cm_sha1_80;
+  key_len = srtp_profile_get_master_key_length(profile);
+  salt_len = srtp_profile_get_master_salt_length(profile);
+  memset(key, 0xff, key_len);
+  memset(salt, 0xee, salt_len);
+  append_salt_to_key(key, key_len, salt, salt_len);
+  policy.key  = key;
+
+  /* initialize SRTP policy from profile  */
+  err = crypto_policy_set_from_profile_for_rtp(&policy.rtp, profile);
+  if (err) return err;
+  err = crypto_policy_set_from_profile_for_rtcp(&policy.rtcp, profile);
+  if (err) return err;
+  policy.ssrc.type  = ssrc_any_inbound;
+  policy.next = NULL;
+    
+  err = srtp_add_stream(s, &policy);
+  if (err)
+    return err;
+  
+  return err_status_ok;
+}
+
+
+
+/*
+ * srtp_create_test_packet(len, ssrc) returns a pointer to a
+ * (malloced) example RTP packet whose data field has the length given
+ * by pkt_octet_len and the SSRC value ssrc.  The total length of the
+ * packet is twelve octets longer, since the header is at the
+ * beginning.  There is room at the end of the packet for a trailer,
+ * and the four octets following the packet are filled with 0xff
+ * values to enable testing for overwrites.
+ *
+ * note that the location of the test packet can (and should) be
+ * deallocated with the free() call once it is no longer needed.
+ */
+
+srtp_hdr_t *
+srtp_create_test_packet(int pkt_octet_len, uint32_t ssrc) {
+  int i;
+  uint8_t *buffer;
+  srtp_hdr_t *hdr;
+  int bytes_in_hdr = 12;
+
+  /* allocate memory for test packet */
+  hdr = malloc(pkt_octet_len + bytes_in_hdr
+	       + SRTP_MAX_TRAILER_LEN + 4);
+  if (!hdr)
+    return NULL;
+  
+  hdr->version = 2;              /* RTP version two     */
+  hdr->p    = 0;                 /* no padding needed   */
+  hdr->x    = 0;                 /* no header extension */
+  hdr->cc   = 0;                 /* no CSRCs            */
+  hdr->m    = 0;                 /* marker bit          */
+  hdr->pt   = 0xf;               /* payload type        */
+  hdr->seq  = htons(0x1234);     /* sequence number     */
+  hdr->ts   = htonl(0xdecafbad); /* timestamp           */
+  hdr->ssrc = htonl(ssrc);       /* synch. source       */
+
+  buffer = (uint8_t *)hdr;
+  buffer += bytes_in_hdr;
+
+  /* set RTP data to 0xab */
+  for (i=0; i < pkt_octet_len; i++)
+    *buffer++ = 0xab;
+
+  /* set post-data value to 0xffff to enable overrun checking */
+  for (i=0; i < SRTP_MAX_TRAILER_LEN+4; i++)
+    *buffer++ = 0xff;
+
+  return hdr;
+}
diff --git a/third_party/srtp/test/getopt_s.c b/third_party/srtp/test/getopt_s.c
new file mode 100644
index 0000000..243ad6e
--- /dev/null
+++ b/third_party/srtp/test/getopt_s.c
@@ -0,0 +1,112 @@
+/*
+ * getopt.c
+ *
+ * a minimal implementation of the getopt() function, written so that
+ * test applications that use that function can run on non-POSIX
+ * platforms 
+ *
+ */
+/*
+ *	
+ * Copyright (c) 2001-2006 Cisco Systems, Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ * 
+ *   Neither the name of the Cisco Systems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdlib.h>  /* for NULL */
+
+int optind_s = 0;
+
+char *optarg_s;
+
+#define GETOPT_FOUND_WITHOUT_ARGUMENT    2
+#define GETOPT_FOUND_WITH_ARGUMENT       1
+#define GETOPT_NOT_FOUND                 0 
+
+static int 
+getopt_check_character(char c, const char *string) {
+  unsigned int max_string_len = 128;
+
+  while (*string != 0) {
+    if (max_string_len == 0) {
+      return '?';
+    }
+    if (*string++ == c) {
+      if (*string == ':') {
+	return GETOPT_FOUND_WITH_ARGUMENT;
+      } else {
+	return GETOPT_FOUND_WITHOUT_ARGUMENT;
+      }
+    }
+  }
+  return GETOPT_NOT_FOUND;
+}
+
+int
+getopt_s(int argc, 
+       char * const argv[], 
+       const char *optstring) {
+
+
+  while (optind_s + 1 < argc) {
+    char *string;
+    
+    /* move 'string' on to next argument */
+    optind_s++;
+    string = argv[optind_s];
+
+    if (string == NULL)
+      return '?'; /* NULL argument string */
+
+    if (string[0] != '-')
+      return -1; /* found an unexpected character */
+
+    switch(getopt_check_character(string[1], optstring)) {
+    case GETOPT_FOUND_WITH_ARGUMENT:
+      if (optind_s + 1 < argc) {
+	optind_s++;
+	optarg_s = argv[optind_s];
+	return string[1]; 
+      } else {
+	return '?';  /* argument missing */
+      }
+    case GETOPT_FOUND_WITHOUT_ARGUMENT:
+      return string[1];
+    case GETOPT_NOT_FOUND:
+    default:
+      return '?'; /* didn't find expected character */
+      break;
+    }
+  }
+
+  return -1;
+}
diff --git a/third_party/srtp/test/lfsr.c b/third_party/srtp/test/lfsr.c
new file mode 100644
index 0000000..28ea02e
--- /dev/null
+++ b/third_party/srtp/test/lfsr.c
@@ -0,0 +1,310 @@
+/*
+ * lfsr.c
+ *
+ */
+
+
+#include <stdio.h>
+#include "datatypes.h"
+
+uint32_t 
+parity(uint32_t x) {
+
+  x ^= (x >> 16);
+  x ^= (x >> 8);
+  x ^= (x >> 4);
+  x ^= (x >> 2);
+  x ^= (x >> 1);
+
+  return x & 1;
+}
+
+
+/* typedef struct { */
+/*   uint32_t register[8]; */
+/* } lfsr_t; */
+
+void
+compute_period(uint32_t feedback_polynomial) {
+  int i;
+  v32_t lfsr;
+  v32_t mask;
+
+  mask.value = feedback_polynomial;
+  lfsr.value = 1;
+
+  printf("polynomial: %s\t", v32_bit_string(mask));
+
+  for (i=0; i < 256; i++) {
+/*     printf("%s\n", v32_bit_string(lfsr)); */
+    if (parity(mask.value & lfsr.value))
+      lfsr.value = ((lfsr.value << 1) | 1) & 0xff;
+    else
+      lfsr.value = (lfsr.value << 1) & 0xff;
+    
+    /* now halt if we're back at the initial state */
+    if (lfsr.value == 1) {
+      printf("period: %d\n", i);
+      break;
+    }
+  }
+}
+
+uint32_t poly0 = 223;
+
+
+uint32_t polynomials[39] = {
+31, 
+47,
+55,
+59,
+61,
+79,
+87,
+91,
+103,
+107,
+109,
+115,
+117,
+121,
+143,
+151,
+157,
+167,
+171,
+173,
+179,
+181,
+185,
+199,
+203,
+205,
+211,
+213,
+227,
+229,
+233, 
+241,
+127,
+191,
+223, 
+239,
+247,
+251,
+253 
+};
+
+char binary_string[32];
+
+char *
+u32_bit_string(uint32_t x, unsigned int length) {
+  unsigned int mask;
+  int index;
+ 
+  mask = 1 << length;
+  index = 0;
+  for (; mask > 0; mask >>= 1)
+    if ((x & mask) == 0)
+      binary_string[index++] = '0';
+    else
+      binary_string[index++] = '1';
+
+  binary_string[index++] = 0;  /* NULL terminate string */
+  return binary_string;
+}
+
+extern int octet_weight[256];
+
+unsigned int 
+weight(uint32_t poly) {
+  int wt = 0;
+
+  /* note: endian-ness makes no difference */
+  wt += octet_weight[poly        & 0xff]; 
+  wt += octet_weight[(poly >> 8) & 0xff];
+  wt += octet_weight[(poly >> 16) & 0xff];
+  wt += octet_weight[(poly >> 24)];
+
+  return wt;
+}
+
+#define MAX_PERIOD 65535
+
+#define debug_print 0
+
+int
+period(uint32_t poly) {
+  int i;
+  uint32_t x;
+
+
+  /* set lfsr to 1 */
+  x = 1;
+#if debug_print
+  printf("%d:\t%s\n", 0, u32_bit_string(x,8));
+#endif
+  for (i=1; i < MAX_PERIOD; i++) {
+    if (x & 1) 
+      x = (x >> 1) ^ poly;
+    else
+      x = (x >> 1);
+
+#if debug_print
+    /* print for a sanity check */
+    printf("%d:\t%s\n", i, u32_bit_string(x,8));
+#endif
+
+    /* check for return to original value */
+    if (x == 1)
+      return i;
+  }
+  return i;
+}
+
+/*
+ * weight distribution computes the weight distribution of the
+ * code generated by the polynomial poly
+ */
+
+#define MAX_LEN    8
+#define MAX_WEIGHT (1 << MAX_LEN)
+
+int A[MAX_WEIGHT+1];
+
+void
+weight_distribution2(uint32_t poly, int *A) {
+  int i;
+  uint32_t x;
+
+  /* zeroize array */
+  for (i=0; i < MAX_WEIGHT+1; i++)
+    A[i] = 0;
+
+  /* loop over all input sequences */
+  
+  
+  /* set lfsr to 1 */
+  x = 1;
+#if debug_print
+  printf("%d:\t%s\n", 0, u32_bit_string(x,8));
+#endif
+  for (i=1; i < MAX_PERIOD; i++) {
+    if (x & 1) 
+      x = (x >> 1) ^ poly;
+    else
+      x = (x >> 1);
+
+#if debug_print
+    /* print for a sanity check */
+    printf("%d:\t%s\n", i, u32_bit_string(x,8));
+#endif
+    
+    /* increment weight */
+    wt += (x & 1);
+
+    /* check for return to original value */
+    if (x == 1)
+      break;
+  }
+
+  /* set zero */
+  A[0] = 0;
+}
+
+
+void
+weight_distribution(uint32_t poly, int *A) {
+  int i;
+  uint32_t x;
+
+  /* zeroize array */
+  for (i=0; i < MAX_WEIGHT+1; i++)
+    A[i] = 0;
+
+  /* set lfsr to 1 */
+  x = 1;
+#if debug_print
+  printf("%d:\t%s\n", 0, u32_bit_string(x,8));
+#endif
+  for (i=1; i < MAX_PERIOD; i++) {
+    if (x & 1) 
+      x = (x >> 1) ^ poly;
+    else
+      x = (x >> 1);
+
+#if debug_print
+    /* print for a sanity check */
+    printf("%d:\t%s\n", i, u32_bit_string(x,8));
+#endif
+
+    /* compute weight, increment proper element */
+    A[weight(x)]++;
+
+    /* check for return to original value */
+    if (x == 1)
+      break;
+  }
+
+  /* set zero */
+  A[0] = 0;
+}
+
+
+
+
+int
+main () {
+
+  int i,j;
+  v32_t x;
+  v32_t p;
+
+  /* originally 0xaf */
+  p.value = 0x9;
+
+  printf("polynomial: %s\tperiod: %d\n",  
+ 	   u32_bit_string(p.value,8), period(p.value)); 
+ 
+   /* compute weight distribution */
+  weight_distribution(p.value, A);
+  
+  /* print weight distribution */
+  for (i=0; i <= 8; i++) {
+    printf("A[%d]: %d\n", i, A[i]);
+  }
+  
+#if 0
+  for (i=0; i < 39; i++) {
+     printf("polynomial: %s\tperiod: %d\n",  
+ 	   u32_bit_string(polynomials[i],8), period(polynomials[i])); 
+   
+     /* compute weight distribution */
+     weight_distribution(p.value, A);
+     
+     /* print weight distribution */
+     for (j=0; j <= 8; j++) {
+       printf("A[%d]: %d\n", j, A[j]);
+     }   
+  }
+#endif
+
+  { 
+    int bits = 8;
+    uint32_t y;
+    for (y=0; y < (1 << bits); y++) {
+      printf("polynomial: %s\tweight: %d\tperiod: %d\n", 
+	     u32_bit_string(y,bits), weight(y), period(y));
+      
+      /* compute weight distribution */
+      weight_distribution(y, A);
+      
+      /* print weight distribution */
+      for (j=0; j <= 8; j++) {
+	printf("A[%d]: %d\n", j, A[j]);
+      }     
+    }
+  }
+
+  return 0;
+}
diff --git a/third_party/srtp/test/rdbx_driver.c b/third_party/srtp/test/rdbx_driver.c
new file mode 100644
index 0000000..7db67a2
--- /dev/null
+++ b/third_party/srtp/test/rdbx_driver.c
@@ -0,0 +1,306 @@
+/*
+ * rdbx_driver.c
+ *
+ * driver for the rdbx implementation (replay database with extended range)
+ *
+ * David A. McGrew
+ * Cisco Systems, Inc.
+ */
+
+/*
+ *	
+ * Copyright (c) 2001-2006, Cisco Systems, Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ * 
+ *   Neither the name of the Cisco Systems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>    /* for printf()          */
+#include "getopt_s.h" /* for local getopt()    */
+
+#include "rdbx.h"
+
+#ifdef ROC_TEST
+#error "rdbx_t won't work with ROC_TEST - bitmask same size as seq_median"
+#endif
+
+#include "ut_sim.h"
+
+err_status_t 
+test_replay_dbx(int num_trials);
+
+double
+rdbx_check_adds_per_second(int num_trials);
+
+void
+usage(char *prog_name) {
+  printf("usage: %s [ -t | -v ]\n", prog_name);
+  exit(255);
+}
+
+int
+main (int argc, char *argv[]) {
+  double rate;
+  err_status_t status;
+  char q;
+  unsigned do_timing_test = 0;
+  unsigned do_validation = 0;
+
+  /* process input arguments */
+  while (1) {
+    q = getopt_s(argc, argv, "tv");
+    if (q == -1) 
+      break;
+    switch (q) {
+    case 't':
+      do_timing_test = 1;
+      break;
+    case 'v':
+      do_validation = 1;
+      break;
+    default:
+      usage(argv[0]);
+    }    
+  }
+
+  printf("rdbx (replay database w/ extended range) test driver\n"
+	 "David A. McGrew\n"
+	 "Cisco Systems, Inc.\n");
+
+  if (!do_validation && !do_timing_test)
+    usage(argv[0]);
+
+  if (do_validation) {
+  printf("testing rdbx_t...\n");
+
+    status = test_replay_dbx(1 << 12);
+    if (status) {
+      printf("failed\n");
+      exit(1);
+    }
+    printf("passed\n");
+  }
+
+  if (do_timing_test) {
+    rate = rdbx_check_adds_per_second(1 << 18);
+    printf("rdbx_check/replay_adds per second: %e\n", rate);
+  }
+  
+  return 0;
+}
+
+void
+print_rdbx(rdbx_t *rdbx) {
+  printf("rdbx: {%llu, %s}\n",
+	 (unsigned long long)(rdbx->index), v128_bit_string(&rdbx->bitmask));
+}
+
+
+/*
+ * rdbx_check_add(rdbx, idx) checks a known-to-be-good idx against
+ * rdbx, then adds it.  if a failure is detected (i.e., the check
+ * indicates that the value is already in rdbx) then
+ * err_status_algo_fail is returned.
+ *
+ */
+
+err_status_t
+rdbx_check_add(rdbx_t *rdbx, uint32_t idx) {
+  int delta;
+  xtd_seq_num_t est;
+  
+  delta = index_guess(&rdbx->index, &est, idx);
+  
+  if (rdbx_check(rdbx, delta) != err_status_ok) {
+    printf("replay_check failed at index %u\n", idx);
+    return err_status_algo_fail;
+  }
+
+  /*
+   * in practice, we'd authenticate the packet containing idx, using
+   * the estimated value est, at this point
+   */
+  
+  if (rdbx_add_index(rdbx, delta) != err_status_ok) {
+    printf("rdbx_add_index failed at index %u\n", idx);
+    return err_status_algo_fail;
+  }  
+
+  return err_status_ok;
+}
+
+/*
+ * rdbx_check_expect_failure(rdbx_t *rdbx, uint32_t idx)
+ * 
+ * checks that a sequence number idx is in the replay database
+ * and thus will be rejected
+ */
+
+err_status_t
+rdbx_check_expect_failure(rdbx_t *rdbx, uint32_t idx) {
+  int delta;
+  xtd_seq_num_t est;
+  err_status_t status;
+
+  delta = index_guess(&rdbx->index, &est, idx);
+
+  status = rdbx_check(rdbx, delta);
+  if (status == err_status_ok) {
+    printf("delta: %d ", delta);
+    printf("replay_check failed at index %u (false positive)\n", idx);
+    return err_status_algo_fail; 
+  }
+
+  return err_status_ok;
+}
+
+err_status_t
+rdbx_check_unordered(rdbx_t *rdbx, uint32_t idx) {
+  err_status_t rstat;
+
+  rstat = rdbx_check(rdbx, idx);
+  if ((rstat != err_status_ok) && (rstat != err_status_replay_old)) {
+    printf("replay_check_unordered failed at index %u\n", idx);
+    return err_status_algo_fail;
+  }
+  return err_status_ok;
+}
+
+#define MAX_IDX 160
+
+err_status_t
+test_replay_dbx(int num_trials) {
+  rdbx_t rdbx;
+  uint32_t idx, ircvd;
+  ut_connection utc;
+  err_status_t status;
+  int num_fp_trials;
+
+  status = rdbx_init(&rdbx);
+  if (status) {
+    printf("replay_init failed with error code %d\n", status);
+    exit(1);
+  }
+
+  /*
+   *  test sequential insertion 
+   */
+  printf("\ttesting sequential insertion...");
+  for (idx=0; idx < num_trials; idx++) {
+    status = rdbx_check_add(&rdbx, idx);
+    if (status)
+      return status;
+  }
+  printf("passed\n");
+
+  /*
+   *  test for false positives by checking all of the index
+   *  values which we've just added
+   *
+   * note that we limit the number of trials here, since allowing the
+   * rollover counter to roll over would defeat this test
+   */
+  num_fp_trials = num_trials % 0x10000;
+  if (num_fp_trials == 0) {
+    printf("warning: no false positive tests performed\n");
+  }
+  printf("\ttesting for false positives...");
+  for (idx=0; idx < num_fp_trials; idx++) {
+    status = rdbx_check_expect_failure(&rdbx, idx);
+    if (status)
+      return status;
+  }
+  printf("passed\n");
+
+  /* re-initialize */
+  if (rdbx_init(&rdbx) != err_status_ok) {
+    printf("replay_init failed\n");
+    return err_status_init_fail;
+  }
+
+  /*
+   * test non-sequential insertion 
+   *
+   * this test covers only fase negatives, since the values returned
+   * by ut_next_index(...) are distinct
+   */
+  ut_init(&utc);
+
+  printf("\ttesting non-sequential insertion...");  
+  for (idx=0; idx < num_trials; idx++) {
+    ircvd = ut_next_index(&utc);
+    status = rdbx_check_unordered(&rdbx, ircvd);
+    if (status)
+      return status;
+  }
+  printf("passed\n");
+
+  return err_status_ok;
+}
+
+
+
+#include <time.h>       /* for clock()  */
+#include <stdlib.h>     /* for random() */
+
+double
+rdbx_check_adds_per_second(int num_trials) {
+  uint32_t i;
+  int delta;
+  rdbx_t rdbx;
+  xtd_seq_num_t est;
+  clock_t timer;
+  int failures;                    /* count number of failures        */
+  
+  if (rdbx_init(&rdbx) != err_status_ok) {
+    printf("replay_init failed\n");
+    exit(1);
+  }  
+
+  failures = 0;
+  timer = clock();
+  for(i=0; i < num_trials; i++) {
+    
+    delta = index_guess(&rdbx.index, &est, i);
+    
+    if (rdbx_check(&rdbx, delta) != err_status_ok) 
+      ++failures;
+    else
+      if (rdbx_add_index(&rdbx, delta) != err_status_ok)
+	++failures;
+  }
+  timer = clock() - timer;
+
+  printf("number of failures: %d \n", failures);
+
+  return (double) CLOCKS_PER_SEC * num_trials / timer;
+}
+
diff --git a/third_party/srtp/test/replay_driver.c b/third_party/srtp/test/replay_driver.c
new file mode 100644
index 0000000..369a77a
--- /dev/null
+++ b/third_party/srtp/test/replay_driver.c
@@ -0,0 +1,209 @@
+/*
+ * replay_driver.c
+ *
+ * A driver for the replay_database implementation
+ *
+ * David A. McGrew
+ * Cisco Systems, Inc.
+ */
+
+/*
+ *	
+ * Copyright (c) 2001-2006, Cisco Systems, Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ * 
+ *   Neither the name of the Cisco Systems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+
+#include "rdb.h"
+#include "ut_sim.h"
+
+/*
+ * num_trials defines the number of trials that are used in the
+ * validation functions below
+ */
+
+unsigned num_trials = 1 << 16;
+
+err_status_t
+test_rdb_db(void);
+
+double
+rdb_check_adds_per_second(void);
+
+int
+main (void) {
+  err_status_t err;
+  
+  printf("testing anti-replay database (rdb_t)...\n");
+  err = test_rdb_db();
+  if (err) {
+    printf("failed\n");
+    exit(1);
+  }
+  printf("done\n");
+
+  printf("rdb_check/rdb_adds per second: %e\n",
+	 rdb_check_adds_per_second());
+  
+  return 0;
+}
+
+
+void
+print_rdb(rdb_t *rdb) {
+  printf("rdb: {%u, %s}\n", rdb->window_start, v128_bit_string(&rdb->bitmask));
+}
+
+err_status_t
+rdb_check_add(rdb_t *rdb, uint32_t idx) {
+
+  if (rdb_check(rdb, idx) != err_status_ok) {
+    printf("rdb_check failed at index %u\n", idx);
+    return err_status_fail;
+  }
+  if (rdb_add_index(rdb, idx) != err_status_ok) {
+    printf("rdb_add_index failed at index %u\n", idx);
+    return err_status_fail;
+  }
+
+  return err_status_ok;
+}
+
+err_status_t
+rdb_check_expect_failure(rdb_t *rdb, uint32_t idx) {
+  err_status_t err;
+  
+  err = rdb_check(rdb, idx);
+  if ((err != err_status_replay_old) && (err != err_status_replay_fail)) {
+    printf("rdb_check failed at index %u (false positive)\n", idx);
+    return err_status_fail;
+  }
+
+  return err_status_ok;
+}
+
+err_status_t
+rdb_check_unordered(rdb_t *rdb, uint32_t idx) {
+  err_status_t rstat;
+
+ /* printf("index: %u\n", idx); */
+  rstat = rdb_check(rdb, idx);
+  if ((rstat != err_status_ok) && (rstat != err_status_replay_old)) {
+    printf("rdb_check_unordered failed at index %u\n", idx);
+    return rstat;
+  }
+  return err_status_ok;
+}
+
+err_status_t
+test_rdb_db() {
+  rdb_t rdb;
+  uint32_t idx, ircvd;
+  ut_connection utc;
+  err_status_t err;
+
+  if (rdb_init(&rdb) != err_status_ok) {
+    printf("rdb_init failed\n");
+    return err_status_init_fail;
+  }
+
+  /* test sequential insertion */
+  for (idx=0; idx < num_trials; idx++) {
+    err = rdb_check_add(&rdb, idx);
+    if (err) 
+      return err;
+  }
+
+  /* test for false positives */
+  for (idx=0; idx < num_trials; idx++) {
+    err = rdb_check_expect_failure(&rdb, idx);
+    if (err) 
+      return err;
+  }
+
+  /* re-initialize */
+  if (rdb_init(&rdb) != err_status_ok) {
+    printf("rdb_init failed\n");
+    return err_status_fail;
+  }
+
+  /* test non-sequential insertion */
+  ut_init(&utc);
+  
+  for (idx=0; idx < num_trials; idx++) {
+    ircvd = ut_next_index(&utc);
+    err = rdb_check_unordered(&rdb, ircvd);
+    if (err) 
+      return err;
+  }
+
+  return err_status_ok;
+}
+
+#include <time.h>       /* for clock()  */
+#include <stdlib.h>     /* for random() */
+
+#define REPLAY_NUM_TRIALS 10000000
+
+double
+rdb_check_adds_per_second(void) {
+  uint32_t i;
+  rdb_t rdb;
+  clock_t timer;
+  int failures;                    /* count number of failures        */
+  
+  if (rdb_init(&rdb) != err_status_ok) {
+    printf("rdb_init failed\n");
+    exit(1);
+  }  
+
+  timer = clock();
+  for(i=0; i < REPLAY_NUM_TRIALS; i+=3) {
+    if (rdb_check(&rdb, i+2) != err_status_ok)
+      ++failures;
+    if (rdb_add_index(&rdb, i+2) != err_status_ok)
+      ++failures;
+    if (rdb_check(&rdb, i+1) != err_status_ok)
+      ++failures;
+    if (rdb_add_index(&rdb, i+1) != err_status_ok)
+      ++failures;
+    if (rdb_check(&rdb, i) != err_status_ok)
+      ++failures;
+    if (rdb_add_index(&rdb, i) != err_status_ok)
+      ++failures;
+  }
+  timer = clock() - timer;
+
+  return (double) CLOCKS_PER_SEC * REPLAY_NUM_TRIALS / timer;
+}
diff --git a/third_party/srtp/test/roc_driver.c b/third_party/srtp/test/roc_driver.c
new file mode 100644
index 0000000..396c9a7
--- /dev/null
+++ b/third_party/srtp/test/roc_driver.c
@@ -0,0 +1,165 @@
+/*
+ * roc_driver.c
+ *
+ * test driver for rollover counter replay implementation
+ *
+ * David A. McGrew
+ * Cisco Systems, Inc.
+ */
+
+/*
+ *	
+ * Copyright (c) 2001-2006, Cisco Systems, Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ * 
+ *   Neither the name of the Cisco Systems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <stdio.h>
+
+/*
+ * defining ROC_TEST causes small datatypes to be used in
+ * xtd_seq_num_t - this allows the functions to be exhaustively tested.
+ */
+#if ROC_NEEDS_TO_BE_TESTED
+#define ROC_TEST     
+#endif
+
+#include "rdbx.h"
+#include "ut_sim.h"
+
+err_status_t
+roc_test(int num_trials);
+
+int
+main (void) {
+  err_status_t status;
+
+  printf("rollover counter test driver\n"
+	 "David A. McGrew\n"
+	 "Cisco Systems, Inc.\n");
+  
+  printf("testing index functions...");
+  status = roc_test(1 << 18);
+  if (status) {
+    printf("failed\n");
+    exit(status);
+  }
+  printf("passed\n");
+  return 0;
+}
+
+
+#define ROC_VERBOSE 0
+
+err_status_t
+roc_test(int num_trials) {
+  xtd_seq_num_t local, est, ref;
+  ut_connection utc;
+  int i, num_bad_est = 0;
+  int delta;
+  uint32_t ircvd;
+  double failure_rate;
+
+  index_init(&local);
+  index_init(&ref);
+  index_init(&est);
+
+  printf("\n\ttesting sequential insertion...");
+  for (i=0; i < 2048; i++) {
+    delta = index_guess(&local, &est, (uint16_t) ref);
+#if ROC_VERBOSE
+    printf("%lld, %lld, %d\n", ref, est,  i);
+#endif
+    if (ref != est) {
+#if ROC_VERBOSE
+      printf(" *bad estimate*\n");
+#endif
+      ++num_bad_est;
+    }
+    index_advance(&ref, 1);
+  }
+  failure_rate = (double) num_bad_est / num_trials;
+  if (failure_rate > 0.01) {
+    printf("error: failure rate too high (%d bad estimates in %d trials)\n", 
+	   num_bad_est, num_trials);
+    return err_status_algo_fail;
+  }
+  printf("done\n");
+
+
+  printf("\ttesting non-sequential insertion...");
+  index_init(&local);
+  index_init(&ref);
+  index_init(&est);
+  ut_init(&utc);
+  
+  for (i=0; i < num_trials; i++) {
+    
+    /* get next seq num from unreliable transport simulator */
+    ircvd = ut_next_index(&utc);
+    
+    /* set ref to value of ircvd */
+    ref = ircvd; 
+
+    /* estimate index based on low bits of ircvd */
+    delta = index_guess(&local, &est, (uint16_t) ref);
+#if ROC_VERBOSE
+    printf("ref: %lld, local: %lld, est: %lld, ircvd: %d, delta: %d\n", 
+	   ref, local, est, ircvd, delta);
+#endif
+    
+    /* now update local xtd_seq_num_t as necessary */
+    if (delta > 0) 
+      index_advance(&local, delta);
+
+    if (ref != est) {
+#if ROC_VERBOSE
+      printf(" *bad estimate*\n");
+#endif
+      /* record failure event */
+      ++num_bad_est;
+      
+      /* reset local value to correct value */
+      local = ref;
+    }
+  }
+  failure_rate = (double) num_bad_est / num_trials;
+  if (failure_rate > 0.01) {
+    printf("error: failure rate too high (%d bad estimates in %d trials)\n", 
+	   num_bad_est, num_trials);
+    return err_status_algo_fail;
+  }
+  printf("done\n");
+
+  return err_status_ok;
+}
diff --git a/third_party/srtp/test/rtp.c b/third_party/srtp/test/rtp.c
new file mode 100644
index 0000000..69968f3
--- /dev/null
+++ b/third_party/srtp/test/rtp.c
@@ -0,0 +1,167 @@
+/*
+ * rtp.c
+ *
+ * library functions for the real-time transport protocol
+ *
+ * David A. McGrew
+ * Cisco Systems, Inc.
+ */
+
+
+#include "rtp_priv.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+#define PRINT_DEBUG    0    /* set to 1 to print out debugging data */
+#define VERBOSE_DEBUG  0    /* set to 1 to print out more data      */
+
+unsigned int
+rtp_sendto(rtp_sender_t sender, const void* msg, int len) {
+  int octets_sent;
+  err_status_t stat;
+  int pkt_len = len + RTP_HEADER_LEN;
+
+  /* marshal data */
+  strncpy(sender->message.body, msg, len);
+  
+  /* update header */
+  sender->message.header.seq = ntohs(sender->message.header.seq) + 1;
+  sender->message.header.seq = htons(sender->message.header.seq);
+  sender->message.header.ts = ntohl(sender->message.header.ts) + 1;
+  sender->message.header.ts = htonl(sender->message.header.ts);
+  
+  /* apply srtp */
+  stat = srtp_protect(sender->srtp_ctx, &sender->message.header, &pkt_len);
+  if (stat) {
+#if PRINT_DEBUG
+    fprintf(stderr, "error: srtp protection failed with code %d\n", stat);
+#endif
+    return -1;
+  }
+#if VERBOSE_DEBUG
+  srtp_print_packet(&sender->message.header, pkt_len);
+#endif
+  octets_sent = sendto(sender->socket, (void*)&sender->message,
+		       pkt_len, 0, (struct sockaddr *)&sender->addr,
+		       sizeof (struct sockaddr_in));
+
+  if (octets_sent != pkt_len) {
+#if PRINT_DEBUG
+    fprintf(stderr, "error: couldn't send message %s", (char *)msg);
+    perror("");
+#endif
+  }
+
+  return octets_sent;
+}
+
+unsigned int
+rtp_recvfrom(rtp_receiver_t receiver, void *msg, int *len) {
+  int octets_recvd;
+  err_status_t stat;
+  
+  octets_recvd = recvfrom(receiver->socket, (void *)&receiver->message,
+			 *len, 0, (struct sockaddr *) NULL, 0);
+
+  /* verify rtp header */
+  if (receiver->message.header.version != 2) {
+    *len = 0;
+    return -1;
+  }
+
+#if PRINT_DEBUG
+  fprintf(stderr, "%d octets received from SSRC %u\n",
+	  octets_recvd, receiver->message.header.ssrc);
+#endif
+#if VERBOSE_DEBUG
+  srtp_print_packet(&receiver->message.header, octets_recvd);
+#endif
+
+  /* apply srtp */
+  stat = srtp_unprotect(receiver->srtp_ctx,
+			&receiver->message.header, &octets_recvd);
+  if (stat) {
+    fprintf(stderr,
+	    "error: srtp unprotection failed with code %d%s\n", stat,
+	    stat == err_status_replay_fail ? " (replay check failed)" :
+	    stat == err_status_auth_fail ? " (auth check failed)" : "");
+    return -1;
+  }
+  strncpy(msg, receiver->message.body, octets_recvd);
+  
+  return octets_recvd;
+}
+
+int
+rtp_sender_init(rtp_sender_t sender, 
+		int socket, 
+		struct sockaddr_in addr,
+		unsigned int ssrc) {
+
+  /* set header values */
+  sender->message.header.ssrc    = htonl(ssrc);
+  sender->message.header.ts      = 0;
+  sender->message.header.seq     = (uint16_t) rand();
+  sender->message.header.m       = 0;
+  sender->message.header.pt      = 0x1;
+  sender->message.header.version = 2;
+  sender->message.header.p       = 0;
+  sender->message.header.x       = 0;
+  sender->message.header.cc      = 0;
+
+  /* set other stuff */
+  sender->socket = socket;
+  sender->addr = addr;
+
+  return 0;
+}
+
+int
+rtp_receiver_init(rtp_receiver_t rcvr, 
+		  int socket, 
+		  struct sockaddr_in addr,
+		  unsigned int ssrc) {
+  
+  /* set header values */
+  rcvr->message.header.ssrc    = htonl(ssrc);
+  rcvr->message.header.ts      = 0;
+  rcvr->message.header.seq     = 0;
+  rcvr->message.header.m       = 0;
+  rcvr->message.header.pt      = 0x1;
+  rcvr->message.header.version = 2;
+  rcvr->message.header.p       = 0;
+  rcvr->message.header.x       = 0;
+  rcvr->message.header.cc      = 0;
+
+  /* set other stuff */
+  rcvr->socket = socket;
+  rcvr->addr = addr;
+
+  return 0;
+}
+
+int
+rtp_sender_init_srtp(rtp_sender_t sender, const srtp_policy_t *policy) {
+  return srtp_create(&sender->srtp_ctx, policy);
+}
+
+int
+rtp_receiver_init_srtp(rtp_receiver_t sender, const srtp_policy_t *policy) {
+  return srtp_create(&sender->srtp_ctx, policy);
+}
+
+rtp_sender_t 
+rtp_sender_alloc() {
+  return (rtp_sender_t)malloc(sizeof(rtp_sender_ctx_t));
+}
+
+rtp_receiver_t 
+rtp_receiver_alloc() {
+  return (rtp_receiver_t)malloc(sizeof(rtp_receiver_ctx_t));
+}
diff --git a/third_party/srtp/test/rtpw.c b/third_party/srtp/test/rtpw.c
new file mode 100644
index 0000000..e477a77
--- /dev/null
+++ b/third_party/srtp/test/rtpw.c
@@ -0,0 +1,519 @@
+/*
+ * rtpw.c
+ *
+ * rtp word sender/receiver
+ *
+ * David A. McGrew
+ * Cisco Systems, Inc.
+ *
+ * This app is a simple RTP application intended only for testing
+ * libsrtp.  It reads one word at a time from /usr/dict/words (or
+ * whatever file is specified as DICT_FILE), and sends one word out
+ * each USEC_RATE microseconds.  Secure RTP protections can be
+ * applied.  See the usage() function for more details.
+ *
+ */
+
+/*
+ *	
+ * Copyright (c) 2001-2006, Cisco Systems, Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ * 
+ *   Neither the name of the Cisco Systems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include "datatypes.h"
+#include "getopt_s.h"       /* for local getopt()  */
+
+#include <stdio.h>          /* for printf, fprintf */
+#include <stdlib.h>         /* for atoi()          */
+#include <errno.h>
+#include <unistd.h>         /* for close()         */
+
+#include <string.h>         /* for strncpy()       */
+#include <time.h>	    /* for usleep()        */
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#elif defined HAVE_WINSOCK2_H
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# define RTPW_USE_WINSOCK2	1
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#include "srtp.h"           
+#include "rtp.h"
+
+#ifdef RTPW_USE_WINSOCK2
+# define DICT_FILE        "words.txt"
+#else
+# define DICT_FILE        "/usr/share/dict/words"
+#endif
+#define USEC_RATE        (5e5)
+#define MAX_WORD_LEN     128  
+#define ADDR_IS_MULTICAST(a) IN_MULTICAST(htonl(a))
+#define MAX_KEY_LEN      64
+#define MASTER_KEY_LEN   30
+
+
+#ifndef HAVE_USLEEP
+# ifdef HAVE_WINDOWS_H
+#  define usleep(us)	Sleep((us)/1000)
+# else
+#  define usleep(us)	sleep((us)/1000000)
+# endif
+#endif
+
+
+/*
+ * the function usage() prints an error message describing how this
+ * program should be called, then calls exit()
+ */
+
+void
+usage(char *prog_name);
+
+/*
+ * leave_group(...) de-registers from a multicast group
+ */
+
+void
+leave_group(int sock, struct ip_mreq mreq, char *name);
+
+
+/*
+ * program_type distinguishes the [s]rtp sender and receiver cases
+ */
+
+typedef enum { sender, receiver, unknown } program_type;
+
+int
+main (int argc, char *argv[]) {
+  char *dictfile = DICT_FILE;
+  FILE *dict;
+  char word[MAX_WORD_LEN];
+  int sock, ret;
+  struct in_addr rcvr_addr;
+  struct sockaddr_in name;
+  struct ip_mreq mreq;
+#if BEW
+  struct sockaddr_in local;
+#endif 
+  program_type prog_type = unknown;
+  sec_serv_t sec_servs = sec_serv_none;
+  unsigned char ttl = 5;
+  int c;
+  char *input_key = NULL;
+  char *address = NULL;
+  char key[MAX_KEY_LEN];
+  unsigned short port = 0;
+  rtp_sender_t snd;
+  srtp_policy_t policy;
+  err_status_t status;
+  int len;
+  int do_list_mods = 0;
+  uint32_t ssrc = 0xdeadbeef; /* ssrc value hardcoded for now */
+#ifdef RTPW_USE_WINSOCK2
+  WORD wVersionRequested = MAKEWORD(2, 0);
+  WSADATA wsaData;
+
+  ret = WSAStartup(wVersionRequested, &wsaData);
+  if (ret != 0) {
+    fprintf(stderr, "error: WSAStartup() failed: %d\n", ret);
+    exit(1);
+  }
+#endif
+
+  /* initialize srtp library */
+  status = srtp_init();
+  if (status) {
+    printf("error: srtp initialization failed with error code %d\n", status);
+    exit(1);
+  }
+
+  /* check args */
+  while (1) {
+    c = getopt_s(argc, argv, "k:rsaeld:");
+    if (c == -1) {
+      break;
+    }
+    switch (c) {
+    case 'k':
+      input_key = optarg_s;
+      break;
+    case 'e':
+      sec_servs |= sec_serv_conf;
+      break;
+    case 'a':
+      sec_servs |= sec_serv_auth;
+      break;
+    case 'r':
+      prog_type = receiver;
+      break;
+    case 's':
+      prog_type = sender;
+      break;
+    case 'd':
+      status = crypto_kernel_set_debug_module(optarg_s, 1);
+      if (status) {
+        printf("error: set debug module (%s) failed\n", optarg_s);
+        exit(1);
+      }
+      break;
+    case 'l':
+      do_list_mods = 1;
+      break;
+    default:
+      usage(argv[0]);
+    }
+  }
+
+  if (prog_type == unknown) {
+    if (do_list_mods) {
+      status = crypto_kernel_list_debug_modules();
+      if (status) {
+	printf("error: list of debug modules failed\n");
+	exit(1);
+      }
+      return 0;
+    } else {
+      printf("error: neither sender [-s] nor receiver [-r] specified\n");
+      usage(argv[0]);
+    }
+  }
+   
+  if ((sec_servs && !input_key) || (!sec_servs && input_key)) {
+    /* 
+     * a key must be provided if and only if security services have
+     * been requested 
+     */
+    usage(argv[0]);
+  }
+    
+  if (argc != optind_s + 2) {
+    /* wrong number of arguments */
+    usage(argv[0]);
+  }
+
+  /* get address from arg */
+  address = argv[optind_s++];
+
+  /* get port from arg */
+  port = atoi(argv[optind_s++]);
+
+  /* set address */
+#ifdef HAVE_INET_ATON
+  if (0 == inet_aton(address, &rcvr_addr)) {
+    fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address);
+    exit(1);
+  }
+  if (rcvr_addr.s_addr == INADDR_NONE) {
+    fprintf(stderr, "%s: address error", argv[0]);
+    exit(1);
+  }
+#else
+  rcvr_addr.s_addr = inet_addr(address);
+  if (0xffffffff == rcvr_addr.s_addr) {
+    fprintf(stderr, "%s: cannot parse IP v4 address %s\n", argv[0], address);
+    exit(1);
+  }
+#endif
+
+  /* open socket */
+  sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+  if (sock < 0) {
+    int err;
+#ifdef RTPW_USE_WINSOCK2
+    err = WSAGetLastError();
+#else
+    err = errno;
+#endif
+    fprintf(stderr, "%s: couldn't open socket: %d\n", argv[0], err);
+    exit(1);
+  }
+
+  name.sin_addr   = rcvr_addr;    
+  name.sin_family = PF_INET;
+  name.sin_port   = htons(port);
+ 
+  if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
+    if (prog_type == sender) {
+      ret = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, 
+  	               sizeof(ttl));
+      if (ret < 0) {
+	fprintf(stderr, "%s: Failed to set TTL for multicast group", argv[0]);
+	perror("");
+	exit(1);
+      }
+    }
+
+    mreq.imr_multiaddr.s_addr = rcvr_addr.s_addr;
+    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+    ret = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void*)&mreq,
+		     sizeof(mreq));
+    if (ret < 0) {
+      fprintf(stderr, "%s: Failed to join multicast group", argv[0]);
+      perror("");
+      exit(1);
+    }
+  }
+
+  /* report security services selected on the command line */
+  printf("security services: ");
+  if (sec_servs & sec_serv_conf)
+    printf("confidentiality ");
+  if (sec_servs & sec_serv_auth)
+    printf("message authentication");
+  if (sec_servs == sec_serv_none)
+    printf("none");
+  printf("\n");
+  
+  /* set up the srtp policy and master key */    
+  if (sec_servs) {
+    /* 
+     * create policy structure, using the default mechanisms but 
+     * with only the security services requested on the command line,
+     * using the right SSRC value
+     */
+    switch (sec_servs) {
+    case sec_serv_conf_and_auth:
+      crypto_policy_set_rtp_default(&policy.rtp);
+      crypto_policy_set_rtcp_default(&policy.rtcp);
+      break;
+    case sec_serv_conf:
+      crypto_policy_set_aes_cm_128_null_auth(&policy.rtp);
+      crypto_policy_set_rtcp_default(&policy.rtcp);      
+      break;
+    case sec_serv_auth:
+      crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp);
+      crypto_policy_set_rtcp_default(&policy.rtcp);
+      break;
+    default:
+      printf("error: unknown security service requested\n");
+      return -1;
+    } 
+    policy.ssrc.type  = ssrc_specific;
+    policy.ssrc.value = ssrc;
+    policy.key  = (uint8_t *) key;
+    policy.next = NULL;
+    policy.rtp.sec_serv = sec_servs;
+    policy.rtcp.sec_serv = sec_serv_none;  /* we don't do RTCP anyway */
+
+    /*
+     * read key from hexadecimal on command line into an octet string
+     */
+    len = hex_string_to_octet_string(key, input_key, MASTER_KEY_LEN*2);
+    
+    /* check that hex string is the right length */
+    if (len < MASTER_KEY_LEN*2) {
+      fprintf(stderr, 
+	      "error: too few digits in key/salt "
+	      "(should be %d hexadecimal digits, found %d)\n",
+	      MASTER_KEY_LEN*2, len);
+      exit(1);    
+    } 
+    if (strlen(input_key) > MASTER_KEY_LEN*2) {
+      fprintf(stderr, 
+	      "error: too many digits in key/salt "
+	      "(should be %d hexadecimal digits, found %u)\n",
+	      MASTER_KEY_LEN*2, (unsigned)strlen(input_key));
+      exit(1);    
+    }
+    
+    printf("set master key/salt to %s/", octet_string_hex_string(key, 16));
+    printf("%s\n", octet_string_hex_string(key+16, 14));
+  
+  } else {
+    /*
+     * we're not providing security services, so set the policy to the
+     * null policy
+     *
+     * Note that this policy does not conform to the SRTP
+     * specification, since RTCP authentication is required.  However,
+     * the effect of this policy is to turn off SRTP, so that this
+     * application is now a vanilla-flavored RTP application.
+     */
+    policy.key                 = (uint8_t *)key;
+    policy.ssrc.type           = ssrc_specific;
+    policy.ssrc.value          = ssrc;
+    policy.rtp.cipher_type     = NULL_CIPHER;
+    policy.rtp.cipher_key_len  = 0; 
+    policy.rtp.auth_type       = NULL_AUTH;
+    policy.rtp.auth_key_len    = 0;
+    policy.rtp.auth_tag_len    = 0;
+    policy.rtp.sec_serv        = sec_serv_none;   
+    policy.rtcp.cipher_type    = NULL_CIPHER;
+    policy.rtcp.cipher_key_len = 0; 
+    policy.rtcp.auth_type      = NULL_AUTH;
+    policy.rtcp.auth_key_len   = 0;
+    policy.rtcp.auth_tag_len   = 0;
+    policy.rtcp.sec_serv       = sec_serv_none;   
+    policy.next                = NULL;
+  }
+
+  if (prog_type == sender) {
+
+#if BEW
+    /* bind to local socket (to match crypto policy, if need be) */
+    memset(&local, 0, sizeof(struct sockaddr_in));
+    local.sin_addr.s_addr = htonl(INADDR_ANY);
+    local.sin_port = htons(port);
+    ret = bind(sock, (struct sockaddr *) &local, sizeof(struct sockaddr_in));
+    if (ret < 0) {
+      fprintf(stderr, "%s: bind failed\n", argv[0]);
+      perror("");
+      exit(1); 
+    }
+#endif /* BEW */
+
+    /* initialize sender's rtp and srtp contexts */
+    snd = rtp_sender_alloc();
+    if (snd == NULL) {
+      fprintf(stderr, "error: malloc() failed\n");
+      exit(1);
+    }
+    rtp_sender_init(snd, sock, name, ssrc); 
+    status = rtp_sender_init_srtp(snd, &policy);
+    if (status) {
+      fprintf(stderr, 
+	      "error: srtp_create() failed with code %d\n", 
+	      status);
+      exit(1);
+    }
+ 
+    /* open dictionary */
+    dict = fopen (dictfile, "r");
+    if (dict == NULL) {
+      fprintf(stderr, "%s: couldn't open file %s\n", argv[0], dictfile);
+      if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
+  	leave_group(sock, mreq, argv[0]);
+      }
+      exit(1);
+    }
+          
+    /* read words from dictionary, then send them off */
+    while (fgets(word, MAX_WORD_LEN, dict) != NULL) { 
+      len = strlen(word) + 1;  /* plus one for null */
+      
+      if (len > MAX_WORD_LEN) 
+	printf("error: word %s too large to send\n", word);
+      else {
+	rtp_sendto(snd, word, len);
+        printf("sending word: %s", word);
+      }
+      usleep(USEC_RATE);
+    }
+    
+  } else  { /* prog_type == receiver */
+    rtp_receiver_t rcvr;
+        
+    if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) {
+      close(sock);
+      fprintf(stderr, "%s: socket bind error\n", argv[0]);
+      perror(NULL);
+      if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
+    	leave_group(sock, mreq, argv[0]);
+      }
+      exit(1);
+    }
+
+    rcvr = rtp_receiver_alloc();
+    if (rcvr == NULL) {
+      fprintf(stderr, "error: malloc() failed\n");
+      exit(1);
+    }
+    rtp_receiver_init(rcvr, sock, name, ssrc);
+    status = rtp_receiver_init_srtp(rcvr, &policy);
+    if (status) {
+      fprintf(stderr, 
+	      "error: srtp_create() failed with code %d\n", 
+	      status);
+      exit(1);
+    }
+
+    /* get next word and loop */
+    while (1) {
+      len = MAX_WORD_LEN;
+      if (rtp_recvfrom(rcvr, word, &len) > -1)
+	printf("\tword: %s", word);
+    }
+      
+  } 
+
+  if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
+    leave_group(sock, mreq, argv[0]);
+  }
+
+#ifdef RTPW_USE_WINSOCK2
+  WSACleanup();
+#endif
+
+  return 0;
+}
+
+
+void
+usage(char *string) {
+
+  printf("usage: %s [-d <debug>]* [-k <key> [-a][-e]] "
+	 "[-s | -r] dest_ip dest_port\n"
+	 "or     %s -l\n"
+	 "where  -a use message authentication\n"
+	 "       -e use encryption\n"
+	 "       -k <key>  sets the srtp master key\n"
+	 "       -s act as rtp sender\n"
+	 "       -r act as rtp receiver\n"
+	 "       -l list debug modules\n"
+	 "       -d <debug> turn on debugging for module <debug>\n",
+	 string, string);
+  exit(1);
+  
+}
+
+
+void
+leave_group(int sock, struct ip_mreq mreq, char *name) {
+  int ret;
+
+  ret = setsockopt(sock, IPPROTO_IP, IP_DROP_MEMBERSHIP, (void*)&mreq,
+		   sizeof(mreq));
+  if (ret < 0) {
+	fprintf(stderr, "%s: Failed to leave multicast group", name);
+	perror("");
+  }
+}
+
diff --git a/third_party/srtp/test/rtpw_test.sh b/third_party/srtp/test/rtpw_test.sh
new file mode 100644
index 0000000..f82e937
--- /dev/null
+++ b/third_party/srtp/test/rtpw_test.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+# 
+# usage: rtpw_test <rtpw_commands>
+# 
+# tests the rtpw sender and receiver functions
+
+RTPW=rtpw
+DEST_PORT=9999
+DURATION=3
+
+key=2b2edc5034f61a72345ca5986d7bfd0189aa6dc2ecab32fd9af74df6dfc6
+
+ARGS="-k $key -ae"
+
+# First, we run "killall" to get rid of all existing rtpw processes.
+# This step also enables this script to clean up after itself; if this
+# script is interrupted after the rtpw processes are started but before
+# they are killed, those processes will linger.  Re-running the script
+# will get rid of them.
+
+killall rtpw 2&>/dev/null
+
+if test -x $RTPW; then
+
+echo  $0 ": starting rtpw receiver process... "
+
+$RTPW $* $ARGS -r 0.0.0.0 $DEST_PORT  &
+
+receiver_pid=$!
+
+echo $0 ": receiver PID = $receiver_pid"
+
+sleep 1 
+
+# verify that the background job is running
+ps | grep -q $receiver_pid
+retval=$?
+echo $retval
+if [ $retval != 0 ]; then
+    echo $0 ": error"
+    exit 254
+fi
+
+echo  $0 ": starting rtpw sender process..."
+
+$RTPW $* $ARGS -s 127.0.0.1 $DEST_PORT  &
+
+sender_pid=$!
+
+echo $0 ": sender PID = $sender_pid"
+
+# verify that the background job is running
+ps | grep -q $sender_pid
+retval=$?
+echo $retval
+if [ $retval != 0 ]; then
+    echo $0 ": error"
+    exit 255
+fi
+
+sleep $DURATION
+
+kill $receiver_pid
+kill $sender_pid
+
+echo $0 ": done (test passed)"
+
+else 
+
+echo "error: can't find executable" $RTPW
+exit 1
+
+fi
+
+# EOF
+
+
diff --git a/third_party/srtp/test/srtp_driver.c b/third_party/srtp/test/srtp_driver.c
new file mode 100644
index 0000000..12d1c8c
--- /dev/null
+++ b/third_party/srtp/test/srtp_driver.c
@@ -0,0 +1,1491 @@
+/*
+ * srtp_driver.c
+ * 
+ * a test driver for libSRTP
+ *
+ * David A. McGrew
+ * Cisco Systems, Inc.
+ */
+/*
+ *	
+ * Copyright (c) 2001-2006, Cisco Systems, Inc.
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * 
+ *   Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ * 
+ *   Neither the name of the Cisco Systems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#include <string.h>   /* for memcpy()          */
+#include <time.h>     /* for clock()           */
+#include <stdlib.h>   /* for malloc(), free()  */
+#include <stdio.h>    /* for print(), fflush() */
+#include "getopt_s.h" /* for local getopt()    */
+
+#include "srtp_priv.h"
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#elif defined HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+
+#define PRINT_REFERENCE_PACKET 1
+
+err_status_t
+srtp_validate(void);
+
+err_status_t
+srtp_create_big_policy(srtp_policy_t **list);
+
+err_status_t
+srtp_test_remove_stream(void);
+
+double
+srtp_bits_per_second(int msg_len_octets, const srtp_policy_t *policy);
+
+double
+srtp_rejections_per_second(int msg_len_octets, const srtp_policy_t *policy);
+
+void
+srtp_do_timing(const srtp_policy_t *policy);
+
+void
+srtp_do_rejection_timing(const srtp_policy_t *policy);
+
+err_status_t
+srtp_test(const srtp_policy_t *policy);
+
+err_status_t
+srtcp_test(const srtp_policy_t *policy);
+
+err_status_t
+srtp_session_print_policy(srtp_t srtp);
+
+err_status_t
+srtp_print_policy(const srtp_policy_t *policy); 
+
+char *
+srtp_packet_to_string(srtp_hdr_t *hdr, int packet_len);
+
+double
+mips_estimate(int num_trials, int *ignore);
+
+extern uint8_t test_key[30];
+
+void
+usage(char *prog_name) {
+  printf("usage: %s [ -t ][ -c ][ -v ][-d <debug_module> ]* [ -l ]\n"
+         "  -t         run timing test\n"
+	 "  -r         run rejection timing test\n"
+         "  -c         run codec timing test\n"
+         "  -v         run validation tests\n"
+         "  -d <mod>   turn on debugging module <mod>\n"
+         "  -l         list debugging modules\n", prog_name);
+  exit(1);
+}
+
+/*
+ * The policy_array is a null-terminated array of policy structs. it
+ * is declared at the end of this file
+ */
+
+extern const srtp_policy_t *policy_array[];
+
+
+/* the wildcard_policy is declared below; it has a wildcard ssrc */
+
+extern const srtp_policy_t wildcard_policy;
+
+/*
+ * mod_driver debug module - debugging module for this test driver
+ *
+ * we use the crypto_kernel debugging system in this driver, which 
+ * makes the interface uniform and increases portability
+ */ 
+
+debug_module_t mod_driver = {
+  0,                  /* debugging is off by default */
+  "driver"            /* printable name for module   */
+};
+
+int
+main (int argc, char *argv[]) {
+  char q;
+  unsigned do_timing_test    = 0;
+  unsigned do_rejection_test = 0;
+  unsigned do_codec_timing   = 0;
+  unsigned do_validation     = 0;
+  unsigned do_list_mods      = 0;
+  err_status_t status;
+
+  /* 
+   * verify that the compiler has interpreted the header data
+   * structure srtp_hdr_t correctly
+   */
+  if (sizeof(srtp_hdr_t) != 12) {
+     printf("error: srtp_hdr_t has incorrect size"
+	    "(size is %ld bytes, expected 12)\n", 
+	    sizeof(srtp_hdr_t));
+    exit(1);
+  }
+
+  /* initialize srtp library */
+  status = srtp_init();
+  if (status) {
+    printf("error: srtp init failed with error code %d\n", status);
+    exit(1);
+  }
+
+  /*  load srtp_driver debug module */
+  status = crypto_kernel_load_debug_module(&mod_driver);
+    if (status) {
+    printf("error: load of srtp_driver debug module failed "
+           "with error code %d\n", status);
+    exit(1);   
+  }
+
+  /* process input arguments */
+  while (1) {
+    q = getopt_s(argc, argv, "trcvld:");
+    if (q == -1) 
+      break;
+    switch (q) {
+    case 't':
+      do_timing_test = 1;
+      break;
+    case 'r':
+      do_rejection_test = 1;
+      break;
+    case 'c':
+      do_codec_timing = 1;
+      break;
+    case 'v':
+      do_validation = 1;
+      break;
+    case 'l':
+      do_list_mods = 1;
+      break;
+    case 'd':
+      status = crypto_kernel_set_debug_module(optarg_s, 1);
+      if (status) {
+        printf("error: set debug module (%s) failed\n", optarg_s);
+        exit(1);
+      }  
+      break;
+    default:
+      usage(argv[0]);
+    }    
+  }
+
+  if (!do_validation && !do_timing_test && !do_codec_timing 
+      && !do_list_mods && !do_rejection_test)
+    usage(argv[0]);
+
+  if (do_list_mods) {
+    status = crypto_kernel_list_debug_modules();
+    if (status) {
+      printf("error: list of debug modules failed\n");
+      exit(1);
+    }
+  }
+  
+  if (do_validation) {
+    const srtp_policy_t **policy = policy_array;
+    srtp_policy_t *big_policy;
+
+    /* loop over policy array, testing srtp and srtcp for each policy */
+    while (*policy != NULL) {
+      printf("testing srtp_protect and srtp_unprotect\n");
+      if (srtp_test(*policy) == err_status_ok)
+	printf("passed\n\n");
+      else {
+	printf("failed\n");
+	exit(1);
+      }
+      printf("testing srtp_protect_rtcp and srtp_unprotect_rtcp\n");
+      if (srtcp_test(*policy) == err_status_ok)
+	printf("passed\n\n");
+      else {
+	printf("failed\n");
+	exit(1);
+      }
+      policy++;
+    }
+
+    /* create a big policy list and run tests on it */
+    status = srtp_create_big_policy(&big_policy);
+    if (status) {
+      printf("unexpected failure with error code %d\n", status);
+      exit(1);
+    }
+    printf("testing srtp_protect and srtp_unprotect with big policy\n");
+    if (srtp_test(big_policy) == err_status_ok)
+      printf("passed\n\n");
+    else {
+      printf("failed\n");
+      exit(1);
+    }
+
+    /* run test on wildcard policy */
+    printf("testing srtp_protect and srtp_unprotect on "
+	   "wildcard ssrc policy\n");
+    if (srtp_test(&wildcard_policy) == err_status_ok)
+      printf("passed\n\n");
+    else {
+      printf("failed\n");
+      exit(1);
+    }   
+
+    /*
+     * run validation test against the reference packets - note 
+     * that this test only covers the default policy
+     */
+    printf("testing srtp_protect and srtp_unprotect against "
+	   "reference packets\n");
+    if (srtp_validate() == err_status_ok) 
+      printf("passed\n\n");
+    else {
+      printf("failed\n");
+       exit(1); 
+    }
+
+    /*
+     * test the function srtp_remove_stream()
+     */
+    printf("testing srtp_remove_stream()...");
+    if (srtp_test_remove_stream() == err_status_ok)
+      printf("passed\n");
+    else {
+      printf("failed\n");
+      exit(1);
+    }
+  }
+  
+  if (do_timing_test) {
+    const srtp_policy_t **policy = policy_array;
+    
+    /* loop over policies, run timing test for each */
+    while (*policy != NULL) {
+      srtp_print_policy(*policy);
+      srtp_do_timing(*policy);
+      policy++;
+    }
+  }
+
+  if (do_rejection_test) {
+    const srtp_policy_t **policy = policy_array;
+    
+    /* loop over policies, run rejection timing test for each */
+    while (*policy != NULL) {
+      srtp_print_policy(*policy);
+      srtp_do_rejection_timing(*policy);
+      policy++;
+    }
+  }
+  
+  if (do_codec_timing) {
+    srtp_policy_t policy;
+    int ignore;
+    double mips = mips_estimate(1000000000, &ignore);
+
+    crypto_policy_set_rtp_default(&policy.rtp);
+    crypto_policy_set_rtcp_default(&policy.rtcp);
+    policy.ssrc.type  = ssrc_specific;
+    policy.ssrc.value = 0xdecafbad;
+    policy.key  = test_key;
+    policy.next = NULL;
+
+    printf("mips estimate: %e\n", mips);
+
+    printf("testing srtp processing time for voice codecs:\n");
+    printf("codec\t\tlength (octets)\t\tsrtp instructions/second\n");
+    printf("G.711\t\t%d\t\t\t%e\n", 80, 
+           (double) mips * (80 * 8) / 
+	   srtp_bits_per_second(80, &policy) / .01 );
+    printf("G.711\t\t%d\t\t\t%e\n", 160, 
+           (double) mips * (160 * 8) / 
+	   srtp_bits_per_second(160, &policy) / .02);
+    printf("G.726-32\t%d\t\t\t%e\n", 40, 
+           (double) mips * (40 * 8) / 
+	   srtp_bits_per_second(40, &policy) / .01 );
+    printf("G.726-32\t%d\t\t\t%e\n", 80, 
+           (double) mips * (80 * 8) / 
+	   srtp_bits_per_second(80, &policy) / .02);
+    printf("G.729\t\t%d\t\t\t%e\n", 10, 
+           (double) mips * (10 * 8) / 
+	   srtp_bits_per_second(10, &policy) / .01 );
+    printf("G.729\t\t%d\t\t\t%e\n", 20, 
+           (double) mips * (20 * 8) /
+	   srtp_bits_per_second(20, &policy) / .02 );
+    printf("Wideband\t%d\t\t\t%e\n", 320, 
+           (double) mips * (320 * 8) /
+	   srtp_bits_per_second(320, &policy) / .01 );
+    printf("Wideband\t%d\t\t\t%e\n", 640, 
+           (double) mips * (640 * 8) /
+	   srtp_bits_per_second(640, &policy) / .02 );
+  }
+
+  return 0;  
+}
+
+
+
+/*
+ * srtp_create_test_packet(len, ssrc) returns a pointer to a
+ * (malloced) example RTP packet whose data field has the length given
+ * by pkt_octet_len and the SSRC value ssrc.  The total length of the
+ * packet is twelve octets longer, since the header is at the
+ * beginning.  There is room at the end of the packet for a trailer,
+ * and the four octets following the packet are filled with 0xff
+ * values to enable testing for overwrites.
+ *
+ * note that the location of the test packet can (and should) be
+ * deallocated with the free() call once it is no longer needed.
+ */
+
+srtp_hdr_t *
+srtp_create_test_packet(int pkt_octet_len, uint32_t ssrc) {
+  int i;
+  uint8_t *buffer;
+  srtp_hdr_t *hdr;
+  int bytes_in_hdr = 12;
+
+  /* allocate memory for test packet */
+  hdr = (srtp_hdr_t*) malloc(pkt_octet_len + bytes_in_hdr
+	       + SRTP_MAX_TRAILER_LEN + 4);
+  if (!hdr)
+    return NULL;
+  
+  hdr->version = 2;              /* RTP version two     */
+  hdr->p    = 0;                 /* no padding needed   */
+  hdr->x    = 0;                 /* no header extension */
+  hdr->cc   = 0;                 /* no CSRCs            */
+  hdr->m    = 0;                 /* marker bit          */
+  hdr->pt   = 0xf;               /* payload type        */
+  hdr->seq  = htons(0x1234);     /* sequence number     */
+  hdr->ts   = htonl(0xdecafbad); /* timestamp           */
+  hdr->ssrc = htonl(ssrc);       /* synch. source       */
+
+  buffer = (uint8_t *)hdr;
+  buffer += bytes_in_hdr;
+
+  /* set RTP data to 0xab */
+  for (i=0; i < pkt_octet_len; i++)
+    *buffer++ = 0xab;
+
+  /* set post-data value to 0xffff to enable overrun checking */
+  for (i=0; i < SRTP_MAX_TRAILER_LEN+4; i++)
+    *buffer++ = 0xff;
+
+  return hdr;
+}
+
+void
+srtp_do_timing(const srtp_policy_t *policy) {
+  int len;
+
+  /*
+   * note: the output of this function is formatted so that it
+   * can be used in gnuplot.  '#' indicates a comment, and "\r\n"
+   * terminates a record
+   */
+  
+  printf("# testing srtp throughput:\r\n");
+  printf("# mesg length (octets)\tthroughput (megabits per second)\r\n");
+  
+  for (len=16; len <= 2048; len *= 2)
+    printf("%d\t\t\t%f\r\n", len, 
+	   srtp_bits_per_second(len, policy) / 1.0E6);
+  
+  /* these extra linefeeds let gnuplot know that a dataset is done */
+  printf("\r\n\r\n");  
+
+}
+
+void
+srtp_do_rejection_timing(const srtp_policy_t *policy) {
+  int len;
+
+  /*
+   * note: the output of this function is formatted so that it
+   * can be used in gnuplot.  '#' indicates a comment, and "\r\n"
+   * terminates a record
+   */
+  
+  printf("# testing srtp rejection throughput:\r\n");
+  printf("# mesg length (octets)\trejections per second\r\n");
+  
+  for (len=8; len <= 2048; len *= 2)
+    printf("%d\t\t\t%e\r\n", len, srtp_rejections_per_second(len, policy));
+  
+  /* these extra linefeeds let gnuplot know that a dataset is done */
+  printf("\r\n\r\n");  
+
+}
+
+
+#define MAX_MSG_LEN 1024
+
+double
+srtp_bits_per_second(int msg_len_octets, const srtp_policy_t *policy) {
+  srtp_t srtp;
+  srtp_hdr_t *mesg;  
+  int i;
+  clock_t timer;
+  int num_trials = 100000;
+  int len;
+  uint32_t ssrc;
+  err_status_t status;
+
+  /*
+   * allocate and initialize an srtp session
+   */
+  status = srtp_create(&srtp, policy);
+  if (status) {
+    printf("error: srtp_create() failed with error code %d\n", status);
+    exit(1);
+  }
+
+  /*
+   * if the ssrc is unspecified, use a predetermined one
+   */
+  if (policy->ssrc.type != ssrc_specific) {
+    ssrc = 0xdeadbeef;
+  } else {
+    ssrc = policy->ssrc.value;
+  }
+
+  /*
+   * create a test packet
+   */
+  mesg = srtp_create_test_packet(msg_len_octets, ssrc);
+  if (mesg == NULL)
+    return 0.0;   /* indicate failure by returning zero */
+  
+  timer = clock();
+  for (i=0; i < num_trials; i++) {
+    err_status_t status;
+    len = msg_len_octets + 12;  /* add in rtp header length */
+    
+    /* srtp protect message */
+    status = srtp_protect(srtp, mesg, &len);
+    if (status) {
+      printf("error: srtp_protect() failed with error code %d\n", status);
+      exit(1);
+    }
+
+    /* increment message number */
+    mesg->seq = htons(ntohs(mesg->seq) + 1);
+
+  }
+  timer = clock() - timer;
+
+  free(mesg);
+  
+  return (double) (msg_len_octets) * 8 *
+                  num_trials * CLOCKS_PER_SEC / timer;   
+}
+
+double
+srtp_rejections_per_second(int msg_len_octets, const srtp_policy_t *policy) {
+  srtp_ctx_t *srtp;
+  srtp_hdr_t *mesg; 
+  int i;
+  int len;
+  clock_t timer;
+  int num_trials = 1000000;
+  uint32_t ssrc = policy->ssrc.value;
+  err_status_t status;
+
+  /*
+   * allocate and initialize an srtp session
+   */
+  status = srtp_create(&srtp, policy);
+  if (status) {
+    printf("error: srtp_create() failed with error code %d\n", status);
+    exit(1);
+  } 
+
+  mesg = srtp_create_test_packet(msg_len_octets, ssrc);
+  if (mesg == NULL)
+    return 0.0;  /* indicate failure by returning zero */
+  
+  len = msg_len_octets;  
+  srtp_protect(srtp, (srtp_hdr_t *)mesg, &len);
+  
+  timer = clock();
+  for (i=0; i < num_trials; i++) {
+    len = msg_len_octets;
+    srtp_unprotect(srtp, (srtp_hdr_t *)mesg, &len);
+  }
+  timer = clock() - timer;
+
+  free(mesg);
+  
+  return (double) num_trials * CLOCKS_PER_SEC / timer;   
+}
+
+
+void
+err_check(err_status_t s) {
+  if (s == err_status_ok) 
+    return;
+  else
+    fprintf(stderr, "error: unexpected srtp failure (code %d)\n", s);
+  exit (1);
+}
+
+err_status_t
+srtp_test(const srtp_policy_t *policy) {
+  int i;
+  srtp_t srtp_sender;
+  srtp_t srtp_rcvr;
+  err_status_t status = err_status_ok;
+  srtp_hdr_t *hdr, *hdr2;
+  uint8_t hdr_enc[64];
+  uint8_t *pkt_end;
+  int msg_len_octets, msg_len_enc;
+  int len;
+  int tag_length = policy->rtp.auth_tag_len; 
+  uint32_t ssrc;
+  srtp_policy_t *rcvr_policy;
+
+  err_check(srtp_create(&srtp_sender, policy));
+
+  /* print out policy */
+  err_check(srtp_session_print_policy(srtp_sender)); 
+
+  /*
+   * initialize data buffer, using the ssrc in the policy unless that
+   * value is a wildcard, in which case we'll just use an arbitrary
+   * one
+   */
+  if (policy->ssrc.type != ssrc_specific)
+    ssrc = 0xdecafbad;
+  else
+    ssrc = policy->ssrc.value;
+  msg_len_octets = 28;
+  hdr = srtp_create_test_packet(msg_len_octets, ssrc);
+
+  if (hdr == NULL)
+    return err_status_alloc_fail;
+  hdr2 = srtp_create_test_packet(msg_len_octets, ssrc);
+  if (hdr2 == NULL) {
+    free(hdr);
+    return err_status_alloc_fail;
+  }
+
+  /* set message length */
+  len = msg_len_octets;
+
+  debug_print(mod_driver, "before protection:\n%s", 	      
+	      srtp_packet_to_string(hdr, len));
+
+#if PRINT_REFERENCE_PACKET
+  debug_print(mod_driver, "reference packet before protection:\n%s", 	      
+	      octet_string_hex_string((uint8_t *)hdr, len));
+#endif
+  err_check(srtp_protect(srtp_sender, hdr, &len));
+
+  debug_print(mod_driver, "after protection:\n%s", 	      
+	      srtp_packet_to_string(hdr, len));
+#if PRINT_REFERENCE_PACKET
+  debug_print(mod_driver, "after protection:\n%s", 	      
+	      octet_string_hex_string((uint8_t *)hdr, len));
+#endif
+
+  /* save protected message and length */
+  memcpy(hdr_enc, hdr, len);
+  msg_len_enc = len;
+
+  /* 
+   * check for overrun of the srtp_protect() function
+   *
+   * The packet is followed by a value of 0xfffff; if the value of the
+   * data following the packet is different, then we know that the
+   * protect function is overwriting the end of the packet.
+   */
+  pkt_end = (uint8_t *)hdr + sizeof(srtp_hdr_t) 
+    + msg_len_octets + tag_length;
+  for (i = 0; i < 4; i++)
+    if (pkt_end[i] != 0xff) {
+      fprintf(stdout, "overwrite in srtp_protect() function "
+              "(expected %x, found %x in trailing octet %d)\n",
+              0xff, ((uint8_t *)hdr)[i], i);
+      free(hdr);
+      free(hdr2);
+      return err_status_algo_fail;
+    }  
+
+  /*
+   * if the policy includes confidentiality, check that ciphertext is
+   * different than plaintext
+   * 
+   * Note that this check will give false negatives, with some small
+   * probability, especially if the packets are short.  For that
+   * reason, we skip this check if the plaintext is less than four
+   * octets long.
+   */
+  if ((policy->rtp.sec_serv & sec_serv_conf) && (msg_len_octets >= 4)) {
+    printf("testing that ciphertext is distinct from plaintext...");
+    status = err_status_algo_fail;
+    for (i=12; i < msg_len_octets+12; i++)
+      if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
+	status = err_status_ok;
+      }
+    if (status) {
+      printf("failed\n");
+      free(hdr);
+      free(hdr2);
+      return status;
+    }
+    printf("passed\n");
+  }
+  
+  /*
+   * if the policy uses a 'wildcard' ssrc, then we need to make a copy
+   * of the policy that changes the direction to inbound
+   *
+   * we always copy the policy into the rcvr_policy, since otherwise
+   * the compiler would fret about the constness of the policy
+   */
+  rcvr_policy = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
+  if (rcvr_policy == NULL)
+    return err_status_alloc_fail;
+  memcpy(rcvr_policy, policy, sizeof(srtp_policy_t));
+  if (policy->ssrc.type == ssrc_any_outbound) {
+    rcvr_policy->ssrc.type = ssrc_any_inbound;       
+  } 
+
+  err_check(srtp_create(&srtp_rcvr, rcvr_policy));
+   
+  err_check(srtp_unprotect(srtp_rcvr, hdr, &len));
+
+  debug_print(mod_driver, "after unprotection:\n%s", 	      
+	      srtp_packet_to_string(hdr, len));
+
+  /* verify that the unprotected packet matches the origial one */
+  for (i=0; i < msg_len_octets; i++)
+    if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
+      fprintf(stdout, "mismatch at octet %d\n", i);
+      status = err_status_algo_fail;
+    }
+  if (status) {
+    free(hdr);
+    free(hdr2);
+    return status;
+  }
+
+  /* 
+   * if the policy includes authentication, then test for false positives
+   */  
+  if (policy->rtp.sec_serv & sec_serv_auth) {
+    char *data = ((char *)hdr) + 12;
+    
+    printf("testing for false positives in replay check...");
+
+    /* set message length */
+    len = msg_len_enc;
+
+    /* unprotect a second time - should fail with a replay error */
+    status = srtp_unprotect(srtp_rcvr, hdr_enc, &len);
+    if (status != err_status_replay_fail) {
+      printf("failed with error code %d\n", status);
+      free(hdr); 
+      free(hdr2);
+      return status;
+    } else {
+      printf("passed\n");
+    }
+
+    printf("testing for false positives in auth check...");
+
+    /* increment sequence number in header */
+    hdr->seq++; 
+
+    /* set message length */
+    len = msg_len_octets;
+
+    /* apply protection */
+    err_check(srtp_protect(srtp_sender, hdr, &len));
+    
+    /* flip bits in packet */
+    data[0] ^= 0xff;
+
+    /* unprotect, and check for authentication failure */
+    status = srtp_unprotect(srtp_rcvr, hdr, &len);
+    if (status != err_status_auth_fail) {
+      printf("failed\n");
+      free(hdr); 
+      free(hdr2);
+      return status;
+    } else {
+      printf("passed\n");
+    }
+            
+  }
+
+  err_check(srtp_dealloc(srtp_sender));
+  err_check(srtp_dealloc(srtp_rcvr));
+
+  free(hdr);
+  free(hdr2);
+  return err_status_ok;
+}
+
+
+err_status_t
+srtcp_test(const srtp_policy_t *policy) {
+  int i;
+  srtp_t srtcp_sender;
+  srtp_t srtcp_rcvr;
+  err_status_t status = err_status_ok;
+  srtp_hdr_t *hdr, *hdr2;
+  uint8_t hdr_enc[64];
+  uint8_t *pkt_end;
+  int msg_len_octets, msg_len_enc;
+  int len;
+  int tag_length = policy->rtp.auth_tag_len; 
+  uint32_t ssrc;
+  srtp_policy_t *rcvr_policy;
+
+  err_check(srtp_create(&srtcp_sender, policy));
+
+  /* print out policy */
+  err_check(srtp_session_print_policy(srtcp_sender)); 
+
+  /*
+   * initialize data buffer, using the ssrc in the policy unless that
+   * value is a wildcard, in which case we'll just use an arbitrary
+   * one
+   */
+  if (policy->ssrc.type != ssrc_specific)
+    ssrc = 0xdecafbad;
+  else
+    ssrc = policy->ssrc.value;
+  msg_len_octets = 28;
+  hdr = srtp_create_test_packet(msg_len_octets, ssrc);
+
+  if (hdr == NULL)
+    return err_status_alloc_fail;
+  hdr2 = srtp_create_test_packet(msg_len_octets, ssrc);
+  if (hdr2 == NULL) {
+    free(hdr);
+    return err_status_alloc_fail;
+  }
+
+  /* set message length */
+  len = msg_len_octets;
+
+  debug_print(mod_driver, "before protection:\n%s", 	      
+	      srtp_packet_to_string(hdr, len));
+
+#if PRINT_REFERENCE_PACKET
+  debug_print(mod_driver, "reference packet before protection:\n%s", 	      
+	      octet_string_hex_string((uint8_t *)hdr, len));
+#endif
+  err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len));
+
+  debug_print(mod_driver, "after protection:\n%s", 	      
+	      srtp_packet_to_string(hdr, len));
+#if PRINT_REFERENCE_PACKET
+  debug_print(mod_driver, "after protection:\n%s", 	      
+	      octet_string_hex_string((uint8_t *)hdr, len));
+#endif
+
+  /* save protected message and length */
+  memcpy(hdr_enc, hdr, len);
+  msg_len_enc = len;
+
+  /* 
+   * check for overrun of the srtp_protect() function
+   *
+   * The packet is followed by a value of 0xfffff; if the value of the
+   * data following the packet is different, then we know that the
+   * protect function is overwriting the end of the packet.
+   */
+  pkt_end = (uint8_t *)hdr + sizeof(srtp_hdr_t) 
+    + msg_len_octets + tag_length;
+  for (i = 0; i < 4; i++)
+    if (pkt_end[i] != 0xff) {
+      fprintf(stdout, "overwrite in srtp_protect_rtcp() function "
+              "(expected %x, found %x in trailing octet %d)\n",
+              0xff, ((uint8_t *)hdr)[i], i);
+      free(hdr);
+      free(hdr2);
+      return err_status_algo_fail;
+    }  
+
+  /*
+   * if the policy includes confidentiality, check that ciphertext is
+   * different than plaintext
+   * 
+   * Note that this check will give false negatives, with some small
+   * probability, especially if the packets are short.  For that
+   * reason, we skip this check if the plaintext is less than four
+   * octets long.
+   */
+  if ((policy->rtp.sec_serv & sec_serv_conf) && (msg_len_octets >= 4)) {
+    printf("testing that ciphertext is distinct from plaintext...");
+    status = err_status_algo_fail;
+    for (i=12; i < msg_len_octets+12; i++)
+      if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
+	status = err_status_ok;
+      }
+    if (status) {
+      printf("failed\n");
+      free(hdr);
+      free(hdr2);
+      return status;
+    }
+    printf("passed\n");
+  }
+  
+  /*
+   * if the policy uses a 'wildcard' ssrc, then we need to make a copy
+   * of the policy that changes the direction to inbound
+   *
+   * we always copy the policy into the rcvr_policy, since otherwise
+   * the compiler would fret about the constness of the policy
+   */
+  rcvr_policy = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
+  if (rcvr_policy == NULL)
+    return err_status_alloc_fail;
+  memcpy(rcvr_policy, policy, sizeof(srtp_policy_t));
+  if (policy->ssrc.type == ssrc_any_outbound) {
+    rcvr_policy->ssrc.type = ssrc_any_inbound;       
+  } 
+
+  err_check(srtp_create(&srtcp_rcvr, rcvr_policy));
+   
+  err_check(srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len));
+
+  debug_print(mod_driver, "after unprotection:\n%s", 	      
+	      srtp_packet_to_string(hdr, len));
+
+  /* verify that the unprotected packet matches the origial one */
+  for (i=0; i < msg_len_octets; i++)
+    if (((uint8_t *)hdr)[i] != ((uint8_t *)hdr2)[i]) {
+      fprintf(stdout, "mismatch at octet %d\n", i);
+      status = err_status_algo_fail;
+    }
+  if (status) {
+    free(hdr);
+    free(hdr2);
+    return status;
+  }
+
+  /* 
+   * if the policy includes authentication, then test for false positives
+   */  
+  if (policy->rtp.sec_serv & sec_serv_auth) {
+    char *data = ((char *)hdr) + 12;
+    
+    printf("testing for false positives in replay check...");
+
+    /* set message length */
+    len = msg_len_enc;
+
+    /* unprotect a second time - should fail with a replay error */
+    status = srtp_unprotect_rtcp(srtcp_rcvr, hdr_enc, &len);
+    if (status != err_status_replay_fail) {
+      printf("failed with error code %d\n", status);
+      free(hdr); 
+      free(hdr2);
+      return status;
+    } else {
+      printf("passed\n");
+    }
+
+    printf("testing for false positives in auth check...");
+
+    /* increment sequence number in header */
+    hdr->seq++; 
+
+    /* set message length */
+    len = msg_len_octets;
+
+    /* apply protection */
+    err_check(srtp_protect_rtcp(srtcp_sender, hdr, &len));
+    
+    /* flip bits in packet */
+    data[0] ^= 0xff;
+
+    /* unprotect, and check for authentication failure */
+    status = srtp_unprotect_rtcp(srtcp_rcvr, hdr, &len);
+    if (status != err_status_auth_fail) {
+      printf("failed\n");
+      free(hdr); 
+      free(hdr2);
+      return status;
+    } else {
+      printf("passed\n");
+    }
+            
+  }
+
+  err_check(srtp_dealloc(srtcp_sender));
+  err_check(srtp_dealloc(srtcp_rcvr));
+
+  free(hdr);
+  free(hdr2);
+  return err_status_ok;
+}
+
+
+err_status_t
+srtp_session_print_policy(srtp_t srtp) {
+  char *serv_descr[4] = {
+    "none",
+    "confidentiality",
+    "authentication",
+    "confidentiality and authentication"
+  };
+  char *direction[3] = {
+    "unknown",
+    "outbound",
+    "inbound"
+  };
+  srtp_stream_t stream;
+
+  /* sanity checking */
+  if (srtp == NULL)
+    return err_status_fail;
+
+  /* if there's a template stream, print it out */
+  if (srtp->stream_template != NULL) {
+    stream = srtp->stream_template;
+    printf("# SSRC:          any %s\r\n"
+	   "# rtp cipher:    %s\r\n"
+	   "# rtp auth:      %s\r\n"
+	   "# rtp services:  %s\r\n" 
+           "# rtcp cipher:   %s\r\n"
+	   "# rtcp auth:     %s\r\n"
+	   "# rtcp services: %s\r\n",
+	   direction[stream->direction],
+	   stream->rtp_cipher->type->description,
+	   stream->rtp_auth->type->description,
+	   serv_descr[stream->rtp_services],
+	   stream->rtcp_cipher->type->description,
+	   stream->rtcp_auth->type->description,
+	   serv_descr[stream->rtcp_services]);
+  }
+
+  /* loop over streams in session, printing the policy of each */
+  stream = srtp->stream_list;
+  while (stream != NULL) {
+    if (stream->rtp_services > sec_serv_conf_and_auth)
+      return err_status_bad_param;
+    
+    printf("# SSRC:          0x%08x\r\n"
+	   "# rtp cipher:    %s\r\n"
+	   "# rtp auth:      %s\r\n"
+	   "# rtp services:  %s\r\n" 
+           "# rtcp cipher:   %s\r\n"
+	   "# rtcp auth:     %s\r\n"
+	   "# rtcp services: %s\r\n",
+	   stream->ssrc,
+	   stream->rtp_cipher->type->description,
+	   stream->rtp_auth->type->description,
+	   serv_descr[stream->rtp_services],
+	   stream->rtcp_cipher->type->description,
+	   stream->rtcp_auth->type->description,
+	   serv_descr[stream->rtcp_services]);
+
+    /* advance to next stream in the list */
+    stream = stream->next;
+  } 
+  return err_status_ok;
+}
+
+err_status_t
+srtp_print_policy(const srtp_policy_t *policy) {
+  err_status_t status;
+  srtp_t session;
+
+  status = srtp_create(&session, policy);
+  if (status)
+    return status;
+  status = srtp_session_print_policy(session);
+  if (status)
+    return status;
+  status = srtp_dealloc(session);
+  if (status)
+    return status;
+  return err_status_ok;
+}
+
+/* 
+ * srtp_print_packet(...) is for debugging only 
+ * it prints an RTP packet to the stdout
+ *
+ * note that this function is *not* threadsafe
+ */
+
+#include <stdio.h>
+
+#define MTU 2048
+
+char packet_string[MTU];
+
+char *
+srtp_packet_to_string(srtp_hdr_t *hdr, int pkt_octet_len) {
+  int octets_in_rtp_header = 12;
+  uint8_t *data = ((uint8_t *)hdr)+octets_in_rtp_header;
+  int hex_len = pkt_octet_len-octets_in_rtp_header;
+
+  /* sanity checking */
+  if ((hdr == NULL) || (pkt_octet_len > MTU))
+    return NULL;
+
+  /* write packet into string */
+  sprintf(packet_string, 
+	  "(s)rtp packet: {\n"
+	  "   version:\t%d\n" 
+	  "   p:\t\t%d\n"     
+	  "   x:\t\t%d\n"     
+	  "   cc:\t\t%d\n"    
+	  "   m:\t\t%d\n"     
+	  "   pt:\t\t%x\n"    
+	  "   seq:\t\t%x\n"   
+	  "   ts:\t\t%x\n"    
+	  "   ssrc:\t%x\n"    
+	  "   data:\t%s\n"    
+	  "} (%d octets in total)\n", 
+	  hdr->version,  
+	  hdr->p,	       
+	  hdr->x,	       
+	  hdr->cc,       
+	  hdr->m,	       
+	  hdr->pt,       
+	  hdr->seq,      
+	  hdr->ts,       
+	  hdr->ssrc,      
+  	  octet_string_hex_string(data, hex_len),
+	  pkt_octet_len);
+
+  return packet_string;
+}
+
+/*
+ * mips_estimate() is a simple function to estimate the number of
+ * instructions per second that the host can perform.  note that this
+ * function can be grossly wrong; you may want to have a manual sanity
+ * check of its output!
+ *
+ * the 'ignore' pointer is there to convince the compiler to not just
+ * optimize away the function
+ */
+
+double
+mips_estimate(int num_trials, int *ignore) {
+  clock_t t;
+  int i, sum;
+
+  sum = 0;
+  t = clock();
+  for (i=0; i<num_trials; i++)
+    sum += i;
+  t = clock() - t;
+
+/*   printf("%d\n", sum); */
+  *ignore = sum;
+
+  return (double) num_trials * CLOCKS_PER_SEC / t;
+}
+
+
+/*
+ * srtp_validate() verifies the correctness of libsrtp by comparing
+ * some computed packets against some pre-computed reference values.
+ * These packets were made with the default SRTP policy.
+ */
+
+
+err_status_t
+srtp_validate() {
+  unsigned char test_key[30] = {
+    0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0,
+    0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39,
+    0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
+    0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
+  };
+  uint8_t srtp_plaintext_ref[28] = {
+    0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, 
+    0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
+    0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 
+    0xab, 0xab, 0xab, 0xab
+  };
+  uint8_t srtp_plaintext[38] = {
+    0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, 
+    0xca, 0xfe, 0xba, 0xbe, 0xab, 0xab, 0xab, 0xab,
+    0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 
+    0xab, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+  uint8_t srtp_ciphertext[38] = {
+    0x80, 0x0f, 0x12, 0x34, 0xde, 0xca, 0xfb, 0xad, 
+    0xca, 0xfe, 0xba, 0xbe, 0x4e, 0x55, 0xdc, 0x4c,
+    0xe7, 0x99, 0x78, 0xd8, 0x8c, 0xa4, 0xd2, 0x15, 
+    0x94, 0x9d, 0x24, 0x02, 0xb7, 0x8d, 0x6a, 0xcc,
+    0x99, 0xea, 0x17, 0x9b, 0x8d, 0xbb
+  };
+  srtp_t srtp_snd, srtp_recv;
+  err_status_t status;
+  int len;
+  srtp_policy_t policy;
+  
+  /*
+   * create a session with a single stream using the default srtp
+   * policy and with the SSRC value 0xcafebabe
+   */
+  crypto_policy_set_rtp_default(&policy.rtp);
+  crypto_policy_set_rtcp_default(&policy.rtcp);
+  policy.ssrc.type  = ssrc_specific;
+  policy.ssrc.value = 0xcafebabe;
+  policy.key  = test_key;
+  policy.next = NULL;
+
+  status = srtp_create(&srtp_snd, &policy);
+  if (status)
+    return status;
+ 
+  /* 
+   * protect plaintext, then compare with ciphertext 
+   */
+  len = 28;
+  status = srtp_protect(srtp_snd, srtp_plaintext, &len);
+  if (status || (len != 38))
+    return err_status_fail;
+
+  debug_print(mod_driver, "ciphertext:\n  %s", 	      
+	      octet_string_hex_string(srtp_plaintext, len));
+  debug_print(mod_driver, "ciphertext reference:\n  %s", 	      
+	      octet_string_hex_string(srtp_ciphertext, len));
+
+  if (octet_string_is_eq(srtp_plaintext, srtp_ciphertext, len))
+    return err_status_fail;
+  
+  /*
+   * create a receiver session context comparable to the one created
+   * above - we need to do this so that the replay checking doesn't
+   * complain
+   */
+  status = srtp_create(&srtp_recv, &policy);
+  if (status)
+    return status;
+
+  /*
+   * unprotect ciphertext, then compare with plaintext 
+   */
+  status = srtp_unprotect(srtp_recv, srtp_ciphertext, &len);
+  if (status || (len != 28))
+    return status;
+  
+  if (octet_string_is_eq(srtp_ciphertext, srtp_plaintext_ref, len))
+    return err_status_fail;
+
+  return err_status_ok;
+}
+
+
+err_status_t
+srtp_create_big_policy(srtp_policy_t **list) {
+  extern const srtp_policy_t *policy_array[];
+  srtp_policy_t *p, *tmp;
+  int i = 0;
+  uint32_t ssrc = 0;
+
+  /* sanity checking */
+  if ((list == NULL) || (policy_array[0] == NULL))
+    return err_status_bad_param;
+
+  /* 
+   * loop over policy list, mallocing a new list and copying values
+   * into it (and incrementing the SSRC value as we go along)
+   */
+  tmp = NULL;
+  while (policy_array[i] != NULL) {
+    p  = (srtp_policy_t*) malloc(sizeof(srtp_policy_t));
+    if (p == NULL)
+      return err_status_bad_param;
+    memcpy(p, policy_array[i], sizeof(srtp_policy_t));
+    p->ssrc.type = ssrc_specific;
+    p->ssrc.value = ssrc++;
+    p->next = tmp;
+    tmp = p;
+    i++;
+  }
+  *list = p;
+ 
+  return err_status_ok;
+}
+
+err_status_t
+srtp_test_remove_stream() { 
+  err_status_t status;
+  srtp_policy_t *policy_list;
+  srtp_t session;
+  srtp_stream_t stream;
+  /* 
+   * srtp_get_stream() is a libSRTP internal function that we declare
+   * here so that we can use it to verify the correct operation of the
+   * library
+   */ 
+  extern srtp_stream_t srtp_get_stream(srtp_t srtp, uint32_t ssrc);
+  
+
+  status = srtp_create_big_policy(&policy_list);
+  if (status)
+    return status;
+
+  status = srtp_create(&session, policy_list);
+  if (status)
+    return status;
+
+  /*
+   * check for false positives by trying to remove a stream that's not
+   * in the session
+   */
+  status = srtp_remove_stream(session, htonl(0xaaaaaaaa));
+  if (status != err_status_no_ctx)
+    return err_status_fail;
+  
+  /* 
+   * check for false negatives by removing stream 0x1, then
+   * searching for streams 0x0 and 0x2
+   */
+  status = srtp_remove_stream(session, htonl(0x1));
+  if (status != err_status_ok)
+    return err_status_fail;
+  stream = srtp_get_stream(session, htonl(0x0));
+  if (stream == NULL)
+    return err_status_fail;
+  stream = srtp_get_stream(session, htonl(0x2));
+  if (stream == NULL)
+    return err_status_fail;  
+
+  return err_status_ok;  
+}
+
+/*
+ * srtp policy definitions - these definitions are used above
+ */
+
+unsigned char test_key[30] = {
+    0xe1, 0xf9, 0x7a, 0x0d, 0x3e, 0x01, 0x8b, 0xe0,
+    0xd6, 0x4f, 0xa3, 0x2c, 0x06, 0xde, 0x41, 0x39,
+    0x0e, 0xc6, 0x75, 0xad, 0x49, 0x8a, 0xfe, 0xeb,
+    0xb6, 0x96, 0x0b, 0x3a, 0xab, 0xe6
+};
+
+
+const srtp_policy_t default_policy = {
+  { ssrc_any_outbound, 0 },  /* SSRC                           */
+  {                      /* SRTP policy                    */                  
+    AES_128_ICM,            /* cipher type                 */
+    30,                     /* cipher key length in octets */
+    HMAC_SHA1,              /* authentication func type    */
+    16,                     /* auth key length in octets   */
+    10,                     /* auth tag length in octets   */
+    sec_serv_conf_and_auth  /* security services flag      */
+  },
+  {                      /* SRTCP policy                   */
+    AES_128_ICM,            /* cipher type                 */
+    30,                     /* cipher key length in octets */
+    HMAC_SHA1,              /* authentication func type    */
+    16,                     /* auth key length in octets   */
+    10,                     /* auth tag length in octets   */
+    sec_serv_conf_and_auth  /* security services flag      */
+  },
+  test_key,
+  NULL
+};
+
+const srtp_policy_t aes_tmmh_policy = {
+  { ssrc_any_outbound, 0 },     /* SSRC                        */
+  { 
+    AES_128_ICM,            /* cipher type                 */
+    30,                     /* cipher key length in octets */
+    UST_TMMHv2,             /* authentication func type    */
+    94,                     /* auth key length in octets   */
+    4,                      /* auth tag length in octets   */
+    sec_serv_conf_and_auth  /* security services flag      */
+  },
+  { 
+    AES_128_ICM,            /* cipher type                 */
+    30,                     /* cipher key length in octets */
+    UST_TMMHv2,             /* authentication func type    */
+    94,                     /* auth key length in octets   */
+    4,                      /* auth tag length in octets   */
+    sec_serv_conf_and_auth  /* security services flag      */
+  },
+  test_key,
+  NULL
+};
+
+const srtp_policy_t tmmh_only_policy = {
+  { ssrc_any_outbound, 0 },     /* SSRC                        */
+  {
+    AES_128_ICM,            /* cipher type                 */
+    30,                     /* cipher key length in octets */
+    UST_TMMHv2,             /* authentication func type    */
+    94,                     /* auth key length in octets   */
+    4,                      /* auth tag length in octets   */
+    sec_serv_auth           /* security services flag      */
+  },
+  {
+    AES_128_ICM,            /* cipher type                 */
+    30,                     /* cipher key length in octets */
+    UST_TMMHv2,             /* authentication func type    */
+    94,                     /* auth key length in octets   */
+    4,                      /* auth tag length in octets   */
+    sec_serv_auth           /* security services flag      */
+  },
+  test_key,
+  NULL
+};
+
+const srtp_policy_t aes_only_policy = {
+  { ssrc_any_outbound, 0 },     /* SSRC                        */ 
+  {
+    AES_128_ICM,            /* cipher type                 */
+    30,                     /* cipher key length in octets */
+    NULL_AUTH,              /* authentication func type    */
+    0,                      /* auth key length in octets   */
+    0,                      /* auth tag length in octets   */
+    sec_serv_conf           /* security services flag      */
+  },
+  {
+    AES_128_ICM,            /* cipher type                 */
+    30,                     /* cipher key length in octets */
+    NULL_AUTH,              /* authentication func type    */
+    0,                      /* auth key length in octets   */
+    0,                      /* auth tag length in octets   */
+    sec_serv_conf           /* security services flag      */
+  },
+  test_key,
+  NULL
+};
+
+const srtp_policy_t hmac_only_policy = {
+  { ssrc_any_outbound, 0 },     /* SSRC                        */
+  {
+    NULL_CIPHER,            /* cipher type                 */
+    0,                      /* cipher key length in octets */
+    HMAC_SHA1,              /* authentication func type    */
+    20,                     /* auth key length in octets   */
+    4,                      /* auth tag length in octets   */
+    sec_serv_auth           /* security services flag      */
+  },  
+  {
+    NULL_CIPHER,            /* cipher type                 */
+    0,                      /* cipher key length in octets */
+    HMAC_SHA1,              /* authentication func type    */
+    20,                     /* auth key length in octets   */
+    4,                      /* auth tag length in octets   */
+    sec_serv_auth           /* security services flag      */
+  },
+  test_key,
+  NULL
+};
+
+const srtp_policy_t null_policy = {
+  { ssrc_any_outbound, 0 },     /* SSRC                        */ 
+  {
+    NULL_CIPHER,            /* cipher type                 */
+    0,                      /* cipher key length in octets */
+    NULL_AUTH,              /* authentication func type    */
+    0,                      /* auth key length in octets   */
+    0,                      /* auth tag length in octets   */
+    sec_serv_none           /* security services flag      */  
+  },
+  {
+    NULL_CIPHER,            /* cipher type                 */
+    0,                      /* cipher key length in octets */
+    NULL_AUTH,              /* authentication func type    */
+    0,                      /* auth key length in octets   */
+    0,                      /* auth tag length in octets   */
+    sec_serv_none           /* security services flag      */  
+  },
+  test_key,
+  NULL
+};
+
+
+/*
+ * an array of pointers to the policies listed above
+ *
+ * This array is used to test various aspects of libSRTP for
+ * different cryptographic policies.  The order of the elements
+ * matters - the timing test generates output that can be used
+ * in a plot (see the gnuplot script file 'timing').  If you 
+ * add to this list, you should do it at the end.
+ */
+
+#define USE_TMMH 0
+
+const srtp_policy_t *
+policy_array[] = {
+  &hmac_only_policy,
+#if USE_TMMH
+  &tmmh_only_policy,
+#endif
+  &aes_only_policy,
+#if USE_TMMH
+  &aes_tmmh_policy,
+#endif
+  &default_policy,
+  &null_policy,
+  NULL
+};
+
+const srtp_policy_t wildcard_policy = {
+  { ssrc_any_outbound, 0 }, /* SSRC                        */
+  {                      /* SRTP policy                    */                  
+    AES_128_ICM,            /* cipher type                 */
+    30,                     /* cipher key length in octets */
+    HMAC_SHA1,              /* authentication func type    */
+    16,                     /* auth key length in octets   */
+    10,                     /* auth tag length in octets   */
+    sec_serv_conf_and_auth  /* security services flag      */
+  },
+  {                      /* SRTCP policy                   */
+    AES_128_ICM,            /* cipher type                 */
+    30,                     /* cipher key length in octets */
+    HMAC_SHA1,              /* authentication func type    */
+    16,                     /* auth key length in octets   */
+    10,                     /* auth tag length in octets   */
+    sec_serv_conf_and_auth  /* security services flag      */
+  },
+  test_key,
+  NULL
+};