Hello, attached patch is just a demonstration. I'd like to get comments, and preferably also some help for the actual implementation. Problems: 1) The key is hardcoded (dkey variable). Is adding uint8_t *key, int keylen to AVFormatContext an acceptable to "export" this? 2) Seeking does not work with encrypted files 3) SSL configure stuff is needed - or alternatively a standalone AES implementation might be interesting as well... 4) Code needs quite a bit of general cleanup, it seems much too complicated to me for what it does Any volunteers to help out? Greetings, Reimar D?ffinger -------------- next part -------------- Index: libavformat/mxf.c =================================================================== --- libavformat/mxf.c (revision 7437) +++ libavformat/mxf.c (working copy) @@ -45,6 +45,7 @@ //#define DEBUG +#include <openssl/aes.h> #include "avformat.h" typedef uint8_t UID[16]; @@ -173,6 +174,7 @@ /* partial keys to match */ static const uint8_t mxf_header_partition_pack_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x02 }; static const uint8_t mxf_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01 }; +static const uint8_t mxf_encrypted_triplet_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x04,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x7e,0x01,0x00 }; #define IS_KLV_KEY(x, y) (!memcmp(x, y, sizeof(y))) @@ -181,20 +183,8 @@ static int64_t klv_decode_ber_length(ByteIOContext *pb) { - int64_t size = 0; - uint8_t length = get_byte(pb); - int type = length >> 7; - - if (type) { /* long form */ - int bytes_num = length & 0x7f; - /* SMPTE 379M 5.3.4 guarantee that bytes_num must not exceed 8 bytes */ - if (bytes_num > 8) - return -1; - while (bytes_num--) - size = size << 8 | get_byte(pb); - } else { - size = length & 0x7f; - } + uint64_t size; + GET_BER(size, get_byte(pb), return -1;); return size; } @@ -210,6 +200,8 @@ { int i; + if (!IS_KLV_KEY(klv->key, mxf_essence_element_key)) + return -1; for (i = 0; i < s->nb_streams; i++) { MXFTrack *track = s->streams[i]->priv_data; /* SMPTE 379M 7.3 */ @@ -228,8 +220,7 @@ if (length > 61444) /* worst case PAL 1920 samples 8 channels */ return -1; - get_buffer(pb, buffer, length); - av_new_packet(pkt, length); + memcpy(buffer, pkt->data, length); data_ptr = pkt->data; end_ptr = buffer + length; buf_ptr = buffer + 4; /* skip SMPTE 331M header */ @@ -249,6 +240,62 @@ return 0; } +static int get_enc_src_klv(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}; + uint64_t size; + uint64_t source_sz; + uint64_t ptoff; + uint8_t *p = pkt->data; + uint8_t *end = &pkt->data[pkt->size]; + char ivec[16]; + uint8_t dkey[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + AES_KEY key; + AES_set_decrypt_key(dkey, 128, &key); + // crypto context + if (&p[9 + 16] > end) return -1; + GET_BER(size, *p++ , return -1;); + if (size != 16) return -1; + p += size; + // plaintext offset + if (&p[9 + 8] > end) return -1; + GET_BER(size, *p++ , return -1;); + if (size != 8) return -1; + ptoff = (BE_32(p) << 32) | BE_32(p + 4); + p += size; + // source klv key + if (&p[9 + 16] > end) return -1; + GET_BER(size, *p++ , return -1;); + if (size != 16) return -1; + memcpy(&klv->key, p, 16); + p += 16; + // source size + if (&p[9 + 8] > end) return -1; + GET_BER(size, *p++ , return -1;); + if (size != 8) return -1; + source_sz = BE_32(p + 4); + p += size; + // enc. code + if (&p[9] > end) return -1; + GET_BER(size, *p++ , return -1;); + if (&p[size] > end || &p[size] < p) return -1; + if (size < 32) return -1; + memcpy(ivec, p, 16); + p += 16; + AES_cbc_encrypt(p, &pkt->data[ptoff], 16, &key, ivec, AES_DECRYPT); + if (memcmp(&pkt->data[ptoff], checkv, 16)) return -1; + p += 16; + size -= 32; + if (size < ptoff) return -1; + memcpy(pkt->data, p, ptoff); + size -= ptoff; + p += ptoff; + if (size < source_sz) return -1; + AES_cbc_encrypt(p, &pkt->data[ptoff], size, &key, ivec, AES_DECRYPT); + pkt->size = source_sz; + return 0; +} + static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) { KLVPacket klv; @@ -261,21 +308,27 @@ #ifdef DEBUG PRINT_KEY("read packet", klv.key); #endif - if (IS_KLV_KEY(klv.key, mxf_essence_element_key)) { - int index = mxf_get_stream_index(s, &klv); + if (IS_KLV_KEY(klv.key, mxf_essence_element_key) || + IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { + int index; + av_get_packet(&s->pb, pkt, klv.length); + if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) && + get_enc_src_klv(s, pkt, &klv) < 0) + av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); + index = mxf_get_stream_index(s, &klv); if (index < 0) { av_log(s, AV_LOG_ERROR, "error getting stream index\n"); - url_fskip(&s->pb, klv.length); + av_free_packet(pkt); return -1; } /* check for 8 channels AES3 element */ if (klv.key[12] == 0x06 && klv.key[13] == 0x01 && klv.key[14] == 0x10) { if (mxf_get_d10_aes3_packet(&s->pb, s->streams[index], pkt, klv.length) < 0) { av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n"); + av_free_packet(pkt); return -1; } - } else - av_get_packet(&s->pb, pkt, klv.length); + } pkt->stream_index = index; return 0; } else @@ -707,6 +760,7 @@ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, CODEC_ID_MPEG2VIDEO, Frame }, /* MPEG-ES Frame wrapped */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0xe0,0x02 }, CODEC_ID_MPEG2VIDEO, Clip }, /* MPEG-ES Clip wrapped, 0xe0 MPV stream id */ { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x04,0x61,0x07 }, CODEC_ID_MPEG2VIDEO, Clip }, /* MPEG-ES Custom wrapped, 0x61 ??? stream id */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x0D,0x01,0x03,0x01,0x02,0x0b,0x01,0x00 }, CODEC_ID_MPEG2VIDEO, Frame }, /* MPEG-ES Frame wrapped, encrypted ??? */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, CODEC_ID_NONE, Frame }, }; @@ -982,7 +1036,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_essence_element_key) || + IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { /* FIXME avoid seek */ url_fseek(&s->pb, klv.offset, SEEK_SET); break; Index: libavutil/common.h =================================================================== --- libavutil/common.h (revision 7437) +++ libavutil/common.h (working copy) @@ -201,6 +201,30 @@ #define MKBETAG(a,b,c,d) (d | (c << 8) | (b << 16) | (a << 24)) /*! + * \def GET_BER(val, GET_BYTE, ERROR) + * converts BER encoded integer (up to 8 bytes long) to its 64-bit value + * \param val is the output and should be of type uint64_t. It holds the converted + * 64 bit integer and should be a left value. + * \param GET_BYTE gets BER encoded bytes from any proper source. It can be + * a function or a statement whose return value or evaluated value is of type + * uint8_t. It will be executed up to 9 times. + * \param ERROR action that should be taken when an invalid BER byte is returned + * from GET_BYTE. It should be a statement that jumps out of the macro, + * like exit(), goto, return, break, or continue. + */ +#define GET_BER(val, GET_BYTE, ERROR)\ + val= GET_BYTE;\ + if (val & 0x80) { /* long form */\ + int bytes_num = val & 0x7f;\ + val = 0;\ + /* SMPTE 379M 5.3.4 guarantee that bytes_num must not exceed 8 bytes */\ + if (bytes_num > 8)\ + ERROR\ + while (bytes_num--)\ + val = val << 8 | GET_BYTE;\ + } + +/*! * \def GET_UTF8(val, GET_BYTE, ERROR) * converts a utf-8 character (up to 4 bytes long) to its 32-bit ucs-4 encoded form * \param val is the output and should be of type uint32_t. It holds the converted
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4