summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2019-05-13 16:08:33 +0100
committerCarl Hetherington <cth@carlh.net>2019-05-13 16:08:33 +0100
commit257fce15e8b4dfa112d039e7888e3ec04e523198 (patch)
tree3afe5047010bb71aaa3851ef3b2f438509bccad3 /src/lib
parent5de2fd90b92829cea8ab297c6fce81c582332cb7 (diff)
swaroop: basics of encrypted MP4 playback.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/decrypted_ecinema_kdm.cc38
-rw-r--r--src/lib/decrypted_ecinema_kdm.h12
-rw-r--r--src/lib/encrypted_ecinema_kdm.cc18
-rw-r--r--src/lib/encrypted_ecinema_kdm.h12
-rw-r--r--src/lib/ffmpeg.cc9
-rw-r--r--src/lib/ffmpeg_content.cc20
-rw-r--r--src/lib/ffmpeg_content.h26
-rw-r--r--src/lib/ffmpeg_decoder.cc7
-rw-r--r--src/lib/ffmpeg_examiner.cc7
-rw-r--r--src/lib/ffmpeg_examiner.h10
-rw-r--r--src/lib/util.h4
11 files changed, 143 insertions, 20 deletions
diff --git a/src/lib/decrypted_ecinema_kdm.cc b/src/lib/decrypted_ecinema_kdm.cc
index 2cb4f61d7..a03004e43 100644
--- a/src/lib/decrypted_ecinema_kdm.cc
+++ b/src/lib/decrypted_ecinema_kdm.cc
@@ -22,21 +22,53 @@
#include "encrypted_ecinema_kdm.h"
#include "decrypted_ecinema_kdm.h"
+#include "exceptions.h"
#include <dcp/key.h>
+#include <dcp/util.h>
#include <dcp/certificate.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+using std::string;
+using std::runtime_error;
using dcp::Certificate;
-DecryptedECinemaKDM::DecryptedECinemaKDM (dcp::Key content_key)
- : _content_key (content_key)
+DecryptedECinemaKDM::DecryptedECinemaKDM (string id, dcp::Key content_key)
+ : _id (id)
+ , _content_key (content_key)
{
}
+DecryptedECinemaKDM::DecryptedECinemaKDM (EncryptedECinemaKDM kdm, string private_key)
+ : _id (kdm.id())
+{
+ /* Read the private key */
+
+ BIO* bio = BIO_new_mem_buf (const_cast<char *> (private_key.c_str()), -1);
+ if (!bio) {
+ throw runtime_error ("could not create memory BIO");
+ }
+
+ RSA* rsa = PEM_read_bio_RSAPrivateKey (bio, 0, 0, 0);
+ if (!rsa) {
+ throw FileError ("could not read RSA private key file", private_key);
+ }
+
+ uint8_t value[RSA_size(rsa)];
+ int const len = RSA_private_decrypt (kdm.key().size(), kdm.key().data().get(), value, rsa, RSA_PKCS1_OAEP_PADDING);
+ if (len == -1) {
+ throw KDMError (ERR_error_string(ERR_get_error(), 0), "");
+ }
+
+ _content_key = dcp::Key (value, len);
+}
+
EncryptedECinemaKDM
DecryptedECinemaKDM::encrypt (Certificate recipient)
{
- return EncryptedECinemaKDM (_content_key, recipient);
+ return EncryptedECinemaKDM (_id, _content_key, recipient);
}
#endif
diff --git a/src/lib/decrypted_ecinema_kdm.h b/src/lib/decrypted_ecinema_kdm.h
index b0fc2064d..f61402b7b 100644
--- a/src/lib/decrypted_ecinema_kdm.h
+++ b/src/lib/decrypted_ecinema_kdm.h
@@ -28,11 +28,21 @@
class DecryptedECinemaKDM
{
public:
- DecryptedECinemaKDM (dcp::Key content_key);
+ DecryptedECinemaKDM (std::string id, dcp::Key content_key);
+ DecryptedECinemaKDM (EncryptedECinemaKDM kdm, std::string private_key);
EncryptedECinemaKDM encrypt (dcp::Certificate recipient);
+ std::string id () const {
+ return _id;
+ }
+
+ dcp::Key key () const {
+ return _content_key;
+ }
+
private:
+ std::string _id;
/** unenecrypted content key */
dcp::Key _content_key;
};
diff --git a/src/lib/encrypted_ecinema_kdm.cc b/src/lib/encrypted_ecinema_kdm.cc
index e277eb997..ab9e15e85 100644
--- a/src/lib/encrypted_ecinema_kdm.cc
+++ b/src/lib/encrypted_ecinema_kdm.cc
@@ -23,6 +23,8 @@
#include "encrypted_ecinema_kdm.h"
#include <dcp/key.h>
#include <dcp/certificate.h>
+#include <dcp/util.h>
+#include <libcxml/cxml.h>
#include <libxml++/libxml++.h>
#include <openssl/rsa.h>
#include <iostream>
@@ -32,13 +34,24 @@ using std::string;
using boost::shared_ptr;
using dcp::Certificate;
-EncryptedECinemaKDM::EncryptedECinemaKDM (dcp::Key content_key, Certificate recipient)
+EncryptedECinemaKDM::EncryptedECinemaKDM (string id, dcp::Key content_key, Certificate recipient)
+ : _id (id)
{
RSA* rsa = recipient.public_key ();
_content_key = dcp::Data (RSA_size(rsa));
int const N = RSA_public_encrypt (content_key.length(), content_key.value(), _content_key.data().get(), rsa, RSA_PKCS1_OAEP_PADDING);
}
+EncryptedECinemaKDM::EncryptedECinemaKDM (string xml)
+{
+ cxml::Document doc ("ECinemaSecurityMessage");
+ doc.read_string (xml);
+ _id = doc.string_child ("Id");
+ _content_key = dcp::Data (256);
+ int const len = dcp::base64_decode (doc.string_child("Key"), _content_key.data().get(), _content_key.size());
+ _content_key.set_size (len);
+}
+
string
EncryptedECinemaKDM::as_xml () const
{
@@ -57,7 +70,8 @@ EncryptedECinemaKDM::as_xml () const
}
xmlpp::Document document;
- xmlpp::Element* root = document.create_root_node ("ECinemaSecurityMesage");
+ xmlpp::Element* root = document.create_root_node ("ECinemaSecurityMessage");
+ root->add_child("Id")->add_child_text(_id);
root->add_child("Key")->add_child_text(lines);
return document.write_to_string ("UTF-8");
}
diff --git a/src/lib/encrypted_ecinema_kdm.h b/src/lib/encrypted_ecinema_kdm.h
index fc6fbdb65..ece1e3161 100644
--- a/src/lib/encrypted_ecinema_kdm.h
+++ b/src/lib/encrypted_ecinema_kdm.h
@@ -32,14 +32,24 @@ class DecryptedECinemaKDM;
class EncryptedECinemaKDM
{
public:
+ explicit EncryptedECinemaKDM (std::string xml);
std::string as_xml () const;
+ std::string id () const {
+ return _id;
+ }
+
+ dcp::Data key () const {
+ return _content_key;
+ }
+
private:
friend class DecryptedECinemaKDM;
- EncryptedECinemaKDM (dcp::Key key, dcp::Certificate recipient);
+ EncryptedECinemaKDM (std::string id, dcp::Key key, dcp::Certificate recipient);
+ std::string _id;
/** encrypted content key */
dcp::Data _content_key;
};
diff --git a/src/lib/ffmpeg.cc b/src/lib/ffmpeg.cc
index ab5148cfa..d6a592f88 100644
--- a/src/lib/ffmpeg.cc
+++ b/src/lib/ffmpeg.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
@@ -27,8 +27,10 @@
#include "dcpomatic_log.h"
#include "ffmpeg_subtitle_stream.h"
#include "ffmpeg_audio_stream.h"
+#include "decrypted_ecinema_kdm.h"
#include "digester.h"
#include "compose.hpp"
+#include "config.h"
#include <dcp/raw_convert.h>
extern "C" {
#include <libavcodec/avcodec.h>
@@ -123,8 +125,9 @@ FFmpeg::setup_general ()
*/
av_dict_set (&options, "analyzeduration", raw_convert<string> (5 * 60 * 1000000).c_str(), 0);
av_dict_set (&options, "probesize", raw_convert<string> (5 * 60 * 1000000).c_str(), 0);
- if (_ffmpeg_content->decryption_key()) {
- av_dict_set (&options, "decryption_key", _ffmpeg_content->decryption_key()->c_str(), 0);
+ if (_ffmpeg_content->kdm()) {
+ DecryptedECinemaKDM kdm (_ffmpeg_content->kdm().get(), Config::instance()->decryption_chain()->key().get());
+ av_dict_set (&options, "decryption_key", kdm.key().hex().c_str(), 0);
}
int e = avformat_open_input (&_format_context, 0, 0, &options);
diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc
index 69d743215..e291b8e7c 100644
--- a/src/lib/ffmpeg_content.cc
+++ b/src/lib/ffmpeg_content.cc
@@ -61,6 +61,7 @@ using namespace dcpomatic;
int const FFmpegContentProperty::SUBTITLE_STREAMS = 100;
int const FFmpegContentProperty::SUBTITLE_STREAM = 101;
int const FFmpegContentProperty::FILTERS = 102;
+int const FFmpegContentProperty::KDM = 103;
FFmpegContent::FFmpegContent (boost::filesystem::path p)
: Content (p)
@@ -125,7 +126,6 @@ FFmpegContent::FFmpegContent (cxml::ConstNodePtr node, int version, list<string>
_color_trc = get_optional_enum<AVColorTransferCharacteristic>(node, "ColorTransferCharacteristic");
_colorspace = get_optional_enum<AVColorSpace>(node, "Colorspace");
_bits_per_pixel = node->optional_number_child<int> ("BitsPerPixel");
- _decryption_key = node->optional_string_child ("DecryptionKey");
_encrypted = node->optional_bool_child("Encrypted").get_value_or(false);
}
@@ -248,9 +248,6 @@ FFmpegContent::as_xml (xmlpp::Node* node, bool with_paths) const
if (_bits_per_pixel) {
node->add_child("BitsPerPixel")->add_child_text (raw_convert<string> (*_bits_per_pixel));
}
- if (_decryption_key) {
- node->add_child("DecryptionKey")->add_child_text (_decryption_key.get());
- }
if (_encrypted) {
node->add_child("Encypted")->add_child_text ("1");
}
@@ -325,6 +322,10 @@ FFmpegContent::examine (shared_ptr<const Film> film, shared_ptr<Job> job)
if (examiner->has_video ()) {
set_default_colour_conversion ();
}
+
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+ _id = examiner->id ();
+#endif
}
string
@@ -687,3 +688,14 @@ FFmpegContent::take_settings_from (shared_ptr<const Content> c)
Content::take_settings_from (c);
_filters = fc->_filters;
}
+
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+void
+FFmpegContent::add_kdm (EncryptedECinemaKDM kdm)
+{
+ ChangeSignaller<Content> cc (this, FFmpegContentProperty::KDM);
+ boost::mutex::scoped_lock lm (_mutex);
+ _kdm = kdm;
+
+}
+#endif
diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h
index 8871301b1..6c572f242 100644
--- a/src/lib/ffmpeg_content.h
+++ b/src/lib/ffmpeg_content.h
@@ -21,6 +21,9 @@
#ifndef DCPOMATIC_FFMPEG_CONTENT_H
#define DCPOMATIC_FFMPEG_CONTENT_H
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+#include "encrypted_ecinema_kdm.h"
+#endif
#include "content.h"
#include "audio_stream.h"
@@ -41,6 +44,7 @@ public:
/** The chosen subtitle stream, or something about it */
static int const SUBTITLE_STREAM;
static int const FILTERS;
+ static int const KDM;
};
class FFmpegContent : public Content
@@ -98,16 +102,25 @@ public:
void signal_subtitle_stream_changed ();
- boost::optional<std::string> decryption_key () const {
- boost::mutex::scoped_lock lm (_mutex);
- return _decryption_key;
- }
+#ifdef DCPOMATIC_VARIANT_SWAROOP
bool encrypted () const {
boost::mutex::scoped_lock lm (_mutex);
return _encrypted;
}
+ void add_kdm (EncryptedECinemaKDM kdm);
+
+ boost::optional<EncryptedECinemaKDM> kdm () const {
+ return _kdm;
+ }
+
+ boost::optional<std::string> id () const {
+ return _id;
+ }
+
+#endif
+
private:
void add_properties (boost::shared_ptr<const Film> film, std::list<UserProperty> &) const;
@@ -125,8 +138,11 @@ private:
boost::optional<AVColorTransferCharacteristic> _color_trc;
boost::optional<AVColorSpace> _colorspace;
boost::optional<int> _bits_per_pixel;
- boost::optional<std::string> _decryption_key;
+#ifdef DCPOMATIC_VARIANT_SWAROOP
bool _encrypted;
+ boost::optional<EncryptedECinemaKDM> _kdm;
+ boost::optional<std::string> _id;
+#endif
};
#endif
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index 0e65a6d6b..c52723da3 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -59,7 +59,6 @@ extern "C" {
#include "i18n.h"
-
using std::cout;
using std::string;
using std::vector;
@@ -159,6 +158,12 @@ FFmpegDecoder::flush ()
bool
FFmpegDecoder::pass ()
{
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+ if (_ffmpeg_content->encrypted() && !_ffmpeg_content->kdm()) {
+ return true;
+ }
+#endif
+
int r = av_read_frame (_format_context, &_packet);
/* AVERROR_INVALIDDATA can apparently be returned sometimes even when av_read_frame
diff --git a/src/lib/ffmpeg_examiner.cc b/src/lib/ffmpeg_examiner.cc
index 382b71b83..a4c5eb128 100644
--- a/src/lib/ffmpeg_examiner.cc
+++ b/src/lib/ffmpeg_examiner.cc
@@ -166,6 +166,13 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Jo
DCPOMATIC_ASSERT (fabs (*_rotation - 90 * round (*_rotation / 90)) < 2);
}
+
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+ AVDictionaryEntry* e = av_dict_get (_format_context->metadata, SWAROOP_ID_TAG, 0, 0);
+ if (e) {
+ _id = e->value;
+ }
+#endif
}
void
diff --git a/src/lib/ffmpeg_examiner.h b/src/lib/ffmpeg_examiner.h
index d2e6e1a0a..1c0dad3dc 100644
--- a/src/lib/ffmpeg_examiner.h
+++ b/src/lib/ffmpeg_examiner.h
@@ -75,6 +75,12 @@ public:
return _rotation;
}
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+ boost::optional<std::string> id () const {
+ return _id;
+ }
+#endif
+
private:
void video_packet (AVCodecContext *);
void audio_packet (AVCodecContext *, boost::shared_ptr<FFmpegAudioStream>);
@@ -94,6 +100,10 @@ private:
boost::optional<double> _rotation;
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+ boost::optional<std::string> _id;
+#endif
+
struct SubtitleStart
{
SubtitleStart (std::string id_, bool image_, dcpomatic::ContentTime time_)
diff --git a/src/lib/util.h b/src/lib/util.h
index b760f7f4b..b95a0af58 100644
--- a/src/lib/util.h
+++ b/src/lib/util.h
@@ -63,6 +63,10 @@ namespace dcp {
#define CLOSED_CAPTION_LINES 3
/** Maximum line length of closed caption viewers */
#define CLOSED_CAPTION_LENGTH 30
+/* We are mis-using episode_id here, as non-iTunes metadata tags are ignored.
+ I tried the use_metadata_tags option but it didn't seem to make any difference.
+*/
+#define SWAROOP_ID_TAG "episode_id"
extern std::string program_name;
extern bool is_batch_converter;