From a726ac41fc98e6abdf4d10d2e7b3358878ecf2de Mon Sep 17 00:00:00 2001 From: Francois Cartegnie <fcvlcdev@free.fr> Date: Thu, 18 Apr 2019 19:42:40 +0200 Subject: [PATCH] demux: adaptive: move decryption to base classes --- .../adaptive/encryption/CommonEncryption.cpp | 16 +++++-- .../adaptive/encryption/CommonEncryption.hpp | 8 +++- modules/demux/adaptive/encryption/Keyring.cpp | 1 + modules/demux/adaptive/playlist/Segment.cpp | 29 ++++++++++- modules/demux/adaptive/playlist/Segment.h | 11 ++++- .../demux/adaptive/playlist/SegmentChunk.cpp | 29 +++++++++++ .../demux/adaptive/playlist/SegmentChunk.hpp | 8 ++++ modules/demux/hls/playlist/HLSSegment.cpp | 48 ++++--------------- modules/demux/hls/playlist/HLSSegment.hpp | 8 ++-- modules/demux/hls/playlist/Parser.cpp | 11 ++--- 10 files changed, 109 insertions(+), 60 deletions(-) diff --git a/modules/demux/adaptive/encryption/CommonEncryption.cpp b/modules/demux/adaptive/encryption/CommonEncryption.cpp index 31709dea7090..743e04e860e8 100644 --- a/modules/demux/adaptive/encryption/CommonEncryption.cpp +++ b/modules/demux/adaptive/encryption/CommonEncryption.cpp @@ -23,6 +23,8 @@ #endif #include "CommonEncryption.hpp" +#include "Keyring.hpp" +#include "../SharedResources.hpp" #include <vlc_common.h> @@ -44,12 +46,13 @@ CommonEncryptionSession::CommonEncryptionSession() ctx = NULL; } + CommonEncryptionSession::~CommonEncryptionSession() { close(); } -bool CommonEncryptionSession::start(const CommonEncryption &enc) +bool CommonEncryptionSession::start(SharedResources *res, const CommonEncryption &enc) { if(ctx) close(); @@ -57,11 +60,18 @@ bool CommonEncryptionSession::start(const CommonEncryption &enc) #ifdef HAVE_GCRYPT if(encryption.method == CommonEncryption::Method::AES_128) { + if(key.empty()) + { + if(!encryption.uri.empty()) + key = res->getKeyring()->getKey(res->getAuthStorage(), encryption.uri); + if(key.size() != 16) + return false; + } + vlc_gcrypt_init(); gcry_cipher_hd_t handle; if( gcry_cipher_open(&handle, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0) || - encryption.key.size() != 16 || - gcry_cipher_setkey(handle, &encryption.key[0], 16) || + gcry_cipher_setkey(handle, &key[0], 16) || gcry_cipher_setiv(handle, &encryption.iv[0], 16) ) { gcry_cipher_close(handle); diff --git a/modules/demux/adaptive/encryption/CommonEncryption.hpp b/modules/demux/adaptive/encryption/CommonEncryption.hpp index 25d3984bf3cc..66631c3d2a48 100644 --- a/modules/demux/adaptive/encryption/CommonEncryption.hpp +++ b/modules/demux/adaptive/encryption/CommonEncryption.hpp @@ -21,9 +21,12 @@ #define COMMONENCRYPTION_H #include <vector> +#include <string> namespace adaptive { + class SharedResources; + namespace encryption { class CommonEncryption @@ -36,7 +39,7 @@ namespace adaptive AES_128, AES_SAMPLE, } method; - std::vector<unsigned char> key; + std::string uri; std::vector<unsigned char> iv; }; @@ -46,11 +49,12 @@ namespace adaptive CommonEncryptionSession(); ~CommonEncryptionSession(); - bool start(const CommonEncryption &); + bool start(SharedResources *, const CommonEncryption &); void close(); size_t decrypt(void *, size_t, bool); private: + std::vector<unsigned char> key; CommonEncryption encryption; void *ctx; }; diff --git a/modules/demux/adaptive/encryption/Keyring.cpp b/modules/demux/adaptive/encryption/Keyring.cpp index 68e2f25daf18..baa630a1bcf1 100644 --- a/modules/demux/adaptive/encryption/Keyring.cpp +++ b/modules/demux/adaptive/encryption/Keyring.cpp @@ -53,6 +53,7 @@ KeyringKey Keyring::getKey(AuthStorage *auth, const std::string &uri) if(it == keys.end()) { /* Pretty bad inside the lock */ + msg_Dbg(obj, "Retrieving AES key %s", uri.c_str()); block_t *p_block = Retrieve::HTTP(obj, auth, uri); if(p_block) { diff --git a/modules/demux/adaptive/playlist/Segment.cpp b/modules/demux/adaptive/playlist/Segment.cpp index 40cba1acdf8b..36051a94500b 100644 --- a/modules/demux/adaptive/playlist/Segment.cpp +++ b/modules/demux/adaptive/playlist/Segment.cpp @@ -67,7 +67,22 @@ void ISegment::onChunkDownload(block_t **, SegmentChunk *, BaseRepresentation *) } -SegmentChunk* ISegment::toChunk(SharedResources *, AbstractConnectionManager *connManager, +bool ISegment::prepareChunk(SharedResources *res, SegmentChunk *chunk, BaseRepresentation *) +{ + if(encryption.method != CommonEncryption::Method::NONE) + { + CommonEncryptionSession *encryptionSession = new CommonEncryptionSession(); + if(!encryptionSession->start(res, encryption)) + { + delete encryptionSession; + return false; + } + chunk->setEncryptionSession(encryptionSession); + } + return true; +} + +SegmentChunk* ISegment::toChunk(SharedResources *res, AbstractConnectionManager *connManager, size_t index, BaseRepresentation *rep) { const std::string url = getUrlSegment().toString(index, rep); @@ -79,8 +94,13 @@ SegmentChunk* ISegment::toChunk(SharedResources *, AbstractConnectionManager *co source->setBytesRange(BytesRange(startByte, endByte)); SegmentChunk *chunk = new (std::nothrow) SegmentChunk(this, source, rep); - if( chunk ) + if(chunk) { + if(!prepareChunk(res, chunk, rep)) + { + delete chunk; + return NULL; + } connManager->start(source); return chunk; } @@ -163,6 +183,11 @@ int ISegment::compare(ISegment *other) const return 0; } +void ISegment::setEncryption(CommonEncryption &e) +{ + encryption = e; +} + int ISegment::getClassId() const { return classId; diff --git a/modules/demux/adaptive/playlist/Segment.h b/modules/demux/adaptive/playlist/Segment.h index 1a2c217d58e7..28494ca2b6ae 100644 --- a/modules/demux/adaptive/playlist/Segment.h +++ b/modules/demux/adaptive/playlist/Segment.h @@ -30,6 +30,7 @@ #include <vector> #include "ICanonicalUrl.hpp" #include "../http/Chunk.h" +#include "../encryption/CommonEncryption.hpp" #include "../tools/Properties.hpp" #include "Time.hpp" @@ -49,6 +50,7 @@ namespace adaptive class SegmentChunk; using namespace http; + using namespace encryption; class ISegment : public ICanonicalUrl { @@ -72,6 +74,7 @@ namespace adaptive virtual void debug (vlc_object_t *,int = 0) const; virtual bool contains (size_t byte) const; virtual int compare (ISegment *) const; + void setEncryption (CommonEncryption &); int getClassId () const; Property<stime_t> startTime; Property<stime_t> duration; @@ -80,9 +83,15 @@ namespace adaptive static const int CLASSID_ISEGMENT = 0; /* callbacks */ - virtual void onChunkDownload (block_t **, SegmentChunk *, BaseRepresentation *); + virtual void onChunkDownload (block_t **, + SegmentChunk *, + BaseRepresentation *); protected: + virtual bool prepareChunk (SharedResources *, + SegmentChunk *, + BaseRepresentation *); + CommonEncryption encryption; size_t startByte; size_t endByte; std::string debugName; diff --git a/modules/demux/adaptive/playlist/SegmentChunk.cpp b/modules/demux/adaptive/playlist/SegmentChunk.cpp index 4616e869ad5a..19ce1d5b748e 100644 --- a/modules/demux/adaptive/playlist/SegmentChunk.cpp +++ b/modules/demux/adaptive/playlist/SegmentChunk.cpp @@ -24,9 +24,14 @@ #include "SegmentChunk.hpp" #include "Segment.h" #include "BaseRepresentation.h" +#include "../encryption/CommonEncryption.hpp" + +#include <vlc_block.h> + #include <cassert> using namespace adaptive::playlist; +using namespace adaptive::encryption; using namespace adaptive; SegmentChunk::SegmentChunk(ISegment *segment_, AbstractChunkSource *source, @@ -37,16 +42,35 @@ SegmentChunk::SegmentChunk(ISegment *segment_, AbstractChunkSource *source, segment->chunksuse.Set(segment->chunksuse.Get() + 1); rep = rep_; discontinuity = segment_->discontinuity; + encryptionSession = NULL; } SegmentChunk::~SegmentChunk() { assert(segment->chunksuse.Get() > 0); segment->chunksuse.Set(segment->chunksuse.Get() - 1); + delete encryptionSession; +} + +bool SegmentChunk::decrypt(block_t **pp_block) +{ + block_t *p_block = *pp_block; + + if(encryptionSession) + { + bool b_last = isEmpty(); + p_block->i_buffer = encryptionSession->decrypt(p_block->p_buffer, + p_block->i_buffer, b_last); + if(b_last) + encryptionSession->close(); + } + + return true; } void SegmentChunk::onDownload(block_t **pp_block) { + decrypt(pp_block); segment->onChunkDownload(pp_block, this, rep); } @@ -58,3 +82,8 @@ StreamFormat SegmentChunk::getStreamFormat() const return StreamFormat(); } +void SegmentChunk::setEncryptionSession(CommonEncryptionSession *s) +{ + delete encryptionSession; + encryptionSession = s; +} diff --git a/modules/demux/adaptive/playlist/SegmentChunk.hpp b/modules/demux/adaptive/playlist/SegmentChunk.hpp index 5673301c83e6..9807763a792f 100644 --- a/modules/demux/adaptive/playlist/SegmentChunk.hpp +++ b/modules/demux/adaptive/playlist/SegmentChunk.hpp @@ -27,10 +27,15 @@ namespace adaptive { + namespace encryption + { + class CommonEncryptionSession; + } namespace playlist { using namespace http; + using namespace encryption; class BaseRepresentation; class ISegment; @@ -40,13 +45,16 @@ namespace adaptive public: SegmentChunk(ISegment *segment, AbstractChunkSource *, BaseRepresentation *); virtual ~SegmentChunk(); + void setEncryptionSession(CommonEncryptionSession *); StreamFormat getStreamFormat() const; bool discontinuity; protected: + bool decrypt(block_t **); virtual void onDownload(block_t **); // reimpl ISegment *segment; BaseRepresentation *rep; + CommonEncryptionSession *encryptionSession; }; } diff --git a/modules/demux/hls/playlist/HLSSegment.cpp b/modules/demux/hls/playlist/HLSSegment.cpp index a3f26256e1b5..9b3f6718513b 100644 --- a/modules/demux/hls/playlist/HLSSegment.cpp +++ b/modules/demux/hls/playlist/HLSSegment.cpp @@ -24,10 +24,7 @@ #include "HLSSegment.hpp" #include "../adaptive/playlist/SegmentChunk.hpp" #include "../adaptive/playlist/BaseRepresentation.h" -#include "../adaptive/encryption/CommonEncryption.hpp" -#include <vlc_common.h> -#include <vlc_block.h> using namespace hls::playlist; @@ -42,47 +39,23 @@ HLSSegment::~HLSSegment() { } -void HLSSegment::onChunkDownload(block_t **pp_block, SegmentChunk *chunk, BaseRepresentation *) +bool HLSSegment::prepareChunk(SharedResources *res, SegmentChunk *chunk, BaseRepresentation *rep) { - block_t *p_block = *pp_block; - -#ifndef HAVE_GCRYPT - (void)chunk; -#else if(encryption.method == CommonEncryption::Method::AES_128) { if (encryption.iv.size() != 16) { + uint64_t sequence = getSequenceNumber() - Segment::SEQUENCE_FIRST; encryption.iv.clear(); encryption.iv.resize(16); - encryption.iv[15] = (getSequenceNumber() - Segment::SEQUENCE_FIRST) & 0xff; - encryption.iv[14] = ((getSequenceNumber() - Segment::SEQUENCE_FIRST) >> 8)& 0xff; - encryption.iv[13] = ((getSequenceNumber() - Segment::SEQUENCE_FIRST) >> 16)& 0xff; - encryption.iv[12] = ((getSequenceNumber() - Segment::SEQUENCE_FIRST) >> 24)& 0xff; - } - - block_t *p_block = *pp_block; - /* first bytes */ - if(chunk->getBytesRead() == p_block->i_buffer) - { - if(!encryptSession.start(encryption)) - { - p_block->i_buffer = 0; - return; - } + encryption.iv[15] = (sequence >> 0) & 0xff; + encryption.iv[14] = (sequence >> 8) & 0xff; + encryption.iv[13] = (sequence >> 16) & 0xff; + encryption.iv[12] = (sequence >> 24) & 0xff; } - - bool b_last = chunk->isEmpty(); - p_block->i_buffer = encryptSession.decrypt(p_block->p_buffer, p_block->i_buffer, b_last); - if(b_last) - encryptSession.close(); - } - else -#endif - if(encryption.method != CommonEncryption::Method::NONE) - { - p_block->i_buffer = 0; } + + return Segment::prepareChunk(res, chunk, rep); } vlc_tick_t HLSSegment::getUTCTime() const @@ -90,11 +63,6 @@ vlc_tick_t HLSSegment::getUTCTime() const return utcTime; } -void HLSSegment::setEncryption(CommonEncryption &enc) -{ - encryption = enc; -} - int HLSSegment::compare(ISegment *segment) const { HLSSegment *hlssegment = dynamic_cast<HLSSegment *>(segment); diff --git a/modules/demux/hls/playlist/HLSSegment.hpp b/modules/demux/hls/playlist/HLSSegment.hpp index 22cee023c362..e06f9e465bc1 100644 --- a/modules/demux/hls/playlist/HLSSegment.hpp +++ b/modules/demux/hls/playlist/HLSSegment.hpp @@ -27,6 +27,7 @@ namespace hls { namespace playlist { + using namespace adaptive; using namespace adaptive::playlist; using namespace adaptive::encryption; @@ -37,16 +38,13 @@ namespace hls public: HLSSegment( ICanonicalUrl *parent, uint64_t sequence ); virtual ~HLSSegment(); - void setEncryption(CommonEncryption &); vlc_tick_t getUTCTime() const; virtual int compare(ISegment *) const; /* reimpl */ protected: vlc_tick_t utcTime; - virtual void onChunkDownload(block_t **, SegmentChunk *, BaseRepresentation *); /* reimpl */ - - CommonEncryption encryption; - CommonEncryptionSession encryptSession; + virtual bool prepareChunk(SharedResources *, SegmentChunk *, + BaseRepresentation *); /* reimpl */ }; } } diff --git a/modules/demux/hls/playlist/Parser.cpp b/modules/demux/hls/playlist/Parser.cpp index e3e698d747c3..109ca08a91a6 100644 --- a/modules/demux/hls/playlist/Parser.cpp +++ b/modules/demux/hls/playlist/Parser.cpp @@ -316,7 +316,7 @@ void M3U8Parser::parseSegments(vlc_object_t *, Representation *rep, const std::l keytag->getAttributeByName("URI") ) { encryption.method = CommonEncryption::Method::AES_128; - encryption.key.clear(); + encryption.uri.clear(); Url keyurl(keytag->getAttributeByName("URI")->quotedString()); if(!keyurl.hasScheme()) @@ -324,11 +324,8 @@ void M3U8Parser::parseSegments(vlc_object_t *, Representation *rep, const std::l keyurl.prepend(Helper::getDirectoryPath(rep->getPlaylistUrl().toString()).append("/")); } - M3U8 *m3u8 = dynamic_cast<M3U8 *>(rep->getPlaylist()); - if(likely(m3u8)) - encryption.key = resources->getKeyring()->getKey( - resources->getAuthStorage(), - keyurl.toString()); + encryption.uri = keyurl.toString(); + if(keytag->getAttributeByName("IV")) { encryption.iv.clear(); @@ -339,7 +336,7 @@ void M3U8Parser::parseSegments(vlc_object_t *, Representation *rep, const std::l { /* unsupported or invalid */ encryption.method = CommonEncryption::Method::NONE; - encryption.key.clear(); + encryption.uri.clear(); encryption.iv.clear(); } } -- GitLab