1 /*
2  * rtp_decoder.c
3  *
4  * decoder structures and functions for SRTP pcap decoder
5  *
6  * Example:
7  * $ wget --no-check-certificate \
8  *     https://raw.githubusercontent.com/gteissier/srtp-decrypt/master/marseillaise-srtp.pcap
9  * $ ./test/rtp_decoder -a -t 10 -e 128 -b \
10  *     aSBrbm93IGFsbCB5b3VyIGxpdHRsZSBzZWNyZXRz \
11  *         < ~/marseillaise-srtp.pcap \
12  *         | text2pcap -t "%M:%S." -u 10000,10000 - - \
13  *         > ./marseillaise-rtp.pcap
14  *
15  * There is also a different way of setting up key size and tag size
16  * based upon RFC 4568 crypto suite specification, i.e.:
17  *
18  * $ ./test/rtp_decoder -s AES_CM_128_HMAC_SHA1_80 -b \
19  *     aSBrbm93IGFsbCB5b3VyIGxpdHRsZSBzZWNyZXRz ...
20  *
21  * Audio can be extracted using extractaudio utility from the RTPproxy
22  * package:
23  *
24  * $ extractaudio -A ./marseillaise-rtp.pcap ./marseillaise-out.wav
25  *
26  * Bernardo Torres <bernardo@torresautomacao.com.br>
27  *
28  * Some structure and code from https://github.com/gteissier/srtp-decrypt
29  */
30 /*
31  *
32  * Copyright (c) 2001-2017 Cisco Systems, Inc.
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  *
39  *   Redistributions of source code must retain the above copyright
40  *   notice, this list of conditions and the following disclaimer.
41  *
42  *   Redistributions in binary form must reproduce the above
43  *   copyright notice, this list of conditions and the following
44  *   disclaimer in the documentation and/or other materials provided
45  *   with the distribution.
46  *
47  *   Neither the name of the Cisco Systems, Inc. nor the names of its
48  *   contributors may be used to endorse or promote products derived
49  *   from this software without specific prior written permission.
50  *
51  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
52  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
53  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
54  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
55  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
56  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
57  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
58  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
60  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
61  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
62  * OF THE POSSIBILITY OF SUCH DAMAGE.
63  *
64  */
65 #include "getopt_s.h" /* for local getopt()  */
66 #include <assert.h>   /* for assert()  */
67 
68 #include <pcap.h>
69 #include "rtp_decoder.h"
70 #include "util.h"
71 
72 #ifndef timersub
73 #define timersub(a, b, result)                                                 \
74     do {                                                                       \
75         (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                          \
76         (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                       \
77         if ((result)->tv_usec < 0) {                                           \
78             --(result)->tv_sec;                                                \
79             (result)->tv_usec += 1000000;                                      \
80         }                                                                      \
81     } while (0)
82 #endif
83 
84 #define MAX_KEY_LEN 96
85 #define MAX_FILTER 256
86 
87 struct srtp_crypto_suite {
88     const char *can_name;
89     int gcm_on;
90     int key_size;
91     int tag_size;
92 };
93 
94 static struct srtp_crypto_suite srtp_crypto_suites[] = {
95 #if 0
96   {.can_name = "F8_128_HMAC_SHA1_32", .gcm_on = 0, .key_size = 128, .tag_size = 4},
97 #endif
98     {.can_name = "AES_CM_128_HMAC_SHA1_32",
99      .gcm_on = 0,
100      .key_size = 128,
101      .tag_size = 4 },
102     {.can_name = "AES_CM_128_HMAC_SHA1_80",
103      .gcm_on = 0,
104      .key_size = 128,
105      .tag_size = 10 },
106     {.can_name = "AES_192_CM_HMAC_SHA1_32",
107      .gcm_on = 0,
108      .key_size = 192,
109      .tag_size = 4 },
110     {.can_name = "AES_192_CM_HMAC_SHA1_80",
111      .gcm_on = 0,
112      .key_size = 192,
113      .tag_size = 10 },
114     {.can_name = "AES_256_CM_HMAC_SHA1_32",
115      .gcm_on = 0,
116      .key_size = 256,
117      .tag_size = 4 },
118     {.can_name = "AES_256_CM_HMAC_SHA1_80",
119      .gcm_on = 0,
120      .key_size = 256,
121      .tag_size = 10 },
122     {.can_name = "AEAD_AES_128_GCM",
123      .gcm_on = 1,
124      .key_size = 128,
125      .tag_size = 16 },
126     {.can_name = "AEAD_AES_256_GCM",
127      .gcm_on = 1,
128      .key_size = 256,
129      .tag_size = 16 },
130     {.can_name = NULL }
131 };
132 
rtp_decoder_srtp_log_handler(srtp_log_level_t level,const char * msg,void * data)133 void rtp_decoder_srtp_log_handler(srtp_log_level_t level,
134                                   const char *msg,
135                                   void *data)
136 {
137     char level_char = '?';
138     switch (level) {
139     case srtp_log_level_error:
140         level_char = 'e';
141         break;
142     case srtp_log_level_warning:
143         level_char = 'w';
144         break;
145     case srtp_log_level_info:
146         level_char = 'i';
147         break;
148     case srtp_log_level_debug:
149         level_char = 'd';
150         break;
151     }
152     fprintf(stderr, "SRTP-LOG [%c]: %s\n", level_char, msg);
153 }
154 
main(int argc,char * argv[])155 int main(int argc, char *argv[])
156 {
157     char errbuf[PCAP_ERRBUF_SIZE];
158     bpf_u_int32 pcap_net = 0;
159     pcap_t *pcap_handle;
160 #if BEW
161     struct sockaddr_in local;
162 #endif
163     srtp_sec_serv_t sec_servs = sec_serv_none;
164     int c;
165     struct srtp_crypto_suite scs, *i_scsp;
166     scs.key_size = 128;
167     scs.tag_size = 0;
168     int gcm_on = 0;
169     char *input_key = NULL;
170     int b64_input = 0;
171     char key[MAX_KEY_LEN];
172     struct bpf_program fp;
173     char filter_exp[MAX_FILTER] = "";
174     rtp_decoder_t dec;
175     srtp_policy_t policy = { { 0 } };
176     rtp_decoder_mode_t mode = mode_rtp;
177     srtp_err_status_t status;
178     int len;
179     int expected_len;
180     int do_list_mods = 0;
181 
182     fprintf(stderr, "Using %s [0x%x]\n", srtp_get_version_string(),
183             srtp_get_version());
184 
185     /* initialize srtp library */
186     status = srtp_init();
187     if (status) {
188         fprintf(stderr,
189                 "error: srtp initialization failed with error code %d\n",
190                 status);
191         exit(1);
192     }
193 
194     status = srtp_install_log_handler(rtp_decoder_srtp_log_handler, NULL);
195     if (status) {
196         fprintf(stderr, "error: install log handler failed\n");
197         exit(1);
198     }
199 
200     /* check args */
201     while (1) {
202         c = getopt_s(argc, argv, "b:k:gt:ae:ld:f:s:m:");
203         if (c == -1) {
204             break;
205         }
206         switch (c) {
207         case 'b':
208             b64_input = 1;
209         /* fall thru */
210         case 'k':
211             input_key = optarg_s;
212             break;
213         case 'e':
214             scs.key_size = atoi(optarg_s);
215             if (scs.key_size != 128 && scs.key_size != 192 &&
216                 scs.key_size != 256) {
217                 fprintf(
218                     stderr,
219                     "error: encryption key size must be 128, 192 or 256 (%d)\n",
220                     scs.key_size);
221                 exit(1);
222             }
223             input_key = malloc(scs.key_size);
224             sec_servs |= sec_serv_conf;
225             break;
226         case 't':
227             scs.tag_size = atoi(optarg_s);
228             break;
229         case 'a':
230             sec_servs |= sec_serv_auth;
231             break;
232         case 'g':
233             gcm_on = 1;
234             sec_servs |= sec_serv_auth;
235             break;
236         case 'd':
237             status = srtp_set_debug_module(optarg_s, 1);
238             if (status) {
239                 fprintf(stderr, "error: set debug module (%s) failed\n",
240                         optarg_s);
241                 exit(1);
242             }
243             break;
244         case 'f':
245             if (strlen(optarg_s) > MAX_FILTER) {
246                 fprintf(stderr, "error: filter bigger than %d characters\n",
247                         MAX_FILTER);
248                 exit(1);
249             }
250             fprintf(stderr, "Setting filter as %s\n", optarg_s);
251             strcpy(filter_exp, optarg_s);
252             break;
253         case 'l':
254             do_list_mods = 1;
255             break;
256         case 's':
257             for (i_scsp = &srtp_crypto_suites[0]; i_scsp->can_name != NULL;
258                  i_scsp++) {
259                 if (strcasecmp(i_scsp->can_name, optarg_s) == 0) {
260                     break;
261                 }
262             }
263             if (i_scsp->can_name == NULL) {
264                 fprintf(stderr, "Unknown/unsupported crypto suite name %s\n",
265                         optarg_s);
266                 exit(1);
267             }
268             scs = *i_scsp;
269             input_key = malloc(scs.key_size);
270             sec_servs |= sec_serv_conf | sec_serv_auth;
271             gcm_on = scs.gcm_on;
272             break;
273         case 'm':
274             if (strcasecmp("rtp", optarg_s) == 0) {
275                 mode = mode_rtp;
276             } else if (strcasecmp("rtcp", optarg_s) == 0) {
277                 mode = mode_rtcp;
278             } else if (strcasecmp("rtcp-mux", optarg_s) == 0) {
279                 mode = mode_rtcp_mux;
280             } else {
281                 fprintf(stderr, "Unknown/unsupported mode %s\n", optarg_s);
282                 exit(1);
283             }
284             break;
285         default:
286             usage(argv[0]);
287         }
288     }
289 
290     if (scs.tag_size == 0) {
291         if (gcm_on) {
292             scs.tag_size = 16;
293         } else {
294             scs.tag_size = 10;
295         }
296     }
297 
298     if (gcm_on && scs.tag_size != 8 && scs.tag_size != 16) {
299         fprintf(stderr, "error: GCM tag size must be 8 or 16 (%d)\n",
300                 scs.tag_size);
301         exit(1);
302     }
303 
304     if (!gcm_on && scs.tag_size != 4 && scs.tag_size != 10) {
305         fprintf(stderr, "error: non GCM tag size must be 4 or 10 (%d)\n",
306                 scs.tag_size);
307         exit(1);
308     }
309 
310     if (do_list_mods) {
311         status = srtp_list_debug_modules();
312         if (status) {
313             fprintf(stderr, "error: list of debug modules failed\n");
314             exit(1);
315         }
316         return 0;
317     }
318 
319     if ((sec_servs && !input_key) || (!sec_servs && input_key)) {
320         /*
321          * a key must be provided if and only if security services have
322          * been requested
323          */
324         if (input_key == NULL) {
325             fprintf(stderr, "key not provided\n");
326         }
327         if (!sec_servs) {
328             fprintf(stderr, "no secservs\n");
329         }
330         fprintf(stderr, "provided\n");
331         usage(argv[0]);
332     }
333 
334     /* report security services selected on the command line */
335     fprintf(stderr, "security services: ");
336     if (sec_servs & sec_serv_conf)
337         fprintf(stderr, "confidentiality ");
338     if (sec_servs & sec_serv_auth)
339         fprintf(stderr, "message authentication");
340     if (sec_servs == sec_serv_none)
341         fprintf(stderr, "none");
342     fprintf(stderr, "\n");
343 
344     /* set up the srtp policy and master key */
345     if (sec_servs) {
346         /*
347          * create policy structure, using the default mechanisms but
348          * with only the security services requested on the command line,
349          * using the right SSRC value
350          */
351         switch (sec_servs) {
352         case sec_serv_conf_and_auth:
353             if (gcm_on) {
354 #ifdef OPENSSL
355                 switch (scs.key_size) {
356                 case 128:
357                     if (scs.tag_size == 16) {
358                         srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp);
359                         srtp_crypto_policy_set_aes_gcm_128_16_auth(
360                             &policy.rtcp);
361                     } else {
362                         srtp_crypto_policy_set_aes_gcm_128_8_auth(&policy.rtp);
363                         srtp_crypto_policy_set_aes_gcm_128_8_auth(&policy.rtcp);
364                     }
365                     break;
366                 case 256:
367                     if (scs.tag_size == 16) {
368                         srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtp);
369                         srtp_crypto_policy_set_aes_gcm_256_16_auth(
370                             &policy.rtcp);
371                     } else {
372                         srtp_crypto_policy_set_aes_gcm_256_8_auth(&policy.rtp);
373                         srtp_crypto_policy_set_aes_gcm_256_8_auth(&policy.rtcp);
374                     }
375                     break;
376                 }
377 #else
378                 fprintf(stderr, "error: GCM mode only supported when using the "
379                                 "OpenSSL crypto engine.\n");
380                 return 0;
381 #endif
382             } else {
383                 switch (scs.key_size) {
384                 case 128:
385                     if (scs.tag_size == 4) {
386                         srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(
387                             &policy.rtp);
388                         srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(
389                             &policy.rtcp);
390                     } else {
391                         srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(
392                             &policy.rtp);
393                         srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(
394                             &policy.rtcp);
395                     }
396                     break;
397                 case 192:
398 #ifdef OPENSSL
399                     if (scs.tag_size == 4) {
400                         srtp_crypto_policy_set_aes_cm_192_hmac_sha1_32(
401                             &policy.rtp);
402                         srtp_crypto_policy_set_aes_cm_192_hmac_sha1_80(
403                             &policy.rtcp);
404                     } else {
405                         srtp_crypto_policy_set_aes_cm_192_hmac_sha1_80(
406                             &policy.rtp);
407                         srtp_crypto_policy_set_aes_cm_192_hmac_sha1_80(
408                             &policy.rtcp);
409                     }
410 #else
411                     fprintf(stderr,
412                             "error: AES 192 mode only supported when using the "
413                             "OpenSSL crypto engine.\n");
414                     return 0;
415 
416 #endif
417                     break;
418                 case 256:
419                     if (scs.tag_size == 4) {
420                         srtp_crypto_policy_set_aes_cm_256_hmac_sha1_32(
421                             &policy.rtp);
422                         srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80(
423                             &policy.rtcp);
424                     } else {
425                         srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80(
426                             &policy.rtp);
427                         srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80(
428                             &policy.rtcp);
429                     }
430                     break;
431                 }
432             }
433             break;
434         case sec_serv_conf:
435             if (gcm_on) {
436                 fprintf(
437                     stderr,
438                     "error: GCM mode must always be used with auth enabled\n");
439                 return -1;
440             } else {
441                 switch (scs.key_size) {
442                 case 128:
443                     srtp_crypto_policy_set_aes_cm_128_null_auth(&policy.rtp);
444                     srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(
445                         &policy.rtcp);
446                     break;
447                 case 192:
448 #ifdef OPENSSL
449                     srtp_crypto_policy_set_aes_cm_192_null_auth(&policy.rtp);
450                     srtp_crypto_policy_set_aes_cm_192_hmac_sha1_80(
451                         &policy.rtcp);
452 #else
453                     fprintf(stderr,
454                             "error: AES 192 mode only supported when using the "
455                             "OpenSSL crypto engine.\n");
456                     return 0;
457 
458 #endif
459                     break;
460                 case 256:
461                     srtp_crypto_policy_set_aes_cm_256_null_auth(&policy.rtp);
462                     srtp_crypto_policy_set_aes_cm_256_hmac_sha1_80(
463                         &policy.rtcp);
464                     break;
465                 }
466             }
467             break;
468         case sec_serv_auth:
469             if (gcm_on) {
470 #ifdef OPENSSL
471                 switch (scs.key_size) {
472                 case 128:
473                     srtp_crypto_policy_set_aes_gcm_128_8_only_auth(&policy.rtp);
474                     srtp_crypto_policy_set_aes_gcm_128_8_only_auth(
475                         &policy.rtcp);
476                     break;
477                 case 256:
478                     srtp_crypto_policy_set_aes_gcm_256_8_only_auth(&policy.rtp);
479                     srtp_crypto_policy_set_aes_gcm_256_8_only_auth(
480                         &policy.rtcp);
481                     break;
482                 }
483 #else
484                 printf("error: GCM mode only supported when using the OpenSSL "
485                        "crypto engine.\n");
486                 return 0;
487 #endif
488             } else {
489                 srtp_crypto_policy_set_null_cipher_hmac_sha1_80(&policy.rtp);
490                 srtp_crypto_policy_set_rtcp_default(&policy.rtcp);
491             }
492             break;
493         default:
494             fprintf(stderr, "error: unknown security service requested\n");
495             return -1;
496         }
497 
498         policy.key = (uint8_t *)key;
499         policy.ekt = NULL;
500         policy.next = NULL;
501         policy.window_size = 128;
502         policy.allow_repeat_tx = 0;
503         policy.rtp.sec_serv = sec_servs;
504         policy.rtcp.sec_serv =
505             sec_servs; // sec_serv_none;  /* we don't do RTCP anyway */
506         fprintf(stderr, "setting tag len %d\n", scs.tag_size);
507         policy.rtp.auth_tag_len = scs.tag_size;
508 
509         if (gcm_on && scs.tag_size != 8) {
510             fprintf(stderr, "setted tag len %d\n", scs.tag_size);
511             policy.rtp.auth_tag_len = scs.tag_size;
512         }
513 
514         /*
515          * read key from hexadecimal or base64 on command line into an octet
516          * string
517          */
518         if (b64_input) {
519             int pad;
520             expected_len = policy.rtp.cipher_key_len * 4 / 3;
521             len = base64_string_to_octet_string(key, &pad, input_key,
522                                                 strlen(input_key));
523         } else {
524             expected_len = policy.rtp.cipher_key_len * 2;
525             len = hex_string_to_octet_string(key, input_key, expected_len);
526         }
527         /* check that hex string is the right length */
528         if (len < expected_len) {
529             fprintf(stderr, "error: too few digits in key/salt "
530                             "(should be %d digits, found %d)\n",
531                     expected_len, len);
532             exit(1);
533         }
534         if (strlen(input_key) > policy.rtp.cipher_key_len * 2) {
535             fprintf(stderr, "error: too many digits in key/salt "
536                             "(should be %d hexadecimal digits, found %u)\n",
537                     policy.rtp.cipher_key_len * 2, (unsigned)strlen(input_key));
538             exit(1);
539         }
540 
541         fprintf(stderr, "set master key/salt to %s/",
542                 octet_string_hex_string(key, 16));
543         fprintf(stderr, "%s\n", octet_string_hex_string(key + 16, 14));
544 
545     } else {
546         fprintf(stderr,
547                 "error: neither encryption or authentication were selected\n");
548         exit(1);
549     }
550 
551     pcap_handle = pcap_open_offline("-", errbuf);
552 
553     if (!pcap_handle) {
554         fprintf(stderr, "libpcap failed to open file '%s'\n", errbuf);
555         exit(1);
556     }
557     assert(pcap_handle != NULL);
558     if ((pcap_compile(pcap_handle, &fp, filter_exp, 1, pcap_net)) == -1) {
559         fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp,
560                 pcap_geterr(pcap_handle));
561         return (2);
562     }
563     if (pcap_setfilter(pcap_handle, &fp) == -1) {
564         fprintf(stderr, "couldn't install filter %s: %s\n", filter_exp,
565                 pcap_geterr(pcap_handle));
566         return (2);
567     }
568     dec = rtp_decoder_alloc();
569     if (dec == NULL) {
570         fprintf(stderr, "error: malloc() failed\n");
571         exit(1);
572     }
573     fprintf(stderr, "Starting decoder\n");
574     if (rtp_decoder_init(dec, policy, mode)) {
575         fprintf(stderr, "error: init failed\n");
576         exit(1);
577     }
578 
579     pcap_loop(pcap_handle, 0, rtp_decoder_handle_pkt, (u_char *)dec);
580 
581     if (dec->mode == mode_rtp || dec->mode == mode_rtcp_mux) {
582         fprintf(stderr, "RTP packets decoded: %d\n", dec->rtp_cnt);
583     }
584     if (dec->mode == mode_rtcp || dec->mode == mode_rtcp_mux) {
585         fprintf(stderr, "RTCP packets decoded: %d\n", dec->rtcp_cnt);
586     }
587     fprintf(stderr, "Packet decode errors: %d\n", dec->error_cnt);
588 
589     rtp_decoder_deinit(dec);
590     rtp_decoder_dealloc(dec);
591 
592     status = srtp_shutdown();
593     if (status) {
594         fprintf(stderr, "error: srtp shutdown failed with error code %d\n",
595                 status);
596         exit(1);
597     }
598 
599     return 0;
600 }
601 
usage(char * string)602 void usage(char *string)
603 {
604     fprintf(
605         stderr,
606         "usage: %s [-d <debug>]* [[-k][-b] <key>] [-a][-t][-e] [-s "
607         "<srtp-crypto-suite>] [-m <mode>]\n"
608         "or     %s -l\n"
609         "where  -a use message authentication\n"
610         "       -e <key size> use encryption (use 128 or 256 for key size)\n"
611         "       -g Use AES-GCM mode (must be used with -e)\n"
612         "       -t <tag size> Tag size to use (in GCM mode use 8 or 16)\n"
613         "       -k <key>  sets the srtp master key given in hexadecimal\n"
614         "       -b <key>  sets the srtp master key given in base64\n"
615         "       -l list debug modules\n"
616         "       -f \"<pcap filter>\" to filter only the desired SRTP packets\n"
617         "       -d <debug> turn on debugging for module <debug>\n"
618         "       -s \"<srtp-crypto-suite>\" to set both key and tag size based\n"
619         "          on RFC4568-style crypto suite specification\n"
620         "       -m <mode> set the mode to be one of [rtp]|rtcp|rtcp-mux\n",
621         string, string);
622     exit(1);
623 }
624 
rtp_decoder_alloc(void)625 rtp_decoder_t rtp_decoder_alloc(void)
626 {
627     return (rtp_decoder_t)malloc(sizeof(rtp_decoder_ctx_t));
628 }
629 
rtp_decoder_dealloc(rtp_decoder_t rtp_ctx)630 void rtp_decoder_dealloc(rtp_decoder_t rtp_ctx)
631 {
632     free(rtp_ctx);
633 }
634 
rtp_decoder_deinit(rtp_decoder_t decoder)635 int rtp_decoder_deinit(rtp_decoder_t decoder)
636 {
637     if (decoder->srtp_ctx) {
638         return srtp_dealloc(decoder->srtp_ctx);
639     }
640     return 0;
641 }
642 
rtp_decoder_init(rtp_decoder_t dcdr,srtp_policy_t policy,rtp_decoder_mode_t mode)643 int rtp_decoder_init(rtp_decoder_t dcdr,
644                      srtp_policy_t policy,
645                      rtp_decoder_mode_t mode)
646 {
647     dcdr->rtp_offset = DEFAULT_RTP_OFFSET;
648     dcdr->srtp_ctx = NULL;
649     dcdr->start_tv.tv_usec = 0;
650     dcdr->start_tv.tv_sec = 0;
651     dcdr->frame_nr = -1;
652     dcdr->error_cnt = 0;
653     dcdr->rtp_cnt = 0;
654     dcdr->rtcp_cnt = 0;
655     dcdr->mode = mode;
656     dcdr->policy = policy;
657     dcdr->policy.ssrc.type = ssrc_any_inbound;
658 
659     if (srtp_create(&dcdr->srtp_ctx, &dcdr->policy)) {
660         return 1;
661     }
662     return 0;
663 }
664 
665 /*
666  * decodes key as base64
667  */
668 
hexdump(const void * ptr,size_t size)669 void hexdump(const void *ptr, size_t size)
670 {
671     int i, j;
672     const unsigned char *cptr = ptr;
673 
674     for (i = 0; i < size; i += 16) {
675         fprintf(stdout, "%04x ", i);
676         for (j = 0; j < 16 && i + j < size; j++) {
677             fprintf(stdout, "%02x ", cptr[i + j]);
678         }
679         fprintf(stdout, "\n");
680     }
681 }
682 
rtp_decoder_handle_pkt(u_char * arg,const struct pcap_pkthdr * hdr,const u_char * bytes)683 void rtp_decoder_handle_pkt(u_char *arg,
684                             const struct pcap_pkthdr *hdr,
685                             const u_char *bytes)
686 {
687     rtp_decoder_t dcdr = (rtp_decoder_t)arg;
688     rtp_msg_t message;
689     int rtp;
690     int pktsize;
691     struct timeval delta;
692     int octets_recvd;
693     srtp_err_status_t status;
694     dcdr->frame_nr++;
695 
696     if ((dcdr->start_tv.tv_sec == 0) && (dcdr->start_tv.tv_usec == 0)) {
697         dcdr->start_tv = hdr->ts;
698     }
699 
700     if (hdr->caplen < dcdr->rtp_offset) {
701         return;
702     }
703     const void *rtp_packet = bytes + dcdr->rtp_offset;
704 
705     memcpy((void *)&message, rtp_packet, hdr->caplen - dcdr->rtp_offset);
706     pktsize = hdr->caplen - dcdr->rtp_offset;
707     octets_recvd = pktsize;
708 
709     if (octets_recvd == -1) {
710         return;
711     }
712 
713     if (dcdr->mode == mode_rtp) {
714         rtp = 1;
715     } else if (dcdr->mode == mode_rtcp) {
716         rtp = 0;
717     } else {
718         rtp = 1;
719         if (octets_recvd >= 2) {
720             /* rfc5761 */
721             u_char payload_type = *(bytes + dcdr->rtp_offset + 1) & 0x7f;
722             rtp = payload_type < 64 || payload_type > 95;
723         }
724     }
725 
726     if (rtp) {
727         /* verify rtp header */
728         if (message.header.version != 2) {
729             return;
730         }
731 
732         status = srtp_unprotect(dcdr->srtp_ctx, &message, &octets_recvd);
733         if (status) {
734             dcdr->error_cnt++;
735             return;
736         }
737         dcdr->rtp_cnt++;
738     } else {
739         status = srtp_unprotect_rtcp(dcdr->srtp_ctx, &message, &octets_recvd);
740         if (status) {
741             dcdr->error_cnt++;
742             return;
743         }
744         dcdr->rtcp_cnt++;
745     }
746     timersub(&hdr->ts, &dcdr->start_tv, &delta);
747     fprintf(stdout, "%02ld:%02ld.%06ld\n", delta.tv_sec / 60, delta.tv_sec % 60,
748             (long)delta.tv_usec);
749     hexdump(&message, octets_recvd);
750 }
751 
rtp_print_error(srtp_err_status_t status,char * message)752 void rtp_print_error(srtp_err_status_t status, char *message)
753 {
754     // clang-format off
755     fprintf(stderr,
756             "error: %s %d%s\n", message, status,
757             status == srtp_err_status_replay_fail ? " (replay check failed)" :
758             status == srtp_err_status_bad_param ? " (bad param)" :
759             status == srtp_err_status_no_ctx ? " (no context)" :
760             status == srtp_err_status_cipher_fail ? " (cipher failed)" :
761             status == srtp_err_status_key_expired ? " (key expired)" :
762             status == srtp_err_status_auth_fail ? " (auth check failed)" : "");
763     // clang-format on
764 }
765