[vlc-commits] demux: adaptive: refactor HLS encryption into adaptive
Francois Cartegnie
git at videolan.org
Thu May 9 18:05:40 CEST 2019
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Wed Apr 17 18:46:55 2019 +0200| [f47c77ac17a129a0aef5d8e59c9051d456c60c54] | committer: Francois Cartegnie
demux: adaptive: refactor HLS encryption into adaptive
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=f47c77ac17a129a0aef5d8e59c9051d456c60c54
---
modules/demux/Makefile.am | 2 +
.../demux/adaptive/encryption/CommonEncryption.cpp | 125 +++++++++++++++++++++
.../demux/adaptive/encryption/CommonEncryption.hpp | 60 ++++++++++
modules/demux/hls/playlist/HLSSegment.cpp | 86 ++++----------
modules/demux/hls/playlist/HLSSegment.hpp | 28 +----
modules/demux/hls/playlist/Parser.cpp | 8 +-
6 files changed, 217 insertions(+), 92 deletions(-)
diff --git a/modules/demux/Makefile.am b/modules/demux/Makefile.am
index 85d4b3fba9..a3e1bd6fee 100644
--- a/modules/demux/Makefile.am
+++ b/modules/demux/Makefile.am
@@ -319,6 +319,8 @@ libadaptive_plugin_la_SOURCES = \
demux/adaptive/playlist/Url.cpp \
demux/adaptive/playlist/Url.hpp \
demux/adaptive/playlist/Templates.hpp \
+ demux/adaptive/encryption/CommonEncryption.cpp \
+ demux/adaptive/encryption/CommonEncryption.hpp \
demux/adaptive/logic/AbstractAdaptationLogic.cpp \
demux/adaptive/logic/AbstractAdaptationLogic.h \
demux/adaptive/logic/AlwaysBestAdaptationLogic.cpp \
diff --git a/modules/demux/adaptive/encryption/CommonEncryption.cpp b/modules/demux/adaptive/encryption/CommonEncryption.cpp
new file mode 100644
index 0000000000..31709dea70
--- /dev/null
+++ b/modules/demux/adaptive/encryption/CommonEncryption.cpp
@@ -0,0 +1,125 @@
+/*****************************************************************************
+ * CommonEncryption.cpp
+ *****************************************************************************
+ * Copyright (C) 2015-2019 VLC authors and VideoLAN
+ *
+ * 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
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "CommonEncryption.hpp"
+
+#include <vlc_common.h>
+
+#ifdef HAVE_GCRYPT
+ #include <gcrypt.h>
+ #include <vlc_gcrypt.h>
+#endif
+
+using namespace adaptive::encryption;
+
+
+CommonEncryption::CommonEncryption()
+{
+ method = CommonEncryption::Method::NONE;
+}
+
+CommonEncryptionSession::CommonEncryptionSession()
+{
+ ctx = NULL;
+}
+
+CommonEncryptionSession::~CommonEncryptionSession()
+{
+ close();
+}
+
+bool CommonEncryptionSession::start(const CommonEncryption &enc)
+{
+ if(ctx)
+ close();
+ encryption = enc;
+#ifdef HAVE_GCRYPT
+ if(encryption.method == CommonEncryption::Method::AES_128)
+ {
+ 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_setiv(handle, &encryption.iv[0], 16) )
+ {
+ gcry_cipher_close(handle);
+ ctx = NULL;
+ return false;
+ }
+ ctx = handle;
+ }
+#endif
+ return true;
+}
+
+void CommonEncryptionSession::close()
+{
+ gcry_cipher_hd_t handle = reinterpret_cast<gcry_cipher_hd_t>(ctx);
+#ifdef HAVE_GCRYPT
+ if(ctx)
+ gcry_cipher_close(handle);
+ ctx = NULL;
+#endif
+}
+
+size_t CommonEncryptionSession::decrypt(void *inputdata, size_t inputbytes, bool last)
+{
+ gcry_cipher_hd_t handle = reinterpret_cast<gcry_cipher_hd_t>(ctx);
+#ifndef HAVE_GCRYPT
+ (void)data;
+ (void)bytes;
+ (void)last;
+#else
+ if(encryption.method == CommonEncryption::Method::AES_128 && ctx)
+ {
+ if ((inputbytes % 16) != 0 || inputbytes < 16 ||
+ gcry_cipher_decrypt(handle, inputdata, inputbytes, NULL, 0))
+ {
+ inputbytes = 0;
+ }
+ else if(last)
+ {
+ /* last bytes */
+ /* remove the PKCS#7 padding from the buffer */
+ const uint8_t pad = reinterpret_cast<uint8_t *>(inputdata)[inputbytes - 1];
+ for(uint8_t i=0; i<pad && i<=16; i++)
+ {
+ if(reinterpret_cast<uint8_t *>(inputdata)[inputbytes - i - 1] != pad)
+ break;
+
+ if(i==pad)
+ inputbytes -= pad;
+ }
+ }
+ }
+ else
+#endif
+ if(encryption.method != CommonEncryption::Method::NONE)
+ {
+ inputbytes = 0;
+ }
+
+ return inputbytes;
+}
diff --git a/modules/demux/adaptive/encryption/CommonEncryption.hpp b/modules/demux/adaptive/encryption/CommonEncryption.hpp
new file mode 100644
index 0000000000..25d3984bf3
--- /dev/null
+++ b/modules/demux/adaptive/encryption/CommonEncryption.hpp
@@ -0,0 +1,60 @@
+/*****************************************************************************
+ * CommonEncryption.hpp
+ *****************************************************************************
+ * Copyright (C) 2015-2019 VLC authors and VideoLAN
+ *
+ * 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
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifndef COMMONENCRYPTION_H
+#define COMMONENCRYPTION_H
+
+#include <vector>
+
+namespace adaptive
+{
+ namespace encryption
+ {
+ class CommonEncryption
+ {
+ public:
+ CommonEncryption();
+ enum Method
+ {
+ NONE,
+ AES_128,
+ AES_SAMPLE,
+ } method;
+ std::vector<unsigned char> key;
+ std::vector<unsigned char> iv;
+ };
+
+ class CommonEncryptionSession
+ {
+ public:
+ CommonEncryptionSession();
+ ~CommonEncryptionSession();
+
+ bool start(const CommonEncryption &);
+ void close();
+ size_t decrypt(void *, size_t, bool);
+
+ private:
+ CommonEncryption encryption;
+ void *ctx;
+ };
+ }
+}
+
+#endif
diff --git a/modules/demux/hls/playlist/HLSSegment.cpp b/modules/demux/hls/playlist/HLSSegment.cpp
index c43f6a58ad..a3f26256e1 100644
--- a/modules/demux/hls/playlist/HLSSegment.cpp
+++ b/modules/demux/hls/playlist/HLSSegment.cpp
@@ -24,36 +24,22 @@
#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>
-#ifdef HAVE_GCRYPT
- #include <vlc_gcrypt.h>
-#endif
using namespace hls::playlist;
-SegmentEncryption::SegmentEncryption()
-{
- method = SegmentEncryption::NONE;
-}
-
HLSSegment::HLSSegment( ICanonicalUrl *parent, uint64_t seq ) :
Segment( parent )
{
setSequenceNumber(seq);
utcTime = 0;
-#ifdef HAVE_GCRYPT
- ctx = NULL;
-#endif
}
HLSSegment::~HLSSegment()
{
-#ifdef HAVE_GCRYPT
- if(ctx)
- gcry_cipher_close(ctx);
-#endif
}
void HLSSegment::onChunkDownload(block_t **pp_block, SegmentChunk *chunk, BaseRepresentation *)
@@ -63,67 +49,37 @@ void HLSSegment::onChunkDownload(block_t **pp_block, SegmentChunk *chunk, BaseRe
#ifndef HAVE_GCRYPT
(void)chunk;
#else
- if(encryption.method == SegmentEncryption::AES_128)
+ if(encryption.method == CommonEncryption::Method::AES_128)
{
- block_t *p_block = *pp_block;
- /* first bytes */
- if(!ctx && chunk->getBytesRead() == p_block->i_buffer)
+ if (encryption.iv.size() != 16)
{
- vlc_gcrypt_init();
- if (encryption.iv.size() != 16)
- {
- 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;
- }
-
- if( gcry_cipher_open(&ctx, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 0) ||
- encryption.key.size() != 16 ||
- gcry_cipher_setkey(ctx, &encryption.key[0], 16) ||
- gcry_cipher_setiv(ctx, &encryption.iv[0], 16) )
- {
- gcry_cipher_close(ctx);
- ctx = NULL;
- }
+ 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;
}
- if(ctx)
+ block_t *p_block = *pp_block;
+ /* first bytes */
+ if(chunk->getBytesRead() == p_block->i_buffer)
{
- if ((p_block->i_buffer % 16) != 0 || p_block->i_buffer < 16 ||
- gcry_cipher_decrypt(ctx, p_block->p_buffer, p_block->i_buffer, NULL, 0))
+ if(!encryptSession.start(encryption))
{
p_block->i_buffer = 0;
- gcry_cipher_close(ctx);
- ctx = NULL;
- }
- else
- {
- /* last bytes */
- if(chunk->isEmpty())
- {
- /* remove the PKCS#7 padding from the buffer */
- const uint8_t pad = p_block->p_buffer[p_block->i_buffer - 1];
- for(uint8_t i=0; i<pad && i<=16; i++)
- {
- if(p_block->p_buffer[p_block->i_buffer - i - 1] != pad)
- break;
-
- if(i==pad)
- p_block->i_buffer -= pad;
- }
-
- gcry_cipher_close(ctx);
- ctx = NULL;
- }
+ return;
}
}
+
+ 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 != SegmentEncryption::NONE)
+ if(encryption.method != CommonEncryption::Method::NONE)
{
p_block->i_buffer = 0;
}
@@ -134,7 +90,7 @@ vlc_tick_t HLSSegment::getUTCTime() const
return utcTime;
}
-void HLSSegment::setEncryption(SegmentEncryption &enc)
+void HLSSegment::setEncryption(CommonEncryption &enc)
{
encryption = enc;
}
diff --git a/modules/demux/hls/playlist/HLSSegment.hpp b/modules/demux/hls/playlist/HLSSegment.hpp
index b96a558aef..22cee023c3 100644
--- a/modules/demux/hls/playlist/HLSSegment.hpp
+++ b/modules/demux/hls/playlist/HLSSegment.hpp
@@ -21,30 +21,14 @@
#define HLSSEGMENT_HPP
#include "../adaptive/playlist/Segment.h"
-#include <vector>
-#ifdef HAVE_GCRYPT
- #include <gcrypt.h>
-#endif
+#include "../adaptive/encryption/CommonEncryption.hpp"
namespace hls
{
namespace playlist
{
using namespace adaptive::playlist;
-
- class SegmentEncryption
- {
- public:
- SegmentEncryption();
- enum
- {
- NONE,
- AES_128,
- AES_SAMPLE,
- } method;
- std::vector<uint8_t> key;
- std::vector<uint8_t> iv;
- };
+ using namespace adaptive::encryption;
class HLSSegment : public Segment
{
@@ -53,7 +37,7 @@ namespace hls
public:
HLSSegment( ICanonicalUrl *parent, uint64_t sequence );
virtual ~HLSSegment();
- void setEncryption(SegmentEncryption &);
+ void setEncryption(CommonEncryption &);
vlc_tick_t getUTCTime() const;
virtual int compare(ISegment *) const; /* reimpl */
@@ -61,10 +45,8 @@ namespace hls
vlc_tick_t utcTime;
virtual void onChunkDownload(block_t **, SegmentChunk *, BaseRepresentation *); /* reimpl */
- SegmentEncryption encryption;
-#ifdef HAVE_GCRYPT
- gcry_cipher_hd_t ctx;
-#endif
+ CommonEncryption encryption;
+ CommonEncryptionSession encryptSession;
};
}
}
diff --git a/modules/demux/hls/playlist/Parser.cpp b/modules/demux/hls/playlist/Parser.cpp
index db4d72bbef..d722a0792c 100644
--- a/modules/demux/hls/playlist/Parser.cpp
+++ b/modules/demux/hls/playlist/Parser.cpp
@@ -204,7 +204,7 @@ void M3U8Parser::parseSegments(vlc_object_t *, Representation *rep, const std::l
bool discontinuity = false;
std::size_t prevbyterangeoffset = 0;
const SingleValueTag *ctx_byterange = NULL;
- SegmentEncryption encryption;
+ CommonEncryption encryption;
const ValuesListTag *ctx_extinf = NULL;
std::list<Tag *>::const_iterator it;
@@ -282,7 +282,7 @@ void M3U8Parser::parseSegments(vlc_object_t *, Representation *rep, const std::l
discontinuity = false;
}
- if(encryption.method != SegmentEncryption::NONE)
+ if(encryption.method != CommonEncryption::Method::NONE)
segment->setEncryption(encryption);
}
break;
@@ -312,7 +312,7 @@ void M3U8Parser::parseSegments(vlc_object_t *, Representation *rep, const std::l
keytag->getAttributeByName("METHOD")->value == "AES-128" &&
keytag->getAttributeByName("URI") )
{
- encryption.method = SegmentEncryption::AES_128;
+ encryption.method = CommonEncryption::Method::AES_128;
encryption.key.clear();
Url keyurl(keytag->getAttributeByName("URI")->quotedString());
@@ -333,7 +333,7 @@ void M3U8Parser::parseSegments(vlc_object_t *, Representation *rep, const std::l
else
{
/* unsupported or invalid */
- encryption.method = SegmentEncryption::NONE;
+ encryption.method = CommonEncryption::Method::NONE;
encryption.key.clear();
encryption.iv.clear();
}
More information about the vlc-commits
mailing list