summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-09-19 20:44:42 +0100
committerCarl Hetherington <cth@carlh.net>2013-09-19 20:44:42 +0100
commit8d6c3c9ae554430582dcb016897e87f6d04d5d78 (patch)
tree5b329eeb60fe7372cc89740d4cf8fa1d5fe51614
parent827901db3d834465b1121c9f8041b9faf4923ec9 (diff)
Various encryption-related stuff.
-rw-r--r--examples/make_dcp.cc4
-rw-r--r--src/certificates.cc50
-rw-r--r--src/certificates.h16
-rw-r--r--src/cpl.cc28
-rw-r--r--src/dcp.cc4
-rw-r--r--src/kdm.cc27
-rw-r--r--src/kdm.h35
-rw-r--r--src/key.cc99
-rw-r--r--src/key.h61
-rw-r--r--src/mxf_asset.cc54
-rw-r--r--src/mxf_asset.h35
-rw-r--r--src/picture_asset.cc20
-rw-r--r--src/picture_asset.h9
-rw-r--r--src/reel.cc8
-rw-r--r--src/sound_asset.cc10
-rw-r--r--src/sound_asset.h7
-rw-r--r--src/wscript2
-rw-r--r--test/certificates_test.cc9
-rw-r--r--test/dcp_test.cc2
-rw-r--r--test/encryption_test.cc12
-rw-r--r--test/error_test.cc4
-rw-r--r--test/kdm_test.cc28
-rw-r--r--test/recovery_test.cc4
23 files changed, 361 insertions, 167 deletions
diff --git a/examples/make_dcp.cc b/examples/make_dcp.cc
index 6da9cf20..9222caaa 100644
--- a/examples/make_dcp.cc
+++ b/examples/make_dcp.cc
@@ -75,7 +75,7 @@ main ()
for 2K projectors.
*/
boost::shared_ptr<libdcp::MonoPictureAsset> picture_asset (
- new libdcp::MonoPictureAsset (video_frame, "My Film DCP", "video.mxf", 0, 24, 48, false, libdcp::Size (1998, 1080), false)
+ new libdcp::MonoPictureAsset (video_frame, "My Film DCP", "video.mxf", 0, 24, 48, libdcp::Size (1998, 1080), false)
);
/* Now we will create a `sound asset', which is made up of a WAV file for each channel of audio. Here we're using
@@ -95,7 +95,7 @@ main ()
/* Now we can create the sound asset using these files */
boost::shared_ptr<libdcp::SoundAsset> sound_asset (
- new libdcp::SoundAsset (sound_files, "My Film DCP", "audio.mxf", 0, 24, 48, false, false)
+ new libdcp::SoundAsset (sound_files, "My Film DCP", "audio.mxf", 0, 24, 48, false)
);
/* Now that we have the assets, we can create a Reel to put them in and add it to the CPL */
diff --git a/src/certificates.cc b/src/certificates.cc
index 3566fba0..6d9c449d 100644
--- a/src/certificates.cc
+++ b/src/certificates.cc
@@ -43,7 +43,7 @@ Certificate::Certificate (X509* c)
}
-Certificate::Certificate (string const & filename)
+Certificate::Certificate (boost::filesystem::path filename)
: _certificate (0)
{
FILE* f = fopen (filename.c_str(), "r");
@@ -56,13 +56,52 @@ Certificate::Certificate (string const & filename)
}
}
+Certificate::Certificate (string cert)
+{
+ read_string (cert);
+}
+
+Certificate::Certificate (Certificate const & other)
+{
+ read_string (other.certificate (true));
+}
+
+void
+Certificate::read_string (string cert)
+{
+ BIO* bio = BIO_new_mem_buf (const_cast<char *> (cert.c_str ()), -1);
+ if (!bio) {
+ throw MiscError ("could not create memory BIO");
+ }
+
+ _certificate = PEM_read_bio_X509 (bio, 0, 0, 0);
+ if (!_certificate) {
+ throw MiscError ("could not read X509 certificate from memory BIO");
+ }
+
+ BIO_free (bio);
+}
+
Certificate::~Certificate ()
{
X509_free (_certificate);
}
+Certificate &
+Certificate::operator= (Certificate const & other)
+{
+ if (this == &other) {
+ return *this;
+ }
+
+ X509_free (_certificate);
+ read_string (other.certificate ());
+
+ return *this;
+}
+
string
-Certificate::certificate () const
+Certificate::certificate (bool with_begin_end) const
{
assert (_certificate);
@@ -82,8 +121,11 @@ Certificate::certificate () const
BIO_free (bio);
- boost::replace_all (s, "-----BEGIN CERTIFICATE-----\n", "");
- boost::replace_all (s, "\n-----END CERTIFICATE-----\n", "");
+ if (!with_begin_end) {
+ boost::replace_all (s, "-----BEGIN CERTIFICATE-----\n", "");
+ boost::replace_all (s, "\n-----END CERTIFICATE-----\n", "");
+ }
+
return s;
}
diff --git a/src/certificates.h b/src/certificates.h
index 9caea5a7..ef2e63b4 100644
--- a/src/certificates.h
+++ b/src/certificates.h
@@ -24,6 +24,7 @@
#include <list>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
+#include <boost/filesystem.hpp>
#undef X509_NAME
#include <openssl/x509.h>
@@ -35,18 +36,25 @@ namespace xmlpp {
namespace libdcp {
-class Certificate : public boost::noncopyable
+class Certificate
{
public:
Certificate ()
: _certificate (0)
{}
- Certificate (std::string const &);
+ Certificate (boost::filesystem::path);
+ Certificate (std::string);
Certificate (X509 *);
+ Certificate (Certificate const &);
~Certificate ();
- std::string certificate () const;
+ Certificate& operator= (Certificate const &);
+
+ /** @param with_begin_end true to include BEGIN CERTIFICATE / END CERTIFICATE markers
+ * @return the whole certificate as a string.
+ */
+ std::string certificate (bool with_begin_end = false) const;
std::string issuer () const;
std::string serial () const;
std::string subject () const;
@@ -54,6 +62,8 @@ public:
std::string thumbprint () const;
private:
+ void read_string (std::string);
+
static std::string name_for_xml (X509_NAME *);
static std::string asn_to_utf8 (ASN1_STRING *);
static std::string get_name_part (X509_NAME *, int);
diff --git a/src/cpl.cc b/src/cpl.cc
index 0791353a..2c0bf6c4 100644
--- a/src/cpl.cc
+++ b/src/cpl.cc
@@ -444,21 +444,29 @@ CPL::make_kdm (
xmlpp::Element* authenticated_private = root->add_child("AuthenticatedPrivate");
authenticated_private->set_attribute ("Id", "ID_AuthenticatedPrivate");
xmlAddID (0, doc->cobj(), (const xmlChar *) "ID_AuthenticatedPrivate", authenticated_private->get_attribute("Id")->cobj());
- {
- xmlpp::Element* encrypted_key = authenticated_private->add_child ("EncryptedKey", "enc");
- {
- xmlpp::Element* encryption_method = encrypted_key->add_child ("EncryptionMethod", "enc");
- encryption_method->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p");
- encryption_method->add_child("DigestMethod", "ds")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
- }
+ /* Hex keys that we have already written into the node */
+ list<Key> written_keys;
+
+ list<shared_ptr<const Asset> > a = assets();
+ for (list<shared_ptr<const Asset> >::iterator i = a.begin(); i != a.end(); ++i) {
+ /* XXX: non-MXF assets? */
+ shared_ptr<const MXFAsset> mxf = boost::dynamic_pointer_cast<const MXFAsset> (*i);
+ if (!mxf || find (written_keys.begin(), written_keys.end(), mxf->key ()) != written_keys.end ()) {
+ continue;
+ }
+
+ xmlpp::Element* encrypted_key = authenticated_private->add_child ("EncryptedKey", "enc");
+ xmlpp::Element* encryption_method = encrypted_key->add_child ("EncryptionMethod", "enc");
+ encryption_method->set_attribute ("Algorithm", "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p");
+ encryption_method->add_child("DigestMethod", "ds")->set_attribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
xmlpp::Element* cipher_data = authenticated_private->add_child ("CipherData", "enc");
- cipher_data->add_child("CipherValue", "enc")->add_child_text("XXX");
+ cipher_data->add_child("CipherValue", "enc")->add_child_text(mxf->key()->hex());
+
+ written_keys.push_back (mxf->key().get());
}
}
- /* XXX: x2 one for each mxf? */
-
{
xmlpp::Element* signature = root->add_child("Signature", "ds");
diff --git a/src/dcp.cc b/src/dcp.cc
index b5da1c2f..d21b3b4e 100644
--- a/src/dcp.cc
+++ b/src/dcp.cc
@@ -349,10 +349,10 @@ DCP::encrypted () const
void
DCP::add_kdm (KDM const & kdm)
{
- list<KDMCipher> ciphers = kdm.ciphers ();
+ list<KDMKey> keys = kdm.keys ();
for (list<shared_ptr<CPL> >::iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
- for (list<KDMCipher>::iterator j = ciphers.begin(); j != ciphers.end(); ++j) {
+ for (list<KDMKey>::iterator j = keys.begin(); j != keys.end(); ++j) {
if (j->cpl_id() == (*i)->id()) {
(*i)->add_kdm (kdm);
}
diff --git a/src/kdm.cc b/src/kdm.cc
index 09935ca3..bbfd3832 100644
--- a/src/kdm.cc
+++ b/src/kdm.cc
@@ -80,7 +80,7 @@ KDM::KDM (boost::filesystem::path kdm, boost::filesystem::path private_key)
throw MiscError (String::compose ("Could not decrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
}
- _ciphers.push_back (KDMCipher (decrypted, decrypted_len));
+ _keys.push_back (KDMKey (decrypted, decrypted_len));
delete[] decrypted;
}
@@ -88,7 +88,7 @@ KDM::KDM (boost::filesystem::path kdm, boost::filesystem::path private_key)
}
-KDMCipher::KDMCipher (unsigned char const * raw, int len)
+KDMKey::KDMKey (unsigned char const * raw, int len)
{
switch (len) {
case 134:
@@ -99,8 +99,7 @@ KDMCipher::KDMCipher (unsigned char const * raw, int len)
_key_id = get_uuid (&raw, 16);
_not_valid_before = get (&raw, 25);
_not_valid_after = get (&raw, 25);
- memcpy (_key_raw, raw, 16);
- _key_string = get_hex (&raw, 16);
+ _key = Key (raw);
break;
case 138:
/* SMPTE */
@@ -111,8 +110,7 @@ KDMCipher::KDMCipher (unsigned char const * raw, int len)
_key_id = get_uuid (&raw, 16);
_not_valid_before = get (&raw, 25);
_not_valid_after = get (&raw, 25);
- memcpy (_key_raw, raw, 16);
- _key_string = get_hex (&raw, 16);
+ _key = Key (raw);
break;
default:
assert (false);
@@ -120,7 +118,7 @@ KDMCipher::KDMCipher (unsigned char const * raw, int len)
}
string
-KDMCipher::get (unsigned char const ** p, int N) const
+KDMKey::get (unsigned char const ** p, int N) const
{
string g;
for (int i = 0; i < N; ++i) {
@@ -132,7 +130,7 @@ KDMCipher::get (unsigned char const ** p, int N) const
}
string
-KDMCipher::get_uuid (unsigned char const ** p, int N) const
+KDMKey::get_uuid (unsigned char const ** p, int N) const
{
stringstream g;
@@ -146,16 +144,3 @@ KDMCipher::get_uuid (unsigned char const ** p, int N) const
return g.str ();
}
-
-string
-KDMCipher::get_hex (unsigned char const ** p, int N) const
-{
- stringstream g;
-
- for (int i = 0; i < N; ++i) {
- g << setw(2) << setfill('0') << hex << static_cast<int> (**p);
- (*p)++;
- }
-
- return g.str ();
-}
diff --git a/src/kdm.h b/src/kdm.h
index 06f15e33..c012c101 100644
--- a/src/kdm.h
+++ b/src/kdm.h
@@ -21,16 +21,17 @@
#define LIBDCP_KDM_H
#include <boost/filesystem.hpp>
+#include "key.h"
namespace libdcp {
-/** A single cipher for encrypting or decrypting an MXF. One or more of these
+/** A single key for encrypting or decrypting an MXF. One or more of these
* are delivered in a KDM.
*/
-class KDMCipher
+class KDMKey
{
public:
- KDMCipher (unsigned char const *, int);
+ KDMKey (unsigned char const *, int);
std::string structure_id () const {
return _structure_id;
@@ -47,11 +48,11 @@ public:
std::string key_type () const {
return _key_type;
}
-
+
std::string key_id () const {
return _key_id;
}
-
+
std::string not_valid_before () const {
return _not_valid_before;
}
@@ -60,30 +61,22 @@ public:
return _not_valid_after;
}
- /** The key as a hex string */
- std::string key_string () const {
- return _key_string;
- }
-
- /** The key as 16 raw bytes */
- unsigned char const * key_raw () const {
- return _key_raw;
+ Key key () const {
+ return _key;
}
private:
std::string get (unsigned char const **, int) const;
std::string get_uuid (unsigned char const **, int) const;
- std::string get_hex (unsigned char const **, int) const;
std::string _structure_id;
std::string _signer_thumbprint;
std::string _cpl_id;
- std::string _key_type;
- std::string _key_id;
std::string _not_valid_before;
std::string _not_valid_after;
- std::string _key_string;
- unsigned char _key_raw[16];
+ std::string _key_type;
+ std::string _key_id;
+ Key _key;
};
class KDM
@@ -91,12 +84,12 @@ class KDM
public:
KDM (boost::filesystem::path, boost::filesystem::path);
- std::list<KDMCipher> ciphers () const {
- return _ciphers;
+ std::list<KDMKey> keys () const {
+ return _keys;
}
private:
- std::list<KDMCipher> _ciphers;
+ std::list<KDMKey> _keys;
};
diff --git a/src/key.cc b/src/key.cc
new file mode 100644
index 00000000..8cac04a3
--- /dev/null
+++ b/src/key.cc
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <sstream>
+#include <string>
+#include <iomanip>
+#include "AS_DCP.h"
+#include "KM_prng.h"
+#include "KM_util.h"
+#include "key.h"
+
+using std::string;
+using std::stringstream;
+using std::setw;
+using std::setfill;
+using namespace libdcp;
+
+Key::Key ()
+ : _value (new uint8_t[ASDCP::KeyLen])
+{
+ Kumu::FortunaRNG rng;
+ rng.FillRandom (_value, ASDCP::KeyLen);
+}
+
+Key::Key (uint8_t const * value)
+ : _value (new uint8_t[ASDCP::KeyLen])
+{
+ memcpy (_value, value, ASDCP::KeyLen);
+}
+
+Key::Key (string value)
+ : _value (new uint8_t[ASDCP::KeyLen])
+{
+ unsigned int length;
+ Kumu::hex2bin (value.c_str(), _value, ASDCP::KeyLen, &length);
+}
+
+Key::Key (Key const & other)
+ : _value (new uint8_t[ASDCP::KeyLen])
+{
+ memcpy (_value, other._value, ASDCP::KeyLen);
+}
+
+Key::~Key ()
+{
+ delete[] _value;
+}
+
+Key &
+Key::operator= (Key const & other)
+{
+ if (this == &other) {
+ return *this;
+ }
+
+ memcpy (_value, other._value, ASDCP::KeyLen);
+ return *this;
+}
+
+string
+Key::hex () const
+{
+ stringstream g;
+
+ for (unsigned int i = 0; i < ASDCP::KeyLen; ++i) {
+ g << setw(2) << setfill('0') << std::hex << static_cast<int> (_value[i]);
+ }
+
+ return g.str ();
+}
+
+bool
+libdcp::operator== (Key const & a, Key const & b)
+{
+ return memcmp (a.value(), b.value(), ASDCP::KeyLen) == 0;
+}
+
+bool
+libdcp::operator!= (Key const & a, Key const & b)
+{
+ return !(a == b);
+}
+
diff --git a/src/key.h b/src/key.h
new file mode 100644
index 00000000..fbadfd33
--- /dev/null
+++ b/src/key.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef LIBDCP_KEY_H
+#define LIBDCP_KEY_H
+
+#include <stdint.h>
+
+namespace libdcp {
+
+/** A key for encrypting MXFs */
+class Key
+{
+public:
+ /** Create a new, random key */
+ Key ();
+
+ /** Create a Key from a raw key value */
+ Key (uint8_t const *);
+
+ /** Create a Key from a hex key value */
+ Key (std::string);
+
+ Key (Key const &);
+ ~Key ();
+
+ Key& operator= (Key const &);
+
+ uint8_t* value () const {
+ return _value;
+ }
+
+ std::string hex () const;
+
+private:
+ /** Raw key value */
+ uint8_t* _value;
+};
+
+extern bool operator== (Key const & a, Key const & b);
+extern bool operator!= (Key const & a, Key const & b);
+
+}
+
+#endif
diff --git a/src/mxf_asset.cc b/src/mxf_asset.cc
index 54c204e7..bcfe6085 100644
--- a/src/mxf_asset.cc
+++ b/src/mxf_asset.cc
@@ -46,46 +46,25 @@ using namespace libdcp;
MXFAsset::MXFAsset (string directory, string file_name)
: Asset (directory, file_name)
, _progress (0)
- , _encrypted (false)
, _encryption_context (0)
, _decryption_context (0)
{
}
-MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal<void (float)>* progress, int edit_rate, int intrinsic_duration, bool encrypted)
+MXFAsset::MXFAsset (string directory, string file_name, boost::signals2::signal<void (float)>* progress, int edit_rate, int intrinsic_duration)
: Asset (directory, file_name, edit_rate, intrinsic_duration)
, _progress (progress)
- , _encrypted (encrypted)
, _encryption_context (0)
, _decryption_context (0)
{
- if (_encrypted) {
- /* Generate an encryption key and a UUID for it */
- _key_id = make_uuid ();
- uint8_t key_buffer[ASDCP::KeyLen];
- Kumu::FortunaRNG rng;
- rng.FillRandom (key_buffer, ASDCP::KeyLen);
- char key_string[ASDCP::KeyLen * 4];
- Kumu::bin2hex (key_buffer, ASDCP::KeyLen, key_string, ASDCP::KeyLen * 4);
- _key_value = key_string;
-
- _encryption_context = new ASDCP::AESEncContext;
- if (ASDCP_FAILURE (_encryption_context->InitKey (key_buffer))) {
- throw MiscError ("could not set up encryption context");
- }
-
- uint8_t cbc_buffer[ASDCP::CBC_BLOCK_SIZE];
-
- if (ASDCP_FAILURE (_encryption_context->SetIVec (rng.FillRandom (cbc_buffer, ASDCP::CBC_BLOCK_SIZE)))) {
- throw MiscError ("could not set up CBC initialization vector");
- }
- }
+
}
MXFAsset::~MXFAsset ()
{
delete _encryption_context;
+ delete _decryption_context;
}
void
@@ -104,7 +83,7 @@ MXFAsset::fill_writer_info (ASDCP::WriterInfo* writer_info, string uuid, bool in
Kumu::hex2bin (uuid.c_str(), writer_info->AssetUUID, Kumu::UUID_Length, &c);
assert (c == Kumu::UUID_Length);
- if (_encrypted) {
+ if (_key) {
Kumu::GenRandomUUID (writer_info->ContextID);
writer_info->EncryptedEssence = true;
@@ -159,16 +138,35 @@ MXFAsset::write_to_cpl (xmlpp::Element* node, bool interop) const
a->add_child ("IntrinsicDuration")->add_child_text (lexical_cast<string> (_intrinsic_duration));
a->add_child ("EntryPoint")->add_child_text (lexical_cast<string> (_entry_point));
a->add_child ("Duration")->add_child_text (lexical_cast<string> (_duration));
- if (_encrypted) {
+ if (!_key_id.empty ()) {
a->add_child("KeyId")->add_child_text ("urn:uuid:" + _key_id);
}
}
void
-MXFAsset::set_kdm_cipher (KDMCipher cipher)
+MXFAsset::set_key (Key key)
{
+ _key = key;
+
+ if (_key_id.empty ()) {
+ /* No key ID so far; we now need one */
+ _key_id = make_uuid ();
+ }
+
_decryption_context = new ASDCP::AESDecContext;
- if (ASDCP_FAILURE (_decryption_context->InitKey (cipher.key_raw ()))) {
+ if (ASDCP_FAILURE (_decryption_context->InitKey (_key->value ()))) {
throw MiscError ("could not set up decryption context");
}
+
+ _encryption_context = new ASDCP::AESEncContext;
+ if (ASDCP_FAILURE (_encryption_context->InitKey (_key->value ()))) {
+ throw MiscError ("could not set up encryption context");
+ }
+
+ uint8_t cbc_buffer[ASDCP::CBC_BLOCK_SIZE];
+
+ Kumu::FortunaRNG rng;
+ if (ASDCP_FAILURE (_encryption_context->SetIVec (rng.FillRandom (cbc_buffer, ASDCP::CBC_BLOCK_SIZE)))) {
+ throw MiscError ("could not set up CBC initialization vector");
+ }
}
diff --git a/src/mxf_asset.h b/src/mxf_asset.h
index 3f6ecc59..d681970e 100644
--- a/src/mxf_asset.h
+++ b/src/mxf_asset.h
@@ -22,6 +22,7 @@
#include <boost/signals2.hpp>
#include "asset.h"
+#include "key.h"
namespace ASDCP {
class AESEncContext;
@@ -32,7 +33,6 @@ namespace libdcp
{
class MXFMetadata;
-class KDMCipher;
/** @brief Parent class for assets which have MXF files */
class MXFAsset : public Asset
@@ -55,7 +55,13 @@ public:
* @param edit_rate Edit rate in frames per second (usually equal to the video frame rate).
* @param intrinsic_duration Duration of the whole asset in frames.
*/
- MXFAsset (std::string directory, std::string file_name, boost::signals2::signal<void (float)>* progress, int edit_rate, int intrinsic_duration, bool encrypted);
+ MXFAsset (
+ std::string directory,
+ std::string file_name,
+ boost::signals2::signal<void (float)>* progress,
+ int edit_rate,
+ int intrinsic_duration
+ );
~MXFAsset ();
@@ -72,19 +78,23 @@ public:
void add_typed_key_id (xmlpp::Element *) const;
- std::string key_id () const {
- return _key_id;
+ bool encrypted () const {
+ return !_key_id.empty ();
}
- void set_key_id (std::string k) {
- _key_id = k;
+ void set_key_id (std::string i) {
+ _key_id = i;
}
- bool encrypted () const {
- return !_key_id.empty ();
+ std::string key_id () const {
+ return _key_id;
}
+
+ void set_key (Key);
- void set_kdm_cipher (KDMCipher);
+ boost::optional<Key> key () const {
+ return _key;
+ }
protected:
virtual std::string key_type () const = 0;
@@ -95,13 +105,10 @@ protected:
/** Signal to emit to report progress, or 0 */
boost::signals2::signal<void (float)>* _progress;
- bool _encrypted;
ASDCP::AESEncContext* _encryption_context;
- /** Key used to encrypt, or empty if _encryption is false */
- std::string _key_value;
- /** UUID of encryption key */
- std::string _key_id;
ASDCP::AESDecContext* _decryption_context;
+ std::string _key_id;
+ boost::optional<Key> _key;
};
}
diff --git a/src/picture_asset.cc b/src/picture_asset.cc
index 1c480348..5903b394 100644
--- a/src/picture_asset.cc
+++ b/src/picture_asset.cc
@@ -54,8 +54,8 @@ using boost::dynamic_pointer_cast;
using boost::lexical_cast;
using namespace libdcp;
-PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2::signal<void (float)>* progress, int fps, int intrinsic_duration, bool encrypted, Size size)
- : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration, encrypted)
+PictureAsset::PictureAsset (string directory, string mxf_name, boost::signals2::signal<void (float)>* progress, int fps, int intrinsic_duration, Size size)
+ : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration)
, _size (size)
{
@@ -195,12 +195,11 @@ MonoPictureAsset::MonoPictureAsset (
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- bool encrypted,
Size size,
bool interop,
MXFMetadata const & metadata
)
- : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, encrypted, size)
+ : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, size)
{
construct (get_path, interop, metadata);
}
@@ -212,18 +211,17 @@ MonoPictureAsset::MonoPictureAsset (
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- bool encrypted,
Size size,
bool interop,
MXFMetadata const & metadata
)
- : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, encrypted, size)
+ : PictureAsset (directory, mxf_name, progress, fps, intrinsic_duration, size)
{
construct (boost::bind (&MonoPictureAsset::path_from_list, this, _1, files), interop, metadata);
}
-MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, Size size, bool encrypted)
- : PictureAsset (directory, mxf_name, 0, fps, 0, encrypted, size)
+MonoPictureAsset::MonoPictureAsset (string directory, string mxf_name, int fps, Size size)
+ : PictureAsset (directory, mxf_name, 0, fps, 0, size)
{
}
@@ -437,7 +435,7 @@ PictureAsset::frame_buffer_equals (
StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int fps, int intrinsic_duration)
- : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration, false, Size (0, 0))
+ : PictureAsset (directory, mxf_name, 0, fps, intrinsic_duration, Size (0, 0))
{
ASDCP::JP2K::MXFSReader reader;
if (ASDCP_FAILURE (reader.OpenRead (path().string().c_str()))) {
@@ -472,8 +470,8 @@ PictureAsset::key_type () const
return "MDIK";
}
-StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int fps, Size size, bool encrypted)
- : PictureAsset (directory, mxf_name, 0, fps, 0, encrypted, size)
+StereoPictureAsset::StereoPictureAsset (string directory, string mxf_name, int fps, Size size)
+ : PictureAsset (directory, mxf_name, 0, fps, 0, size)
{
}
diff --git a/src/picture_asset.h b/src/picture_asset.h
index 7fcc2efb..398f8868 100644
--- a/src/picture_asset.h
+++ b/src/picture_asset.h
@@ -64,7 +64,6 @@ public:
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- bool encrypted,
Size
);
@@ -112,7 +111,6 @@ public:
* @param fps Video frames per second.
* @param intrinsic_duration Total number of frames in the asset.
* @param size Size of images in pixels.
- * @param encrypted true if asset should be encrypted.
*/
MonoPictureAsset (
std::vector<std::string> const & files,
@@ -121,7 +119,6 @@ public:
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- bool encrypted,
Size size,
bool interop,
MXFMetadata const & metadata = MXFMetadata ()
@@ -137,7 +134,6 @@ public:
* @param fps Video frames per second.
* @param intrinsic_duration Total number of frames in the asset.
* @param size Size of images in pixels.
- * @param encrypted true if asset should be encrypted.
*/
MonoPictureAsset (
boost::function<std::string (int)> get_path,
@@ -146,7 +142,6 @@ public:
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- bool encrypted,
Size size,
bool interop,
MXFMetadata const & metadata = MXFMetadata ()
@@ -166,7 +161,7 @@ public:
* @param fps Video frames per second.
* @param size Size in pixels that the picture frames will be.
*/
- MonoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size, bool encrypted);
+ MonoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size);
/** Start a progressive write to a MonoPictureAsset */
boost::shared_ptr<PictureAssetWriter> start_write (bool, bool, MXFMetadata const & metadata = MXFMetadata ());
@@ -195,7 +190,7 @@ public:
* @param fps Video frames per second.
* @param size Size in pixels that the picture frames will be.
*/
- StereoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size, bool encrypted);
+ StereoPictureAsset (std::string directory, std::string mxf_name, int fps, Size size);
/** Start a progressive write to a StereoPictureAsset */
boost::shared_ptr<PictureAssetWriter> start_write (bool, bool, MXFMetadata const & metadata = MXFMetadata ());
diff --git a/src/reel.cc b/src/reel.cc
index 43c934ea..ffb184ab 100644
--- a/src/reel.cc
+++ b/src/reel.cc
@@ -93,14 +93,14 @@ Reel::encrypted () const
void
Reel::add_kdm (KDM const & kdm)
{
- list<KDMCipher> ciphers = kdm.ciphers ();
+ list<KDMKey> keys = kdm.keys ();
- for (list<KDMCipher>::iterator i = ciphers.begin(); i != ciphers.end(); ++i) {
+ for (list<KDMKey>::iterator i = keys.begin(); i != keys.end(); ++i) {
if (i->key_id() == _main_picture->key_id()) {
- _main_picture->set_kdm_cipher (*i);
+ _main_picture->set_key (i->key ());
}
if (i->key_id() == _main_sound->key_id()) {
- _main_sound->set_kdm_cipher (*i);
+ _main_sound->set_key (i->key ());
}
}
}
diff --git a/src/sound_asset.cc b/src/sound_asset.cc
index 29fbc0d7..6f74e54a 100644
--- a/src/sound_asset.cc
+++ b/src/sound_asset.cc
@@ -49,11 +49,10 @@ SoundAsset::SoundAsset (
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- bool encrypted,
bool interop,
MXFMetadata const & metadata
)
- : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration, encrypted)
+ : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration)
, _channels (files.size ())
, _sampling_rate (0)
{
@@ -70,11 +69,10 @@ SoundAsset::SoundAsset (
int fps,
int intrinsic_duration,
int channels,
- bool encrypted,
bool interop,
MXFMetadata const & metadata
)
- : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration, encrypted)
+ : MXFAsset (directory, mxf_name, progress, fps, intrinsic_duration)
, _channels (channels)
, _sampling_rate (0)
{
@@ -104,8 +102,8 @@ SoundAsset::SoundAsset (string directory, string mxf_name)
_intrinsic_duration = desc.ContainerDuration;
}
-SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int channels, int sampling_rate, bool encrypted)
- : MXFAsset (directory, mxf_name, 0, fps, 0, encrypted)
+SoundAsset::SoundAsset (string directory, string mxf_name, int fps, int channels, int sampling_rate)
+ : MXFAsset (directory, mxf_name, 0, fps, 0)
, _channels (channels)
, _sampling_rate (sampling_rate)
{
diff --git a/src/sound_asset.h b/src/sound_asset.h
index cf015c30..339e67f8 100644
--- a/src/sound_asset.h
+++ b/src/sound_asset.h
@@ -79,7 +79,6 @@ public:
* @param length Length in frames.
* @param start_frame Frame in the source to start writing from.
* @param intrinsic_duration Length of the whole asset in frames.
- * @param encrypted true if asset should be encrypted.
* Note that this is different to entry_point in that the asset will contain no data before start_frame.
*/
SoundAsset (
@@ -89,7 +88,6 @@ public:
boost::signals2::signal<void (float)>* progress,
int fps,
int intrinsic_duration,
- bool encrypted,
bool interop,
MXFMetadata const & metadata = MXFMetadata ()
);
@@ -103,7 +101,6 @@ public:
* @param fps Frames per second.
* @param intrinsic_duration Length of the whole asset in frames.
* @param channels Number of audio channels.
- * @param encrypted true if asset should be encrypted.
*/
SoundAsset (
boost::function<std::string (Channel)> get_path,
@@ -113,7 +110,6 @@ public:
int fps,
int intrinsic_duration,
int channels,
- bool encrypted,
bool interop,
MXFMetadata const & metadata = MXFMetadata ()
);
@@ -128,8 +124,7 @@ public:
std::string mxf_name,
int fps,
int channels,
- int sampling_rate,
- bool encrypted
+ int sampling_rate
);
boost::shared_ptr<SoundAssetWriter> start_write (bool, MXFMetadata const & metadata = MXFMetadata ());
diff --git a/src/wscript b/src/wscript
index 904b367d..8634125c 100644
--- a/src/wscript
+++ b/src/wscript
@@ -20,6 +20,7 @@ def build(bld):
gamma_lut.cc
image.cc
kdm.cc
+ key.cc
metadata.cc
mxf_asset.cc
picture_asset.cc
@@ -55,6 +56,7 @@ def build(bld):
gamma_lut.h
image.h
kdm.h
+ key.h
lut.h
lut_cache.h
metadata.h
diff --git a/test/certificates_test.cc b/test/certificates_test.cc
index 40e550cb..ba29549b 100644
--- a/test/certificates_test.cc
+++ b/test/certificates_test.cc
@@ -21,9 +21,9 @@ BOOST_AUTO_TEST_CASE (certificates)
{
libdcp::CertificateChain c;
- c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("test/ref/crypt/ca.self-signed.pem")));
- c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("test/ref/crypt/intermediate.signed.pem")));
- c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("test/ref/crypt/leaf.signed.pem")));
+ c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("test/ref/crypt/ca.self-signed.pem"))));
+ c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("test/ref/crypt/intermediate.signed.pem"))));
+ c.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("test/ref/crypt/leaf.signed.pem"))));
list<shared_ptr<libdcp::Certificate> > leaf_to_root = c.leaf_to_root ();
@@ -71,4 +71,7 @@ BOOST_AUTO_TEST_CASE (certificates)
"dnQualifier=ndND9A/cODo2rTdrbLVmfQnoaSc=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
);
+ /* Check that reconstruction from a string works */
+ libdcp::Certificate test (c.root()->certificate (true));
+ BOOST_CHECK_EQUAL (test.certificate(), c.root()->certificate());
}
diff --git a/test/dcp_test.cc b/test/dcp_test.cc
index 1b943694..d4207d5a 100644
--- a/test/dcp_test.cc
+++ b/test/dcp_test.cc
@@ -45,7 +45,6 @@ BOOST_AUTO_TEST_CASE (dcp_test)
&d.Progress,
24,
24,
- false,
libdcp::Size (32, 32),
false,
mxf_meta
@@ -60,7 +59,6 @@ BOOST_AUTO_TEST_CASE (dcp_test)
24,
2,
false,
- false,
mxf_meta
));
diff --git a/test/encryption_test.cc b/test/encryption_test.cc
index 1b0de19a..3501befc 100644
--- a/test/encryption_test.cc
+++ b/test/encryption_test.cc
@@ -39,9 +39,9 @@ BOOST_AUTO_TEST_CASE (encryption)
libdcp::DCP d ("build/test/DCP/bar");
libdcp::CertificateChain chain;
- chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("build/test/signer/ca.self-signed.pem")));
- chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("build/test/signer/intermediate.signed.pem")));
- chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate ("build/test/signer/leaf.signed.pem")));
+ chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("build/test/signer/ca.self-signed.pem"))));
+ chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("build/test/signer/intermediate.signed.pem"))));
+ chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (boost::filesystem::path ("build/test/signer/leaf.signed.pem"))));
shared_ptr<libdcp::Signer> signer (
new libdcp::Signer (
@@ -59,12 +59,13 @@ BOOST_AUTO_TEST_CASE (encryption)
&d.Progress,
24,
24,
- true,
libdcp::Size (32, 32),
false,
mxf_metadata
));
+ mp->set_key (libdcp::Key ());
+
shared_ptr<libdcp::SoundAsset> ms (new libdcp::SoundAsset (
wav,
"build/test/bar",
@@ -73,10 +74,11 @@ BOOST_AUTO_TEST_CASE (encryption)
24,
24,
2,
- true,
false,
mxf_metadata
));
+
+ ms->set_key (libdcp::Key ());
cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (mp, ms, shared_ptr<libdcp::SubtitleAsset> ())));
d.add_cpl (cpl);
diff --git a/test/error_test.cc b/test/error_test.cc
index 380363b4..5477ca5a 100644
--- a/test/error_test.cc
+++ b/test/error_test.cc
@@ -29,12 +29,12 @@ BOOST_AUTO_TEST_CASE (error_test)
/* Trying to create video/audio MXFs using a non-existant file should throw an exception */
BOOST_CHECK_THROW (
- new libdcp::MonoPictureAsset (p, "build/test/fred", "video.mxf", &d.Progress, 24, 24, false, libdcp::Size (32, 32), false),
+ new libdcp::MonoPictureAsset (p, "build/test/fred", "video.mxf", &d.Progress, 24, 24, libdcp::Size (32, 32), false),
libdcp::FileError
);
BOOST_CHECK_THROW (
- new libdcp::SoundAsset (p, "build/test/fred", "audio.mxf", &d.Progress, 24, 24, false, false),
+ new libdcp::SoundAsset (p, "build/test/fred", "audio.mxf", &d.Progress, 24, 24, false),
libdcp::FileError
);
}
diff --git a/test/kdm_test.cc b/test/kdm_test.cc
index f536e189..a85bada7 100644
--- a/test/kdm_test.cc
+++ b/test/kdm_test.cc
@@ -26,19 +26,19 @@ BOOST_AUTO_TEST_CASE (kdm_test)
"test/data/private.key"
);
- list<libdcp::KDMCipher> ciphers = kdm.ciphers ();
+ list<libdcp::KDMKey> keys = kdm.keys ();
- BOOST_CHECK_EQUAL (ciphers.size(), 2);
-
- BOOST_CHECK_EQUAL (ciphers.front().cpl_id(), "eece17de-77e8-4a55-9347-b6bab5724b9f");
- BOOST_CHECK_EQUAL (ciphers.front().key_id(), "4ac4f922-8239-4831-b23b-31426d0542c4");
- BOOST_CHECK_EQUAL (ciphers.front().not_valid_before(), "2013-07-06T20:04:58+00:00");
- BOOST_CHECK_EQUAL (ciphers.front().not_valid_after(), "2023-07-02T20:04:56+00:00");
- BOOST_CHECK_EQUAL (ciphers.front().key_string(), "8a2729c3e5b65c45d78305462104c3fb");
-
- BOOST_CHECK_EQUAL (ciphers.back().cpl_id(), "eece17de-77e8-4a55-9347-b6bab5724b9f");
- BOOST_CHECK_EQUAL (ciphers.back().key_id(), "73baf5de-e195-4542-ab28-8a465f7d4079");
- BOOST_CHECK_EQUAL (ciphers.back().not_valid_before(), "2013-07-06T20:04:58+00:00");
- BOOST_CHECK_EQUAL (ciphers.back().not_valid_after(), "2023-07-02T20:04:56+00:00");
- BOOST_CHECK_EQUAL (ciphers.back().key_string(), "5327fb7ec2e807bd57059615bf8a169d");
+ BOOST_CHECK_EQUAL (keys.size(), 2);
+
+ BOOST_CHECK_EQUAL (keys.front().cpl_id(), "eece17de-77e8-4a55-9347-b6bab5724b9f");
+ BOOST_CHECK_EQUAL (keys.front().key_id(), "4ac4f922-8239-4831-b23b-31426d0542c4");
+ BOOST_CHECK_EQUAL (keys.front().not_valid_before(), "2013-07-06T20:04:58+00:00");
+ BOOST_CHECK_EQUAL (keys.front().not_valid_after(), "2023-07-02T20:04:56+00:00");
+ BOOST_CHECK_EQUAL (keys.front().key().hex(), "8a2729c3e5b65c45d78305462104c3fb");
+
+ BOOST_CHECK_EQUAL (keys.back().cpl_id(), "eece17de-77e8-4a55-9347-b6bab5724b9f");
+ BOOST_CHECK_EQUAL (keys.back().key_id(), "73baf5de-e195-4542-ab28-8a465f7d4079");
+ BOOST_CHECK_EQUAL (keys.back().not_valid_before(), "2013-07-06T20:04:58+00:00");
+ BOOST_CHECK_EQUAL (keys.back().not_valid_after(), "2023-07-02T20:04:56+00:00");
+ BOOST_CHECK_EQUAL (keys.back().key().hex(), "5327fb7ec2e807bd57059615bf8a169d");
}
diff --git a/test/recovery_test.cc b/test/recovery_test.cc
index 277ea678..d8ffea6a 100644
--- a/test/recovery_test.cc
+++ b/test/recovery_test.cc
@@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE (recovery)
boost::filesystem::remove_all ("build/test/baz");
boost::filesystem::create_directories ("build/test/baz");
- shared_ptr<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset ("build/test/baz", "video1.mxf", 24, libdcp::Size (32, 32), false));
+ shared_ptr<libdcp::MonoPictureAsset> mp (new libdcp::MonoPictureAsset ("build/test/baz", "video1.mxf", 24, libdcp::Size (32, 32)));
shared_ptr<libdcp::PictureAssetWriter> writer = mp->start_write (false, false);
int written_size = 0;
@@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE (recovery)
Kumu::ResetTestRNG ();
#endif
- mp.reset (new libdcp::MonoPictureAsset ("build/test/baz", "video2.mxf", 24, libdcp::Size (32, 32), false));
+ mp.reset (new libdcp::MonoPictureAsset ("build/test/baz", "video2.mxf", 24, libdcp::Size (32, 32)));
writer = mp->start_write (true, false);
writer->write (data, size);