2 Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
34 #include "colour_conversion.h"
37 #include "decrypted_kdm.h"
38 #include "encrypted_kdm.h"
39 #include "mono_picture_asset.h"
40 #include "mono_picture_asset_reader.h"
41 #include "mono_picture_frame.h"
42 #include "openjpeg_image.h"
43 #include "picture_asset_writer.h"
45 #include "reel_file_asset.h"
46 #include "reel_mono_picture_asset.h"
47 #include "reel_picture_asset.h"
48 #include "reel_sound_asset.h"
49 #include "reel_smpte_subtitle_asset.h"
51 #include "smpte_subtitle_asset.h"
52 #include "sound_asset.h"
53 #include "sound_asset_writer.h"
54 #include "stream_operators.h"
56 #include <boost/test/unit_test.hpp>
57 #include <boost/scoped_array.hpp>
60 using std::dynamic_pointer_cast;
62 using std::make_shared;
65 using std::shared_ptr;
67 using boost::optional;
68 using boost::scoped_array;
71 pair<uint8_t*, dcp::Size>
72 get_frame (dcp::DCP const & dcp)
74 shared_ptr<const dcp::Reel> reel = dcp.cpls().front()->reels().front ();
75 shared_ptr<dcp::PictureAsset> picture = reel->main_picture()->asset ();
76 BOOST_CHECK (picture);
78 shared_ptr<const dcp::MonoPictureAsset> mono_picture = dynamic_pointer_cast<const dcp::MonoPictureAsset> (picture);
79 shared_ptr<const dcp::MonoPictureAssetReader> reader = mono_picture->start_read ();
80 shared_ptr<const dcp::MonoPictureFrame> j2k_frame = reader->get_frame (0);
81 shared_ptr<dcp::OpenJPEGImage> xyz = j2k_frame->xyz_image();
83 uint8_t* argb = new uint8_t[xyz->size().width * xyz->size().height * 4];
84 dcp::xyz_to_rgba (j2k_frame->xyz_image(), dcp::ColourConversion::srgb_to_xyz(), argb, xyz->size().width * 4);
85 return make_pair (argb, xyz->size ());
88 /** Decrypt an encrypted test DCP and check that its first frame is the same as the unencrypted version */
89 BOOST_AUTO_TEST_CASE (decryption_test1)
91 boost::filesystem::path plaintext_path = private_test;
92 plaintext_path /= "TONEPLATES-SMPTE-PLAINTEXT_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV";
93 dcp::DCP plaintext (plaintext_path.string ());
95 BOOST_CHECK_EQUAL (plaintext.any_encrypted(), false);
97 boost::filesystem::path encrypted_path = private_test;
98 encrypted_path /= "TONEPLATES-SMPTE-ENCRYPTED_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV";
99 dcp::DCP encrypted (encrypted_path.string ());
101 BOOST_CHECK_EQUAL (encrypted.any_encrypted(), true);
103 dcp::DecryptedKDM kdm (
105 dcp::file_to_string ("test/data/kdm_TONEPLATES-SMPTE-ENC_.smpte-430-2.ROOT.NOT_FOR_PRODUCTION_20130706_20230702_CAR_OV_t1_8971c838.xml")
107 dcp::file_to_string ("test/data/private.key")
112 pair<uint8_t *, dcp::Size> plaintext_frame = get_frame (plaintext);
113 pair<uint8_t *, dcp::Size> encrypted_frame = get_frame (encrypted);
115 /* Check that plaintext and encrypted are the same */
117 BOOST_CHECK_EQUAL (plaintext_frame.second, encrypted_frame.second);
121 plaintext_frame.first,
122 encrypted_frame.first,
123 plaintext_frame.second.width * plaintext_frame.second.height * 4
128 delete[] plaintext_frame.first;
129 delete[] encrypted_frame.first;
132 /** Load in a KDM that didn't work at first */
133 BOOST_AUTO_TEST_CASE (failing_kdm_test)
135 dcp::DecryptedKDM kdm (
136 dcp::EncryptedKDM (dcp::file_to_string ("test/data/target.pem.crt.de5d4eba-e683-41ca-bdda-aa4ad96af3f4.kdm.xml")),
137 dcp::file_to_string ("test/data/private.key")
142 /** Make an encrypted SMPTE DCP with picture, sound and subs and check that the keys get distributed to the assets
143 * when we read it back in.
145 BOOST_AUTO_TEST_CASE (decryption_test2)
147 boost::filesystem::path dir = "build/test/decryption_test2";
148 boost::filesystem::create_directory(dir);
150 auto context_id = dcp::make_uuid();
153 auto picture_asset = make_shared<dcp::MonoPictureAsset>(dcp::Fraction(24, 1), dcp::Standard::SMPTE);
154 picture_asset->set_key (key);
155 picture_asset->set_context_id (context_id);
156 auto picture_writer = picture_asset->start_write(dir / "picture.mxf", false);
157 dcp::ArrayData picture("test/data/flat_red.j2c");
158 for (int i = 0; i < 24; ++i) {
159 picture_writer->write(picture);
161 picture_writer->finalize();
163 auto sound_asset = make_shared<dcp::SoundAsset>(dcp::Fraction(24, 1), 48000, 2, dcp::LanguageTag("en-GB"), dcp::Standard::SMPTE);
164 sound_asset->set_key (key);
165 sound_asset->set_context_id (context_id);
166 auto sound_writer = sound_asset->start_write(dir / "sound.mxf");
167 std::array<float, 48000> left;
168 std::array<float, 48000> right;
169 for (int i = 0; i < 48000; ++i) {
170 left[i] = sin (2 * M_PI * i * 440 / 48000) * 0.25;
171 right[i] = sin (2 * M_PI * i * 880 / 48000) * 0.25;
173 std::array<float*, 2> audio;
174 audio[0] = left.data();
175 audio[1] = right.data();
176 sound_writer->write (audio.data(), 48000);
177 sound_writer->finalize ();
179 auto subs_asset = make_shared<dcp::SMPTESubtitleAsset>();
180 subs_asset->set_key (key);
181 subs_asset->set_context_id (context_id);
182 subs_asset->add(make_shared<dcp::SubtitleString>(
185 dcp::Colour(255, 255, 255),
189 dcp::Time(0, 0, 5, 0, 24),
190 0.5, dcp::HAlign::CENTER,
191 0.5, dcp::VAlign::CENTER,
195 dcp::Colour(0, 0, 0),
196 dcp::Time(), dcp::Time(), 0
198 subs_asset->write (dir / "subs.mxf");
200 auto reel = make_shared<dcp::Reel>();
201 auto reel_picture_asset = make_shared<dcp::ReelMonoPictureAsset>(picture_asset, 0);
202 auto reel_sound_asset = make_shared<dcp::ReelSoundAsset>(sound_asset, 0);
203 auto reel_subs_asset = make_shared<dcp::ReelSMPTESubtitleAsset>(subs_asset, dcp::Fraction(24, 1), 120, 0);
204 reel->add(reel_picture_asset);
205 reel->add(reel_sound_asset);
206 reel->add(reel_subs_asset);
208 auto cpl = std::make_shared<dcp::CPL>("My film", dcp::ContentKind::FEATURE, dcp::Standard::SMPTE);
215 map<shared_ptr<const dcp::ReelFileAsset>, dcp::Key> keys;
216 keys[reel_picture_asset] = key;
217 keys[reel_sound_asset] = key;
218 keys[reel_subs_asset] = key;
220 dcp::DecryptedKDM kdm (cpl->id(), keys, dcp::LocalTime(), dcp::LocalTime(), "foo", "bar", "baz");
222 dcp::DCP dcp_read (dir);
226 BOOST_REQUIRE_EQUAL (dcp_read.cpls().size(), 1U);
227 auto cpl_read = dcp_read.cpls()[0];
228 BOOST_REQUIRE_EQUAL (cpl_read->reels().size(), 1U);
229 auto reel_read = cpl_read->reels()[0];
231 BOOST_REQUIRE (reel_read->main_picture());
232 BOOST_CHECK (reel_read->main_picture()->asset()->key());
233 BOOST_REQUIRE (reel_read->main_sound());
234 BOOST_CHECK (reel_read->main_sound()->asset()->key());
235 BOOST_REQUIRE (reel_read->main_subtitle());
236 auto smpte_sub = dynamic_pointer_cast<dcp::SMPTESubtitleAsset>(reel_read->main_subtitle()->asset());
237 BOOST_REQUIRE (smpte_sub);
238 BOOST_CHECK (smpte_sub->key());