[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