# HG changeset patch # User bcoudurier # Date 1171198233 0 # Node ID de2cf54eb68f0ce5f4b14e7d34e84024efbd8cd7 # Parent d8c6b719a0700b98f7ee94870126abbb9d53aa3b mxf aes decryption support, patch by Reimar, simplified to only look for first crypto context, will be extended once we get files with multiple cryptocontext, and hope that they won't have broken container ul diff -r d8c6b719a070 -r de2cf54eb68f mxf.c --- a/mxf.c Sun Feb 11 12:37:28 2007 +0000 +++ b/mxf.c Sun Feb 11 12:50:33 2007 +0000 @@ -46,6 +46,7 @@ //#define DEBUG #include "avformat.h" +#include "aes.h" typedef uint8_t UID[16]; @@ -60,8 +61,16 @@ Descriptor, Track, EssenceContainerData, + CryptoContext, }; +typedef struct MXFCryptoContext { + UID uid; + enum MXFMetadataSetType type; + UID context_uid; + UID source_container_ul; +} MXFCryptoContext; + typedef struct MXFStructuralComponent { UID uid; enum MXFMetadataSetType type; @@ -137,6 +146,7 @@ int metadata_sets_count; const uint8_t *sync_key; AVFormatContext *fc; + struct AVAES *aesc; } MXFContext; typedef struct KLVPacket { @@ -173,6 +183,7 @@ static const uint8_t mxf_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01 }; /* complete keys to match */ static const uint8_t mxf_encrypted_triplet_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 }; +static const uint8_t mxf_encrypted_essence_container[] = { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0b,0x01,0x00 }; #define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y))) @@ -245,6 +256,63 @@ return 0; } +static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv) +{ + static const uint8_t checkv[16] = {0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b}; + MXFContext *mxf = s->priv_data; + ByteIOContext *pb = &s->pb; + offset_t end = url_ftell(pb) + klv->length; + uint64_t size; + uint64_t orig_size; + uint64_t plaintext_size; + uint8_t ivec[16]; + uint8_t tmpbuf[16]; + int index; + + if (!mxf->aesc && s->key && s->keylen == 16) { + mxf->aesc = av_malloc(av_aes_size); + av_aes_init(mxf->aesc, s->key, 128, 1); + } + // crypto context + url_fskip(pb, klv_decode_ber_length(pb)); + // plaintext offset + klv_decode_ber_length(pb); + plaintext_size = get_be64(pb); + // source klv key + klv_decode_ber_length(pb); + get_buffer(pb, klv->key, 16); + if (!IS_KLV_KEY(klv, mxf_essence_element_key)) goto err_out; + index = mxf_get_stream_index(s, klv); + if (index < 0) goto err_out; + // source size + klv_decode_ber_length(pb); + orig_size = get_be64(pb); + if (orig_size < plaintext_size) goto err_out; + // enc. code + size = klv_decode_ber_length(pb); + if (size < 32 || size - 32 < orig_size) goto err_out; + get_buffer(pb, ivec, 16); + get_buffer(pb, tmpbuf, 16); + if (mxf->aesc) + av_aes_crypt(mxf->aesc, tmpbuf, tmpbuf, 1, ivec, 1); + if (memcmp(tmpbuf, checkv, 16)) + av_log(s, AV_LOG_ERROR, "probably incorrect decryption key\n"); + size -= 32; + av_get_packet(pb, pkt, size); + size -= plaintext_size; + if (mxf->aesc) + av_aes_crypt(mxf->aesc, &pkt->data[plaintext_size], + &pkt->data[plaintext_size], size >> 4, ivec, 1); + pkt->size = orig_size; + pkt->stream_index = index; + url_fskip(pb, end - url_ftell(pb)); + return 0; + +err_out: + url_fskip(pb, end - url_ftell(pb)); + return -1; +} + static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) { MXFContext *mxf = s->priv_data; @@ -259,9 +327,13 @@ PRINT_KEY("read packet", klv.key); #endif if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { + int res = mxf_decrypt_triplet(s, pkt, &klv); mxf->sync_key = mxf_encrypted_triplet_key; - av_log(s, AV_LOG_ERROR, "encrypted triplet not supported\n"); - return -1; + if (res < 0) { + av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); + return -1; + } + return 0; } if (IS_KLV_KEY(klv.key, mxf_essence_element_key)) { int index = mxf_get_stream_index(s, &klv); @@ -294,6 +366,19 @@ return 0; } +static int mxf_read_metadata_cryptographic_context(MXFCryptoContext *cryptocontext, ByteIOContext *pb, int tag) +{ + switch(tag) { + case 0xFFFE: + get_buffer(pb, cryptocontext->context_uid, 16); + break; + case 0xFFFD: + get_buffer(pb, cryptocontext->source_container_ul, 16); + break; + } + return 0; +} + static int mxf_read_metadata_content_storage(MXFContext *mxf, ByteIOContext *pb, int tag) { switch (tag) { @@ -601,6 +686,7 @@ MXFTrack *temp_track = NULL; MXFDescriptor *descriptor = NULL; MXFStructuralComponent *component = NULL; + UID *essence_container_ul = NULL; const MXFCodecUL *codec_ul = NULL; const MXFCodecUL *container_ul = NULL; AVStream *st; @@ -697,6 +783,19 @@ PRINT_KEY("essence codec ul", descriptor->essence_codec_ul); PRINT_KEY("essence container ul", descriptor->essence_container_ul); #endif + essence_container_ul = &descriptor->essence_container_ul; + /* HACK: replacing the original key with mxf_encrypted_essence_container + * is not allowed according to s429-6, try to find correct information anyway */ + if (IS_KLV_KEY(essence_container_ul, mxf_encrypted_essence_container)) { + av_log(mxf->fc, AV_LOG_INFO, "broken encrypted mxf file\n"); + for (k = 0; k < mxf->metadata_sets_count; k++) { + MXFMetadataSet *metadata = mxf->metadata_sets[k]; + if (metadata->type == CryptoContext) { + essence_container_ul = &((MXFCryptoContext *)metadata)->source_container_ul; + break; + } + } + } /* TODO: drop PictureEssenceCoding and SoundEssenceCompression, only check EssenceContainer */ codec_ul = mxf_get_codec_ul(mxf_codec_uls, &descriptor->essence_codec_ul); st->codec->codec_id = codec_ul->id; @@ -705,7 +804,7 @@ st->codec->extradata_size = descriptor->extradata_size; } if (st->codec->codec_type == CODEC_TYPE_VIDEO) { - container_ul = mxf_get_codec_ul(mxf_picture_essence_container_uls, &descriptor->essence_container_ul); + container_ul = mxf_get_codec_ul(mxf_picture_essence_container_uls, essence_container_ul); if (st->codec->codec_id == CODEC_ID_NONE) st->codec->codec_id = container_ul->id; st->codec->width = descriptor->width; @@ -713,7 +812,7 @@ st->codec->bits_per_sample = descriptor->bits_per_sample; /* Uncompressed */ st->need_parsing = 2; /* only parse headers */ } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) { - container_ul = mxf_get_codec_ul(mxf_sound_essence_container_uls, &descriptor->essence_container_ul); + container_ul = mxf_get_codec_ul(mxf_sound_essence_container_uls, essence_container_ul); if (st->codec->codec_id == CODEC_ID_NONE) st->codec->codec_id = container_ul->id; st->codec->channels = descriptor->channels; @@ -759,6 +858,7 @@ { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 }, mxf_read_metadata_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* AES3 */ { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3A,0x00 }, mxf_read_metadata_track, sizeof(MXFTrack), Track }, /* Static Track */ { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3B,0x00 }, mxf_read_metadata_track, sizeof(MXFTrack), Track }, /* Generic Track */ + { { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x04,0x01,0x02,0x02,0x00,0x00 }, mxf_read_metadata_cryptographic_context, sizeof(MXFCryptoContext), CryptoContext }, { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, NULL, 0, AnyType }, }; @@ -823,7 +923,8 @@ #ifdef DEBUG PRINT_KEY("read header", klv.key); #endif - if (IS_KLV_KEY(klv.key, mxf_essence_element_key)) { + if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) || + IS_KLV_KEY(klv.key, mxf_essence_element_key)) { /* FIXME avoid seek */ url_fseek(&s->pb, klv.offset, SEEK_SET); break; @@ -868,6 +969,7 @@ av_freep(&mxf->metadata_sets[i]); } av_freep(&mxf->metadata_sets); + av_freep(&mxf->aesc); return 0; }