From 3526252ff2fd80a459c72ab1c55ea5a6ee61aa2f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 23 Dec 2018 21:04:38 +0000 Subject: [PATCH] swaroop: encrypt decryption private key with motherboard UUID. --- src/lib/config.cc | 47 +++++++++++++++++++++++++++++++++------------ src/lib/config.h | 3 +++ src/lib/cross.cc | 27 ++++++++++++++++++++++++++ src/lib/cross.h | 1 + src/lib/crypto.cc | 16 +++++++-------- src/lib/crypto.h | 6 +++--- test/crypto_test.cc | 8 ++++---- 7 files changed, 81 insertions(+), 27 deletions(-) diff --git a/src/lib/config.cc b/src/lib/config.cc index e61eea3a6..172890dcf 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -32,6 +32,7 @@ #include "film.h" #include "dkdm_wrapper.h" #include "compose.hpp" +#include "crypto.h" #include #include #include @@ -61,6 +62,7 @@ using boost::shared_ptr; using boost::optional; using boost::dynamic_pointer_cast; using boost::algorithm::trim; +using boost::shared_array; using dcp::raw_convert; Config* Config::_instance = 0; @@ -435,7 +437,19 @@ try BOOST_FOREACH (cxml::NodePtr i, decryption->node_children ("Certificate")) { c->add (dcp::Certificate (i->content ())); } - c->set_key (decryption->string_child ("PrivateKey")); + optional key = decryption->optional_string_child ("PrivateKey"); +#ifdef DCPOMATIC_VARIANT_SWAROOP + if (key) { + c->set_key (*key); + } else { + dcp::Data encrypted_key (path("private")); + dcp::Data iv (path("iv")); + c->set_key (dcpomatic::decrypt (encrypted_key, key_from_uuid(), iv)); + } +#else + DCPOMATIC_ASSERT (key); + c->set_key (*key); +#endif _decryption_chain = c; } else { _decryption_chain = create_certificate_chain (); @@ -599,6 +613,19 @@ Config::write () const write_cinemas (); } +#ifdef DCPOMATIC_VARIANT_SWAROOP +/* Make up a key from the machine UUID */ +dcp::Data +Config::key_from_uuid () const +{ + dcp::Data key (dcpomatic::crypto_key_length()); + memset (key.data().get(), 0, key.size()); + string const magic = command_and_read ("dcpomatic2_uuid"); + strncpy ((char *) key.data().get(), magic.c_str(), dcpomatic::crypto_key_length()); + return key; +} +#endif + void Config::write_config () const { @@ -771,18 +798,7 @@ Config::write_config () const BOOST_FOREACH (dcp::Certificate const & i, _signer_chain->unordered()) { signer->add_child("Certificate")->add_child_text (i.certificate (true)); } -#ifdef DCPOMATIC_SWAROOP - FILE* f = fopen_boost (path("private"), "wb"); - if (!f) { - throw FileError ("Could not open file for writing", path("private")); - } - shared_array iv = dcpomatic::random_iv (); - dcp::Data encrypted_key = dcpomatic::encrypt (_signer_chain->key().get(), key, iv); - fwrite (encrypted_key.data().get(), encrypted_key.data().size(), 1, f); - fclose (f); -#else signer->add_child("PrivateKey")->add_child_text (_signer_chain->key().get ()); -#endif /* [XML] Decryption Certificate chain and private key to use when decrypting KDMs */ xmlpp::Element* decryption = root->add_child ("Decryption"); @@ -790,7 +806,14 @@ Config::write_config () const BOOST_FOREACH (dcp::Certificate const & i, _decryption_chain->unordered()) { decryption->add_child("Certificate")->add_child_text (i.certificate (true)); } +#ifdef DCPOMATIC_VARIANT_SWAROOP + dcp::Data iv = dcpomatic::random_iv (); + dcp::Data encrypted_key = dcpomatic::encrypt (_decryption_chain->key().get(), key_from_uuid(), iv); + encrypted_key.write (path("private")); + iv.write (path("iv")); +#else decryption->add_child("PrivateKey")->add_child_text (_decryption_chain->key().get ()); +#endif /* [XML] History Filename of DCP to present in the File menu of the GUI; there can be more than one of these tags. diff --git a/src/lib/config.h b/src/lib/config.h index 0e5f9dfd1..e28928226 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -1083,6 +1083,9 @@ private: boost::filesystem::path directory_or (boost::optional dir, boost::filesystem::path a) const; void add_to_history_internal (std::vector& h, boost::filesystem::path p); void backup (); +#ifdef DCPOMATIC_VARIANT_SWAROOP + dcp::Data key_from_uuid () const; +#endif template void maybe_set (T& member, T new_value, Property prop = OTHER) { diff --git a/src/lib/cross.cc b/src/lib/cross.cc index e3fb22f39..171bf2c81 100644 --- a/src/lib/cross.cc +++ b/src/lib/cross.cc @@ -474,3 +474,30 @@ home_directory () return boost::filesystem::path(getenv("HOMEDRIVE")) / boost::filesystem::path(getenv("HOMEPATH")); #endif } + +string +command_and_read (string cmd) +{ +#ifdef DCPOMATIC_LINUX + FILE* pipe = popen (cmd.c_str(), "r"); + if (!pipe) { + throw runtime_error ("popen failed"); + } + + string result; + char buffer[128]; + try { + while (fgets(buffer, sizeof(buffer), pipe)) { + result += buffer; + } + } catch (...) { + pclose (pipe); + throw; + } + + pclose (pipe); + return result; +#endif + + return ""; +} diff --git a/src/lib/cross.h b/src/lib/cross.h index ee5e7919a..06e198e99 100644 --- a/src/lib/cross.h +++ b/src/lib/cross.h @@ -56,6 +56,7 @@ extern void start_player (boost::filesystem::path dcpomatic); extern uint64_t thread_id (); extern int avio_open_boost (AVIOContext** s, boost::filesystem::path file, int flags); extern boost::filesystem::path home_directory (); +extern std::string command_and_read (std::string cmd); /** @class Waker * @brief A class which tries to keep the computer awake on various operating systems. diff --git a/src/lib/crypto.cc b/src/lib/crypto.cc index 69e041cb2..b02a3d34c 100644 --- a/src/lib/crypto.cc +++ b/src/lib/crypto.cc @@ -35,24 +35,24 @@ using namespace dcpomatic; /** The cipher that this code uses */ #define CIPHER EVP_aes_256_cbc() -shared_array +dcp::Data dcpomatic::random_iv () { EVP_CIPHER const * cipher = CIPHER; - shared_array iv (new unsigned char[EVP_CIPHER_iv_length(cipher)]); - RAND_bytes (iv.get(), EVP_CIPHER_iv_length(cipher)); + dcp::Data iv (EVP_CIPHER_iv_length(cipher)); + RAND_bytes (iv.data().get(), iv.size()); return iv; } dcp::Data -dcpomatic::encrypt (string plaintext, shared_array key, shared_array iv) +dcpomatic::encrypt (string plaintext, dcp::Data key, dcp::Data iv) { EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new (); if (!ctx) { throw CryptoError ("could not create cipher context"); } - int r = EVP_EncryptInit_ex (ctx, CIPHER, 0, key.get(), iv.get()); + int r = EVP_EncryptInit_ex (ctx, CIPHER, 0, key.data().get(), iv.data().get()); if (r != 1) { throw CryptoError ("could not initialise cipher context for encryption"); } @@ -60,7 +60,7 @@ dcpomatic::encrypt (string plaintext, shared_array key, sha dcp::Data ciphertext (plaintext.size() * 2); int len; - r = EVP_EncryptUpdate (ctx, ciphertext.data().get(), &len, (unsigned char const *) plaintext.c_str(), plaintext.size()); + r = EVP_EncryptUpdate (ctx, ciphertext.data().get(), &len, (uint8_t const *) plaintext.c_str(), plaintext.size()); if (r != 1) { throw CryptoError ("could not encrypt data"); } @@ -80,14 +80,14 @@ dcpomatic::encrypt (string plaintext, shared_array key, sha } string -dcpomatic::decrypt (dcp::Data ciphertext, shared_array key, shared_array iv) +dcpomatic::decrypt (dcp::Data ciphertext, dcp::Data key, dcp::Data iv) { EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new (); if (!ctx) { throw CryptoError ("could not create cipher context"); } - int r = EVP_DecryptInit_ex (ctx, CIPHER, 0, key.get(), iv.get()); + int r = EVP_DecryptInit_ex (ctx, CIPHER, 0, key.data().get(), iv.data().get()); if (r != 1) { throw CryptoError ("could not initialise cipher context for decryption"); } diff --git a/src/lib/crypto.h b/src/lib/crypto.h index ea46162a4..e450d4db1 100644 --- a/src/lib/crypto.h +++ b/src/lib/crypto.h @@ -22,9 +22,9 @@ namespace dcpomatic { -boost::shared_array random_iv (); -dcp::Data encrypt (std::string plaintext, boost::shared_array key, boost::shared_array iv); -std::string decrypt (dcp::Data ciphertext, boost::shared_array key, boost::shared_array iv); +dcp::Data random_iv (); +dcp::Data encrypt (std::string plaintext, dcp::Data key, dcp::Data iv); +std::string decrypt (dcp::Data ciphertext, dcp::Data key, dcp::Data iv); int crypto_key_length (); } diff --git a/test/crypto_test.cc b/test/crypto_test.cc index 576a6ebc6..586535dfe 100644 --- a/test/crypto_test.cc +++ b/test/crypto_test.cc @@ -30,15 +30,15 @@ using boost::shared_array; BOOST_AUTO_TEST_CASE (crypto_test) { - shared_array key (new unsigned char[dcpomatic::crypto_key_length()]); - shared_array iv = dcpomatic::random_iv (); + dcp::Data key (dcpomatic::crypto_key_length()); + dcp::Data iv = dcpomatic::random_iv (); - RAND_bytes (key.get(), dcpomatic::crypto_key_length()); + RAND_bytes (key.data().get(), dcpomatic::crypto_key_length()); dcp::Data ciphertext = dcpomatic::encrypt ("Can you see any fish?", key, iv); BOOST_REQUIRE_EQUAL (dcpomatic::decrypt (ciphertext, key, iv), "Can you see any fish?"); - key[5]++; + key.data()[5]++; BOOST_REQUIRE_THROW (dcpomatic::decrypt (ciphertext, key, iv), CryptoError); } -- 2.30.2