[vlc-devel] [PATCH] HLS output: add encryption support
Rafaël Carré
funman at videolan.org
Tue Mar 6 22:45:49 CET 2012
Set --sout-livehttp-key-uri to the URI which will be written in the m3u8
VLC will fetch the key and use it for encryption
The key is per stream and not per segment
---
Note, it was suggested that we provide a way to set the key without fetching it.
i.e. have a --key=0x12345678 (up to 32 digits), in case the key is fetched from
a keyserver which is accessible only to the client.
modules/access_output/Modules.am | 12 +++-
modules/access_output/livehttp.c | 152 ++++++++++++++++++++++++++++++++++++--
2 files changed, 155 insertions(+), 9 deletions(-)
diff --git a/modules/access_output/Modules.am b/modules/access_output/Modules.am
index 631b600..43bb5c2 100644
--- a/modules/access_output/Modules.am
+++ b/modules/access_output/Modules.am
@@ -1,6 +1,5 @@
SOURCES_access_output_dummy = dummy.c
SOURCES_access_output_file = file.c
-SOURCES_access_output_livehttp = livehttp.c
SOURCES_access_output_udp = udp.c
SOURCES_access_output_http = http.c bonjour.c bonjour.h
SOURCES_access_output_shout = shout.c
@@ -17,10 +16,19 @@ libaccess_output_rtmp_plugin_la_DEPENDENCIES =
libvlc_LTLIBRARIES += \
libaccess_output_dummy_plugin.la \
libaccess_output_file_plugin.la \
- libaccess_output_livehttp_plugin.la \
libaccess_output_udp_plugin.la \
libaccess_output_http_plugin.la \
$(NULL)
+
+if HAVE_GCRYPT
+libaccess_output_livehttp_plugin_la_SOURCES = livehttp.c
+libaccess_output_livehttp_plugin_la_CFLAGS = $(AM_CFLAGS) $(GCRYPT_CFLAGS)
+libaccess_output_livehttp_plugin_la_LIBADD = $(AM_LIBADD) $(GCRYPT_LIBS) -lgpg-error
+libaccess_output_livehttp_plugin_la_DEPENDENCIES =
+libvlc_LTLIBRARIES += libaccess_output_livehttp_plugin.la
+endif
+
+
EXTRA_LTLIBRARIES += \
libaccess_output_rtmp_plugin.la \
$(NULL)
diff --git a/modules/access_output/livehttp.c b/modules/access_output/livehttp.c
index d335a64..727ea50 100644
--- a/modules/access_output/livehttp.c
+++ b/modules/access_output/livehttp.c
@@ -37,6 +37,8 @@
# include <unistd.h>
#endif
+#include <gcrypt.h>
+
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_sout.h>
@@ -45,6 +47,10 @@
#include <vlc_strings.h>
#include <vlc_charset.h>
+#include <vlc_rand.h>
+#include <vlc_gcrypt.h>
+#include <vlc_stream.h>
+
#ifndef O_LARGEFILE
# define O_LARGEFILE 0
#endif
@@ -82,6 +88,8 @@ static void Close( vlc_object_t * );
#define RATECONTROL_TEXT N_("Use muxers rate control mechanism")
+#define KEY_TEXT N_("AES key URI for encryption")
+
vlc_module_begin ()
set_description( N_("HTTP Live streaming output") )
set_shortname( N_("LiveHTTP" ))
@@ -97,6 +105,8 @@ vlc_module_begin ()
DELSEGS_TEXT, DELSEGS_LONGTEXT, true )
add_bool( SOUT_CFG_PREFIX "ratecontrol", false,
RATECONTROL_TEXT, RATECONTROL_TEXT, true )
+ add_string( SOUT_CFG_PREFIX "key-uri", NULL,
+ KEY_TEXT, KEY_TEXT, true )
add_string( SOUT_CFG_PREFIX "index", NULL,
INDEX_TEXT, INDEX_LONGTEXT, true )
add_string( SOUT_CFG_PREFIX "index-url", NULL,
@@ -116,6 +126,7 @@ static const char *const ppsz_sout_options[] = {
"index",
"index-url",
"ratecontrol",
+ "key-uri",
NULL
};
@@ -137,9 +148,70 @@ struct sout_access_out_sys_t
bool b_delsegs;
bool b_ratecontrol;
bool b_splitanywhere;
+
+ uint8_t aes_ivs[16];
+ gcry_cipher_hd_t aes_ctx;
+ char *key_uri;
};
/*****************************************************************************
+ * CryptSetup:
+ *****************************************************************************/
+static int CryptSetup( sout_access_out_t *p_access )
+{
+ sout_access_out_sys_t *p_sys = p_access->p_sys;
+
+ p_sys->key_uri = var_GetNonEmptyString( p_access, SOUT_CFG_PREFIX "key-uri" );
+ if (!p_sys->key_uri) /* no encryption requested */
+ return VLC_SUCCESS;
+
+ uint8_t key[16];
+ vlc_gcrypt_init();
+
+ stream_t *s = stream_UrlNew(p_access, p_sys->key_uri);
+ if (!s)
+ {
+ msg_Err( p_access, "Couldn't open key URI %s", p_sys->key_uri);
+ return VLC_EGENERIC;
+ }
+
+ int ret = stream_Read(s, key, 16);
+ stream_Delete(s);
+ if (ret != 16)
+ {
+ msg_Err(p_access, "The AES key loaded doesn't have the right size (%d)",
+ ret);
+ return VLC_EGENERIC;
+ }
+
+ gcry_error_t err = gcry_cipher_open(&p_sys->aes_ctx, GCRY_CIPHER_AES,
+ GCRY_CIPHER_MODE_CBC, 0);
+ if (err) {
+ msg_Err(p_access, "Opening AES cipher failed: %s", gpg_strerror(err));
+ return VLC_EGENERIC;
+ }
+ err = gcry_cipher_setkey(p_sys->aes_ctx, key, 16);
+ if (err) {
+ msg_Err(p_access, "Setting AES key failed: %s", gpg_strerror(err));
+ goto encrypt_fail;
+ }
+
+ vlc_rand_bytes(p_sys->aes_ivs, 16);
+
+ err = gcry_cipher_setiv(p_sys->aes_ctx, p_sys->aes_ivs, 16);
+ if (err) {
+ msg_Err(p_access, "Setting AES IVs failed: %s", gpg_strerror(err));
+ goto encrypt_fail;
+ }
+
+ return VLC_SUCCESS;
+
+encrypt_fail:
+ gcry_cipher_close(p_sys->aes_ctx);
+ return VLC_EGENERIC;
+}
+
+/*****************************************************************************
* Open: open the file
*****************************************************************************/
static int Open( vlc_object_t *p_this )
@@ -195,6 +267,15 @@ static int Open( vlc_object_t *p_this )
p_access->pf_seek = Seek;
p_access->pf_control = Control;
+ if (CryptSetup(p_access))
+ {
+ free( p_sys->key_uri );
+ free( p_sys->psz_indexUrl );
+ free( p_sys->psz_indexPath );
+ free(p_sys);
+ return VLC_EGENERIC;
+ }
+
return VLC_SUCCESS;
}
@@ -267,6 +348,25 @@ static int updateIndexAndDel( sout_access_out_t *p_access, sout_access_out_sys_t
return -1;
}
+ if (p_sys->key_uri) {
+ unsigned long long iv_hi = 0, iv_lo = 0;
+ for (int i = 0; i < 8; i++)
+ {
+ iv_hi |= p_sys->aes_ivs[i] & 0xff;
+ iv_hi <<= 8;
+ iv_lo |= p_sys->aes_ivs[8+i] & 0xff;
+ iv_lo <<= 8;
+ }
+ if ( fprintf(fp,
+ "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\",IV=0X%16.16llx%16.16llx\n",
+ p_sys->key_uri, iv_hi, iv_lo
+ ) < 0 ) {
+ free( psz_idxTmp );
+ fclose( fp );
+ return -1;
+ }
+ }
+
char *psz_idxFormat = p_sys->psz_indexUrl ? p_sys->psz_indexUrl : p_access->psz_path;
for ( uint32_t i = i_firstseg; i <= p_sys->i_segment; i++ )
{
@@ -356,9 +456,12 @@ static void Close( vlc_object_t * p_this )
closeCurrentSegment( p_access, p_sys, true );
free( p_sys->psz_indexUrl );
free( p_sys->psz_indexPath );
+ if (p_sys->key_uri)
+ {
+ gcry_cipher_close(p_sys->aes_ctx);
+ free(p_sys->key_uri);
+ }
free( p_sys );
-
- msg_Dbg( p_access, "livehttp access output closed" );
}
static int Control( sout_access_out_t *p_access, int i_query, va_list args )
@@ -419,9 +522,37 @@ static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
{
size_t i_write = 0;
sout_access_out_sys_t *p_sys = p_access->p_sys;
+ bool b_encrypt = p_sys->key_uri != NULL;
+
+ uint8_t *buf = NULL;
+ size_t size = 0;
+
+ if (p_buffer && !b_encrypt)
+ {
+ buf = p_buffer->p_buffer;
+ size = p_buffer->i_buffer;
+ }
while( p_buffer )
{
+ if (b_encrypt) {
+ size = (p_buffer->i_buffer + 15) & ~15;
+ block_t *padded = block_Realloc(p_buffer, 0, size);
+ if (!padded || !(buf = malloc(size)))
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ gcry_error_t err = gcry_cipher_encrypt (p_sys->aes_ctx,
+ buf, size, p_buffer->p_buffer, p_buffer->i_buffer);
+ if (err) {
+ msg_Err(p_access, "Couldn't encrypt %zu bytes: %s", p_buffer->i_buffer, gpg_strerror(err));
+ return -1;
+ }
+ b_encrypt = false;
+ }
+
if ( p_sys->i_handle >= 0 && ( p_sys->b_splitanywhere || ( p_buffer->i_flags & BLOCK_FLAG_TYPE_I ) ) && ( p_buffer->i_dts-p_sys->i_opendts ) > p_sys->i_seglenm )
{
closeCurrentSegment( p_access, p_sys, false );
@@ -432,8 +563,7 @@ static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
if ( openNextFile( p_access, p_sys ) < 0 )
return -1;
}
- ssize_t val = write ( p_sys->i_handle,
- p_buffer->p_buffer, p_buffer->i_buffer );
+ ssize_t val = write ( p_sys->i_handle, buf, size );
if ( val == -1 )
{
if ( errno == EINTR )
@@ -442,16 +572,24 @@ static ssize_t Write( sout_access_out_t *p_access, block_t *p_buffer )
return -1;
}
- if ( (size_t)val >= p_buffer->i_buffer )
+ if ( (size_t)val >= size )
{
block_t *p_next = p_buffer->p_next;
block_Release (p_buffer);
p_buffer = p_next;
+ b_encrypt = p_sys->key_uri != NULL;
+ if (b_encrypt)
+ free(buf);
+ else if (p_buffer)
+ {
+ buf = p_buffer->p_buffer;
+ size = p_buffer->i_buffer;
+ }
}
else
{
- p_buffer->p_buffer += val;
- p_buffer->i_buffer -= val;
+ buf += val;
+ size -= val;
}
i_write += val;
}
--
1.7.9
More information about the vlc-devel
mailing list