Closed bernardotorres closed 9 years ago
It's not 100% clear what you're proposing. Are you looking to add an option to rtpw that dumps the decrypted data to a pcap file? It doesn't appear all the required code was provided. If you have a contribution, it's probably best to fork libsrtp, apply your changes to your fork, test, and then submit a pull request.
Actually is extract rtp data from a pcap file and decrypt it. But yeah, I guess it's better to fork with a proposed code.
Closing this issue for now. Please submit a pull request when the code is ready.
A good test would be allowing to capture on the wire or offline a SRTP stream.
I have derived code from https://github.com/gteissier/srtp-decrypt (which caused me a few headaches because it didn't work in all cases) and joined it with rtpw test code to make it possible.
There is room for improvement, if you have any particular request or opinion, please express so I can improve the code for it to be approved.
Thanks for libsrtp, btw.
Makefile: CFLAGS=-g -Os -Wall
all: $(CC) -g decrypt-srtp.c -o decrypt-srtp -I /usr/local/include/srtp/ -l pcap -lgcrypt -lsrtp check: ./decrypt-srtp -k aSBrbm93IGFsbCB5b3VyIGxpdHRsZSBzZWNyZXRz < ./marseillaise-srtp.pcap | text2pcap -t "%M:%S." -u 10000,10000 - - > ./marseillaise-rtp.pcap
The code is below:
include <sys/types.h>
include
include
include
include
include
include <arpa/inet.h>
include
include
include "rtp.h"
include "rtp_priv.h"
include "srtp.h"
include
define PRINT_DEBUG 1
define VERBOSE_DEBUG 1
define DICT_FILE "/usr/share/dict/words"
define USEC_RATE (5e5)
define MAX_WORD_LEN 128
define ADDR_IS_MULTICAST(a) IN_MULTICAST(htonl(a))
define MAX_KEY_LEN 96
srtp_t srtp_ctx = NULL;
rtp_msg_t message;
/*
include
define MTU 2048
static const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static unsigned char shiftb64(unsigned char c) { char *p = strchr(b64chars, c); assert(p); return p-b64chars; }
static void decode_block(unsigned 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 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; }
void usage(char *string) {
printf("usage: %s [-d]* [-k [-a][-e]]\n"
"or %s -l\n"
"where -a use message authentication\n"
" -e use encryption (use 128 or 256 for key size)\n"
" -g Use AES-GCM mode (must be used with -e)\n"
" -k sets the srtp master key\n"
" -l list debug modules\n"
" -d turn on debugging for module \n",
string, string);
exit(1);
}
static void decode_sdes(unsigned char in, unsigned char key) { 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(key, octet_string_hex_string(raw, 30), 60); }
static void hexdump(const void ptr, size_t size) { int i, j; const unsigned char cptr = ptr;
for (i = 0; i < size; i += 16) { printf("%04x ", i); for (j = 0; j < 16 && i+j < size; j++) { printf("%02x ", cptr[i+j]); } printf("\n"); } }
static int rtp_offset = 42; /* 14 + 20 + 8 */; static int frame_nr = -1; static struct timeval start_tv = {0, 0};
static void handle_pkt(u_char arg, const struct pcap_pkthdr hdr, const u_char bytes) { int pktsize; struct timeval delta; int octets_recvd; err_status_t stat; int len = NULL; void *msg = NULL; frame_nr += 1; if (start_tv.tv_sec == 0 && start_tv.tv_sec == 0) { start_tv = hdr->ts; }
if (hdr->caplen < rtp_offset) { fprintf(stderr, "frame %d dropped: too short\n", frame_nr); return; } void *rtp_packet = bytes + rtp_offset;
//memcpy(buffer, bytes + rtp_offset, hdr->caplen - rtpoffset); memcpy((void )&message, rtp_packet, hdr->caplen - rtpoffset); / message.header.seq = htons(message.header.seq); message.header.ssrc = htonl(message.header.ssrc); message.header.ts = htonl(message.header.ts); */ pktsize = hdr->caplen - rtp_offset; octets_recvd = pktsize;
if (octets_recvd == -1) { printf("octects less than 1.\n"); //*len = 0; //return -1; return; }
/* verify rtp header _/ if (message.header.version != 2) { printf("rtp version is not 2.\n"); //_len = 0; return; //return -1; }
if PRINT_DEBUG
// printf("%d octets received from SSRC %u\n", // octets_recvd, message.header.ssrc);
endif
if VERBOSE_DEBUG
//printf("PACKET: %s\n", ); // hexdump(bytes + rtp_offset, octets_recvd); // printf(srtp_packet_to_string(&message.header, octets_recvd));
endif
/* apply srtp */ stat = srtp_unprotect(srtp_ctx, &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_bad_param ? " (bad param)" : stat == err_status_no_ctx ? " (no context)" : stat == err_status_cipher_fail ? " (cipher failed)" : stat == err_status_key_expired ? " (key expired)" : stat == err_status_auth_fail ? " (auth check failed)" : ""); //return -1; return; } //strncpy(msg, rtp_packet, octets_recvd);
//printf(srtp_packet_to_string(&message.header, octets_recvd)); timersub(&hdr->ts, &start_tv, &delta); printf("%02ld:%02ld.%06lu\n", delta.tv_sec/60, delta.tv_sec%60, delta.tv_usec); hexdump(&message.header, pktsize); }
int main(int argc, char *argv) { int c; char errbuf[PCAP_ERRBUF_SIZE]; pcap_t pcap;
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; struct sockaddr_in local; sec_serv_t sec_servs = sec_serv_none; unsigned char ttl = 5; int key_size = 128; int gcm_on = 0; char input_key = malloc(MAX_KEY_LEN); char address = NULL; char key[MAX_KEY_LEN]; unsigned short port = 0; rtp_sender_t snd; srtp_policy_t policy; // const struct srtp_policy_t policy; err_status_t status; int len; int do_list_mods = 0; uint32t ssrc = 0xdeadbeef; / ssrc value hardcoded for now /
status = srtp_init();
/* check args / while (1) { c = getopt(argc, argv, "b:k:rsae:ld:"); if (c == -1) { break; } switch (c) { case 'b': //input_key = (unsigned char ) optarg; decode_sdes(optarg, input_key); break; case 'k': input_key = (unsigned char *) optarg; break; case 'e': key_size = atoi(optarg); if (key_size != 128 && key_size != 256) { printf("error: encryption key size must be 128 or 256 (%d)\n", key_size); exit(1); } sec_servs |= sec_serv_conf; break; case 'a': sec_servs |= sec_serv_auth; break; case 'd': status = crypto_kernel_set_debug_module(optarg, 1); if (status) { printf("error: set debug module (%s) failed\n", optarg); exit(1); } break; case 'l': do_list_mods = 1; break; default: 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); } return 0; } if ((sec_servs && !input_key) || (!sec_servs && input_key)) { /* * a key must be provided if and only if security services have * been requested */ fprintf(stderr, "Key was not provided!\n"); usage(argv[0]); }
/* 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 (secservs) { / * 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: if (gcm_on) {
ifdef OPENSSL
else
endif
ifdef OPENSSL
else
endif
/* 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; /
}