diff --git a/configure.ac b/configure.ac index 23992fcc44..ea8aefb508 100644 --- a/configure.ac +++ b/configure.ac @@ -2211,7 +2211,19 @@ AG_GST_CHECK_FEATURE(SNDIO, [sndio audio], sndio, [ dnl *** hls *** translit(dnm, m, l) AM_CONDITIONAL(USE_HLS, true) AG_GST_CHECK_FEATURE(HLS, [http live streaming plugin], hls, [ - AM_PATH_LIBGCRYPT([1.2.0], [ HAVE_HLS="yes" ], [ HAVE_HLS="no" ]) + PKG_CHECK_MODULES(NETTLE, nettle, + [ + AC_DEFINE(HAVE_NETTLE, 1, [Define if nettle is available]) + HAVE_HLS="yes" + ], [ + AM_PATH_LIBGCRYPT([1.2.0], + [ + AC_DEFINE(HAVE_LIBGCRYPT, 1, [Define if libgcrypt is available]) + HAVE_HLS="yes" + ], [ + HAVE_HLS="no" + ]) + ]) ]) else diff --git a/ext/hls/Makefile.am b/ext/hls/Makefile.am index 853944b323..cedf183ddc 100644 --- a/ext/hls/Makefile.am +++ b/ext/hls/Makefile.am @@ -8,11 +8,11 @@ libgstfragmented_la_SOURCES = \ gsthlssink.c \ gstm3u8playlist.c -libgstfragmented_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) $(LIBGCRYPT_CFLAGS) +libgstfragmented_la_CFLAGS = $(GST_PLUGINS_BAD_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GIO_CFLAGS) $(LIBGCRYPT_CFLAGS) $(NETTLE_CFLAGS) libgstfragmented_la_LIBADD = \ $(top_builddir)/gst-libs/gst/uridownloader/libgsturidownloader-@GST_API_VERSION@.la \ $(GST_PLUGINS_BASE_LIBS) -lgstpbutils-$(GST_API_VERSION) -lgstvideo-$(GST_API_VERSION) \ - $(GST_BASE_LIBS) $(GST_LIBS) $(GIO_LIBS) $(LIBM) $(LIBGCRYPT_LIBS) + $(GST_BASE_LIBS) $(GST_LIBS) $(GIO_LIBS) $(LIBM) $(LIBGCRYPT_LIBS) $(NETTLE_LIBS) libgstfragmented_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -no-undefined libgstfragmented_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) diff --git a/ext/hls/gsthlsdemux.c b/ext/hls/gsthlsdemux.c index baa28e336a..96dcc7ff1d 100644 --- a/ext/hls/gsthlsdemux.c +++ b/ext/hls/gsthlsdemux.c @@ -42,7 +42,12 @@ #endif #include +#ifdef HAVE_NETTLE +#include +#include +#else #include +#endif #include "gsthlsdemux.h" static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src_%u", @@ -1231,6 +1236,59 @@ gst_hls_demux_switch_playlist (GstHLSDemux * demux) return gst_hls_demux_change_playlist (demux, bitrate * demux->bitrate_limit); } +#ifdef HAVE_NETTLE +static gboolean +decrypt_fragment (GstHLSDemux * demux, gsize length, + const guint8 * encrypted_data, guint8 * decrypted_data, + const guint8 * key_data, const guint8 * iv_data) +{ + struct CBC_CTX (struct aes_ctx, AES_BLOCK_SIZE) aes_ctx; + + if (length % 16 != 0) + return FALSE; + + aes_set_decrypt_key (&aes_ctx.ctx, 16, key_data); + CBC_SET_IV (&aes_ctx, iv_data); + + CBC_DECRYPT (&aes_ctx, aes_decrypt, length, decrypted_data, encrypted_data); + + return TRUE; +} +#else +static gboolean +decrypt_fragment (GstHLSDemux * demux, gsize length, + const guint8 * encrypted_data, guint8 * decrypted_data, + const guint8 * key_data, const guint8 * iv_data) +{ + gcry_cipher_hd_t aes_ctx = NULL; + gcry_error_t err = 0; + gboolean ret = FALSE; + + err = + gcry_cipher_open (&aes_ctx, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0); + if (err) + goto out; + err = gcry_cipher_setkey (aes_ctx, key_data, 16); + if (err) + goto out; + err = gcry_cipher_setiv (aes_ctx, iv_data, 16); + if (err) + goto out; + err = gcry_cipher_decrypt (aes_ctx, decrypted_data, length, + encrypted_data, length); + if (err) + goto out; + + ret = TRUE; + +out: + if (aes_ctx) + gcry_cipher_close (aes_ctx); + + return ret; +} +#endif + static GstFragment * gst_hls_demux_decrypt_fragment (GstHLSDemux * demux, GstFragment * encrypted_fragment, const gchar * key, const guint8 * iv) @@ -1238,8 +1296,6 @@ gst_hls_demux_decrypt_fragment (GstHLSDemux * demux, GstFragment *key_fragment, *ret = NULL; GstBuffer *key_buffer, *encrypted_buffer, *decrypted_buffer; GstMapInfo key_info, encrypted_info, decrypted_info; - gcry_cipher_hd_t aes_ctx = NULL; - gcry_error_t err = 0; gsize unpadded_size; GST_INFO_OBJECT (demux, "Fetching key %s", key); @@ -1257,21 +1313,9 @@ gst_hls_demux_decrypt_fragment (GstHLSDemux * demux, gst_buffer_map (encrypted_buffer, &encrypted_info, GST_MAP_READ); gst_buffer_map (decrypted_buffer, &decrypted_info, GST_MAP_WRITE); - err = - gcry_cipher_open (&aes_ctx, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0); - if (err) - goto gcry_error; - err = gcry_cipher_setkey (aes_ctx, key_info.data, 16); - if (err) - goto gcry_error; - err = gcry_cipher_setiv (aes_ctx, iv, 16); - if (err) - goto gcry_error; - err = gcry_cipher_decrypt (aes_ctx, decrypted_info.data, decrypted_info.size, - encrypted_info.data, encrypted_info.size); - if (err) - goto gcry_error; - gcry_cipher_close (aes_ctx); + if (!decrypt_fragment (demux, encrypted_info.size, + encrypted_info.data, decrypted_info.data, key_info.data, iv)) + goto decrypt_error; /* Handle pkcs7 unpadding here */ unpadded_size = @@ -1294,12 +1338,8 @@ key_failed: g_object_unref (encrypted_fragment); return ret; -gcry_error: - GST_ERROR_OBJECT (demux, "Failed to decrypt fragment: %s", - gpg_strerror (err)); - - if (aes_ctx) - gcry_cipher_close (aes_ctx); +decrypt_error: + GST_ERROR_OBJECT (demux, "Failed to decrypt fragment"); gst_buffer_unref (key_buffer); gst_buffer_unref (encrypted_buffer);