Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * SRTP encryption/decryption | ||
3 | * Copyright (c) 2012 Martin Storsjo | ||
4 | * | ||
5 | * This file is part of FFmpeg. | ||
6 | * | ||
7 | * FFmpeg is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU Lesser General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2.1 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * FFmpeg is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * Lesser General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU Lesser General Public | ||
18 | * License along with FFmpeg; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
20 | */ | ||
21 | |||
22 | #include "libavutil/base64.h" | ||
23 | #include "libavutil/aes.h" | ||
24 | #include "libavutil/hmac.h" | ||
25 | #include "libavutil/intreadwrite.h" | ||
26 | #include "libavutil/log.h" | ||
27 | #include "libavutil/mem.h" | ||
28 | #include "rtp.h" | ||
29 | #include "rtpdec.h" | ||
30 | #include "srtp.h" | ||
31 | |||
32 | 30 | void ff_srtp_free(struct SRTPContext *s) | |
33 | { | ||
34 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (!s) |
35 | ✗ | return; | |
36 | 30 | av_freep(&s->aes); | |
37 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | if (s->hmac) |
38 | 15 | av_hmac_free(s->hmac); | |
39 | 30 | s->hmac = NULL; | |
40 | } | ||
41 | |||
42 | 108 | static void encrypt_counter(struct AVAES *aes, uint8_t *iv, uint8_t *outbuf, | |
43 | int outlen) | ||
44 | { | ||
45 | int i, j, outpos; | ||
46 |
2/2✓ Branch 0 taken 141 times.
✓ Branch 1 taken 108 times.
|
249 | for (i = 0, outpos = 0; outpos < outlen; i++) { |
47 | uint8_t keystream[16]; | ||
48 | 141 | AV_WB16(&iv[14], i); | |
49 | 141 | av_aes_crypt(aes, keystream, iv, 1, NULL, 0); | |
50 |
4/4✓ Branch 0 taken 1749 times.
✓ Branch 1 taken 63 times.
✓ Branch 2 taken 1671 times.
✓ Branch 3 taken 78 times.
|
1812 | for (j = 0; j < 16 && outpos < outlen; j++, outpos++) |
51 | 1671 | outbuf[outpos] ^= keystream[j]; | |
52 | } | ||
53 | 108 | } | |
54 | |||
55 | 90 | static void derive_key(struct AVAES *aes, const uint8_t *salt, int label, | |
56 | uint8_t *out, int outlen) | ||
57 | { | ||
58 | 90 | uint8_t input[16] = { 0 }; | |
59 | 90 | memcpy(input, salt, 14); | |
60 | // Key derivation rate assumed to be zero | ||
61 | 90 | input[14 - 7] ^= label; | |
62 | 90 | memset(out, 0, outlen); | |
63 | 90 | encrypt_counter(aes, input, out, outlen); | |
64 | 90 | } | |
65 | |||
66 | 15 | int ff_srtp_set_crypto(struct SRTPContext *s, const char *suite, | |
67 | const char *params) | ||
68 | { | ||
69 | uint8_t buf[30]; | ||
70 | |||
71 | 15 | ff_srtp_free(s); | |
72 | |||
73 | // RFC 4568 | ||
74 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
|
15 | if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80") || |
75 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | !strcmp(suite, "SRTP_AES128_CM_HMAC_SHA1_80")) { |
76 | 5 | s->rtp_hmac_size = s->rtcp_hmac_size = 10; | |
77 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) { |
78 | 5 | s->rtp_hmac_size = s->rtcp_hmac_size = 4; | |
79 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | } else if (!strcmp(suite, "SRTP_AES128_CM_HMAC_SHA1_32")) { |
80 | // RFC 5764 section 4.1.2 | ||
81 | 5 | s->rtp_hmac_size = 4; | |
82 | 5 | s->rtcp_hmac_size = 10; | |
83 | } else { | ||
84 | ✗ | av_log(NULL, AV_LOG_WARNING, "SRTP Crypto suite %s not supported\n", | |
85 | suite); | ||
86 | ✗ | return AVERROR(EINVAL); | |
87 | } | ||
88 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
|
15 | if (av_base64_decode(buf, params, sizeof(buf)) != sizeof(buf)) { |
89 | ✗ | av_log(NULL, AV_LOG_WARNING, "Incorrect amount of SRTP params\n"); | |
90 | ✗ | return AVERROR(EINVAL); | |
91 | } | ||
92 | // MKI and lifetime not handled yet | ||
93 | 15 | s->aes = av_aes_alloc(); | |
94 | 15 | s->hmac = av_hmac_alloc(AV_HMAC_SHA1); | |
95 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
|
15 | if (!s->aes || !s->hmac) |
96 | ✗ | return AVERROR(ENOMEM); | |
97 | 15 | memcpy(s->master_key, buf, 16); | |
98 | 15 | memcpy(s->master_salt, buf + 16, 14); | |
99 | |||
100 | // RFC 3711 | ||
101 | 15 | av_aes_init(s->aes, s->master_key, 128, 0); | |
102 | |||
103 | 15 | derive_key(s->aes, s->master_salt, 0x00, s->rtp_key, sizeof(s->rtp_key)); | |
104 | 15 | derive_key(s->aes, s->master_salt, 0x02, s->rtp_salt, sizeof(s->rtp_salt)); | |
105 | 15 | derive_key(s->aes, s->master_salt, 0x01, s->rtp_auth, sizeof(s->rtp_auth)); | |
106 | |||
107 | 15 | derive_key(s->aes, s->master_salt, 0x03, s->rtcp_key, sizeof(s->rtcp_key)); | |
108 | 15 | derive_key(s->aes, s->master_salt, 0x05, s->rtcp_salt, sizeof(s->rtcp_salt)); | |
109 | 15 | derive_key(s->aes, s->master_salt, 0x04, s->rtcp_auth, sizeof(s->rtcp_auth)); | |
110 | 15 | return 0; | |
111 | } | ||
112 | |||
113 | 18 | static void create_iv(uint8_t *iv, const uint8_t *salt, uint64_t index, | |
114 | uint32_t ssrc) | ||
115 | { | ||
116 | uint8_t indexbuf[8]; | ||
117 | int i; | ||
118 | 18 | memset(iv, 0, 16); | |
119 | 18 | AV_WB32(&iv[4], ssrc); | |
120 | 18 | AV_WB64(indexbuf, index); | |
121 |
2/2✓ Branch 0 taken 144 times.
✓ Branch 1 taken 18 times.
|
162 | for (i = 0; i < 8; i++) // index << 16 |
122 | 144 | iv[6 + i] ^= indexbuf[i]; | |
123 |
2/2✓ Branch 0 taken 252 times.
✓ Branch 1 taken 18 times.
|
270 | for (i = 0; i < 14; i++) |
124 | 252 | iv[i] ^= salt[i]; | |
125 | 18 | } | |
126 | |||
127 | 12 | int ff_srtp_decrypt(struct SRTPContext *s, uint8_t *buf, int *lenptr) | |
128 | { | ||
129 | 12 | uint8_t iv[16] = { 0 }, hmac[20]; | |
130 | 12 | int len = *lenptr; | |
131 | 12 | int av_uninit(seq_largest); | |
132 | 12 | uint32_t ssrc, av_uninit(roc); | |
133 | uint64_t index; | ||
134 | int rtcp, hmac_size; | ||
135 | |||
136 | // TODO: Missing replay protection | ||
137 | |||
138 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (len < 2) |
139 | ✗ | return AVERROR_INVALIDDATA; | |
140 | |||
141 |
5/8✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 6 times.
|
12 | rtcp = RTP_PT_IS_RTCP(buf[1]); |
142 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | hmac_size = rtcp ? s->rtcp_hmac_size : s->rtp_hmac_size; |
143 | |||
144 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (len < hmac_size) |
145 | ✗ | return AVERROR_INVALIDDATA; | |
146 | |||
147 | // Authentication HMAC | ||
148 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | av_hmac_init(s->hmac, rtcp ? s->rtcp_auth : s->rtp_auth, sizeof(s->rtp_auth)); |
149 | // If MKI is used, this should exclude the MKI as well | ||
150 | 12 | av_hmac_update(s->hmac, buf, len - hmac_size); | |
151 | |||
152 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (!rtcp) { |
153 | 6 | int seq = AV_RB16(buf + 2); | |
154 | uint32_t v; | ||
155 | uint8_t rocbuf[4]; | ||
156 | |||
157 | // RFC 3711 section 3.3.1, appendix A | ||
158 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | seq_largest = s->seq_initialized ? s->seq_largest : seq; |
159 | 6 | v = roc = s->roc; | |
160 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (seq_largest < 32768) { |
161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (seq - seq_largest > 32768) |
162 | ✗ | v = roc - 1; | |
163 | } else { | ||
164 | ✗ | if (seq_largest - 32768 > seq) | |
165 | ✗ | v = roc + 1; | |
166 | } | ||
167 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (v == roc) { |
168 | 6 | seq_largest = FFMAX(seq_largest, seq); | |
169 | ✗ | } else if (v == roc + 1) { | |
170 | ✗ | seq_largest = seq; | |
171 | ✗ | roc = v; | |
172 | } | ||
173 | 6 | index = seq + (((uint64_t)v) << 16); | |
174 | |||
175 | 6 | AV_WB32(rocbuf, roc); | |
176 | 6 | av_hmac_update(s->hmac, rocbuf, 4); | |
177 | } | ||
178 | |||
179 | 12 | av_hmac_final(s->hmac, hmac, sizeof(hmac)); | |
180 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (memcmp(hmac, buf + len - hmac_size, hmac_size)) { |
181 | ✗ | av_log(NULL, AV_LOG_WARNING, "HMAC mismatch\n"); | |
182 | ✗ | return AVERROR_INVALIDDATA; | |
183 | } | ||
184 | |||
185 | 12 | len -= hmac_size; | |
186 | 12 | *lenptr = len; | |
187 | |||
188 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (len < 12) |
189 | ✗ | return AVERROR_INVALIDDATA; | |
190 | |||
191 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (rtcp) { |
192 | 6 | uint32_t srtcp_index = AV_RB32(buf + len - 4); | |
193 | 6 | len -= 4; | |
194 | 6 | *lenptr = len; | |
195 | |||
196 | 6 | ssrc = AV_RB32(buf + 4); | |
197 | 6 | index = srtcp_index & 0x7fffffff; | |
198 | |||
199 | 6 | buf += 8; | |
200 | 6 | len -= 8; | |
201 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (!(srtcp_index & 0x80000000)) |
202 | ✗ | return 0; | |
203 | } else { | ||
204 | int ext, csrc; | ||
205 | 6 | s->seq_initialized = 1; | |
206 | 6 | s->seq_largest = seq_largest; | |
207 | 6 | s->roc = roc; | |
208 | |||
209 | 6 | csrc = buf[0] & 0x0f; | |
210 | 6 | ext = buf[0] & 0x10; | |
211 | 6 | ssrc = AV_RB32(buf + 8); | |
212 | |||
213 | 6 | buf += 12; | |
214 | 6 | len -= 12; | |
215 | |||
216 | 6 | buf += 4 * csrc; | |
217 | 6 | len -= 4 * csrc; | |
218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (len < 0) |
219 | ✗ | return AVERROR_INVALIDDATA; | |
220 | |||
221 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (ext) { |
222 | ✗ | if (len < 4) | |
223 | ✗ | return AVERROR_INVALIDDATA; | |
224 | ✗ | ext = (AV_RB16(buf + 2) + 1) * 4; | |
225 | ✗ | if (len < ext) | |
226 | ✗ | return AVERROR_INVALIDDATA; | |
227 | ✗ | len -= ext; | |
228 | ✗ | buf += ext; | |
229 | } | ||
230 | } | ||
231 | |||
232 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | create_iv(iv, rtcp ? s->rtcp_salt : s->rtp_salt, index, ssrc); |
233 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | av_aes_init(s->aes, rtcp ? s->rtcp_key : s->rtp_key, 128, 0); |
234 | 12 | encrypt_counter(s->aes, iv, buf, len); | |
235 | |||
236 | 12 | return 0; | |
237 | } | ||
238 | |||
239 | 6 | int ff_srtp_encrypt(struct SRTPContext *s, const uint8_t *in, int len, | |
240 | uint8_t *out, int outlen) | ||
241 | { | ||
242 | 6 | uint8_t iv[16] = { 0 }, hmac[20]; | |
243 | uint64_t index; | ||
244 | uint32_t ssrc; | ||
245 | int rtcp, hmac_size, padding; | ||
246 | uint8_t *buf; | ||
247 | |||
248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (len < 8) |
249 | ✗ | return AVERROR_INVALIDDATA; | |
250 | |||
251 |
5/8✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 3 times.
|
6 | rtcp = RTP_PT_IS_RTCP(in[1]); |
252 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | hmac_size = rtcp ? s->rtcp_hmac_size : s->rtp_hmac_size; |
253 | 6 | padding = hmac_size; | |
254 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (rtcp) |
255 | 3 | padding += 4; // For the RTCP index | |
256 | |||
257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (len + padding > outlen) |
258 | ✗ | return 0; | |
259 | |||
260 | 6 | memcpy(out, in, len); | |
261 | 6 | buf = out; | |
262 | |||
263 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (rtcp) { |
264 | 3 | ssrc = AV_RB32(buf + 4); | |
265 | 3 | index = s->rtcp_index++; | |
266 | |||
267 | 3 | buf += 8; | |
268 | 3 | len -= 8; | |
269 | } else { | ||
270 | int ext, csrc; | ||
271 | 3 | int seq = AV_RB16(buf + 2); | |
272 | |||
273 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (len < 12) |
274 | ✗ | return AVERROR_INVALIDDATA; | |
275 | |||
276 | 3 | ssrc = AV_RB32(buf + 8); | |
277 | |||
278 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (seq < s->seq_largest) |
279 | ✗ | s->roc++; | |
280 | 3 | s->seq_largest = seq; | |
281 | 3 | index = seq + (((uint64_t)s->roc) << 16); | |
282 | |||
283 | 3 | csrc = buf[0] & 0x0f; | |
284 | 3 | ext = buf[0] & 0x10; | |
285 | |||
286 | 3 | buf += 12; | |
287 | 3 | len -= 12; | |
288 | |||
289 | 3 | buf += 4 * csrc; | |
290 | 3 | len -= 4 * csrc; | |
291 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (len < 0) |
292 | ✗ | return AVERROR_INVALIDDATA; | |
293 | |||
294 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (ext) { |
295 | ✗ | if (len < 4) | |
296 | ✗ | return AVERROR_INVALIDDATA; | |
297 | ✗ | ext = (AV_RB16(buf + 2) + 1) * 4; | |
298 | ✗ | if (len < ext) | |
299 | ✗ | return AVERROR_INVALIDDATA; | |
300 | ✗ | len -= ext; | |
301 | ✗ | buf += ext; | |
302 | } | ||
303 | } | ||
304 | |||
305 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | create_iv(iv, rtcp ? s->rtcp_salt : s->rtp_salt, index, ssrc); |
306 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | av_aes_init(s->aes, rtcp ? s->rtcp_key : s->rtp_key, 128, 0); |
307 | 6 | encrypt_counter(s->aes, iv, buf, len); | |
308 | |||
309 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (rtcp) { |
310 | 3 | AV_WB32(buf + len, 0x80000000 | index); | |
311 | 3 | len += 4; | |
312 | } | ||
313 | |||
314 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | av_hmac_init(s->hmac, rtcp ? s->rtcp_auth : s->rtp_auth, sizeof(s->rtp_auth)); |
315 | 6 | av_hmac_update(s->hmac, out, buf + len - out); | |
316 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (!rtcp) { |
317 | uint8_t rocbuf[4]; | ||
318 | 3 | AV_WB32(rocbuf, s->roc); | |
319 | 3 | av_hmac_update(s->hmac, rocbuf, 4); | |
320 | } | ||
321 | 6 | av_hmac_final(s->hmac, hmac, sizeof(hmac)); | |
322 | |||
323 | 6 | memcpy(buf + len, hmac, hmac_size); | |
324 | 6 | len += hmac_size; | |
325 | 6 | return buf + len - out; | |
326 | } | ||
327 |