[Ffmpeg-devel] [RFC] MXF AES decryption
Baptiste Coudurier
baptiste.coudurier
Sun Jan 14 19:26:25 CET 2007
Hi
Reimar D?ffinger wrote:
> Hello,
> another little update.
> On Sat, Jan 13, 2007 at 06:24:30PM +0100, Michael Niedermayer wrote:
>> On Sat, Jan 13, 2007 at 02:13:37PM +0100, Reimar D?ffinger wrote:
> [...]
>>> The key in AVFormatParameters is supposed to be a string for easier
>>> extensibility and easy way to specify on commandline mostly.
>> iam unhappy with this, what about per stream keys? and why not simply
>> pass a uint8_t array? also i hate AVFormatParameters why not use
>> AVFormatContext ?
>
> Per stream keys: I'd like to ignore for now, they could be handled via
> AVStream, but
> 1) there also needs to be a way to associate keys to
> streams, so e.g. the key ID would have to be exported, too
> 2) A key somewhere else would probably still be needed, since it would
> not work for formats where either already the header parsing function
> needs a key and not work well for formats where AVStreams are added
> during playback.
> But I moved it to AVFormatContext in binary format with additional
> keylen field.
>
> Updated patch also should finally really fix seeking for encrypted
> files.
>
>>> The current format is just a hex string like "02045a...", 32 characters for
>>> AES-128 (the only format supported currently).
>>> IMO openssl should be replaced, it is too bloated for such a simple
>>> functionality but I'm not yet sure by what, not to mention that I am not
>>> up to date if it still has such an inconvenient license...
>> <random bloated crpto lib> dependance for just AES is completely unacceptable
>> write your own 2 page implementation of AES
>
> It also uses now my aes128 code, which can also be switched to libgcrypt
> for whoever needs that final bit of speed our code does not yet provide.
>
> Greetings,
> Reimar D?ffinger
>
>
> ------------------------------------------------------------------------
>
> Index: libavformat/avformat.h
> ===================================================================
> --- libavformat/avformat.h (revision 7475)
> +++ libavformat/avformat.h (working copy)
> @@ -25,8 +25,8 @@
> extern "C" {
> #endif
>
> -#define LIBAVFORMAT_VERSION_INT ((51<<16)+(7<<8)+0)
> -#define LIBAVFORMAT_VERSION 51.7.0
> +#define LIBAVFORMAT_VERSION_INT ((51<<16)+(8<<8)+0)
> +#define LIBAVFORMAT_VERSION 51.8.0
> #define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT
>
> #define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION)
> @@ -361,6 +352,8 @@
> int loop_input;
> /* decoding: size of data to probe; encoding unused */
> unsigned int probesize;
> + const char *key;
> + int keylen;
> } AVFormatContext;
Why not uint8_t * ?
> [...[
> @@ -141,7 +166,9 @@
> UID content_storage_uid;
> MXFMetadataSet **metadata_sets;
> int metadata_sets_count;
> + UID *sync_key;
> AVFormatContext *fc;
Should not sync_key be uint8_t * ?
> typedef struct KLVPacket {
> @@ -174,6 +201,9 @@
> /* 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 };
> +/* 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)))
>
> @@ -207,6 +237,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 */
> @@ -225,8 +257,7 @@
Why is that hunk needed ? dont call get_stream_index if key is not
mxf_essence_element_key
> 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 */
> @@ -246,11 +277,58 @@
> return 0;
> }
>
> [...]
>
> +
> static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt)
> {
> KLVPacket klv;
>
> while (!url_feof(&s->pb)) {
> + int encrypted = 0;
> if (klv_read_packet(&klv, &s->pb) < 0) {
> av_log(s, AV_LOG_ERROR, "error reading KLV packet\n");
> return -1;
> @@ -258,21 +336,29 @@
> #ifdef DEBUG
> 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);
> + if (res < 0) {
> + av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n");
> + continue;
> + }
> + encrypted = 1;
> + }
> if (IS_KLV_KEY(klv.key, mxf_essence_element_key)) {
> int 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);
> return -1;
> }
> + if (!encrypted)
> + av_get_packet(&s->pb, pkt, klv.length);
> /* 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");
> return -1;
> }
> - } else
> - av_get_packet(&s->pb, pkt, klv.length);
> + }
> pkt->stream_index = index;
> return 0;
> } else
> @@ -562,6 +648,43 @@
> MXF_READ_LOCAL_TAGS_STOP(Descriptor, MXFDescriptor, descriptor)
> }
I would prefer calling mxf_get_stream_index from klv_decrypt_triplet,
and avoid using that encrypted var in the mail loop.
Also avoid one useless memcpy for unencrypted files and d10_aes3 stream
and that code should be to an AVBitstreamFilter anyway.
> [...]
>
> static int mxf_parse_structural_metadata(MXFContext *mxf)
> {
> MXFPackage *material_package = NULL;
> @@ -679,6 +823,7 @@
> const MXFCodecUL *codec_ul = NULL;
> const MXFCodecUL *container_ul = NULL;
> AVStream *st;
> + UID *essence_container_ul;
>
> if (!(material_track = mxf_resolve_strong_ref(mxf, &material_package->tracks_refs[i], Track))) {
> av_log(mxf->fc, AV_LOG_ERROR, "could not resolve material track strong ref\n");
> @@ -768,9 +913,16 @@
> av_log(mxf->fc, AV_LOG_INFO, "source track %d: stream %d, no descriptor found\n", source_track->track_id, st->index);
> continue;
> }
> + essence_container_ul = descriptor->essence_container_ul;
> + if (IS_KLV_KEY(essence_container_ul, mxf_encrypted_essence_container)) {
> + MXFCryptoContext *cc = mxf_find_track_cryptocontext(mxf, descriptor->linked_track_id);
> + if (cc)
> + essence_container_ul = cc->source_ul;
> + mxf->sync_key = mxf_encrypted_triplet_key;
> + }
That's wrong. descriptor essence container should be original source
coutainer. That file is broken. Working 100% solution must be
implemented, also linked track id is optional in S377M. Yes it is
complicated but a working 100% solution exists.
> [...]
>
> @@ -856,6 +1011,8 @@
> MXFContext *mxf = s->priv_data;
> KLVPacket klv;
>
> + mxf->aesc = aes128_init();
Init must be optional of course.
> if (!mxf_read_sync(&s->pb, mxf_header_partition_pack_key, 14)) {
> av_log(s, AV_LOG_ERROR, "could not find header partition pack key\n");
> return -1;
> @@ -872,7 +1029,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;
We could use header size in partition pack and stop if end is reached.
That should avoid seek and check for keys.
> [...]
>
> @@ -942,6 +1104,7 @@
> /* XXX: use MXF Index */
> static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags)
> {
> + MXFContext *mxf = s->priv_data;
> AVStream *st = s->streams[stream_index];
> int64_t seconds;
>
> @@ -951,7 +1114,7 @@
> sample_time = 0;
> seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den);
> url_fseek(&s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET);
> - if (!mxf_read_sync(&s->pb, mxf_essence_element_key, 12))
> + if (!mxf_read_sync(&s->pb, mxf->sync_key, 12))
> return -1;
>
> /* found KLV key */
>
Seek hunk looks ok.
--
Baptiste COUDURIER GnuPG Key Id: 0x5C1ABAAA
SMARTJOG S.A. http://www.smartjog.com
Key fingerprint 8D77134D20CC9220201FC5DB0AC9325C5C1ABAAA
Phone: +33 1 49966312
More information about the ffmpeg-devel
mailing list