Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 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 "rtp.h" |
||
28 | #include "rtpdec.h" |
||
29 | #include "srtp.h" |
||
30 | |||
31 | void ff_srtp_free(struct SRTPContext *s) |
||
32 | { |
||
33 | if (!s) |
||
34 | return; |
||
35 | av_freep(&s->aes); |
||
36 | if (s->hmac) |
||
37 | av_hmac_free(s->hmac); |
||
38 | s->hmac = NULL; |
||
39 | } |
||
40 | |||
41 | static void encrypt_counter(struct AVAES *aes, uint8_t *iv, uint8_t *outbuf, |
||
42 | int outlen) |
||
43 | { |
||
44 | int i, j, outpos; |
||
45 | for (i = 0, outpos = 0; outpos < outlen; i++) { |
||
46 | uint8_t keystream[16]; |
||
47 | AV_WB16(&iv[14], i); |
||
48 | av_aes_crypt(aes, keystream, iv, 1, NULL, 0); |
||
49 | for (j = 0; j < 16 && outpos < outlen; j++, outpos++) |
||
50 | outbuf[outpos] ^= keystream[j]; |
||
51 | } |
||
52 | } |
||
53 | |||
54 | static void derive_key(struct AVAES *aes, const uint8_t *salt, int label, |
||
55 | uint8_t *out, int outlen) |
||
56 | { |
||
57 | uint8_t input[16] = { 0 }; |
||
58 | memcpy(input, salt, 14); |
||
59 | // Key derivation rate assumed to be zero |
||
60 | input[14 - 7] ^= label; |
||
61 | memset(out, 0, outlen); |
||
62 | encrypt_counter(aes, input, out, outlen); |
||
63 | } |
||
64 | |||
65 | int ff_srtp_set_crypto(struct SRTPContext *s, const char *suite, |
||
66 | const char *params) |
||
67 | { |
||
68 | uint8_t buf[30]; |
||
69 | |||
70 | ff_srtp_free(s); |
||
71 | |||
72 | // RFC 4568 |
||
73 | if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_80") || |
||
74 | !strcmp(suite, "SRTP_AES128_CM_HMAC_SHA1_80")) { |
||
75 | s->rtp_hmac_size = s->rtcp_hmac_size = 10; |
||
76 | } else if (!strcmp(suite, "AES_CM_128_HMAC_SHA1_32")) { |
||
77 | s->rtp_hmac_size = s->rtcp_hmac_size = 4; |
||
78 | } else if (!strcmp(suite, "SRTP_AES128_CM_HMAC_SHA1_32")) { |
||
79 | // RFC 5764 section 4.1.2 |
||
80 | s->rtp_hmac_size = 4; |
||
81 | s->rtcp_hmac_size = 10; |
||
82 | } else { |
||
83 | av_log(NULL, AV_LOG_WARNING, "SRTP Crypto suite %s not supported\n", |
||
84 | suite); |
||
85 | return AVERROR(EINVAL); |
||
86 | } |
||
87 | if (av_base64_decode(buf, params, sizeof(buf)) != sizeof(buf)) { |
||
88 | av_log(NULL, AV_LOG_WARNING, "Incorrect amount of SRTP params\n"); |
||
89 | return AVERROR(EINVAL); |
||
90 | } |
||
91 | // MKI and lifetime not handled yet |
||
92 | s->aes = av_aes_alloc(); |
||
93 | s->hmac = av_hmac_alloc(AV_HMAC_SHA1); |
||
94 | if (!s->aes || !s->hmac) |
||
95 | return AVERROR(ENOMEM); |
||
96 | memcpy(s->master_key, buf, 16); |
||
97 | memcpy(s->master_salt, buf + 16, 14); |
||
98 | |||
99 | // RFC 3711 |
||
100 | av_aes_init(s->aes, s->master_key, 128, 0); |
||
101 | |||
102 | derive_key(s->aes, s->master_salt, 0x00, s->rtp_key, sizeof(s->rtp_key)); |
||
103 | derive_key(s->aes, s->master_salt, 0x02, s->rtp_salt, sizeof(s->rtp_salt)); |
||
104 | derive_key(s->aes, s->master_salt, 0x01, s->rtp_auth, sizeof(s->rtp_auth)); |
||
105 | |||
106 | derive_key(s->aes, s->master_salt, 0x03, s->rtcp_key, sizeof(s->rtcp_key)); |
||
107 | derive_key(s->aes, s->master_salt, 0x05, s->rtcp_salt, sizeof(s->rtcp_salt)); |
||
108 | derive_key(s->aes, s->master_salt, 0x04, s->rtcp_auth, sizeof(s->rtcp_auth)); |
||
109 | return 0; |
||
110 | } |
||
111 | |||
112 | static void create_iv(uint8_t *iv, const uint8_t *salt, uint64_t index, |
||
113 | uint32_t ssrc) |
||
114 | { |
||
115 | uint8_t indexbuf[8]; |
||
116 | int i; |
||
117 | memset(iv, 0, 16); |
||
118 | AV_WB32(&iv[4], ssrc); |
||
119 | AV_WB64(indexbuf, index); |
||
120 | for (i = 0; i < 8; i++) // index << 16 |
||
121 | iv[6 + i] ^= indexbuf[i]; |
||
122 | for (i = 0; i < 14; i++) |
||
123 | iv[i] ^= salt[i]; |
||
124 | } |
||
125 | |||
126 | int ff_srtp_decrypt(struct SRTPContext *s, uint8_t *buf, int *lenptr) |
||
127 | { |
||
128 | uint8_t iv[16] = { 0 }, hmac[20]; |
||
129 | int len = *lenptr; |
||
130 | int av_uninit(seq_largest); |
||
131 | uint32_t ssrc, av_uninit(roc); |
||
132 | uint64_t index; |
||
133 | int rtcp, hmac_size; |
||
134 | |||
135 | // TODO: Missing replay protection |
||
136 | |||
137 | if (len < 2) |
||
138 | return AVERROR_INVALIDDATA; |
||
139 | |||
140 | rtcp = RTP_PT_IS_RTCP(buf[1]); |
||
141 | hmac_size = rtcp ? s->rtcp_hmac_size : s->rtp_hmac_size; |
||
142 | |||
143 | if (len < hmac_size) |
||
144 | return AVERROR_INVALIDDATA; |
||
145 | |||
146 | // Authentication HMAC |
||
147 | av_hmac_init(s->hmac, rtcp ? s->rtcp_auth : s->rtp_auth, sizeof(s->rtp_auth)); |
||
148 | // If MKI is used, this should exclude the MKI as well |
||
149 | av_hmac_update(s->hmac, buf, len - hmac_size); |
||
150 | |||
151 | if (!rtcp) { |
||
152 | int seq = AV_RB16(buf + 2); |
||
153 | uint32_t v; |
||
154 | uint8_t rocbuf[4]; |
||
155 | |||
156 | // RFC 3711 section 3.3.1, appendix A |
||
157 | seq_largest = s->seq_initialized ? s->seq_largest : seq; |
||
158 | v = roc = s->roc; |
||
159 | if (seq_largest < 32768) { |
||
160 | if (seq - seq_largest > 32768) |
||
161 | v = roc - 1; |
||
162 | } else { |
||
163 | if (seq_largest - 32768 > seq) |
||
164 | v = roc + 1; |
||
165 | } |
||
166 | if (v == roc) { |
||
167 | seq_largest = FFMAX(seq_largest, seq); |
||
168 | } else if (v == roc + 1) { |
||
169 | seq_largest = seq; |
||
170 | roc = v; |
||
171 | } |
||
172 | index = seq + (((uint64_t)v) << 16); |
||
173 | |||
174 | AV_WB32(rocbuf, roc); |
||
175 | av_hmac_update(s->hmac, rocbuf, 4); |
||
176 | } |
||
177 | |||
178 | av_hmac_final(s->hmac, hmac, sizeof(hmac)); |
||
179 | if (memcmp(hmac, buf + len - hmac_size, hmac_size)) { |
||
180 | av_log(NULL, AV_LOG_WARNING, "HMAC mismatch\n"); |
||
181 | return AVERROR_INVALIDDATA; |
||
182 | } |
||
183 | |||
184 | len -= hmac_size; |
||
185 | *lenptr = len; |
||
186 | |||
187 | if (len < 12) |
||
188 | return AVERROR_INVALIDDATA; |
||
189 | |||
190 | if (rtcp) { |
||
191 | uint32_t srtcp_index = AV_RB32(buf + len - 4); |
||
192 | len -= 4; |
||
193 | *lenptr = len; |
||
194 | |||
195 | ssrc = AV_RB32(buf + 4); |
||
196 | index = srtcp_index & 0x7fffffff; |
||
197 | |||
198 | buf += 8; |
||
199 | len -= 8; |
||
200 | if (!(srtcp_index & 0x80000000)) |
||
201 | return 0; |
||
202 | } else { |
||
203 | int ext, csrc; |
||
204 | s->seq_initialized = 1; |
||
205 | s->seq_largest = seq_largest; |
||
206 | s->roc = roc; |
||
207 | |||
208 | csrc = buf[0] & 0x0f; |
||
209 | ext = buf[0] & 0x10; |
||
210 | ssrc = AV_RB32(buf + 8); |
||
211 | |||
212 | buf += 12; |
||
213 | len -= 12; |
||
214 | |||
215 | buf += 4 * csrc; |
||
216 | len -= 4 * csrc; |
||
217 | if (len < 0) |
||
218 | return AVERROR_INVALIDDATA; |
||
219 | |||
220 | if (ext) { |
||
221 | if (len < 4) |
||
222 | return AVERROR_INVALIDDATA; |
||
223 | ext = (AV_RB16(buf + 2) + 1) * 4; |
||
224 | if (len < ext) |
||
225 | return AVERROR_INVALIDDATA; |
||
226 | len -= ext; |
||
227 | buf += ext; |
||
228 | } |
||
229 | } |
||
230 | |||
231 | create_iv(iv, rtcp ? s->rtcp_salt : s->rtp_salt, index, ssrc); |
||
232 | av_aes_init(s->aes, rtcp ? s->rtcp_key : s->rtp_key, 128, 0); |
||
233 | encrypt_counter(s->aes, iv, buf, len); |
||
234 | |||
235 | return 0; |
||
236 | } |
||
237 | |||
238 | int ff_srtp_encrypt(struct SRTPContext *s, const uint8_t *in, int len, |
||
239 | uint8_t *out, int outlen) |
||
240 | { |
||
241 | uint8_t iv[16] = { 0 }, hmac[20]; |
||
242 | uint64_t index; |
||
243 | uint32_t ssrc; |
||
244 | int rtcp, hmac_size, padding; |
||
245 | uint8_t *buf; |
||
246 | |||
247 | if (len < 8) |
||
248 | return AVERROR_INVALIDDATA; |
||
249 | |||
250 | rtcp = RTP_PT_IS_RTCP(in[1]); |
||
251 | hmac_size = rtcp ? s->rtcp_hmac_size : s->rtp_hmac_size; |
||
252 | padding = hmac_size; |
||
253 | if (rtcp) |
||
254 | padding += 4; // For the RTCP index |
||
255 | |||
256 | if (len + padding > outlen) |
||
257 | return 0; |
||
258 | |||
259 | memcpy(out, in, len); |
||
260 | buf = out; |
||
261 | |||
262 | if (rtcp) { |
||
263 | ssrc = AV_RB32(buf + 4); |
||
264 | index = s->rtcp_index++; |
||
265 | |||
266 | buf += 8; |
||
267 | len -= 8; |
||
268 | } else { |
||
269 | int ext, csrc; |
||
270 | int seq = AV_RB16(buf + 2); |
||
271 | |||
272 | if (len < 12) |
||
273 | return AVERROR_INVALIDDATA; |
||
274 | |||
275 | ssrc = AV_RB32(buf + 8); |
||
276 | |||
277 | if (seq < s->seq_largest) |
||
278 | s->roc++; |
||
279 | s->seq_largest = seq; |
||
280 | index = seq + (((uint64_t)s->roc) << 16); |
||
281 | |||
282 | csrc = buf[0] & 0x0f; |
||
283 | ext = buf[0] & 0x10; |
||
284 | |||
285 | buf += 12; |
||
286 | len -= 12; |
||
287 | |||
288 | buf += 4 * csrc; |
||
289 | len -= 4 * csrc; |
||
290 | if (len < 0) |
||
291 | return AVERROR_INVALIDDATA; |
||
292 | |||
293 | if (ext) { |
||
294 | if (len < 4) |
||
295 | return AVERROR_INVALIDDATA; |
||
296 | ext = (AV_RB16(buf + 2) + 1) * 4; |
||
297 | if (len < ext) |
||
298 | return AVERROR_INVALIDDATA; |
||
299 | len -= ext; |
||
300 | buf += ext; |
||
301 | } |
||
302 | } |
||
303 | |||
304 | create_iv(iv, rtcp ? s->rtcp_salt : s->rtp_salt, index, ssrc); |
||
305 | av_aes_init(s->aes, rtcp ? s->rtcp_key : s->rtp_key, 128, 0); |
||
306 | encrypt_counter(s->aes, iv, buf, len); |
||
307 | |||
308 | if (rtcp) { |
||
309 | AV_WB32(buf + len, 0x80000000 | index); |
||
310 | len += 4; |
||
311 | } |
||
312 | |||
313 | av_hmac_init(s->hmac, rtcp ? s->rtcp_auth : s->rtp_auth, sizeof(s->rtp_auth)); |
||
314 | av_hmac_update(s->hmac, out, buf + len - out); |
||
315 | if (!rtcp) { |
||
316 | uint8_t rocbuf[4]; |
||
317 | AV_WB32(rocbuf, s->roc); |
||
318 | av_hmac_update(s->hmac, rocbuf, 4); |
||
319 | } |
||
320 | av_hmac_final(s->hmac, hmac, sizeof(hmac)); |
||
321 | |||
322 | memcpy(buf + len, hmac, hmac_size); |
||
323 | len += hmac_size; |
||
324 | return buf + len - out; |
||
325 | } |
||
326 | |||
327 | #ifdef TEST |
||
328 | #include |
||
329 | |||
330 | static const char *aes128_80_key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn"; |
||
331 | |||
332 | static const uint8_t rtp_aes128_80[] = { |
||
333 | // RTP header |
||
334 | 0x80, 0xe0, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, |
||
335 | // encrypted payload |
||
336 | 0x62, 0x69, 0x76, 0xca, 0xc5, |
||
337 | // HMAC |
||
338 | 0xa1, 0xac, 0x1b, 0xb4, 0xa0, 0x1c, 0xd5, 0x49, 0x28, 0x99, |
||
339 | }; |
||
340 | |||
341 | static const uint8_t rtcp_aes128_80[] = { |
||
342 | // RTCP header |
||
343 | 0x81, 0xc9, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78, |
||
344 | // encrypted payload |
||
345 | 0x8a, 0xac, 0xdc, 0xa5, 0x4c, 0xf6, 0x78, 0xa6, 0x62, 0x8f, 0x24, 0xda, |
||
346 | 0x6c, 0x09, 0x3f, 0xa9, 0x28, 0x7a, 0xb5, 0x7f, 0x1f, 0x0f, 0xc9, 0x35, |
||
347 | // RTCP index |
||
348 | 0x80, 0x00, 0x00, 0x03, |
||
349 | // HMAC |
||
350 | 0xe9, 0x3b, 0xc0, 0x5c, 0x0c, 0x06, 0x9f, 0xab, 0xc0, 0xde, |
||
351 | }; |
||
352 | |||
353 | static const char *aes128_32_key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn"; |
||
354 | |||
355 | static const uint8_t rtp_aes128_32[] = { |
||
356 | // RTP header |
||
357 | 0x80, 0xe0, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, |
||
358 | // encrypted payload |
||
359 | 0x62, 0x69, 0x76, 0xca, 0xc5, |
||
360 | // HMAC |
||
361 | 0xa1, 0xac, 0x1b, 0xb4, |
||
362 | }; |
||
363 | |||
364 | static const uint8_t rtcp_aes128_32[] = { |
||
365 | // RTCP header |
||
366 | 0x81, 0xc9, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78, |
||
367 | // encrypted payload |
||
368 | 0x35, 0xe9, 0xb5, 0xff, 0x0d, 0xd1, 0xde, 0x70, 0x74, 0x10, 0xaa, 0x1b, |
||
369 | 0xb2, 0x8d, 0xf0, 0x20, 0x02, 0x99, 0x6b, 0x1b, 0x0b, 0xd0, 0x47, 0x34, |
||
370 | // RTCP index |
||
371 | 0x80, 0x00, 0x00, 0x04, |
||
372 | // HMAC |
||
373 | 0x5b, 0xd2, 0xa9, 0x9d, |
||
374 | }; |
||
375 | |||
376 | static const char *aes128_80_32_key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn"; |
||
377 | |||
378 | static const uint8_t rtp_aes128_80_32[] = { |
||
379 | // RTP header |
||
380 | 0x80, 0xe0, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, |
||
381 | // encrypted payload |
||
382 | 0x62, 0x69, 0x76, 0xca, 0xc5, |
||
383 | // HMAC |
||
384 | 0xa1, 0xac, 0x1b, 0xb4, |
||
385 | }; |
||
386 | |||
387 | static const uint8_t rtcp_aes128_80_32[] = { |
||
388 | // RTCP header |
||
389 | 0x81, 0xc9, 0x00, 0x07, 0x12, 0x34, 0x56, 0x78, |
||
390 | // encrypted payload |
||
391 | 0xd6, 0xae, 0xc1, 0x58, 0x63, 0x70, 0xc9, 0x88, 0x66, 0x26, 0x1c, 0x53, |
||
392 | 0xff, 0x5d, 0x5d, 0x2b, 0x0f, 0x8c, 0x72, 0x3e, 0xc9, 0x1d, 0x43, 0xf9, |
||
393 | // RTCP index |
||
394 | 0x80, 0x00, 0x00, 0x05, |
||
395 | // HMAC |
||
396 | 0x09, 0x16, 0xb4, 0x27, 0x9a, 0xe9, 0x92, 0x26, 0x4e, 0x10, |
||
397 | }; |
||
398 | |||
399 | static void print_data(const uint8_t *buf, int len) |
||
400 | { |
||
401 | int i; |
||
402 | for (i = 0; i < len; i++) |
||
403 | printf("%02x", buf[i]); |
||
404 | printf("\n"); |
||
405 | } |
||
406 | |||
407 | static int test_decrypt(struct SRTPContext *srtp, const uint8_t *in, int len, |
||
408 | uint8_t *out) |
||
409 | { |
||
410 | memcpy(out, in, len); |
||
411 | if (!ff_srtp_decrypt(srtp, out, &len)) { |
||
412 | print_data(out, len); |
||
413 | return len; |
||
414 | } else |
||
415 | return -1; |
||
416 | } |
||
417 | |||
418 | static void test_encrypt(const uint8_t *data, int in_len, const char *suite, |
||
419 | const char *key) |
||
420 | { |
||
421 | struct SRTPContext enc = { 0 }, dec = { 0 }; |
||
422 | int len; |
||
423 | char buf[RTP_MAX_PACKET_LENGTH]; |
||
424 | ff_srtp_set_crypto(&enc, suite, key); |
||
425 | ff_srtp_set_crypto(&dec, suite, key); |
||
426 | len = ff_srtp_encrypt(&enc, data, in_len, buf, sizeof(buf)); |
||
427 | if (!ff_srtp_decrypt(&dec, buf, &len)) { |
||
428 | if (len == in_len && !memcmp(buf, data, len)) |
||
429 | printf("Decrypted content matches input\n"); |
||
430 | else |
||
431 | printf("Decrypted content doesn't match input\n"); |
||
432 | } else { |
||
433 | printf("Decryption failed\n"); |
||
434 | } |
||
435 | ff_srtp_free(&enc); |
||
436 | ff_srtp_free(&dec); |
||
437 | } |
||
438 | |||
439 | int main(void) |
||
440 | { |
||
441 | static const char *aes128_80_suite = "AES_CM_128_HMAC_SHA1_80"; |
||
442 | static const char *aes128_32_suite = "AES_CM_128_HMAC_SHA1_32"; |
||
443 | static const char *aes128_80_32_suite = "SRTP_AES128_CM_HMAC_SHA1_32"; |
||
444 | static const char *test_key = "abcdefghijklmnopqrstuvwxyz1234567890ABCD"; |
||
445 | uint8_t buf[RTP_MAX_PACKET_LENGTH]; |
||
446 | struct SRTPContext srtp = { 0 }; |
||
447 | int len; |
||
448 | ff_srtp_set_crypto(&srtp, aes128_80_suite, aes128_80_key); |
||
449 | len = test_decrypt(&srtp, rtp_aes128_80, sizeof(rtp_aes128_80), buf); |
||
450 | test_encrypt(buf, len, aes128_80_suite, test_key); |
||
451 | test_encrypt(buf, len, aes128_32_suite, test_key); |
||
452 | test_encrypt(buf, len, aes128_80_32_suite, test_key); |
||
453 | test_decrypt(&srtp, rtcp_aes128_80, sizeof(rtcp_aes128_80), buf); |
||
454 | test_encrypt(buf, len, aes128_80_suite, test_key); |
||
455 | test_encrypt(buf, len, aes128_32_suite, test_key); |
||
456 | test_encrypt(buf, len, aes128_80_32_suite, test_key); |
||
457 | ff_srtp_free(&srtp); |
||
458 | |||
459 | memset(&srtp, 0, sizeof(srtp)); // Clear the context |
||
460 | ff_srtp_set_crypto(&srtp, aes128_32_suite, aes128_32_key); |
||
461 | test_decrypt(&srtp, rtp_aes128_32, sizeof(rtp_aes128_32), buf); |
||
462 | test_decrypt(&srtp, rtcp_aes128_32, sizeof(rtcp_aes128_32), buf); |
||
463 | ff_srtp_free(&srtp); |
||
464 | |||
465 | memset(&srtp, 0, sizeof(srtp)); // Clear the context |
||
466 | ff_srtp_set_crypto(&srtp, aes128_80_32_suite, aes128_80_32_key); |
||
467 | test_decrypt(&srtp, rtp_aes128_80_32, sizeof(rtp_aes128_80_32), buf); |
||
468 | test_decrypt(&srtp, rtcp_aes128_80_32, sizeof(rtcp_aes128_80_32), buf); |
||
469 | ff_srtp_free(&srtp); |
||
470 | return 0; |
||
471 | } |
||
472 | #endif /* TEST */>>>>><>>>>>>>>><>>>>>><>>>>> |