Add new constructor. Remove believed unnecessary check for KDM assets being ReelAsse...
[libdcp.git] / src / decrypted_kdm.cc
index 4ffad92323c2a820c1120c663ca4e9fcc48d9f79..8355e1c852ee917e772cb3f1a5a231ae42a63f43 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2017 Carl Hetherington <cth@carlh.net>
 
     This file is part of libdcp.
 
@@ -56,6 +56,7 @@ using std::setw;
 using std::setfill;
 using std::hex;
 using std::pair;
+using std::map;
 using boost::shared_ptr;
 using namespace dcp;
 
@@ -73,34 +74,37 @@ put (uint8_t ** d, uint8_t const * s, int N)
         (*d) += N;
 }
 
-static void
-put_uuid (uint8_t ** d, string id)
+void
+DecryptedKDM::put_uuid (uint8_t ** d, string id)
 {
-        id.erase (std::remove (id.begin(), id.end(), '-'));
-        for (int i = 0; i < 32; i += 2) {
-                locked_stringstream s;
-                s << id[i] << id[i + 1];
-                int h;
-                s >> hex >> h;
-                **d = h;
-                (*d)++;
-        }
+       /* 32 hex digits plus some hyphens */
+       DCP_ASSERT (id.length() == 36);
+#ifdef LIBDCP_WINDOWS
+       __mingw_sscanf (
+#else
+       sscanf (
+#endif
+               id.c_str(),
+               "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+               *d + 0, *d + 1, *d + 2, *d + 3, *d + 4, *d + 5, *d + 6, *d + 7,
+               *d + 8, *d + 9, *d + 10, *d + 11, *d + 12, *d + 13, *d + 14, *d + 15
+               );
+
+       *d += 16;
 }
 
-static string
-get_uuid (unsigned char ** p)
+string
+DecryptedKDM::get_uuid (unsigned char ** p)
 {
-       locked_stringstream g;
-
-       for (int i = 0; i < 16; ++i) {
-               g << setw(2) << setfill('0') << hex << static_cast<int> (**p);
-               (*p)++;
-               if (i == 3 || i == 5 || i == 7 || i == 9) {
-                       g << '-';
-               }
-       }
+       char buffer[37];
+       snprintf (
+               buffer, sizeof(buffer), "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+               (*p)[0], (*p)[1], (*p)[2], (*p)[3], (*p)[4], (*p)[5], (*p)[6], (*p)[7],
+               (*p)[8], (*p)[9], (*p)[10], (*p)[11], (*p)[12], (*p)[13], (*p)[14], (*p)[15]
+               );
 
-       return g.str ();
+       *p += 16;
+       return buffer;
 }
 
 static string
@@ -141,7 +145,7 @@ DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
                int const decrypted_len = RSA_private_decrypt (cipher_value_len, cipher_value, decrypted, rsa, RSA_PKCS1_OAEP_PADDING);
                if (decrypted_len == -1) {
                        delete[] decrypted;
-                       throw MiscError (String::compose ("Could not decrypt KDM (%1)", ERR_error_string (ERR_get_error(), 0)));
+                       throw KDMDecryptionError (ERR_error_string (ERR_get_error(), 0));
                }
 
                unsigned char* p = decrypted;
@@ -162,7 +166,7 @@ DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
                        /* 93 is not-valid-after (a string) [25 bytes] */
                        p += 25;
                        /* 118 is the key [ASDCP::KeyLen bytes] */
-                       _keys.push_back (DecryptedKDMKey ("", key_id, Key (p), cpl_id));
+                       add_key ("", key_id, Key (p), cpl_id);
                        break;
                }
                case 138:
@@ -183,7 +187,7 @@ DecryptedKDM::DecryptedKDM (EncryptedKDM const & kdm, string private_key)
                        /* 97 is not-valid-after (a string) [25 bytes] */
                        p += 25;
                        /* 112 is the key [ASDCP::KeyLen bytes] */
-                       _keys.push_back (DecryptedKDMKey (key_type, key_id, Key (p), cpl_id));
+                       add_key (key_type, key_id, Key (p), cpl_id);
                        break;
                }
                default:
@@ -218,7 +222,27 @@ DecryptedKDM::DecryptedKDM (
 }
 
 DecryptedKDM::DecryptedKDM (
-       boost::shared_ptr<const CPL> cpl,
+       string cpl_id,
+       map<shared_ptr<const ReelMXF>, Key> keys,
+       LocalTime not_valid_before,
+       LocalTime not_valid_after,
+       string annotation_text,
+       string content_title_text,
+       string issue_date
+       )
+       : _not_valid_before (not_valid_before)
+       , _not_valid_after (not_valid_after)
+       , _annotation_text (annotation_text)
+       , _content_title_text (content_title_text)
+       , _issue_date (issue_date)
+{
+       for (map<shared_ptr<const ReelMXF>, Key>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
+               add_key (i->first->key_type(), i->first->key_id().get(), i->second, cpl_id);
+       }
+}
+
+DecryptedKDM::DecryptedKDM (
+       shared_ptr<const CPL> cpl,
        Key key,
        LocalTime not_valid_before,
        LocalTime not_valid_after,
@@ -233,16 +257,18 @@ DecryptedKDM::DecryptedKDM (
        , _issue_date (issue_date)
 {
        /* Create DecryptedKDMKey objects for each encryptable asset */
+       bool did_one = false;
        BOOST_FOREACH(shared_ptr<const ReelAsset> i, cpl->reel_assets ()) {
                shared_ptr<const ReelMXF> mxf = boost::dynamic_pointer_cast<const ReelMXF> (i);
-               shared_ptr<const ReelAsset> asset = boost::dynamic_pointer_cast<const ReelAsset> (i);
-               if (asset && mxf) {
-                       if (!mxf->key_id ()) {
-                               throw NotEncryptedError (asset->id ());
-                       }
-                       _keys.push_back (DecryptedKDMKey (mxf->key_type(), mxf->key_id().get(), key, cpl->id ()));
+               if (mxf && mxf->key_id ()) {
+                       add_key (mxf->key_type(), mxf->key_id().get(), key, cpl->id ());
+                       did_one = true;
                }
        }
+
+       if (!did_one) {
+               throw NotEncryptedError (cpl->id ());
+       }
 }
 
 /** @param type (MDIK, MDAK etc.)
@@ -300,15 +326,15 @@ DecryptedKDM::encrypt (shared_ptr<const CertificateChain> signer, Certificate re
                char out[encrypted_len * 2];
                Kumu::base64encode (encrypted, encrypted_len, out, encrypted_len * 2);
                int const N = strlen (out);
-               locked_stringstream lines;
+               string lines;
                for (int i = 0; i < N; ++i) {
                        if (i > 0 && (i % 64) == 0) {
-                               lines << "\n";
+                               lines += "\n";
                        }
-                       lines << out[i];
+                       lines += out[i];
                }
 
-               keys.push_back (lines.str ());
+               keys.push_back (lines);
        }
 
        string device_list_description = recipient.subject_common_name ();
@@ -320,7 +346,6 @@ DecryptedKDM::encrypt (shared_ptr<const CertificateChain> signer, Certificate re
                signer,
                recipient,
                trusted_devices,
-               device_list_description,
                _keys.front().cpl_id (),
                _content_title_text,
                _annotation_text,