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