[vlc-devel] [PATCH] dcp: read encrypted DCPs

Denis Charmet typx at dinauz.org
Mon Mar 31 11:58:50 CEST 2014


Hi,

Le lundi 31 mars 2014 à 11:25:44, Simona-Marinela Prodea a écrit :
> Allow read of encrypted DCP with KDM
> ---
> @@ -72,6 +71,7 @@ static void Close( vlc_object_t * );
>  vlc_module_begin()
>      set_shortname( N_( "DCP" ) )
>      add_shortcut( "dcp" )
> +    add_loadfile( "kdm", "", KDM_HELP_TEXT, KDM_HELP_LONG_TEXT, false )
>      set_description( N_( "Digital Cinema Package module" ) )
>      set_capability( "access_demux", 0 )
>      set_category( CAT_INPUT )
> @@ -604,6 +604,8 @@ static int Demux( demux_t *p_demux )
>      block_t *p_video_frame = NULL, *p_audio_frame = NULL;
>  
>      PCM::FrameBuffer   AudioFrameBuff( p_sys->i_audio_buffer);
> +    AESDecContext *p_video_aes_ctx = NULL;
> +    AESDecContext *p_audio_aes_ctx = NULL;
>  
>      /* swaping video reels */
>      if  ( p_sys->frame_no == p_sys->p_dcp->video_reels[p_sys->i_video_reel].i_absolute_end )
> @@ -632,6 +634,18 @@ static int Demux( demux_t *p_demux )
>       }
>  
>      /* video frame */
> +
> +    /* initialize AES context, if reel is encrypted */
> +    if( p_sys->p_dcp->video_reels[p_sys->i_video_reel].p_key ) {
> +        p_video_aes_ctx = new (nothrow) AESDecContext;
Isn't it possible to just store your AESDecContext in the p_sys and only
call p_video_aes_ctx->InitKey() when needed? It would avoid to
allocate/free at each iteration.
> +        if( !p_video_aes_ctx )
> +            goto error;
> +        if( ! ASDCP_SUCCESS( p_video_aes_ctx->InitKey( p_sys->p_dcp->video_reels[p_sys->i_video_reel].p_key->getKey() ) ) ) {
> +            msg_Err( p_demux, "ASDCP failed to initialize AES key" );
> +            goto error;
> +        }
> +    }
> +
>      switch( p_sys->PictureEssType )
>      {
>          case ESS_JPEG_2000:
> @@ -646,13 +660,13 @@ static int Demux( demux_t *p_demux )
>                  goto error_asdcp;
>              if ( p_sys->PictureEssType == ESS_JPEG_2000_S ) {
>                  if ( ! ASDCP_SUCCESS(
> -                        p_sys->v_videoReader[p_sys->i_video_reel].p_PicMXFSReader->ReadFrame(nextFrame, JP2K::SP_LEFT, PicFrameBuff, 0, 0)) ) {
> +                        p_sys->v_videoReader[p_sys->i_video_reel].p_PicMXFSReader->ReadFrame(nextFrame, JP2K::SP_LEFT, PicFrameBuff, p_video_aes_ctx, 0)) ) {
>                      PicFrameBuff.SetData(0,0);
>                      goto error_asdcp;
>                  }
>               } else {
>                  if ( ! ASDCP_SUCCESS(
> -                        p_sys->v_videoReader[p_sys->i_video_reel].p_PicMXFReader->ReadFrame(nextFrame, PicFrameBuff, 0, 0)) ) {
> +                        p_sys->v_videoReader[p_sys->i_video_reel].p_PicMXFReader->ReadFrame(nextFrame, PicFrameBuff, p_video_aes_ctx, 0)) ) {
>                      PicFrameBuff.SetData(0,0);
>                      goto error_asdcp;
>                  }
> @@ -670,7 +684,7 @@ static int Demux( demux_t *p_demux )
>                  goto error_asdcp;
>  
>              if ( ! ASDCP_SUCCESS(
> -                    p_sys->v_videoReader[p_sys->i_video_reel].p_VideoMXFReader->ReadFrame(p_sys->frame_no + p_sys->p_dcp->video_reels[p_sys->i_video_reel].i_correction, VideoFrameBuff, 0, 0)) ) {
> +                    p_sys->v_videoReader[p_sys->i_video_reel].p_VideoMXFReader->ReadFrame(p_sys->frame_no + p_sys->p_dcp->video_reels[p_sys->i_video_reel].i_correction, VideoFrameBuff, p_video_aes_ctx, 0)) ) {
>                  VideoFrameBuff.SetData(0,0);
>                  goto error_asdcp;
>              }
> @@ -690,13 +704,25 @@ static int Demux( demux_t *p_demux )
>      if ( ( p_audio_frame = block_Alloc( p_sys->i_audio_buffer )) == NULL ) {
>          goto error;
>      }
> +
> +    /* initialize AES context, if reel is encrypted */
> +    if( p_sys->p_dcp->audio_reels[p_sys->i_audio_reel].p_key ) {
> +        p_audio_aes_ctx = new (nothrow) AESDecContext;
same than before.
> +        if( !p_audio_aes_ctx )
> +            goto error;
> +        if( ! ASDCP_SUCCESS( p_audio_aes_ctx->InitKey( p_sys->p_dcp->audio_reels[p_sys->i_audio_reel].p_key->getKey() ) ) ) {
> +            msg_Err( p_demux, "ASDCP failed to initialize AES key" );
> +            goto error;
> +        }
> +    }
> +
>      if ( ! ASDCP_SUCCESS(
>              AudioFrameBuff.SetData(p_audio_frame->p_buffer, p_sys->i_audio_buffer)) ) {
>          goto error_asdcp;
>      }
>  
>      if ( ! ASDCP_SUCCESS(
> -            p_sys->v_audioReader[p_sys->i_audio_reel].p_AudioMXFReader->ReadFrame(p_sys->frame_no + p_sys->p_dcp->audio_reels[p_sys->i_audio_reel].i_correction, AudioFrameBuff, 0, 0)) ) {
> +            p_sys->v_audioReader[p_sys->i_audio_reel].p_AudioMXFReader->ReadFrame(p_sys->frame_no + p_sys->p_dcp->audio_reels[p_sys->i_audio_reel].i_correction, AudioFrameBuff, p_audio_aes_ctx, 0)) ) {
>          AudioFrameBuff.SetData(0,0);
>          goto error_asdcp;
>      }
> @@ -721,6 +747,11 @@ static int Demux( demux_t *p_demux )
>  
>      p_sys->frame_no++;
>  
> +    if( p_video_aes_ctx )
> +        delete p_video_aes_ctx;
> +    if( p_audio_aes_ctx )
> +        delete p_audio_aes_ctx;
> +
>      return 1;
>  
>  error_asdcp:
> @@ -730,6 +761,10 @@ error:
>          block_Release(p_video_frame);
>      if (p_audio_frame)
>          block_Release(p_audio_frame);
> +    if( p_video_aes_ctx )
> +        delete p_video_aes_ctx;
> +    if( p_audio_aes_ctx )
> +        delete p_audio_aes_ctx;
>      return -1;
>  }
>  
> diff --git a/modules/access/dcp/dcpparser.cpp b/modules/access/dcp/dcpparser.cpp
> index cd42922..f72aab8 100644
> --- a/modules/access/dcp/dcpparser.cpp
> +++ b/modules/access/dcp/dcpparser.cpp
> @@ -9,6 +9,7 @@
>   *          Anthony Giniers
>   *          Ludovic Hoareau
>   *          Loukmane Dessai
> + *          Simona-Marinela Prodea <simona dot marinela dot prodea at gmail dot com>
>   *
>   * This program is free software; you can redistribute it and/or modify it
>   * under the terms of the GNU Lesser General Public License as published by
> @@ -33,17 +34,26 @@
>  # include "config.h"
>  #endif
>  
> +#define KDM_RSA_STRUCT_ID "f1dc124460169a0e85bc300642f866ab"    /* unique Structure ID for all RSA-encrypted AES keys in a KDM */
> +
>  /* VLC core API headers */
>  #include <vlc_common.h>
>  #include <vlc_plugin.h>
>  #include <vlc_xml.h>
>  #include <vlc_url.h>
> +#include <vlc_fs.h>
>  
>  #include <iostream>
>  #include <string>
>  #include <list>
>  #include <vector>
>  
> +/* OpenSSL headers */
> +#include <openssl/pem.h>
> +#include <openssl/rsa.h>
> +#include <openssl/err.h>
> +#include <openssl/ssl.h>
> +
>  #include "dcpparser.h"
>  
>  using namespace std;
> @@ -230,11 +240,13 @@ AssetMap::~AssetMap() { }
>  int AssetMap::Parse ( )
>  {
>      int type = 0;
> +    int retval;
>      int reel_nbr = 0;
>      int index = 0;
>      int sum_duration_vid = 0;
>      int sum_duration_aud = 0;
>      string node;
> +    char *psz_kdm_path;
>  
>      CPL  *cpl;
>      Reel *reel;
> @@ -337,6 +349,40 @@ int AssetMap::Parse ( )
>          return -1;
>      }
>  
> +    /* KDM, if needed */
> +    for( AssetList::iterator iter = _p_asset_list->begin(); iter != _p_asset_list->end(); ++iter )
> +        if( ! (*iter)->getKeyId().empty() )
> +        {
> +            msg_Dbg( p_demux, "DCP is encrypted, searching KDM file...");
> +            psz_kdm_path = var_InheritString( p_demux, "kdm" );
> +            if( !psz_kdm_path || !*psz_kdm_path )
> +            {
> +                msg_Err( p_demux, "cryptographic key IDs found in CPL and no path to KDM given");
> +                if( psz_kdm_path )
> +                    free( psz_kdm_path );
The if is useless, you can call free on NULL pointers.
> +                this->CloseXml();
> +                return VLC_EGENERIC;
> +            }
> +            KDM *p_kdm = new (nothrow) KDM( p_demux, psz_kdm_path, p_dcp );
Do you need it on the heap if you delete it so quickly after?
> +            if( unlikely( p_kdm == NULL ) )
> +            {
> +                if( psz_kdm_path )
> +                    free( psz_kdm_path );
> +                this->CloseXml();
> +                return VLC_ENOMEM;
> +            }
> +            if( psz_kdm_path )
> +                free( psz_kdm_path );
> +            if( ( retval = p_kdm->Parse() ) )
> +            {
> +                delete p_kdm;
> +                this->CloseXml();
> +                return retval;
> +            }
> +            delete p_kdm;
> +            break;
> +        }
> +
>      reel_nbr = cpl->getReelList().size();
>      for(index = 0; index != reel_nbr; ++index)
>      {
> @@ -356,6 +402,7 @@ int AssetMap::Parse ( )
>              video.i_duration = asset->getDuration();
>              video.i_correction = video.i_entrypoint - sum_duration_vid + video.i_duration;
>              video.i_absolute_end = sum_duration_vid;
> +            video.p_key = asset->getAESKeyById( p_dcp->p_key_list, asset->getKeyId() );
>              p_dcp->video_reels.push_back(video);
>              msg_Dbg( this->p_demux, "Video Track: %s",asset->getPath().c_str());
>              msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
> @@ -378,6 +425,7 @@ int AssetMap::Parse ( )
>              audio.i_duration = asset->getDuration();
>              audio.i_correction = audio.i_entrypoint - sum_duration_aud + audio.i_duration;
>              audio.i_absolute_end = sum_duration_aud;
> +            audio.p_key = asset->getAESKeyById( p_dcp->p_key_list, asset->getKeyId() );
>              p_dcp->audio_reels.push_back(audio);
>              msg_Dbg( this->p_demux, "Audio Track: %s",asset->getPath().c_str());
>              msg_Dbg( this->p_demux, "Entry point: %i",asset->getEntryPoint());
> @@ -629,6 +677,18 @@ int Asset::parseChunkList( xml_reader_t *p_xmlReader, string p_node, int p_type)
>      return -1;
>  }
>  
> +AESKey * Asset::getAESKeyById( AESKeyList* p_key_list, const string s_id )
> +{
> +    if( !p_key_list || s_id.empty() )
> +        return NULL;
> +
> +    for( AESKeyList::iterator index = p_key_list->begin(); index != p_key_list->end(); ++index )
> +        if( (*index)->getKeyId() == s_id )
> +            return *index;
> +
> +    return NULL;
> +}
> +
>  int AssetMap::ParseAssetList (xml_reader_t *p_xmlReader, const string p_node, int p_type)
>  {
>      string node;
> @@ -1142,6 +1202,7 @@ int Reel::ParseAsset(string p_node, int p_type, TrackType_t e_track) {
>                  } else if (node == "KeyId") {
>                      if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
>                          return -1;
> +                    asset->setKeyId( s_value );
>                  } else if (node == "Hash") {
>                      if ( ReadEndNode(this->p_xmlReader, node, type, s_value))
>                          return -1;
> @@ -1409,3 +1470,358 @@ int CPL::DummyParse(string p_node, int p_type)
>  
>      return -1;
>  }
> +
> +/*
> + * KDM class
> + */
> +
> +int KDM::Parse()
> +{
> +    string node, s_value;
> +    const string s_root_node = "DCinemaSecurityMessage";
> +    int type;
> +
> +    AESKeyList *_p_key_list = NULL;
> +
> +    /* init XML parser */
> +    if( this->OpenXml() )
> +    {
> +        msg_Err( p_demux, "failed to initialize KDM XML parser" );
> +        return VLC_EGENERIC;
> +    }
> +
> +    msg_Dbg( this->p_demux, "parsing KDM..." );
> +
> +    // read first node and check if it is a KDM
> +    // TODO is this always the name of the tag?
> +    if( ! ( ( XML_READER_STARTELEM == ReadNextNode( this->p_xmlReader, node ) ) && ( node == s_root_node ) ) )
> +    {
> +        msg_Err( this->p_demux, "not a valid XML KDM" );
> +        goto error;
> +    }
> +
> +    while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 )
> +        if( type == XML_READER_STARTELEM && node == "AuthenticatedPrivate" )
> +        {
> +            _p_key_list = new (nothrow) AESKeyList;
> +            if( unlikely( _p_key_list == NULL ) )
> +            {
> +                msg_Err( p_demux, "could not alloc memory" );
Avoid traces when you have memory allocation issues.
> +                goto error;
> +            }
> +            p_dcp->p_key_list = _p_key_list;
I assume that this node can happen only once (or it will leak).
> +            if( this->ParsePrivate( node, type ) )
> +                goto error;
> +
> +            /* keys found so break */
> +            break;
> +        }
> +
> +    if ( (_p_key_list == NULL) ||  (_p_key_list->size() == 0) )
> +    {
> +        msg_Err( p_demux, "Key list empty" );
> +        goto error;
> +    }
> +
> +    /* Close KDM XML */
> +    this->CloseXml();
> +    return VLC_SUCCESS;
> +error:
> +    this->CloseXml();
> +    return VLC_EGENERIC;
> +}
> +
> +int KDM::ParsePrivate( const string p_node, int p_type )
> +{
> +    string node;
> +    int type;
> +    AESKey *key;
> +
> +    /* check that we are where we're supposed to be */
> +    if( p_type != XML_READER_STARTELEM )
> +        goto error;
> +    if( p_node != "AuthenticatedPrivate" )
> +        goto error;
> +
> +    /* loop on EncryptedKey nodes */
> +    while( ( type = ReadNextNode( this->p_xmlReader, node ) ) > 0 )
> +    {
> +        switch( type )
> +        {
> +            case XML_READER_STARTELEM:
> +                if( node != "enc:EncryptedKey" )
> +                    goto error;
> +                key = new (nothrow) AESKey( this->p_demux );
> +                if( unlikely( key == NULL ) )
> +                {
> +                    msg_Err( this->p_demux, "could not alloc memory" );
> +                    return VLC_EGENERIC;
> +                }
> +                if( key->Parse( p_xmlReader, node, type ) )
> +                {
> +                    delete key;
> +                    return VLC_EGENERIC;
> +                }
> +                p_dcp->p_key_list->push_back(key);
> +                break;
> +
> +            case XML_READER_ENDELEM:
> +                if( node == p_node )
> +                    return VLC_SUCCESS;
> +                break;
> +            default:
> +            case XML_READER_TEXT:
> +                goto error;
> +        }
> +    }
> +
> +    /* shouldn't get here */
> +error:
> +    msg_Err( p_demux, "error while parsing AuthenticatedPrivate portion of KDM" );
> +    return VLC_EGENERIC;
> +}
> +
> +/*
> + * AESKey class
> + */
> +
> +int AESKey::Parse( xml_reader_t *p_xmlReader, string p_node, int p_type)
> +{
> +    string node;
> +    string s_value;
> +    int type;
> +
> +    if (p_type != XML_READER_STARTELEM)
> +        goto error;
> +    if( p_node != "enc:EncryptedKey" )
> +        goto error;
> +
> +    while( ( type = ReadNextNode( p_xmlReader, node ) ) > 0 )
> +    {
> +        switch( type )
> +        {
> +            case XML_READER_STARTELEM:
> +                if( node == "enc:CipherValue" )
> +                {
> +                    if( ReadEndNode( p_xmlReader, node, type, s_value ) )
> +                        goto error;
> +                    if( this->decryptRSA( s_value ) )
> +                        return VLC_EGENERIC;
> +                }
> +                break;
> +            case XML_READER_ENDELEM:
> +                if( node == p_node )
> +                    return VLC_SUCCESS;
> +                break;
> +            default:
> +            case XML_READER_TEXT:
> +                goto error;
> +        }
> +    }
> +
> +    /* shouldn't get here */
> +error:
> +    msg_Err( this->p_demux, "error while parsing EncryptedKey" );
> +    return VLC_EGENERIC;
> +}
> +
> +/* decrypts the RSA encrypted AES key from KDM
> + * and saves the needed info
> + */
> +int AESKey::decryptRSA( string s_cipher_text )
> +{
> +    BIO *p_bio;
> +    BIO *p_base64_filter;
> +    RSA *p_rsa_priv_key;
> +    string s_priv_key_path;
> +    char *psz_config_dir;
> +    unsigned char s_cipher_text_binary[256];     /* D-Cinema uses 2048-bit RSA keys, so ciphertext is 256-bytes long */
> +    unsigned char psz_plain_text[256];           /* RSA -> ciphertext length = plaintext length */
> +    int length;
> +
> +    SSL_load_error_strings();
> +
> +    /* get private key file path */
> +    if( ! ( psz_config_dir = config_GetUserDir( VLC_CONFIG_DIR ) ) )
config dir? looks tedious
> +    {
> +        msg_Err( this->p_demux, "could not read user config dir" );
> +        return VLC_EGENERIC;
> +    }
> +    try
> +    {
> +        s_priv_key_path.assign( psz_config_dir );
> +        s_priv_key_path.append( "/priv.key" );
> +    }
> +    catch( ... )
> +    {
> +        msg_Err( this->p_demux, "error while handling string" );
free(psz_config_dir);
> +        return VLC_EGENERIC;
> +    }
> +    if( psz_config_dir )
this will be true at this point of the code
> +        free( psz_config_dir );
> +
> +    /* read private key from file */
> +    if( ! ( p_bio = BIO_new_file( s_priv_key_path.c_str(), "r" ) ) )
> +    {
> +        msg_Err( this->p_demux, "could not open RSA key file" );
> +        return VLC_EGENERIC;
> +    }
> +    if( ! ( p_rsa_priv_key = PEM_read_bio_RSAPrivateKey( p_bio, NULL, NULL, NULL) ) )
> +    {
> +        msg_Err( this->p_demux, "could not read RSA private key" );
> +        goto error;
> +    }
> +    if( ! BIO_free( p_bio ) )
> +    {
> +        msg_Err( this->p_demux, "could not free BIO structure" );
> +        goto error;
> +    }
> +
> +    /* decode cipher from BASE64 to binary */
> +    if( ! ( p_bio = BIO_new_mem_buf( (void*)s_cipher_text.c_str(), s_cipher_text.length() ) ) )
> +    {
> +        msg_Err( this->p_demux, "could not create BIO buffer" );
> +        goto error;
> +    }
> +    if( ! ( p_base64_filter = BIO_new( BIO_f_base64() ) ) )
> +    {
> +        msg_Err( this->p_demux, "could not create BIO filter" );
> +        goto error;
> +    }
> +    p_bio = BIO_push( p_base64_filter, p_bio );
> +    length = BIO_read( p_bio, s_cipher_text_binary, 256 );
> +    if( length != 256 )
> +    {
> +        msg_Err( this->p_demux, "error when reading from BASE64 BIO" );
> +        goto error;
> +    }
> +
> +    /* decrypt */
> +    memset( psz_plain_text, 0, 256 );
> +    length = RSA_private_decrypt(
> +                RSA_size( p_rsa_priv_key), s_cipher_text_binary, psz_plain_text, p_rsa_priv_key, RSA_PKCS1_OAEP_PADDING );
> +
> +    /* interpret the plaintext data */
> +    switch( length )
> +    {
> +        case 138:   /* SMPTE    DCP */
> +            if( this->extractInfo( psz_plain_text, true ) )
> +                goto error;
> +            break;
> +        case 136:   /* Interop  DCP */
> +            if( this->extractInfo( psz_plain_text, false ) )
> +                goto error;
> +            break;
> +        case -1:
> +            msg_Err( this->p_demux, "%s", ERR_error_string( ERR_get_error(), NULL ) );
> +            goto error;
> +        default:
> +            msg_Err( this->p_demux, "CipherValue field length does not match SMPTE nor Interop standards" );
> +            goto error;
> +    }
> +
> +    BIO_free_all( p_bio );
> +    RSA_free( p_rsa_priv_key );
> +    return VLC_SUCCESS;
> +error:
> +    BIO_free_all( p_bio );
> +    RSA_free( p_rsa_priv_key );
> +    return VLC_EGENERIC;
> +}
> +
> +/* extracts and saves the AES key info from the SMPTE-type plaintext
> + * makes checks for integrity of ciphertext
> + * parameter smpte is true for SMPTE DCP, false for Interop
> + * see SMPTE 430-1-2006, section 6.1.2 for the exact structure of the plaintext
> + */
> +int AESKey::extractInfo( unsigned char * psz_plain_text, bool smpte )
> +{
> +    string s_carrier;
> +    char h[3];
> +    int i, ret, pos = 0;
> +
> +    /* check for the structure ID */
> +    while( pos < 16 )
> +    {
> +        ret = snprintf( h, 3, "%02hhx", psz_plain_text[pos] );
> +        if( ret != 2 )
> +        {
> +            msg_Err( this->p_demux, "error while extracting structure ID from decrypted cipher" );
> +            return VLC_EGENERIC;
> +        }
> +        try
> +        {
> +            s_carrier.append( h );
> +        }
> +        catch( ... )
> +        {
> +            msg_Err( this->p_demux, "error while handling string" );
> +            return VLC_EGENERIC;
> +        }
> +        pos++;
> +    }
> +    if( s_carrier.compare( KDM_RSA_STRUCT_ID ) )
> +    {
> +        msg_Err( this->p_demux, "incorrect RSA structure ID: KDM may be broken" );
> +        return VLC_EGENERIC;
> +    }
> +
> +    pos += 36;      /* TODO thumbprint, CPL ID */
> +    if( smpte )     /* only SMPTE DCPs have the 4-byte "KeyType" field */
> +        pos += 4;
> +
> +    /* extract the AES key UUID */
> +    if( ( this->s_key_id = createUUID( strndup( ( const char* )psz_plain_text + pos, 16 ) ) ).empty() )
why duplicating the string and freeing it in createUUID?
> +    {
> +        msg_Err( this->p_demux, "error while extracting AES Key UUID" );
> +        return VLC_EGENERIC;
> +    }
> +    pos += 16;
> +
> +    pos += 50; /* TODO KeyEpoch */
> +
> +    /* extract the AES key */
> +    for( i = pos; i < pos + 16; i++ )
> +        this->ps_key[i-pos] = psz_plain_text[i];
memcpy?
> +
> +    return VLC_SUCCESS;
> +}
> +
> +/* creates a printable, RFC 4122-conform UUID, from a null-terminated string
> + * returns a string containing the UUID
> + */
> +string AESKey::createUUID( char *psz_hex_string )
> +{
> +    string s_uuid;
> +    char h[3];
> +    int i, ret;
> +
> +    if( ! psz_hex_string )
> +        return "";
> +
> +    try
> +    {
> +        s_uuid.append( "urn:uuid:" );
> +        for( i = 0; i < 16; i++ )
> +        {
> +            ret = snprintf( h, 3, "%02hhx", psz_hex_string[i] );  /* each byte can be written as 2 hex digits */
> +            if( ret != 2 )
> +                goto error;
> +            s_uuid.append( h );
> +            if( i == 3 || i == 5 || i == 7 || i == 9 )
> +                s_uuid.append( "-" );
> +        }
> +    }
> +    catch( ... )
> +    {
> +        goto error;
> +    }
> +
> +    free( psz_hex_string );
> +    return s_uuid;
> +error:
> +    msg_Err( this->p_demux, "error while handling string" );
> +    if( psz_hex_string )
> +        free( psz_hex_string );
> +    return "";
> +}
> diff --git a/modules/access/dcp/dcpparser.h b/modules/access/dcp/dcpparser.h
> index 32059f5..3032464 100644
> --- a/modules/access/dcp/dcpparser.h
> +++ b/modules/access/dcp/dcpparser.h
> @@ -8,6 +8,7 @@
>   *          Anthony Giniers
>   *          Ludovic Hoareau
>   *          Loukmane Dessai
> + *          Simona-Marinela Prodea <simona dot marinela dot prodea at gmail dot com>
>   *
>   * This program is free software; you can redistribute it and/or modify it
>   * under the terms of the GNU Lesser General Public License as published by
> @@ -42,6 +43,9 @@
>  #include <vlc_demux.h>
>  #include <vlc_plugin.h>
>  
> +/* ASDCP header */
> +#include <AS_DCP.h>
> +
>  #include <iostream>
>  #include <string>
>  #include <list>
> @@ -67,6 +71,8 @@ typedef enum {
>  class Asset;
>  class AssetList: public std::list<Asset *> {};
>  class PKL;
> +class AESKey;
> +class AESKeyList: public std::list<AESKey *> {};
>  
>  
>  /* This struct stores useful information about an MXF for demux() */
> @@ -77,6 +83,7 @@ struct info_reel
>      int i_duration;
>      int i_correction;       /* entrypoint - sum of previous durations */
>      uint32_t i_absolute_end;     /* correction + duration */
> +    AESKey * p_key;
>  };
>  
>  /* This struct stores the most important information about the DCP */
> @@ -86,12 +93,13 @@ struct dcp_t
>  
>      vector<PKL *> pkls;
>      AssetList *p_asset_list;
> +    AESKeyList *p_key_list;
why storing list pointers instead of lists?
>  
>      vector<info_reel> audio_reels;
>      vector<info_reel> video_reels;
>  
>      dcp_t():
> -        p_asset_list(NULL) {};
> +        p_asset_list(NULL), p_key_list(NULL) {};
>  
>      ~dcp_t( ) {
>          vlc_delete_all(pkls);
> @@ -100,6 +108,10 @@ struct dcp_t
>              delete(p_asset_list);
>  
>          }
> +        if ( p_key_list != NULL ) {
> +            vlc_delete_all(*p_key_list);
> +            delete(p_key_list);
> +        }
>      }
>  };
>  
> @@ -164,6 +176,7 @@ public:
>          else
>              this->s_annotation = this->s_annotation + "--" + p_string;
>      };
> +    void setKeyId(string p_string) { this->s_key_id = p_string; };
>      void setPackingList(bool p_bool) { this->s_path = p_bool; };
>      void setEntryPoint(int i_val) { this->i_entry_point = i_val; };
>      void setDuration (int i_val) { this->i_duration = i_val; };
> @@ -172,6 +185,7 @@ public:
>      string getPath() const { return this->s_path; };
>      string getType() const { return this->s_type; };
>      string getOriginalFilename() const { return this->s_original_filename; };
> +    string getKeyId() const { return this->s_key_id; }
>      int getEntryPoint() const { return this->i_entry_point; };
>      int getDuration() const { return this->i_duration; };
>      int getIntrinsicDuration() const { return this->i_intrisic_duration; };
> @@ -181,6 +195,8 @@ public:
>      int Parse( xml_reader_t *p_xmlReader, string node, int type);
>      int ParsePKL( xml_reader_t *p_xmlReader);
>  
> +    static AESKey * getAESKeyById( AESKeyList* , const string s_id );
> +
>      // TODO: remove
>      void Dump();
>  
> @@ -315,4 +331,41 @@ private:
>  
>      int ParseAssetList (xml_reader_t *p_xmlReader, const string p_node, int p_type);
>  };
> +
> +class KDM : public XmlFile {
> +
> +public:
> +    KDM( demux_t * p_demux, string s_path, dcp_t *_p_dcp )
> +        : XmlFile( p_demux, s_path ), p_dcp(_p_dcp) {}
> +    ~KDM() {};
> +
> +    int Parse();
> +
> +private:
> +    dcp_t *p_dcp;
> +
> +    int ParsePrivate( const string p_node, int p_type );
> +};
> +
> +class AESKey {
> +
> +public:
> +    AESKey( demux_t *demux ): p_demux( demux ) { }
> +
> +    const string getKeyId() { return this->s_key_id; };
> +    const unsigned char * getKey() { return this->ps_key; };
> +
> +    int Parse( xml_reader_t *p_xmlReader, string node, int type );
> +
> +private:
> +    demux_t *p_demux;
> +    string s_key_id;
> +    unsigned char ps_key[16];
> +
> +    int decryptRSA( string s_cipher_text );
> +    int extractInfo( unsigned char * psz_plain_text, bool smpte );
> +
> +    string createUUID( char *psz_hex_string );
> +};
> +
>  #endif /* _DCPPARSER_H */
> -- 
> 1.7.9.5
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel

Regards,

-- 
Denis Charmet - TypX
Le mauvais esprit est un art de vivre



More information about the vlc-devel mailing list