| Index: srtp/test/rtp_decoder.c
|
| diff --git a/srtp/test/rtp_decoder.c b/srtp/test/rtp_decoder.c
|
| deleted file mode 100644
|
| index 5f6f2e4f10d3c98783e63039b60993b446173c93..0000000000000000000000000000000000000000
|
| --- a/srtp/test/rtp_decoder.c
|
| +++ /dev/null
|
| @@ -1,516 +0,0 @@
|
| -/*
|
| - * rtp_decoder.c
|
| - *
|
| - * decoder structures and functions for SRTP pcap decoder
|
| - *
|
| - * Example:
|
| - * $ wget --no-check-certificate https://raw.githubusercontent.com/gteissier/srtp-decrypt/master/marseillaise-srtp.pcap
|
| - * $ ./test/rtp_decoder -a -t 0 -e 128 -b aSBrbm93IGFsbCB5b3VyIGxpdHRsZSBzZWNyZXRz \
|
| - * < ~/marseillaise-srtp.pcap | text2pcap -t "%M:%S." -u 10000,10000 - - > ./marseillaise-rtp.pcap
|
| - *
|
| - * Bernardo Torres <bernardo@torresautomacao.com.br>
|
| - *
|
| - * Some structure and code from https://github.com/gteissier/srtp-decrypt
|
| - */
|
| -/*
|
| - *
|
| - * 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 "getopt_s.h" /* for local getopt() */
|
| -#include <assert.h> /* for assert() */
|
| -
|
| -#include <pcap.h>
|
| -#include "rtp_decoder.h"
|
| -
|
| -#define MAX_KEY_LEN 96
|
| -#define MAX_FILTER 256
|
| -
|
| -int
|
| -main (int argc, char *argv[]) {
|
| - char errbuf[PCAP_ERRBUF_SIZE];
|
| - bpf_u_int32 pcap_net = 0;
|
| - pcap_t *pcap_handle;
|
| -#if BEW
|
| - struct sockaddr_in local;
|
| -#endif
|
| - sec_serv_t sec_servs = sec_serv_none;
|
| - int c;
|
| - int key_size = 128;
|
| - int tag_size = 8;
|
| - int gcm_on = 0;
|
| - char *input_key = NULL;
|
| - int b64_input = 0;
|
| - char key[MAX_KEY_LEN];
|
| - struct bpf_program fp;
|
| - char filter_exp[MAX_FILTER] = "";
|
| - rtp_decoder_t dec;
|
| - srtp_policy_t policy;
|
| - err_status_t status;
|
| - int len;
|
| - int expected_len;
|
| - int do_list_mods = 0;
|
| -
|
| - fprintf(stderr, "Using %s [0x%x]\n", srtp_get_version_string(), srtp_get_version());
|
| -
|
| - /* initialize srtp library */
|
| - status = srtp_init();
|
| - if (status) {
|
| - fprintf(stderr, "error: srtp initialization failed with error code %d\n", status);
|
| - exit(1);
|
| - }
|
| -
|
| - /* check args */
|
| - while (1) {
|
| - c = getopt_s(argc, argv, "b:k:gt:ae:ld:f:");
|
| - if (c == -1) {
|
| - break;
|
| - }
|
| - switch (c) {
|
| - case 'b':
|
| - b64_input = 1;
|
| - /* fall thru */
|
| - case 'k':
|
| - input_key = optarg_s;
|
| - break;
|
| - case 'e':
|
| - key_size = atoi(optarg_s);
|
| - if (key_size != 128 && key_size != 256) {
|
| - fprintf(stderr, "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) {
|
| - fprintf(stderr, "error: GCM tag size must be 8 or 16 (%d)\n", tag_size);
|
| - //exit(1);
|
| - }
|
| - break;
|
| - case 'a':
|
| - sec_servs |= sec_serv_auth;
|
| - break;
|
| - case 'g':
|
| - gcm_on = 1;
|
| - sec_servs |= sec_serv_auth;
|
| - break;
|
| - case 'd':
|
| - status = crypto_kernel_set_debug_module(optarg_s, 1);
|
| - if (status) {
|
| - fprintf(stderr, "error: set debug module (%s) failed\n", optarg_s);
|
| - exit(1);
|
| - }
|
| - break;
|
| - case 'f':
|
| - if(strlen(optarg_s) > MAX_FILTER){
|
| - fprintf(stderr, "error: filter bigger than %d characters\n", MAX_FILTER);
|
| - exit(1);
|
| - }
|
| - fprintf(stderr, "Setting filter as %s\n", optarg_s);
|
| - strcpy(filter_exp, optarg_s);
|
| - break;
|
| - case 'l':
|
| - do_list_mods = 1;
|
| - break;
|
| - default:
|
| - usage(argv[0]);
|
| - }
|
| - }
|
| -
|
| - if (do_list_mods) {
|
| - status = crypto_kernel_list_debug_modules();
|
| - if (status) {
|
| - fprintf(stderr, "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
|
| - */
|
| - 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]);
|
| - }
|
| -
|
| -
|
| -
|
| - /* report security services selected on the command line */
|
| - fprintf(stderr, "security services: ");
|
| - if (sec_servs & sec_serv_conf)
|
| - fprintf(stderr, "confidentiality ");
|
| - if (sec_servs & sec_serv_auth)
|
| - fprintf(stderr, "message authentication");
|
| - if (sec_servs == sec_serv_none)
|
| - fprintf(stderr, "none");
|
| - fprintf(stderr, "\n");
|
| -
|
| - /* set up the srtp policy and master key */
|
| - memset(&policy, 0, sizeof(policy));
|
| - 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:
|
| - if (gcm_on) {
|
| -#ifdef OPENSSL
|
| - switch (key_size) {
|
| - case 128:
|
| - crypto_policy_set_aes_gcm_128_8_auth(&policy.rtp);
|
| - crypto_policy_set_aes_gcm_128_8_auth(&policy.rtcp);
|
| - break;
|
| - case 256:
|
| - crypto_policy_set_aes_gcm_256_8_auth(&policy.rtp);
|
| - crypto_policy_set_aes_gcm_256_8_auth(&policy.rtcp);
|
| - break;
|
| - }
|
| -#else
|
| - fprintf(stderr, "error: GCM mode only supported when using the OpenSSL crypto engine.\n");
|
| - return 0;
|
| -#endif
|
| - } else {
|
| - switch (key_size) {
|
| - case 128:
|
| - crypto_policy_set_rtp_default(&policy.rtp);
|
| - crypto_policy_set_rtcp_default(&policy.rtcp);
|
| - break;
|
| - case 256:
|
| - crypto_policy_set_aes_cm_256_hmac_sha1_80(&policy.rtp);
|
| - crypto_policy_set_rtcp_default(&policy.rtcp);
|
| - break;
|
| - }
|
| - }
|
| - break;
|
| - case sec_serv_conf:
|
| - if (gcm_on) {
|
| - fprintf(stderr, "error: GCM mode must always be used with auth enabled\n");
|
| - return -1;
|
| - } else {
|
| - switch (key_size) {
|
| - case 128:
|
| - crypto_policy_set_aes_cm_128_null_auth(&policy.rtp);
|
| - crypto_policy_set_rtcp_default(&policy.rtcp);
|
| - break;
|
| - case 256:
|
| - crypto_policy_set_aes_cm_256_null_auth(&policy.rtp);
|
| - crypto_policy_set_rtcp_default(&policy.rtcp);
|
| - break;
|
| - }
|
| - }
|
| - break;
|
| - case sec_serv_auth:
|
| - if (gcm_on) {
|
| -#ifdef OPENSSL
|
| - switch (key_size) {
|
| - case 128:
|
| - crypto_policy_set_aes_gcm_128_8_only_auth(&policy.rtp);
|
| - crypto_policy_set_aes_gcm_128_8_only_auth(&policy.rtcp);
|
| - break;
|
| - case 256:
|
| - crypto_policy_set_aes_gcm_256_8_only_auth(&policy.rtp);
|
| - crypto_policy_set_aes_gcm_256_8_only_auth(&policy.rtcp);
|
| - break;
|
| - }
|
| -#else
|
| - printf("error: GCM mode only supported when using the OpenSSL crypto engine.\n");
|
| - return 0;
|
| -#endif
|
| - } else {
|
| - crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp);
|
| - crypto_policy_set_rtcp_default(&policy.rtcp);
|
| - }
|
| - break;
|
| - default:
|
| - fprintf(stderr, "error: unknown security service requested\n");
|
| - return -1;
|
| - }
|
| -
|
| - 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_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;
|
| - }
|
| -
|
| - /*
|
| - * read key from hexadecimal or base64 on command line into an octet string
|
| - */
|
| - if (b64_input) {
|
| - int pad;
|
| - expected_len = policy.rtp.cipher_key_len*4/3;
|
| - len = base64_string_to_octet_string(key, &pad, input_key, expected_len);
|
| - if (pad != 0) {
|
| - fprintf(stderr, "error: padding in base64 unexpected\n");
|
| - exit(1);
|
| - }
|
| - } else {
|
| - expected_len = policy.rtp.cipher_key_len*2;
|
| - len = hex_string_to_octet_string(key, input_key, expected_len);
|
| - }
|
| - /* check that hex string is the right length */
|
| - if (len < expected_len) {
|
| - fprintf(stderr,
|
| - "error: too few digits in key/salt "
|
| - "(should be %d digits, found %d)\n",
|
| - expected_len, len);
|
| - exit(1);
|
| - }
|
| - if (strlen(input_key) > policy.rtp.cipher_key_len*2) {
|
| - fprintf(stderr,
|
| - "error: too many digits in key/salt "
|
| - "(should be %d hexadecimal digits, found %u)\n",
|
| - policy.rtp.cipher_key_len*2, (unsigned)strlen(input_key));
|
| - exit(1);
|
| - }
|
| -
|
| - 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 {
|
| - /*
|
| - * 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.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.window_size = 0;
|
| - policy.allow_repeat_tx = 0;
|
| - policy.ekt = NULL;
|
| - policy.next = NULL;
|
| - }
|
| -
|
| - 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);
|
| -
|
| - status = srtp_shutdown();
|
| - if (status) {
|
| - fprintf(stderr, "error: srtp shutdown failed with error code %d\n", status);
|
| - exit(1);
|
| - }
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -
|
| -void
|
| -usage(char *string) {
|
| -
|
| - fprintf(stderr, "usage: %s [-d <debug>]* [[-k][-b] <key> [-a][-e]]\n"
|
| - "or %s -l\n"
|
| - "where -a use message authentication\n"
|
| - " -e <key size> use encryption (use 128 or 256 for key size)\n"
|
| - " -g Use AES-GCM mode (must be used with -e)\n"
|
| - " -t <tag size> Tag size to use in GCM mode (use 8 or 16)\n"
|
| - " -k <key> sets the srtp master key given in hexadecimal\n"
|
| - " -b <key> sets the srtp master key given in base64\n"
|
| - " -l list debug modules\n"
|
| - " -f \"<pcap filter>\" to filter only the desired SRTP packets\n"
|
| - " -d <debug> turn on debugging for module <debug>\n",
|
| - string, string);
|
| - exit(1);
|
| -
|
| -}
|
| -
|
| -rtp_decoder_t
|
| -rtp_decoder_alloc(void) {
|
| - return (rtp_decoder_t)malloc(sizeof(rtp_decoder_ctx_t));
|
| -}
|
| -
|
| -void
|
| -rtp_decoder_dealloc(rtp_decoder_t rtp_ctx) {
|
| - free(rtp_ctx);
|
| -}
|
| -
|
| -err_status_t
|
| -rtp_decoder_init_srtp(rtp_decoder_t decoder, unsigned int ssrc) {
|
| - decoder->policy.ssrc.value = htonl(ssrc);
|
| - return srtp_create(&decoder->srtp_ctx, &decoder->policy);
|
| -}
|
| -
|
| -int
|
| -rtp_decoder_deinit_srtp(rtp_decoder_t decoder) {
|
| - return srtp_dealloc(decoder->srtp_ctx);
|
| -}
|
| -
|
| -int
|
| -rtp_decoder_init(rtp_decoder_t dcdr, srtp_policy_t policy){
|
| - dcdr->rtp_offset = DEFAULT_RTP_OFFSET;
|
| - dcdr->srtp_ctx = NULL;
|
| - dcdr->start_tv.tv_usec = 0;
|
| - dcdr->start_tv.tv_sec = 0;
|
| - dcdr->frame_nr = -1;
|
| - dcdr->policy = policy;
|
| - dcdr->policy.ssrc.type = ssrc_specific;
|
| - return 0;
|
| -}
|
| -
|
| -/*
|
| - * decodes key as base64
|
| - */
|
| -
|
| -void hexdump(const void *ptr, size_t size) {
|
| - int i, j;
|
| - const unsigned char *cptr = ptr;
|
| -
|
| - for (i = 0; i < size; i += 16) {
|
| - fprintf(stdout, "%04x ", i);
|
| - for (j = 0; j < 16 && i+j < size; j++) {
|
| - fprintf(stdout, "%02x ", cptr[i+j]);
|
| - }
|
| - fprintf(stdout, "\n");
|
| - }
|
| -}
|
| -
|
| -void
|
| -rtp_decoder_handle_pkt(u_char *arg, const struct pcap_pkthdr *hdr,
|
| - const u_char *bytes){
|
| - rtp_decoder_t dcdr = (rtp_decoder_t)arg;
|
| - int pktsize;
|
| - struct timeval delta;
|
| - int octets_recvd;
|
| - err_status_t status;
|
| - dcdr->frame_nr++;
|
| -
|
| - if (dcdr->start_tv.tv_sec == 0 && dcdr->start_tv.tv_sec == 0) {
|
| - dcdr->start_tv = hdr->ts;
|
| - }
|
| -
|
| - if (hdr->caplen < dcdr->rtp_offset) {
|
| - return;
|
| - }
|
| - const void *rtp_packet = bytes + dcdr->rtp_offset;
|
| -
|
| - memcpy((void *)&dcdr->message, rtp_packet, hdr->caplen - dcdr->rtp_offset);
|
| - pktsize = hdr->caplen - dcdr->rtp_offset;
|
| - octets_recvd = pktsize;
|
| -
|
| - if (octets_recvd == -1) {
|
| - return;
|
| - }
|
| -
|
| - /* verify rtp header */
|
| - if (dcdr->message.header.version != 2) {
|
| - return; //return -1;
|
| - }
|
| - if(dcdr->srtp_ctx == NULL){
|
| - status = rtp_decoder_init_srtp(dcdr, dcdr->message.header.ssrc);
|
| - if (status) {
|
| - exit(1);
|
| - }
|
| - }
|
| - if(dcdr->srtp_ctx != NULL){
|
| - }
|
| - status = srtp_unprotect(dcdr->srtp_ctx, &dcdr->message, &octets_recvd);
|
| - if (status){
|
| - return;
|
| - }
|
| - timersub(&hdr->ts, &dcdr->start_tv, &delta);
|
| - fprintf(stdout, "%02ld:%02ld.%06lu\n", delta.tv_sec/60, delta.tv_sec%60, delta.tv_usec);
|
| - hexdump(&dcdr->message, pktsize);
|
| -}
|
| -
|
| -void rtp_print_error(err_status_t status, char *message){
|
| - fprintf(stderr,
|
| - "error: %s %d%s\n", message, status,
|
| - status == err_status_replay_fail ? " (replay check failed)" :
|
| - status == err_status_bad_param ? " (bad param)" :
|
| - status == err_status_no_ctx ? " (no context)" :
|
| - status == err_status_cipher_fail ? " (cipher failed)" :
|
| - status == err_status_key_expired ? " (key expired)" :
|
| - status == err_status_auth_fail ? " (auth check failed)" : "");
|
| -}
|
|
|