]> git.sesse.net Git - vlc/blob - libs/srtp/srtp.c
efc434fdd8983c2697fcc5e67d73b4fa447f6630
[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 (auth))
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     /* RTP key derivation */
335     if (s->kdr != 0)
336     {
337         uint64_t index = (((uint64_t)s->rtp_roc) << 16) | s->rtp_seq;
338         index /= s->kdr;
339
340         for (int i = sizeof (r) - 1; i >= 0; i--)
341         {
342             r[i] = index & 0xff;
343             index = index >> 8;
344         }
345     }
346     else
347         memset (r, 0, sizeof (r));
348
349     if (proto_derive (&s->rtp, prf, salt, saltlen, r, 6, false))
350         return -1;
351
352     /* RTCP key derivation */
353     memcpy (r, &(uint32_t){ htonl (s->rtcp_index) }, 4);
354     if (proto_derive (&s->rtcp, prf, salt, saltlen, r, 4, true))
355         return -1;
356
357     (void)gcry_cipher_close (prf);
358     return 0;
359 }
360
361
362 /**
363  * Sets (or resets) the master key and master salt for a SRTP session.
364  * This must be done at least once before using rtp_send(), rtp_recv(),
365  * rtcp_send() or rtcp_recv(). Also, rekeying is required every
366  * 2^48 RTP packets or 2^31 RTCP packets (whichever comes first),
367  * otherwise the protocol security might be broken.
368  *
369  * @return 0 on success, in case of error:
370  *  EINVAL  invalid or unsupported key/salt sizes combination
371  */
372 int
373 srtp_setkey (srtp_session_t *s, const void *key, size_t keylen,
374              const void *salt, size_t saltlen)
375 {
376     return srtp_derive (s, key, keylen, salt, saltlen) ? EINVAL : 0;
377 }
378
379
380 /**
381  * Sets Roll-over-Counter Carry (RCC) rate for the SRTP session. If not
382  * specified (through this function), the default rate of ONE is assumed
383  * (i.e. every RTP packets will carry the RoC). RCC rate is ignored if none
384  * of the RCC mode has been selected.
385  *
386  * The RCC mode is selected through one of these flags for srtp_create():
387  *  SRTP_RCC_MODE1: integrity protection only for RoC carrying packets
388  *  SRTP_RCC_MODE2: integrity protection for all packets
389  *  SRTP_RCC_MODE3: no integrity protection
390  *
391  * RCC mode 3 is insecure. Compared to plain RTP, it provides confidentiality
392  * (through encryption) but is much more prone to DoS. It can only be used if
393  * anti-spoofing protection is provided by lower network layers (e.g. IPsec,
394  * or trusted routers and proper source address filtering).
395  *
396  * If RCC rate is 1, RCC mode 1 and 2 are functionally identical.
397  *
398  * @param rate RoC Carry rate (MUST NOT be zero)
399  */
400 void srtp_setrcc_rate (srtp_session_t *s, uint16_t rate)
401 {
402     assert (rate != 0);
403     s->rtp_rcc = rate;
404 }
405
406
407 /** AES-CM for RTP (salt = 14 bytes + 2 nul bytes) */
408 static int
409 rtp_crypt (gcry_cipher_hd_t hd, uint32_t ssrc, uint32_t roc, uint16_t seq,
410            const uint32_t *salt, uint8_t *data, size_t len)
411 {
412     /* Determines cryptographic counter (IV) */
413     uint32_t counter[4];
414     counter[0] = salt[0];
415     counter[1] = salt[1] ^ ssrc;
416     counter[2] = salt[2] ^ htonl (roc);
417     counter[3] = salt[3] ^ htonl (seq << 16);
418
419     /* Encryption */
420     return ctr_crypt (hd, counter, data, len);
421 }
422
423
424 /** Determines SRTP Roll-Over-Counter (in host-byte order) */
425 static uint32_t
426 srtp_compute_roc (const srtp_session_t *s, uint16_t seq)
427 {
428     uint32_t roc = s->rtp_roc;
429
430     if (((seq - s->rtp_seq) & 0xffff) < 0x8000)
431     {
432         /* Sequence is ahead, good */
433         if (seq < s->rtp_seq)
434             roc++; /* Sequence number wrap */
435     }
436     else
437     {
438         /* Sequence is late, bad */
439         if (seq > s->rtp_seq)
440             roc--; /* Wrap back */
441     }
442     return roc;
443 }
444
445
446 /** Returns RTP sequence (in host-byte order) */
447 static inline uint16_t rtp_seq (const uint8_t *buf)
448 {
449     return (buf[2] << 8) | buf[3];
450 }
451
452
453 /** Message Authentication and Integrity for RTP */
454 static const uint8_t *
455 rtp_digest (srtp_session_t *s, const uint8_t *data, size_t len,
456             uint32_t roc)
457 {
458     const gcry_md_hd_t md = s->rtp.mac;
459
460     gcry_md_reset (md);
461     gcry_md_write (md, data, len);
462     gcry_md_write (md, &(uint32_t){ htonl (roc) }, 4);
463     return gcry_md_read (md, 0);
464 }
465
466
467 /**
468  * Encrypts/decrypts a RTP packet and updates SRTP context
469  * (CTR block cypher mode of operation has identical encryption and
470  * decryption function).
471  *
472  * @param buf RTP packet to be en-/decrypted
473  * @param len RTP packet length
474  *
475  * @return 0 on success, in case of error:
476  *  EINVAL  malformatted RTP packet
477  *  EACCES  replayed packet or out-of-window or sync lost
478  */
479 static int srtp_crypt (srtp_session_t *s, uint8_t *buf, size_t len)
480 {
481     assert (s != NULL);
482
483     if ((len < 12) || ((buf[0] >> 6) != 2))
484         return EINVAL;
485
486     /* Computes encryption offset */
487     uint16_t offset = 12;
488     offset += (buf[0] & 0xf) * 4; // skips CSRC
489
490     if (buf[0] & 0x10)
491     {
492         uint16_t extlen;
493
494         offset += 4;
495         if (len < offset)
496             return EINVAL;
497
498         memcpy (&extlen, buf + offset - 2, 2);
499         offset += htons (extlen); // skips RTP extension header
500     }
501
502     if (len < offset)
503         return EINVAL;
504
505     /* Determines RTP 48-bits counter and SSRC */
506     uint16_t seq = rtp_seq (buf);
507     uint32_t roc = srtp_compute_roc (s, seq), ssrc;
508     memcpy (&ssrc, buf + 8, 4);
509
510     /* Updates ROC and sequence (it's safe now) */
511     int16_t diff = seq - s->rtp_seq;
512     if (diff > 0)
513     {
514         /* Sequence in the future, good */
515         s->rtp.window = s->rtp.window << diff;
516         s->rtp.window |= 1;
517         s->rtp_seq = seq, s->rtp_roc = roc;
518     }
519     else
520     {
521         /* Sequence in the past/present, bad */
522         diff = -diff;
523         if ((diff >= 64) || ((s->rtp.window >> diff) & 1))
524             return EACCES; /* Replay attack */
525         s->rtp.window |= 1 << diff;
526     }
527
528     /* Encrypt/Decrypt */
529     if (s->flags & SRTP_UNENCRYPTED)
530         return 0;
531
532     if (rtp_crypt (s->rtp.cipher, ssrc, roc, seq, s->rtp.salt,
533                    buf + offset, len - offset))
534         return EINVAL;
535
536     return 0;
537 }
538
539
540 /**
541  * Turns a RTP packet into a SRTP packet: encrypt it, then computes
542  * the authentication tag and appends it.
543  * Note that you can encrypt packet in disorder.
544  *
545  * @param buf RTP packet to be encrypted/digested
546  * @param lenp pointer to the RTP packet length on entry,
547  *             set to the SRTP length on exit (undefined on non-ENOSPC error)
548  * @param bufsize size (bytes) of the packet buffer
549  *
550  * @return 0 on success, in case of error:
551  *  EINVAL  malformatted RTP packet or internal error
552  *  ENOSPC  bufsize is too small to add authentication tag
553  *          (<lenp> will hold the required byte size)
554  *  EACCES  packet would trigger a replay error on receiver
555  */
556 int
557 srtp_send (srtp_session_t *s, uint8_t *buf, size_t *lenp, size_t bufsize)
558 {
559     size_t len = *lenp;
560     int val = srtp_crypt (s, buf, len);
561     if (val)
562         return val;
563
564     if (!(s->flags & SRTP_UNAUTHENTICATED))
565     {
566         size_t tag_len = s->tag_len;
567         *lenp = len + tag_len;
568         if (bufsize < (len + tag_len))
569             return ENOSPC;
570
571         uint32_t roc = srtp_compute_roc (s, rtp_seq (buf));
572         const uint8_t *tag = rtp_digest (s, buf, len, roc);
573         if (rcc_mode (s))
574         {
575             assert (s->rtp_rcc);
576             if ((rtp_seq (buf) % s->rtp_rcc) == 0)
577             {
578                 memcpy (buf + len, &(uint32_t){ htonl (s->rtp_roc) }, 4);
579                 len += 4;
580                 if (rcc_mode (s) == 3)
581                     tag_len = 0;
582                 else
583                     tag_len -= 4;
584             }
585             else
586             {
587                 if (rcc_mode (s) & 1)
588                     tag_len = 0;
589             }
590         }
591         memcpy (buf + len, tag, tag_len);
592     }
593
594     return 0;
595 }
596
597
598 /**
599  * Turns a SRTP packet into a RTP packet: authenticates the packet,
600  * then decrypts it.
601  *
602  * @param buf RTP packet to be digested/decrypted
603  * @param lenp pointer to the SRTP packet length on entry,
604  *             set to the RTP length on exit (undefined in case of error)
605  *
606  * @return 0 on success, in case of error:
607  *  EINVAL  malformatted SRTP packet
608  *  EACCES  authentication failed (spoofed packet or out-of-sync)
609  */
610 int
611 srtp_recv (srtp_session_t *s, uint8_t *buf, size_t *lenp)
612 {
613     size_t len = *lenp;
614     if (len < 12u)
615         return EINVAL;
616
617     if (!(s->flags & SRTP_UNAUTHENTICATED))
618     {
619         size_t tag_len = s->tag_len, roc_len = 0;
620         if (rcc_mode (s))
621         {
622             if ((rtp_seq (buf) % s->rtp_rcc) == 0)
623             {
624                 roc_len = 4;
625                 if (rcc_mode (s) == 3)
626                     tag_len = 0;
627                 else
628                     tag_len -= 4;
629             }
630             else
631             {
632                 if (rcc_mode (s) & 1)
633                     tag_len = 0; // RCC mode 1 or 3: no auth
634             }
635         }
636
637         if (len < (12u + roc_len + tag_len))
638             return EINVAL;
639         len -= roc_len + tag_len;
640
641         uint32_t roc = srtp_compute_roc (s, rtp_seq (buf)), rcc;
642         if (roc_len)
643         {
644             assert (roc_len == 4);
645             memcpy (&rcc, buf + len, 4);
646             rcc = ntohl (rcc);
647         }
648         else
649             rcc = roc;
650
651         const uint8_t *tag = rtp_digest (s, buf, len, rcc);
652         if (memcmp (buf + len + roc_len, tag, s->tag_len))
653             return EACCES;
654
655         if (roc_len)
656         {
657             /* Authenticated packet carried a Roll-Over-Counter */
658             s->rtp_roc += rcc - roc;
659             assert (srtp_compute_roc (s, rtp_seq (buf)) == rcc);
660         }
661         *lenp = len;
662     }
663
664     return srtp_crypt (s, buf, len);
665 }
666
667
668 /** AES-CM for RTCP (salt = 14 bytes + 2 nul bytes) */
669 static int
670 rtcp_crypt (gcry_cipher_hd_t hd, uint32_t ssrc, uint32_t index,
671             const uint32_t *salt, uint8_t *data, size_t len)
672 {
673     return rtp_crypt (hd, ssrc, index >> 16, index & 0xffff, salt, data, len);
674 }
675
676
677 /** Message Authentication and Integrity for RTCP */
678 static const uint8_t *
679 rtcp_digest (gcry_md_hd_t md, const void *data, size_t len)
680 {
681     gcry_md_reset (md);
682     gcry_md_write (md, data, len);
683     return gcry_md_read (md, 0);
684 }
685
686
687 /**
688  * Encrypts/decrypts a RTCP packet and updates SRTCP context
689  * (CTR block cypher mode of operation has identical encryption and
690  * decryption function).
691  *
692  * @param buf RTCP packet to be en-/decrypted
693  * @param len RTCP packet length
694  *
695  * @return 0 on success, in case of error:
696  *  EINVAL  malformatted RTCP packet
697  */
698 static int srtcp_crypt (srtp_session_t *s, uint8_t *buf, size_t len)
699 {
700     assert (s != NULL);
701
702     /* 8-bytes unencrypted header, and 4-bytes unencrypted footer */
703     if ((len < 12) || ((buf[0] >> 6) != 2))
704         return EINVAL;
705
706     uint32_t index;
707     memcpy (&index, buf + len, 4);
708     index = ntohl (index);
709     if (((index >> 31) != 0) != ((s->flags & SRTCP_UNENCRYPTED) == 0))
710         return EINVAL; // E-bit mismatch
711
712     index &= ~(1 << 31); // clear E-bit for counter
713
714     /* Updates SRTCP index (safe here) */
715     int32_t diff = index - s->rtcp_index;
716     if (diff > 0)
717     {
718         /* Packet in the future, good */
719         s->rtcp.window = s->rtcp.window << diff;
720         s->rtcp.window |= 1;
721         s->rtcp_index = index;
722     }
723     else
724     {
725         /* Packet in the past/present, bad */
726         diff = -diff;
727         if ((diff >= 64) || ((s->rtcp.window >> diff) & 1))
728             return EACCES; // replay attack!
729         s->rtp.window |= 1 << diff;
730     }
731
732     /* Crypts SRTCP */
733     if (s->flags & SRTCP_UNENCRYPTED)
734         return 0;
735
736     uint32_t ssrc;
737     memcpy (&ssrc, buf + 4, 4);
738
739     if (rtcp_crypt (s->rtcp.cipher, ssrc, index, s->rtp.salt,
740                     buf + 8, len - 8))
741         return EINVAL;
742     return 0;
743 }
744
745
746 /**
747  * Turns a RTCP packet into a SRTCP packet: encrypt it, then computes
748  * the authentication tag and appends it.
749  *
750  * @param buf RTCP packet to be encrypted/digested
751  * @param lenp pointer to the RTCP packet length on entry,
752  *             set to the SRTCP length on exit (undefined in case of error)
753  * @param bufsize size (bytes) of the packet buffer
754  *
755  * @return 0 on success, in case of error:
756  *  EINVAL  malformatted RTCP packet or internal error
757  *  ENOSPC  bufsize is too small (to add index and authentication tag)
758  */
759 int
760 srtcp_send (srtp_session_t *s, uint8_t *buf, size_t *lenp, size_t bufsize)
761 {
762     size_t len = *lenp;
763     if (bufsize < (len + 4 + s->tag_len))
764         return ENOSPC;
765
766     uint32_t index = ++s->rtcp_index;
767     if (index >> 31)
768         s->rtcp_index = index = 0; /* 31-bit wrap */
769
770     if ((s->flags & SRTCP_UNENCRYPTED) == 0)
771         index |= 0x80000000; /* Set Encrypted bit */
772     memcpy (buf + len, &(uint32_t){ htonl (index) }, 4);
773
774     int val = srtcp_crypt (s, buf, len);
775     if (val)
776         return val;
777
778     len += 4; /* Digests SRTCP index too */
779
780     const uint8_t *tag = rtcp_digest (s->rtp.mac, buf, len);
781     memcpy (buf + len, tag, s->tag_len);
782     *lenp = len + s->tag_len;
783     return 0;
784 }
785
786
787 /**
788  * Turns a SRTCP packet into a RTCP packet: authenticates the packet,
789  * then decrypts it.
790  *
791  * @param buf RTCP packet to be digested/decrypted
792  * @param lenp pointer to the SRTCP packet length on entry,
793  *             set to the RTCP length on exit (undefined in case of error)
794  *
795  * @return 0 on success, in case of error:
796  *  EINVAL  malformatted SRTCP packet
797  *  EACCES  authentication failed (spoofed packet or out-of-sync)
798  */
799 int
800 srtcp_recv (srtp_session_t *s, uint8_t *buf, size_t *lenp)
801 {
802     size_t len = *lenp;
803
804     if (len < (4u + s->tag_len))
805         return EINVAL;
806     len -= s->tag_len;
807
808     const uint8_t *tag = rtcp_digest (s->rtp.mac, buf, len);
809     if (memcmp (buf + len, tag, s->tag_len))
810          return EACCES;
811
812     len -= 4; /* Remove SRTCP index before decryption */
813     *lenp = len;
814     return srtp_crypt (s, buf, len);
815 }
816