https://www.iso.org/standard/68042.html
Signed-off-by: Nachiket Tarate <nachiket.program...@gmail.com> --- libavformat/isom.h | 1 + libavformat/mov.c | 86 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/libavformat/isom.h b/libavformat/isom.h index 5a6d504090..5a17cb9c07 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -237,6 +237,7 @@ typedef struct MOVStreamContext { int has_sidx; // If there is an sidx entry for this stream. struct { struct AVAESCTR* aes_ctr; + struct AVAES *aes_ctx; unsigned int per_sample_iv_size; // Either 0, 8, or 16. AVEncryptionInfo *default_encrypted_sample; MOVEncryptionIndex *encryption_index; diff --git a/libavformat/mov.c b/libavformat/mov.c index 43c55ef4a4..5eda5f3822 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -6623,15 +6623,10 @@ static int mov_read_dfla(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } -static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *sample, uint8_t *input, int size) +static int cenc_scheme_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *sample, uint8_t *input, int size) { int i, ret; - if (sample->scheme != MKBETAG('c','e','n','c') || sample->crypt_byte_block != 0 || sample->skip_byte_block != 0) { - av_log(c->fc, AV_LOG_ERROR, "Only the 'cenc' encryption scheme is supported\n"); - return AVERROR_PATCHWELCOME; - } - if (!sc->cenc.aes_ctr) { /* initialize the cipher */ sc->cenc.aes_ctr = av_aes_ctr_alloc(); @@ -6654,6 +6649,7 @@ static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *s } for (i = 0; i < sample->subsample_count; i++) { + if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) { av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n"); return AVERROR_INVALIDDATA; @@ -6677,6 +6673,84 @@ static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *s return 0; } +static int cbcs_scheme_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *sample, uint8_t *input, int size) +{ + int i, ret; + int encrypted_blocks; + uint8_t iv[16]; + + if (!sc->cenc.aes_ctx) { + /* initialize the cipher */ + sc->cenc.aes_ctx = av_aes_alloc(); + if (!sc->cenc.aes_ctx) { + return AVERROR(ENOMEM); + } + + ret = av_aes_init(sc->cenc.aes_ctx, c->decryption_key, 16 * 8, 1); + if (ret < 0) { + return ret; + } + } + + /* whole-block full sample encryption */ + if (!sample->subsample_count) { + /* decrypt the whole packet */ + memcpy(iv, sample->iv, 16); + av_aes_crypt(sc->cenc.aes_ctx, input, input, size/16, iv, 1); + return 0; + } + + for (i = 0; i < sample->subsample_count; i++) { + + if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) { + av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n"); + return AVERROR_INVALIDDATA; + } + + /* skip the clear bytes */ + input += sample->subsamples[i].bytes_of_clear_data; + size -= sample->subsamples[i].bytes_of_clear_data; + + /* decrypt the encrypted bytes */ + memcpy(iv, sample->iv, 16); + encrypted_blocks = sample->subsamples[i].bytes_of_protected_data/16; + if (encrypted_blocks > 0) { + /* pattern encryption */ + if (sample->crypt_byte_block > 0 && sample->skip_byte_block > 0) { + uint8_t *data = input; + int rem_bytes = sample->subsamples[i].bytes_of_protected_data; + while (rem_bytes > 0) { + if (rem_bytes > 16*sample->crypt_byte_block) { + av_aes_crypt(sc->cenc.aes_ctx, data, data, sample->crypt_byte_block, iv, 1); + data += 16*sample->crypt_byte_block; + rem_bytes -= 16*sample->crypt_byte_block; + } + data += FFMIN(16*sample->skip_byte_block, rem_bytes); + rem_bytes -= FFMIN(16*sample->skip_byte_block, rem_bytes); + } + } else { + av_aes_crypt(sc->cenc.aes_ctx, input, input, encrypted_blocks, iv, 1); + } + } + input += sample->subsamples[i].bytes_of_protected_data; + size -= sample->subsamples[i].bytes_of_protected_data; + } + + return 0; +} + +static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *sample, uint8_t *input, int size) +{ + if (sample->scheme == MKBETAG('c','e','n','c') && sample->crypt_byte_block == 0 && sample->skip_byte_block == 0) { + return cenc_scheme_decrypt(c, sc, sample, input, size); + } else if (sample->scheme == MKBETAG('c','b','c','s')) { + return cbcs_scheme_decrypt(c, sc, sample, input, size); + } else { + av_log(c->fc, AV_LOG_ERROR, "Only 'cenc' and 'cbcs' encryption schemes are supported\n"); + return AVERROR_PATCHWELCOME; + } +} + static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPacket *pkt, int current_index) { MOVFragmentStreamInfo *frag_stream_info; -- 2.17.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".