]> git.sesse.net Git - vlc/blob - libs/srtp/srtp.c
Fix hashing when using RFC4711
[vlc] / libs / srtp / srtp.c
1 /*
2  * Secure RTP with libgcrypt
3  * Copyright (C) 2007  RĂ©mi Denis-Courmont <rdenis # simphalempin , com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 /* TODO:
21  * Useless stuff (because nothing depends on it):
22  * - non-nul key derivation rate
23  * - MKI payload
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include <stdint.h>
31 #include <stddef.h>
32
33 #include "srtp.h"
34
35 #include <stdbool.h>
36 #include <stdlib.h>
37 #include <assert.h>
38 #include <errno.h>
39
40 #include <gcrypt.h>
41
42 #ifdef WIN32
43 # include <winsock2.h>
44 #else
45 # include <netinet/in.h>
46 # include <pthread.h>
47 GCRY_THREAD_OPTION_PTHREAD_IMPL;
48 #endif
49
50 #define debug( ... ) (void)0
51
52 typedef struct srtp_proto_t
53 {
54     gcry_cipher_hd_t cipher;
55     gcry_md_hd_t     mac;
56     uint64_t         window;
57     uint32_t         salt[4];
58 } srtp_proto_t;
59
60 struct srtp_session_t
61 {
62     srtp_proto_t rtp;
63     srtp_proto_t rtcp;
64     unsigned flags;
65     unsigned kdr;
66     uint32_t rtcp_index;
67     uint32_t rtp_roc;
68     uint16_t rtp_seq;
69     uint16_t rtp_rcc;
70     uint8_t  tag_len;
71 };
72
73 enum
74 {
75     SRTP_CRYPT,
76     SRTP_AUTH,
77     SRTP_SALT,
78     SRTCP_CRYPT,
79     SRTCP_AUTH,
80     SRTCP_SALT
81 };
82
83
84 static inline unsigned rcc_mode (const srtp_session_t *s)
85 {
86     return (s->flags >> 4) & 3;
87 }
88
89 static bool libgcrypt_usable = false;
90
91 static void initonce_libgcrypt (void)
92 {
93 #ifndef WIN32
94     gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
95 #endif
96
97     if ((gcry_check_version ("1.1.94") == NULL)
98      || gcry_control (GCRYCTL_DISABLE_SECMEM, 0)
99      || gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0))
100         return;
101
102     libgcrypt_usable = true;
103 }
104
105 static int init_libgcrypt (void)
106 {
107     int retval;
108 #ifndef WIN32
109     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
110     static pthread_once_t once = PTHREAD_ONCE_INIT;
111
112     pthread_mutex_lock (&mutex);
113     pthread_once (&once, initonce_libgcrypt);
114 #else
115 # warning FIXME: This is not thread-safe.
116     if (!libgcrypt_usable)
117         initonce_libgcrypt ();
118 #endif
119
120     retval = libgcrypt_usable ? 0 : -1;
121
122 #ifndef WIN32
123     pthread_mutex_unlock (&mutex);
124 #endif
125
126     return retval;
127
128 }
129
130
131 static void proto_destroy (srtp_proto_t *p)
132 {
133     gcry_md_close (p->mac);
134     gcry_cipher_close (p->cipher);
135 }
136
137
138 /**
139  * Releases all resources associated with a Secure RTP session.
140  */
141 void srtp_destroy (srtp_session_t *s)
142 {
143     assert (s != NULL);
144
145     proto_destroy (&s->rtcp);
146     proto_destroy (&s->rtp);
147     free (s);
148 }
149
150
151 static int proto_create (srtp_proto_t *p, int gcipher, int gmd)
152 {
153     if (gcry_cipher_open (&p->cipher, gcipher, GCRY_CIPHER_MODE_CTR, 0) == 0)
154     {
155         if (gcry_md_open (&p->mac, gmd, GCRY_MD_FLAG_HMAC) == 0)
156             return 0;
157         gcry_cipher_close (p->cipher);
158     }
159     return -1;
160 }
161
162
163 /**
164  * Allocates a Secure RTP one-way session.
165  * The same session cannot be used both ways because this would confuse
166  * internal cryptographic counters; it is however of course feasible to open
167  * multiple simultaneous sessions with the same master key.
168  *
169  * @param encr encryption algorithm number
170  * @param auth authentication algortihm number
171  * @param tag_len authentication tag byte length (NOT including RCC)
172  * @param flags OR'ed optional flags.
173  *
174  * @return NULL in case of error
175  */
176 srtp_session_t *
177 srtp_create (int encr, int auth, unsigned tag_len, int prf, unsigned flags)
178 {
179     if ((flags & ~SRTP_FLAGS_MASK) || init_libgcrypt ())
180         return NULL;
181
182     int cipher, md;
183     switch (encr)
184     {
185         case SRTP_ENCR_NULL:
186             cipher = GCRY_CIPHER_NONE;
187             break;
188
189         case SRTP_ENCR_AES_CM:
190             cipher = GCRY_CIPHER_AES;
191             break;
192
193         default:
194             return NULL;
195     }
196
197     switch (auth)
198     {
199         case SRTP_AUTH_NULL:
200             md = GCRY_MD_NONE;
201             break;
202
203         case SRTP_AUTH_HMAC_SHA1:
204             md = GCRY_MD_SHA1;
205             break;
206
207         default:
208             return NULL;
209     }
210
211     if (tag_len > gcry_md_get_algo_dlen (md))
212         return NULL;
213
214     if (prf != SRTP_PRF_AES_CM)
215         return NULL;
216
217     srtp_session_t *s = malloc (sizeof (*s));
218     if (s == NULL)
219         return NULL;
220
221     memset (s, 0, sizeof (*s));
222     s->flags = flags;
223     s->tag_len = tag_len;
224     s->rtp_rcc = 1; /* Default RCC rate */
225     if (rcc_mode (s))
226     {
227         if (tag_len < 4)
228             goto error;
229     }
230
231     if (proto_create (&s->rtp, cipher, md) == 0)
232     {
233         if (proto_create (&s->rtcp, cipher, md) == 0)
234             return s;
235         proto_destroy (&s->rtp);
236     }
237
238 error:
239     free (s);
240     return NULL;
241 }
242
243
244 /**
245  * Counter Mode encryption/decryption (ctr length = 16 bytes)
246  * with non-padded (truncated) text
247  */
248 static int
249 ctr_crypt (gcry_cipher_hd_t hd, const void *ctr, uint8_t *data, size_t len)
250 {
251     const size_t ctrlen = 16;
252     div_t d = div (len, ctrlen);
253
254     if (gcry_cipher_setctr (hd, ctr, ctrlen)
255      || gcry_cipher_encrypt (hd, data, d.quot * ctrlen, NULL, 0))
256         return -1;
257
258     if (d.rem)
259     {
260         /* Truncated last block */
261         uint8_t dummy[ctrlen];
262         data += d.quot * ctrlen;
263         memcpy (dummy, data, d.rem);
264         memset (dummy + d.rem, 0, ctrlen - d.rem);
265
266         if (gcry_cipher_encrypt (hd, dummy, ctrlen, data, ctrlen))
267             return -1;
268         memcpy (data, dummy, d.rem);
269     }
270
271     return 0;
272 }
273
274
275 /**
276  * AES-CM key derivation (saltlen = 14 bytes)
277  */
278 static int
279 derive (gcry_cipher_hd_t prf, const void *salt,
280         const uint8_t *r, size_t rlen, uint8_t label,
281         void *out, size_t outlen)
282 {
283     uint8_t iv[16];
284
285     memcpy (iv, salt, 14);
286     iv[14] = iv[15] = 0;
287
288     assert (rlen < 14);
289     iv[13 - rlen] ^= label;
290     for (size_t i = 0; i < rlen; i++)
291         iv[sizeof (iv) - rlen + i] ^= r[i];
292
293     memset (out, 0, outlen);
294     return ctr_crypt (prf, iv, out, outlen);
295 }
296
297
298 static int
299 proto_derive (srtp_proto_t *p, gcry_cipher_hd_t prf,
300               const void *salt, size_t saltlen,
301               const uint8_t *r, size_t rlen, bool rtcp)
302 {
303     if (saltlen != 14)
304         return -1;
305
306     uint8_t keybuf[20];
307     uint8_t label = rtcp ? SRTCP_CRYPT : SRTP_CRYPT;
308
309     if (derive (prf, salt, r, rlen, label++, keybuf, 16)
310      || gcry_cipher_setkey (p->cipher, keybuf, 16)
311      || derive (prf, salt, r, rlen, label++, keybuf, 20)
312      || gcry_md_setkey (p->mac, keybuf, 20)
313      || derive (prf, salt, r, rlen, label, p->salt, 14))
314         return -1;
315
316     return 0;
317 }
318
319
320 /**
321  * SRTP/SRTCP cipher/salt/MAC keys derivation.
322  */
323 static int
324 srtp_derive (srtp_session_t *s, const void *key, size_t keylen,
325              const void *salt, size_t saltlen)
326 {
327     gcry_cipher_hd_t prf;
328     uint8_t r[6];
329
330     if (gcry_cipher_open (&prf, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CTR, 0)
331      || gcry_cipher_setkey (prf, key, keylen))
332         return -1;
333
334 #if 0
335     /* RTP key derivation */
336     if (s->kdr != 0)
337     {
338         uint64_t index = (((uint64_t)s->rtp_roc) << 16) | s->rtp_seq;
339         index /= s->kdr;
340
341         for (int i = sizeof (r) - 1; i >= 0; i--)
342         {
343             r[i] = index & 0xff;
344             index = index >> 8;
345         }
346     }
347     else
348 #endif
349         memset (r, 0, sizeof (r));
350
351     if (proto_derive (&s->rtp, prf, salt, saltlen, r, 6, false))
352         return -1;
353
354     /* RTCP key derivation */
355     memcpy (r, &(uint32_t){ htonl (s->rtcp_index) }, 4);
356     if (proto_derive (&s->rtcp, prf, salt, saltlen, r, 4, true))
357         return -1;
358
359     (void)gcry_cipher_close (prf);
360     return 0;
361 }
362
363
364 /**
365  * Sets (or resets) the master key and master salt for a SRTP session.
366  * This must be done at least once before using rtp_send(), rtp_recv(),
367  * rtcp_send() or rtcp_recv(). Also, rekeying is required every
368  * 2^48 RTP packets or 2^31 RTCP packets (whichever comes first),
369  * otherwise the protocol security might be broken.
370  *
371  * @return 0 on success, in case of error:
372  *  EINVAL  invalid or unsupported key/salt sizes combination
373  */
374 int
375 srtp_setkey (srtp_session_t *s, const void *key, size_t keylen,
376              const void *salt, size_t saltlen)
377 {
378     return srtp_derive (s, key, keylen, salt, saltlen) ? EINVAL : 0;
379 }
380
381
382 /**
383  * Sets Roll-over-Counter Carry (RCC) rate for the SRTP session. If not
384  * specified (through this function), the default rate of ONE is assumed
385  * (i.e. every RTP packets will carry the RoC). RCC rate is ignored if none
386  * of the RCC mode has been selected.
387  *
388  * The RCC mode is selected through one of these flags for srtp_create():
389  *  SRTP_RCC_MODE1: integrity protection only for RoC carrying packets
390  *  SRTP_RCC_MODE2: integrity protection for all packets
391  *  SRTP_RCC_MODE3: no integrity protection
392  *
393  * RCC mode 3 is insecure. Compared to plain RTP, it provides confidentiality
394  * (through encryption) but is much more prone to DoS. It can only be used if
395  * anti-spoofing protection is provided by lower network layers (e.g. IPsec,
396  * or trusted routers and proper source address filtering).
397  *
398  * If RCC rate is 1, RCC mode 1 and 2 are functionally identical.
399  *
400  * @param rate RoC Carry rate (MUST NOT be zero)
401  */
402 void srtp_setrcc_rate (srtp_session_t *s, uint16_t rate)
403 {
404     assert (rate != 0);
405     s->rtp_rcc = rate;
406 }
407
408
409 /** AES-CM for RTP (salt = 14 bytes + 2 nul bytes) */
410 static int
411 rtp_crypt (gcry_cipher_hd_t hd, uint32_t ssrc, uint32_t roc, uint16_t seq,
412            const uint32_t *salt, uint8_t *data, size_t len)
413 {
414     /* Determines cryptographic counter (IV) */
415     uint32_t counter[4];
416     counter[0] = salt[0];
417     counter[1] = salt[1] ^ ssrc;
418     counter[2] = salt[2] ^ htonl (roc);
419     counter[3] = salt[3] ^ htonl (seq << 16);
420
421     /* Encryption */
422     return ctr_crypt (hd, counter, data, len);
423 }
424
425
426 /** Determines SRTP Roll-Over-Counter (in host-byte order) */
427 static uint32_t
428 srtp_compute_roc (const srtp_session_t *s, uint16_t seq)
429 {
430     uint32_t roc = s->rtp_roc;
431
432     if (((seq - s->rtp_seq) & 0xffff) < 0x8000)
433     {
434         /* Sequence is ahead, good */
435         if (seq < s->rtp_seq)
436             roc++; /* Sequence number wrap */
437     }
438     else
439     {
440         /* Sequence is late, bad */
441         if (seq > s->rtp_seq)
442             roc--; /* Wrap back */
443     }
444     return roc;
445 }
446
447
448 /** Returns RTP sequence (in host-byte order) */
449 static inline uint16_t rtp_seq (const uint8_t *buf)
450 {
451     return (buf[2] << 8) | buf[3];
452 }
453
454
455 /** Message Authentication and Integrity for RTP */
456 static const uint8_t *
457 rtp_digest (srtp_session_t *s, const uint8_t *data, size_t len,
458             uint32_t roc)
459 {
460     const gcry_md_hd_t md = s->rtp.mac;
461
462     gcry_md_reset (md);
463     gcry_md_write (md, data, len);
464     gcry_md_write (md, &(uint32_t){ htonl (roc) }, 4);
465     return gcry_md_read (md, 0);
466 }
467
468
469 /**
470  * Encrypts/decrypts a RTP packet and updates SRTP context
471  * (CTR block cypher mode of operation has identical encryption and
472  * decryption function).
473  *
474  * @param buf RTP packet to be en-/decrypted
475  * @param len RTP packet length
476  *
477  * @return 0 on success, in case of error:
478  *  EINVAL  malformatted RTP packet
479  *  EACCES  replayed packet or out-of-window or sync lost
480  */
481 static int srtp_crypt (srtp_session_t *s, uint8_t *buf, size_t len)
482 {
483     assert (s != NULL);
484
485     if ((len < 12) || ((buf[0] >> 6) != 2))
486         return EINVAL;
487
488     /* Computes encryption offset */
489     uint16_t offset = 12;
490     offset += (buf[0] & 0xf) * 4; // skips CSRC
491
492     if (buf[0] & 0x10)
493     {
494         uint16_t extlen;
495
496         offset += 4;
497         if (len < offset)
498             return EINVAL;
499
500         memcpy (&extlen, buf + offset - 2, 2);
501         offset += htons (extlen); // skips RTP extension header
502     }
503
504     if (len < offset)
505         return EINVAL;
506
507     /* Determines RTP 48-bits counter and SSRC */
508     uint16_t seq = rtp_seq (buf);
509     uint32_t roc = srtp_compute_roc (s, seq), ssrc;
510     memcpy (&ssrc, buf + 8, 4);
511
512     /* Updates ROC and sequence (it's safe now) */
513     int16_t diff = seq - s->rtp_seq;
514     if (diff > 0)
515     {
516         /* Sequence in the future, good */
517         s->rtp.window = s->rtp.window << diff;
518         s->rtp.window |= 1;
519         s->rtp_seq = seq, s->rtp_roc = roc;
520     }
521     else
522     {
523         /* Sequence in the past/present, bad */
524         diff = -diff;
525         if ((diff >= 64) || ((s->rtp.window >> diff) & 1))
526             return EACCES; /* Replay attack */
527         s->rtp.window |= 1 << diff;
528     }
529
530     /* Encrypt/Decrypt */
531     if (s->flags & SRTP_UNENCRYPTED)
532         return 0;
533
534     if (rtp_crypt (s->rtp.cipher, ssrc, roc, seq, s->rtp.salt,
535                    buf + offset, len - offset))
536         return EINVAL;
537
538     return 0;
539 }
540
541
542 /**
543  * Turns a RTP packet into a SRTP packet: encrypt it, then computes
544  * the authentication tag and appends it.
545  * Note that you can encrypt packet in disorder.
546  *
547  * @param buf RTP packet to be encrypted/digested
548  * @param lenp pointer to the RTP packet length on entry,
549  *             set to the SRTP length on exit (undefined on non-ENOSPC error)
550  * @param bufsize size (bytes) of the packet buffer
551  *
552  * @return 0 on success, in case of error:
553  *  EINVAL  malformatted RTP packet or internal error
554  *  ENOSPC  bufsize is too small to add authentication tag
555  *          (<lenp> will hold the required byte size)
556  *  EACCES  packet would trigger a replay error on receiver
557  */
558 int
559 srtp_send (srtp_session_t *s, uint8_t *buf, size_t *lenp, size_t bufsize)
560 {
561     size_t len = *lenp;
562     int val = srtp_crypt (s, buf, len);
563     if (val)
564         return val;
565
566     if (!(s->flags & SRTP_UNAUTHENTICATED))
567     {
568         size_t tag_len = s->tag_len;
569         *lenp = len + tag_len;
570         if (bufsize < (len + tag_len))
571             return ENOSPC;
572
573         uint32_t roc = srtp_compute_roc (s, rtp_seq (buf));
574         const uint8_t *tag = rtp_digest (s, buf, len, roc);
575         if (rcc_mode (s))
576         {
577             assert (s->rtp_rcc);
578             if ((rtp_seq (buf) % s->rtp_rcc) == 0)
579             {
580                 memcpy (buf + len, &(uint32_t){ htonl (s->rtp_roc) }, 4);
581                 len += 4;
582                 if (rcc_mode (s) == 3)
583                     tag_len = 0;
584                 else
585                     tag_len -= 4;
586             }
587             else
588             {
589                 if (rcc_mode (s) & 1)
590                     tag_len = 0;
591             }
592         }
593         memcpy (buf + len, tag, tag_len);
594     }
595
596     return 0;
597 }
598
599
600 /**
601  * Turns a SRTP packet into a RTP packet: authenticates the packet,
602  * then decrypts it.
603  *
604  * @param buf RTP packet to be digested/decrypted
605  * @param lenp pointer to the SRTP packet length on entry,
606  *             set to the RTP length on exit (undefined in case of error)
607  *
608  * @return 0 on success, in case of error:
609  *  EINVAL  malformatted SRTP packet
610  *  EACCES  authentication failed (spoofed packet or out-of-sync)
611  */
612 int
613 srtp_recv (srtp_session_t *s, uint8_t *buf, size_t *lenp)
614 {
615     size_t len = *lenp;
616     if (len < 12u)
617         return EINVAL;
618
619     if (!(s->flags & SRTP_UNAUTHENTICATED))
620     {
621         size_t tag_len = s->tag_len, roc_len = 0;
622         if (rcc_mode (s))
623         {
624             if ((rtp_seq (buf) % s->rtp_rcc) == 0)
625             {
626                 roc_len = 4;
627                 if (rcc_mode (s) == 3)
628                     tag_len = 0;
629                 else
630                     tag_len -= 4;
631             }
632             else
633             {
634                 if (rcc_mode (s) & 1)
635                     tag_len = 0; // RCC mode 1 or 3: no auth
636             }
637         }
638
639         if (len < (12u + roc_len + tag_len))
640             return EINVAL;
641         len -= roc_len + tag_len;
642
643         uint32_t roc = srtp_compute_roc (s, rtp_seq (buf)), rcc;
644         if (roc_len)
645         {
646             assert (roc_len == 4);
647             memcpy (&rcc, buf + len, 4);
648             rcc = ntohl (rcc);
649         }
650         else
651             rcc = roc;
652
653         const uint8_t *tag = rtp_digest (s, buf, len, rcc);
654 #if 0
655         printf ("Computed: 0x");
656         for (unsigned i = 0; i < tag_len; i++)
657             printf ("%02x", tag[i]);
658         printf ("\nReceived: 0x");
659         for (unsigned i = 0; i < tag_len; i++)
660             printf ("%02x", buf[len + roc_len + i]);
661         puts ("");
662 #endif
663         if (memcmp (buf + len + roc_len, tag, tag_len))
664             return EACCES;
665
666         if (roc_len)
667         {
668             /* Authenticated packet carried a Roll-Over-Counter */
669             s->rtp_roc += rcc - roc;
670             assert (srtp_compute_roc (s, rtp_seq (buf)) == rcc);
671         }
672         *lenp = len;
673     }
674
675     return srtp_crypt (s, buf, len);
676 }
677
678
679 /** AES-CM for RTCP (salt = 14 bytes + 2 nul bytes) */
680 static int
681 rtcp_crypt (gcry_cipher_hd_t hd, uint32_t ssrc, uint32_t index,
682             const uint32_t *salt, uint8_t *data, size_t len)
683 {
684     return rtp_crypt (hd, ssrc, index >> 16, index & 0xffff, salt, data, len);
685 }
686
687
688 /** Message Authentication and Integrity for RTCP */
689 static const uint8_t *
690 rtcp_digest (gcry_md_hd_t md, const void *data, size_t len)
691 {
692     gcry_md_reset (md);
693     gcry_md_write (md, data, len);
694     return gcry_md_read (md, 0);
695 }
696
697
698 /**
699  * Encrypts/decrypts a RTCP packet and updates SRTCP context
700  * (CTR block cypher mode of operation has identical encryption and
701  * decryption function).
702  *
703  * @param buf RTCP packet to be en-/decrypted
704  * @param len RTCP packet length
705  *
706  * @return 0 on success, in case of error:
707  *  EINVAL  malformatted RTCP packet
708  */
709 static int srtcp_crypt (srtp_session_t *s, uint8_t *buf, size_t len)
710 {
711     assert (s != NULL);
712
713     /* 8-bytes unencrypted header, and 4-bytes unencrypted footer */
714     if ((len < 12) || ((buf[0] >> 6) != 2))
715         return EINVAL;
716
717     uint32_t index;
718     memcpy (&index, buf + len, 4);
719     index = ntohl (index);
720     if (((index >> 31) != 0) != ((s->flags & SRTCP_UNENCRYPTED) == 0))
721         return EINVAL; // E-bit mismatch
722
723     index &= ~(1 << 31); // clear E-bit for counter
724
725     /* Updates SRTCP index (safe here) */
726     int32_t diff = index - s->rtcp_index;
727     if (diff > 0)
728     {
729         /* Packet in the future, good */
730         s->rtcp.window = s->rtcp.window << diff;
731         s->rtcp.window |= 1;
732         s->rtcp_index = index;
733     }
734     else
735     {
736         /* Packet in the past/present, bad */
737         diff = -diff;
738         if ((diff >= 64) || ((s->rtcp.window >> diff) & 1))
739             return EACCES; // replay attack!
740         s->rtp.window |= 1 << diff;
741     }
742
743     /* Crypts SRTCP */
744     if (s->flags & SRTCP_UNENCRYPTED)
745         return 0;
746
747     uint32_t ssrc;
748     memcpy (&ssrc, buf + 4, 4);
749
750     if (rtcp_crypt (s->rtcp.cipher, ssrc, index, s->rtp.salt,
751                     buf + 8, len - 8))
752         return EINVAL;
753     return 0;
754 }
755
756
757 /**
758  * Turns a RTCP packet into a SRTCP packet: encrypt it, then computes
759  * the authentication tag and appends it.
760  *
761  * @param buf RTCP packet to be encrypted/digested
762  * @param lenp pointer to the RTCP packet length on entry,
763  *             set to the SRTCP length on exit (undefined in case of error)
764  * @param bufsize size (bytes) of the packet buffer
765  *
766  * @return 0 on success, in case of error:
767  *  EINVAL  malformatted RTCP packet or internal error
768  *  ENOSPC  bufsize is too small (to add index and authentication tag)
769  */
770 int
771 srtcp_send (srtp_session_t *s, uint8_t *buf, size_t *lenp, size_t bufsize)
772 {
773     size_t len = *lenp;
774     if (bufsize < (len + 4 + s->tag_len))
775         return ENOSPC;
776
777     uint32_t index = ++s->rtcp_index;
778     if (index >> 31)
779         s->rtcp_index = index = 0; /* 31-bit wrap */
780
781     if ((s->flags & SRTCP_UNENCRYPTED) == 0)
782         index |= 0x80000000; /* Set Encrypted bit */
783     memcpy (buf + len, &(uint32_t){ htonl (index) }, 4);
784
785     int val = srtcp_crypt (s, buf, len);
786     if (val)
787         return val;
788
789     len += 4; /* Digests SRTCP index too */
790
791     const uint8_t *tag = rtcp_digest (s->rtp.mac, buf, len);
792     memcpy (buf + len, tag, s->tag_len);
793     *lenp = len + s->tag_len;
794     return 0;
795 }
796
797
798 /**
799  * Turns a SRTCP packet into a RTCP packet: authenticates the packet,
800  * then decrypts it.
801  *
802  * @param buf RTCP packet to be digested/decrypted
803  * @param lenp pointer to the SRTCP packet length on entry,
804  *             set to the RTCP length on exit (undefined in case of error)
805  *
806  * @return 0 on success, in case of error:
807  *  EINVAL  malformatted SRTCP packet
808  *  EACCES  authentication failed (spoofed packet or out-of-sync)
809  */
810 int
811 srtcp_recv (srtp_session_t *s, uint8_t *buf, size_t *lenp)
812 {
813     size_t len = *lenp;
814
815     if (len < (4u + s->tag_len))
816         return EINVAL;
817     len -= s->tag_len;
818
819     const uint8_t *tag = rtcp_digest (s->rtp.mac, buf, len);
820     if (memcmp (buf + len, tag, s->tag_len))
821          return EACCES;
822
823     len -= 4; /* Remove SRTCP index before decryption */
824     *lenp = len;
825     return srtp_crypt (s, buf, len);
826 }
827