* Adding support for pcap decryption
diff --git a/Makefile.in b/Makefile.in
index 9374ab7..7613e74 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -152,7 +152,7 @@
 
 $(testapp): libsrtp.a
 
-test/rtpw$(EXE): test/rtpw.c test/rtp.c test/getopt_s.c
+test/rtpw$(EXE): test/rtpw.c test/rtp.c test/rtp_decoder.c test/getopt_s.c
 	$(COMPILE) $(LDFLAGS) -o $@ $^ $(LIBS) $(SRTPLIB)
 
 test/srtp_driver$(EXE): test/srtp_driver.c test/getopt_s.c
diff --git a/configure b/configure
index 895e8cd..50a3f08 100755
--- a/configure
+++ b/configure
@@ -5032,6 +5032,64 @@
 
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_create in -lpcap" >&5
+$as_echo_n "checking for pcap_create in -lpcap... " >&6; }
+if ${ac_cv_lib_pcap_pcap_create+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpcap  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pcap_create ();
+int
+main ()
+{
+return pcap_create ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pcap_pcap_create=yes
+else
+  ac_cv_lib_pcap_pcap_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_create" >&5
+$as_echo "$ac_cv_lib_pcap_pcap_create" >&6; }
+if test "x$ac_cv_lib_pcap_pcap_create" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPCAP 1
+_ACEOF
+
+  LIBS="-lpcap $LIBS"
+
+fi
+
+for ac_header in pcap/pcap.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "pcap/pcap.h" "ac_cv_header_pcap_pcap_h" "$ac_includes_default"
+if test "x$ac_cv_header_pcap_pcap_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_PCAP_PCAP_H 1
+_ACEOF
+
+fi
+
+done
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use syslog for error reporting" >&5
 $as_echo_n "checking whether to use syslog for error reporting... " >&6; }
 # Check whether --enable-syslog was given.
diff --git a/configure.in b/configure.in
index acf445b..41f1f32 100644
--- a/configure.in
+++ b/configure.in
@@ -182,6 +182,10 @@
 AC_SUBST(RNG_EXTRA_OBJS)
 AC_SUBST(HMAC_OBJS)
 
+dnl Checking for PCAP
+AC_CHECK_LIB([pcap],[pcap_create])
+AC_CHECK_HEADERS([pcap/pcap.h])
+
 AC_MSG_CHECKING(whether to use syslog for error reporting)
 AC_ARG_ENABLE(syslog,
   [AS_HELP_STRING([--enable-syslog], [use syslog for error reporting])],
diff --git a/test/rtpw.c b/test/rtpw.c
index eb4b035..3777ebd 100644
--- a/test/rtpw.c
+++ b/test/rtpw.c
@@ -66,6 +66,10 @@
 #include <string.h>         /* for strncpy()       */
 #include <time.h>	    /* for usleep()        */
 
+#include <assert.h>         /* for assert() */
+
+#include <pcap.h>           /* for pcap functions and datatypes */
+
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>         /* for close()         */
 #endif
@@ -85,6 +89,7 @@
 
 #include "srtp.h"           
 #include "rtp.h"
+#include "rtp_decoder.h"
 
 #ifdef RTPW_USE_WINSOCK2
 # define DICT_FILE        "words.txt"
@@ -92,10 +97,10 @@
 # define DICT_FILE        "/usr/share/dict/words"
 #endif
 #define USEC_RATE        (5e5)
-#define MAX_WORD_LEN     128  
+#define MAX_WORD_LEN      128
 #define ADDR_IS_MULTICAST(a) IN_MULTICAST(htonl(a))
 #define MAX_KEY_LEN      96
-
+#define MAX_FILTER 256
 
 #ifndef HAVE_USLEEP
 # ifdef HAVE_WINDOWS_H
@@ -105,6 +110,13 @@
 # endif
 #endif
 
+unsigned char shiftb64(unsigned char c);
+
+void decode_block(char *in, unsigned char *out);
+/*
+ * decode base64 key
+ */
+char *decode_sdes(char *in, char *out);
 
 /*
  * the function usage() prints an error message describing how this
@@ -138,17 +150,20 @@
  * program_type distinguishes the [s]rtp sender and receiver cases
  */
 
-typedef enum { sender, receiver, unknown } program_type;
+typedef enum { sender, receiver, decoder, unknown } program_type;
 
 int
 main (int argc, char *argv[]) {
   char *dictfile = DICT_FILE;
   FILE *dict;
   char word[MAX_WORD_LEN];
-  int sock, ret;
+  int sock = 0, ret;
   struct in_addr rcvr_addr;
   struct sockaddr_in name;
   struct ip_mreq mreq;
+  char errbuf[PCAP_ERRBUF_SIZE];
+  bpf_u_int32 pcap_net = 0;
+  pcap_t *pcap_handle;
 #if BEW
   struct sockaddr_in local;
 #endif 
@@ -162,7 +177,10 @@
   char *input_key = NULL;
   char *address = NULL;
   char key[MAX_KEY_LEN];
+  struct bpf_program fp;
+  char filter_exp[MAX_FILTER] = "";
   unsigned short port = 0;
+  rtp_decoder_t dec;
   rtp_sender_t snd;
   srtp_policy_t policy;
   err_status_t status;
@@ -193,11 +211,16 @@
 
   /* check args */
   while (1) {
-    c = getopt_s(argc, argv, "k:rsgt:ae:ld:");
+    c = getopt_s(argc, argv, "b:k:rspgt:ae:ld:");
     if (c == -1) {
       break;
     }
     switch (c) {
+	case 'b':
+	  fprintf(stderr, "Decoding\n");
+		decode_sdes(optarg_s, input_key);
+		fprintf(stderr, "Decoded\n");
+		break;
     case 'k':
       input_key = optarg_s;
       break;
@@ -207,14 +230,16 @@
         printf("error: encryption key size must be 128 or 256 (%d)\n", key_size);
         exit(1);
       }
+      input_key = malloc(key_size);
       sec_servs |= sec_serv_conf;
       break;
     case 't':
       tag_size = atoi(optarg_s);
+      /*
       if (tag_size != 8 && tag_size != 16) {
         printf("error: GCM tag size must be 8 or 16 (%d)\n", tag_size);
         exit(1);
-      }
+      }*/
       break;
     case 'a':
       sec_servs |= sec_serv_auth;
@@ -229,6 +254,10 @@
     case 's':
       prog_type = sender;
       break;
+    case 'p':
+      prog_type = decoder;
+	  fprintf(stderr, "Choosing decoder\n");
+      break;
     case 'd':
       status = crypto_kernel_set_debug_module(optarg_s, 1);
       if (status) {
@@ -253,7 +282,7 @@
       }
       return 0;
     } else {
-      printf("error: neither sender [-s] nor receiver [-r] specified\n");
+      printf("error: neither sender [-s] receiver [-r] nor pcap decoder [-p] specified\n");
       usage(argv[0]);
     }
   }
@@ -263,86 +292,97 @@
      * a key must be provided if and only if security services have
      * been requested 
      */
+	  if(input_key == NULL){
+		  fprintf(stderr, "key not provided\n");
+	  }
+	  if(!sec_servs){
+		  fprintf(stderr, "no secservs\n");
+	  }
+    fprintf(stderr, "provided\n");
     usage(argv[0]);
   }
-    
-  if (argc != optind_s + 2) {
-    /* wrong number of arguments */
-    usage(argv[0]);
-  }
+   
+  if (prog_type == receiver || prog_type == sender) {
+	  if (argc != optind_s + 2) {
+	    /* wrong number of arguments */
+	    usage(argv[0]);
+	  }
 
-  /* get address from arg */
-  address = argv[optind_s++];
+  
+	  /* get address from arg */
+	  address = argv[optind_s++];
 
-  /* get port from arg */
-  port = atoi(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
+	  /* 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);
-  }
+	  /* 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);
+	  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);
-      }
-    }
+	  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);
-    }
-  }
+	    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: ");
+  fprintf(stderr, "security services: ");
   if (sec_servs & sec_serv_conf)
-    printf("confidentiality ");
+    fprintf(stderr, "confidentiality ");
   if (sec_servs & sec_serv_auth)
-    printf("message authentication");
+    fprintf(stderr, "message authentication");
   if (sec_servs == sec_serv_none)
-    printf("none");
-  printf("\n");
+    fprintf(stderr, "none");
+  fprintf(stderr, "\n");
   
   /* set up the srtp policy and master key */    
   if (sec_servs) {
@@ -425,17 +465,19 @@
       printf("error: unknown security service requested\n");
       return -1;
     } 
-    policy.ssrc.type  = ssrc_specific;
-    policy.ssrc.value = ssrc;
+
     policy.key  = (uint8_t *) key;
     policy.ekt  = NULL;
     policy.next = NULL;
     policy.window_size = 128;
     policy.allow_repeat_tx = 0;
     policy.rtp.sec_serv = sec_servs;
-    policy.rtcp.sec_serv = sec_serv_none;  /* we don't do RTCP anyway */
-
+    policy.rtcp.sec_serv = sec_servs; //sec_serv_none;  /* we don't do RTCP anyway */
+      fprintf(stderr, "setting tag len %d\n", tag_size);
+policy.rtp.auth_tag_len = tag_size;
+  
     if (gcm_on && tag_size != 8) {
+      fprintf(stderr, "setted tag len %d\n", tag_size);
 	policy.rtp.auth_tag_len = tag_size;
     }
 
@@ -460,8 +502,8 @@
       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));
+    fprintf(stderr, "set master key/salt to %s/", octet_string_hex_string(key, 16));
+    fprintf(stderr, "%s\n", octet_string_hex_string(key+16, 14));
   
   } else {
     /*
@@ -551,7 +593,7 @@
     rtp_sender_dealloc(snd);
 
     fclose(dict);
-  } else  { /* prog_type == receiver */
+  } else if (prog_type == receiver) {
     rtp_receiver_t rcvr;
         
     if (bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0) {
@@ -582,27 +624,59 @@
     while (!interrupted) {
       len = MAX_WORD_LEN;
       if (rtp_recvfrom(rcvr, word, &len) > -1)
-	printf("\tword: %s\n", word);
+	       printf("\tword: %s\n", word);
     }
-      
     rtp_receiver_deinit_srtp(rcvr);
     rtp_receiver_dealloc(rcvr);
-  } 
 
-  if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
-    leave_group(sock, mreq, argv[0]);
+  } else if(prog_type == decoder){
+    pcap_handle = pcap_open_offline("-", errbuf);
+
+    if (!pcap_handle) {
+        fprintf(stderr, "libpcap failed to open file '%s'\n", errbuf);
+        exit(1);
+    }
+    assert(pcap_handle != NULL);
+    if ((pcap_compile(pcap_handle, &fp, filter_exp, 1, pcap_net)) == -1){
+        fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp,
+            pcap_geterr(pcap_handle));
+        return (2);
+    }
+    if (pcap_setfilter(pcap_handle, &fp) == -1){
+      fprintf(stderr, "couldn't install filter %s: %s\n", filter_exp,
+          pcap_geterr(pcap_handle));
+      return (2);
+    }
+    dec = rtp_decoder_alloc();
+    if (dec == NULL) {
+      fprintf(stderr, "error: malloc() failed\n");
+      exit(1);
+    }
+    fprintf(stderr, "Starting decoder\n");
+    rtp_decoder_init(dec, policy);
+
+    pcap_loop(pcap_handle, 0, rtp_decoder_handle_pkt, (u_char *)dec);
+
+    rtp_decoder_deinit_srtp(dec);
+    rtp_decoder_dealloc(dec);
   }
 
+  if (prog_type == receiver || prog_type == sender) {
+	  if (ADDR_IS_MULTICAST(rcvr_addr.s_addr)) {
+	    leave_group(sock, mreq, argv[0]);
+	  }
+
 #ifdef RTPW_USE_WINSOCK2
-  ret = closesocket(sock);
+  	  ret = closesocket(sock);
 #else
-  ret = close(sock);
+ 	  ret = close(sock);
 #endif
-  if (ret < 0) {
-    fprintf(stderr, "%s: Failed to close socket", argv[0]);
-    perror("");
-  }
+      if (ret < 0) {
+         fprintf(stderr, "%s: Failed to close socket", argv[0]);
+         perror("");
+      }
 
+	}
   status = srtp_shutdown();
   if (status) {
     printf("error: srtp shutdown failed with error code %d\n", status);
@@ -621,7 +695,7 @@
 usage(char *string) {
 
   printf("usage: %s [-d <debug>]* [-k <key> [-a][-e]] "
-	 "[-s | -r] dest_ip dest_port\n"
+	 "[-s | -r | -p] [dest_ip dest_port]\n"
 	 "or     %s -l\n"
 	 "where  -a use message authentication\n"
 	 "       -e <key size> use encryption (use 128 or 256 for key size)\n"
@@ -630,6 +704,7 @@
 	 "       -k <key>  sets the srtp master key\n"
 	 "       -s act as rtp sender\n"
 	 "       -r act as rtp receiver\n"
+	 "       -p act as pcap file decrypter\n"
 	 "       -l list debug modules\n"
 	 "       -d <debug> turn on debugging for module <debug>\n",
 	 string, string);
@@ -688,3 +763,39 @@
 #endif
   return 0;
 }
+
+static const char b64chars[] =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+unsigned char shiftb64(unsigned char c) {
+  char *p = strchr(b64chars, c);
+  assert(p);
+  return p-b64chars;
+}
+
+void decode_block(char *in, unsigned char *out) {
+  unsigned char shifts[4];
+  int i;
+
+  for (i = 0; i < 4; i++) {
+    shifts[i] = shiftb64(in[i]);
+  }
+
+  out[0] = (shifts[0]<<2)|(shifts[1]>>4);
+  out[1] = (shifts[1]<<4)|(shifts[2]>>2);
+  out[2] = (shifts[2]<<6)|shifts[3];
+}
+
+char *decode_sdes(char *in, char *out) {
+  int i;
+  size_t len = strlen((char *) in);
+  assert(len == 40);
+  unsigned char raw[30];
+
+  for (i = 0; 4*i < len; i++) {
+    decode_block(in+4*i, raw+3*i);
+  } 
+
+  memcpy(out, octet_string_hex_string(raw, 30), 60);
+  return out;
+}