| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Apple HTTP Live Streaming Sample Encryption/Decryption | ||
| 3 | * | ||
| 4 | * Copyright (c) 2021 Nachiket Tarate | ||
| 5 | * | ||
| 6 | * This file is part of FFmpeg. | ||
| 7 | * | ||
| 8 | * FFmpeg is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU Lesser General Public | ||
| 10 | * License as published by the Free Software Foundation; either | ||
| 11 | * version 2.1 of the License, or (at your option) any later version. | ||
| 12 | * | ||
| 13 | * FFmpeg is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 16 | * Lesser General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU Lesser General Public | ||
| 19 | * License along with FFmpeg; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | /** | ||
| 24 | * @file | ||
| 25 | * Apple HTTP Live Streaming Sample Encryption | ||
| 26 | * https://developer.apple.com/library/ios/documentation/AudioVideo/Conceptual/HLS_Sample_Encryption | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include "libavutil/aes.h" | ||
| 30 | #include "libavutil/channel_layout.h" | ||
| 31 | #include "libavutil/mem.h" | ||
| 32 | |||
| 33 | #include "hls_sample_encryption.h" | ||
| 34 | |||
| 35 | #include "libavcodec/adts_header.h" | ||
| 36 | #include "libavcodec/adts_parser.h" | ||
| 37 | #include "libavcodec/ac3tab.h" | ||
| 38 | #include "libavcodec/ac3_parser_internal.h" | ||
| 39 | |||
| 40 | |||
| 41 | typedef struct NALUnit { | ||
| 42 | uint8_t *data; | ||
| 43 | int type; | ||
| 44 | int length; | ||
| 45 | int start_code_length; | ||
| 46 | } NALUnit; | ||
| 47 | |||
| 48 | typedef struct AudioFrame { | ||
| 49 | uint8_t *data; | ||
| 50 | int length; | ||
| 51 | int header_length; | ||
| 52 | } AudioFrame; | ||
| 53 | |||
| 54 | typedef struct CodecParserContext { | ||
| 55 | const uint8_t *buf_ptr; | ||
| 56 | const uint8_t *buf_end; | ||
| 57 | } CodecParserContext; | ||
| 58 | |||
| 59 | static const int eac3_sample_rate_tab[] = { 48000, 44100, 32000, 0 }; | ||
| 60 | |||
| 61 | ✗ | void ff_hls_senc_read_audio_setup_info(HLSAudioSetupInfo *info, const uint8_t *buf, size_t size) | |
| 62 | { | ||
| 63 | ✗ | if (size < 8) | |
| 64 | ✗ | return; | |
| 65 | |||
| 66 | ✗ | info->codec_tag = AV_RL32(buf); | |
| 67 | |||
| 68 | /* Always keep this list in sync with the one from hls_read_header() */ | ||
| 69 | ✗ | if (info->codec_tag == MKTAG('z','a','a','c')) | |
| 70 | ✗ | info->codec_id = AV_CODEC_ID_AAC; | |
| 71 | ✗ | else if (info->codec_tag == MKTAG('z','a','c','3')) | |
| 72 | ✗ | info->codec_id = AV_CODEC_ID_AC3; | |
| 73 | ✗ | else if (info->codec_tag == MKTAG('z','e','c','3')) | |
| 74 | ✗ | info->codec_id = AV_CODEC_ID_EAC3; | |
| 75 | else | ||
| 76 | ✗ | info->codec_id = AV_CODEC_ID_NONE; | |
| 77 | |||
| 78 | ✗ | buf += 4; | |
| 79 | ✗ | info->priming = AV_RL16(buf); | |
| 80 | ✗ | buf += 2; | |
| 81 | ✗ | info->version = *buf++; | |
| 82 | ✗ | info->setup_data_length = *buf++; | |
| 83 | |||
| 84 | ✗ | if (info->setup_data_length > size - 8) | |
| 85 | ✗ | info->setup_data_length = size - 8; | |
| 86 | |||
| 87 | ✗ | if (info->setup_data_length > HLS_MAX_AUDIO_SETUP_DATA_LEN) | |
| 88 | ✗ | return; | |
| 89 | |||
| 90 | ✗ | memcpy(info->setup_data, buf, info->setup_data_length); | |
| 91 | } | ||
| 92 | |||
| 93 | ✗ | int ff_hls_senc_parse_audio_setup_info(AVStream *st, HLSAudioSetupInfo *info) | |
| 94 | { | ||
| 95 | ✗ | int ret = 0; | |
| 96 | |||
| 97 | ✗ | st->codecpar->codec_tag = info->codec_tag; | |
| 98 | |||
| 99 | ✗ | if (st->codecpar->codec_id == AV_CODEC_ID_AAC) | |
| 100 | ✗ | return 0; | |
| 101 | |||
| 102 | ✗ | if (st->codecpar->codec_id != AV_CODEC_ID_AC3 && st->codecpar->codec_id != AV_CODEC_ID_EAC3) | |
| 103 | ✗ | return AVERROR_INVALIDDATA; | |
| 104 | |||
| 105 | ✗ | if (st->codecpar->codec_id == AV_CODEC_ID_AC3) { | |
| 106 | ✗ | AC3HeaderInfo *ac3hdr = NULL; | |
| 107 | |||
| 108 | ✗ | ret = avpriv_ac3_parse_header(&ac3hdr, info->setup_data, info->setup_data_length); | |
| 109 | ✗ | if (ret < 0) { | |
| 110 | ✗ | av_free(ac3hdr); | |
| 111 | ✗ | return ret; | |
| 112 | } | ||
| 113 | |||
| 114 | ✗ | st->codecpar->sample_rate = ac3hdr->sample_rate; | |
| 115 | ✗ | av_channel_layout_uninit(&st->codecpar->ch_layout); | |
| 116 | ✗ | av_channel_layout_from_mask(&st->codecpar->ch_layout, ac3hdr->channel_layout); | |
| 117 | ✗ | st->codecpar->bit_rate = ac3hdr->bit_rate; | |
| 118 | |||
| 119 | ✗ | av_free(ac3hdr); | |
| 120 | } else { /* Parse 'dec3' EC3SpecificBox */ | ||
| 121 | GetBitContext gb; | ||
| 122 | uint64_t mask; | ||
| 123 | int data_rate, fscod, acmod, lfeon; | ||
| 124 | |||
| 125 | ✗ | ret = init_get_bits8(&gb, info->setup_data, info->setup_data_length); | |
| 126 | ✗ | if (ret < 0) | |
| 127 | ✗ | return AVERROR_INVALIDDATA; | |
| 128 | |||
| 129 | ✗ | data_rate = get_bits(&gb, 13); | |
| 130 | ✗ | skip_bits(&gb, 3); | |
| 131 | ✗ | fscod = get_bits(&gb, 2); | |
| 132 | ✗ | skip_bits(&gb, 10); | |
| 133 | ✗ | acmod = get_bits(&gb, 3); | |
| 134 | ✗ | lfeon = get_bits(&gb, 1); | |
| 135 | |||
| 136 | ✗ | st->codecpar->sample_rate = eac3_sample_rate_tab[fscod]; | |
| 137 | |||
| 138 | ✗ | mask = ff_ac3_channel_layout_tab[acmod]; | |
| 139 | ✗ | if (lfeon) | |
| 140 | ✗ | mask |= AV_CH_LOW_FREQUENCY; | |
| 141 | |||
| 142 | ✗ | av_channel_layout_uninit(&st->codecpar->ch_layout); | |
| 143 | ✗ | av_channel_layout_from_mask(&st->codecpar->ch_layout, mask); | |
| 144 | |||
| 145 | ✗ | st->codecpar->bit_rate = data_rate*1000; | |
| 146 | } | ||
| 147 | |||
| 148 | ✗ | return 0; | |
| 149 | } | ||
| 150 | |||
| 151 | /* | ||
| 152 | * Remove start code emulation prevention 0x03 bytes | ||
| 153 | */ | ||
| 154 | ✗ | static void remove_scep_3_bytes(NALUnit *nalu) | |
| 155 | { | ||
| 156 | ✗ | int i = 0; | |
| 157 | ✗ | int j = 0; | |
| 158 | |||
| 159 | ✗ | uint8_t *data = nalu->data; | |
| 160 | |||
| 161 | ✗ | while (i < nalu->length) { | |
| 162 | ✗ | if (nalu->length - i > 3 && AV_RB24(&data[i]) == 0x000003) { | |
| 163 | ✗ | data[j++] = data[i++]; | |
| 164 | ✗ | data[j++] = data[i++]; | |
| 165 | ✗ | i++; | |
| 166 | } else { | ||
| 167 | ✗ | data[j++] = data[i++]; | |
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | ✗ | nalu->length = j; | |
| 172 | ✗ | } | |
| 173 | |||
| 174 | ✗ | static int get_next_nal_unit(CodecParserContext *ctx, NALUnit *nalu) | |
| 175 | { | ||
| 176 | ✗ | const uint8_t *nalu_start = ctx->buf_ptr; | |
| 177 | |||
| 178 | ✗ | if (ctx->buf_end - ctx->buf_ptr >= 4 && AV_RB32(ctx->buf_ptr) == 0x00000001) | |
| 179 | ✗ | nalu->start_code_length = 4; | |
| 180 | ✗ | else if (ctx->buf_end - ctx->buf_ptr >= 3 && AV_RB24(ctx->buf_ptr) == 0x000001) | |
| 181 | ✗ | nalu->start_code_length = 3; | |
| 182 | else /* No start code at the beginning of the NAL unit */ | ||
| 183 | ✗ | return -1; | |
| 184 | |||
| 185 | ✗ | ctx->buf_ptr += nalu->start_code_length; | |
| 186 | |||
| 187 | ✗ | while (ctx->buf_ptr < ctx->buf_end) { | |
| 188 | ✗ | if (ctx->buf_end - ctx->buf_ptr >= 4 && AV_RB32(ctx->buf_ptr) == 0x00000001) | |
| 189 | break; | ||
| 190 | ✗ | else if (ctx->buf_end - ctx->buf_ptr >= 3 && AV_RB24(ctx->buf_ptr) == 0x000001) | |
| 191 | ✗ | break; | |
| 192 | ✗ | ctx->buf_ptr++; | |
| 193 | } | ||
| 194 | |||
| 195 | ✗ | nalu->data = (uint8_t *)nalu_start + nalu->start_code_length; | |
| 196 | ✗ | nalu->length = ctx->buf_ptr - nalu->data; | |
| 197 | ✗ | nalu->type = *nalu->data & 0x1F; | |
| 198 | |||
| 199 | ✗ | return 0; | |
| 200 | } | ||
| 201 | |||
| 202 | ✗ | static int decrypt_nal_unit(HLSCryptoContext *crypto_ctx, NALUnit *nalu) | |
| 203 | { | ||
| 204 | ✗ | int ret = 0; | |
| 205 | int rem_bytes; | ||
| 206 | uint8_t *data; | ||
| 207 | uint8_t iv[16]; | ||
| 208 | |||
| 209 | ✗ | ret = av_aes_init(crypto_ctx->aes_ctx, crypto_ctx->key, 16 * 8, 1); | |
| 210 | ✗ | if (ret < 0) | |
| 211 | ✗ | return ret; | |
| 212 | |||
| 213 | /* Remove start code emulation prevention 0x03 bytes */ | ||
| 214 | ✗ | remove_scep_3_bytes(nalu); | |
| 215 | |||
| 216 | ✗ | data = nalu->data + 32; | |
| 217 | ✗ | rem_bytes = nalu->length - 32; | |
| 218 | |||
| 219 | ✗ | memcpy(iv, crypto_ctx->iv, 16); | |
| 220 | |||
| 221 | ✗ | while (rem_bytes > 0) { | |
| 222 | ✗ | if (rem_bytes > 16) { | |
| 223 | ✗ | av_aes_crypt(crypto_ctx->aes_ctx, data, data, 1, iv, 1); | |
| 224 | ✗ | data += 16; | |
| 225 | ✗ | rem_bytes -= 16; | |
| 226 | } | ||
| 227 | ✗ | data += FFMIN(144, rem_bytes); | |
| 228 | ✗ | rem_bytes -= FFMIN(144, rem_bytes); | |
| 229 | } | ||
| 230 | |||
| 231 | ✗ | return 0; | |
| 232 | } | ||
| 233 | |||
| 234 | ✗ | static int decrypt_video_frame(HLSCryptoContext *crypto_ctx, AVPacket *pkt) | |
| 235 | { | ||
| 236 | ✗ | int ret = 0; | |
| 237 | CodecParserContext ctx; | ||
| 238 | NALUnit nalu; | ||
| 239 | uint8_t *data_ptr; | ||
| 240 | ✗ | int move_nalu = 0; | |
| 241 | |||
| 242 | ✗ | memset(&ctx, 0, sizeof(ctx)); | |
| 243 | ✗ | ctx.buf_ptr = pkt->data; | |
| 244 | ✗ | ctx.buf_end = pkt->data + pkt->size; | |
| 245 | |||
| 246 | ✗ | data_ptr = pkt->data; | |
| 247 | |||
| 248 | ✗ | while (ctx.buf_ptr < ctx.buf_end) { | |
| 249 | ✗ | memset(&nalu, 0, sizeof(nalu)); | |
| 250 | ✗ | ret = get_next_nal_unit(&ctx, &nalu); | |
| 251 | ✗ | if (ret < 0) | |
| 252 | ✗ | return ret; | |
| 253 | ✗ | if ((nalu.type == 0x01 || nalu.type == 0x05) && nalu.length > 48) { | |
| 254 | ✗ | int encrypted_nalu_length = nalu.length; | |
| 255 | ✗ | ret = decrypt_nal_unit(crypto_ctx, &nalu); | |
| 256 | ✗ | if (ret < 0) | |
| 257 | ✗ | return ret; | |
| 258 | ✗ | move_nalu = nalu.length != encrypted_nalu_length; | |
| 259 | } | ||
| 260 | ✗ | if (move_nalu) | |
| 261 | ✗ | memmove(data_ptr, nalu.data - nalu.start_code_length, nalu.start_code_length + nalu.length); | |
| 262 | ✗ | data_ptr += nalu.start_code_length + nalu.length; | |
| 263 | } | ||
| 264 | |||
| 265 | ✗ | av_shrink_packet(pkt, data_ptr - pkt->data); | |
| 266 | |||
| 267 | ✗ | return 0; | |
| 268 | } | ||
| 269 | |||
| 270 | ✗ | static int get_next_adts_frame(CodecParserContext *ctx, AudioFrame *frame) | |
| 271 | { | ||
| 272 | ✗ | int ret = 0; | |
| 273 | |||
| 274 | ✗ | AACADTSHeaderInfo *adts_hdr = NULL; | |
| 275 | |||
| 276 | /* Find next sync word 0xFFF */ | ||
| 277 | ✗ | while (ctx->buf_ptr < ctx->buf_end - 1) { | |
| 278 | ✗ | if (*ctx->buf_ptr == 0xFF && (*(ctx->buf_ptr + 1) & 0xF0) == 0xF0) | |
| 279 | ✗ | break; | |
| 280 | ✗ | ctx->buf_ptr++; | |
| 281 | } | ||
| 282 | |||
| 283 | ✗ | if (ctx->buf_ptr >= ctx->buf_end - 1) | |
| 284 | ✗ | return -1; | |
| 285 | |||
| 286 | ✗ | frame->data = (uint8_t*)ctx->buf_ptr; | |
| 287 | |||
| 288 | ✗ | ret = avpriv_adts_header_parse (&adts_hdr, frame->data, ctx->buf_end - frame->data); | |
| 289 | ✗ | if (ret < 0) | |
| 290 | ✗ | return ret; | |
| 291 | |||
| 292 | ✗ | frame->header_length = adts_hdr->crc_absent ? AV_AAC_ADTS_HEADER_SIZE : AV_AAC_ADTS_HEADER_SIZE + 2; | |
| 293 | ✗ | frame->length = adts_hdr->frame_length; | |
| 294 | |||
| 295 | ✗ | av_free(adts_hdr); | |
| 296 | |||
| 297 | ✗ | return 0; | |
| 298 | } | ||
| 299 | |||
| 300 | ✗ | static int get_next_ac3_eac3_sync_frame(CodecParserContext *ctx, AudioFrame *frame) | |
| 301 | { | ||
| 302 | ✗ | int ret = 0; | |
| 303 | |||
| 304 | ✗ | AC3HeaderInfo *hdr = NULL; | |
| 305 | |||
| 306 | /* Find next sync word 0x0B77 */ | ||
| 307 | ✗ | while (ctx->buf_ptr < ctx->buf_end - 1) { | |
| 308 | ✗ | if (*ctx->buf_ptr == 0x0B && *(ctx->buf_ptr + 1) == 0x77) | |
| 309 | ✗ | break; | |
| 310 | ✗ | ctx->buf_ptr++; | |
| 311 | } | ||
| 312 | |||
| 313 | ✗ | if (ctx->buf_ptr >= ctx->buf_end - 1) | |
| 314 | ✗ | return -1; | |
| 315 | |||
| 316 | ✗ | frame->data = (uint8_t*)ctx->buf_ptr; | |
| 317 | ✗ | frame->header_length = 0; | |
| 318 | |||
| 319 | ✗ | ret = avpriv_ac3_parse_header(&hdr, frame->data, ctx->buf_end - frame->data); | |
| 320 | ✗ | if (ret < 0) { | |
| 321 | ✗ | av_free(hdr); | |
| 322 | ✗ | return ret; | |
| 323 | } | ||
| 324 | |||
| 325 | ✗ | frame->length = hdr->frame_size; | |
| 326 | |||
| 327 | ✗ | av_free(hdr); | |
| 328 | |||
| 329 | ✗ | return 0; | |
| 330 | } | ||
| 331 | |||
| 332 | ✗ | static int get_next_sync_frame(enum AVCodecID codec_id, CodecParserContext *ctx, AudioFrame *frame) | |
| 333 | { | ||
| 334 | ✗ | if (codec_id == AV_CODEC_ID_AAC) | |
| 335 | ✗ | return get_next_adts_frame(ctx, frame); | |
| 336 | ✗ | else if (codec_id == AV_CODEC_ID_AC3 || codec_id == AV_CODEC_ID_EAC3) | |
| 337 | ✗ | return get_next_ac3_eac3_sync_frame(ctx, frame); | |
| 338 | else | ||
| 339 | ✗ | return AVERROR_INVALIDDATA; | |
| 340 | } | ||
| 341 | |||
| 342 | ✗ | static int decrypt_sync_frame(enum AVCodecID codec_id, HLSCryptoContext *crypto_ctx, AudioFrame *frame) | |
| 343 | { | ||
| 344 | ✗ | int ret = 0; | |
| 345 | uint8_t *data; | ||
| 346 | int num_of_encrypted_blocks; | ||
| 347 | |||
| 348 | ✗ | ret = av_aes_init(crypto_ctx->aes_ctx, crypto_ctx->key, 16 * 8, 1); | |
| 349 | ✗ | if (ret < 0) | |
| 350 | ✗ | return ret; | |
| 351 | |||
| 352 | ✗ | data = frame->data + frame->header_length + 16; | |
| 353 | |||
| 354 | ✗ | num_of_encrypted_blocks = (frame->length - frame->header_length - 16)/16; | |
| 355 | |||
| 356 | ✗ | av_aes_crypt(crypto_ctx->aes_ctx, data, data, num_of_encrypted_blocks, crypto_ctx->iv, 1); | |
| 357 | |||
| 358 | ✗ | return 0; | |
| 359 | } | ||
| 360 | |||
| 361 | ✗ | static int decrypt_audio_frame(enum AVCodecID codec_id, HLSCryptoContext *crypto_ctx, AVPacket *pkt) | |
| 362 | { | ||
| 363 | ✗ | int ret = 0; | |
| 364 | CodecParserContext ctx; | ||
| 365 | AudioFrame frame; | ||
| 366 | |||
| 367 | ✗ | memset(&ctx, 0, sizeof(ctx)); | |
| 368 | ✗ | ctx.buf_ptr = pkt->data; | |
| 369 | ✗ | ctx.buf_end = pkt->data + pkt->size; | |
| 370 | |||
| 371 | ✗ | while (ctx.buf_ptr < ctx.buf_end) { | |
| 372 | ✗ | memset(&frame, 0, sizeof(frame)); | |
| 373 | ✗ | ret = get_next_sync_frame(codec_id, &ctx, &frame); | |
| 374 | ✗ | if (ret < 0) | |
| 375 | ✗ | return ret; | |
| 376 | ✗ | if (frame.length - frame.header_length > 31) { | |
| 377 | ✗ | ret = decrypt_sync_frame(codec_id, crypto_ctx, &frame); | |
| 378 | ✗ | if (ret < 0) | |
| 379 | ✗ | return ret; | |
| 380 | } | ||
| 381 | ✗ | ctx.buf_ptr += frame.length; | |
| 382 | } | ||
| 383 | |||
| 384 | ✗ | return 0; | |
| 385 | } | ||
| 386 | |||
| 387 | ✗ | int ff_hls_senc_decrypt_frame(enum AVCodecID codec_id, HLSCryptoContext *crypto_ctx, AVPacket *pkt) | |
| 388 | { | ||
| 389 | ✗ | if (codec_id == AV_CODEC_ID_H264) | |
| 390 | ✗ | return decrypt_video_frame(crypto_ctx, pkt); | |
| 391 | ✗ | else if (codec_id == AV_CODEC_ID_AAC || codec_id == AV_CODEC_ID_AC3 || codec_id == AV_CODEC_ID_EAC3) | |
| 392 | ✗ | return decrypt_audio_frame(codec_id, crypto_ctx, pkt); | |
| 393 | |||
| 394 | ✗ | return AVERROR_INVALIDDATA; | |
| 395 | } | ||
| 396 |