* 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;
+}