Fix some ambiguous shared_ptrs, seen on Arch Linux.
[libdcp.git] / test / decryption_test.cc
1 /*
2     Copyright (C) 2013-2019 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
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.
10
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.
15
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/>.
18
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
23     including the two.
24
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.
32 */
33
34 #include "colour_conversion.h"
35 #include "cpl.h"
36 #include "dcp.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"
44 #include "reel.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"
50 #include "rgb_xyz.h"
51 #include "smpte_subtitle_asset.h"
52 #include "sound_asset.h"
53 #include "sound_asset_writer.h"
54 #include "stream_operators.h"
55 #include "test.h"
56 #include <boost/test/unit_test.hpp>
57 #include <boost/scoped_array.hpp>
58
59
60 #ifndef M_PI
61 #define M_PI (3.14159265358979323846)
62 #endif
63
64
65 using std::dynamic_pointer_cast;
66 using std::make_pair;
67 using std::map;
68 using std::pair;
69 using std::shared_ptr;
70 using std::string;
71 using boost::optional;
72 using boost::scoped_array;
73
74
75 pair<uint8_t*, dcp::Size>
76 get_frame (dcp::DCP const & dcp)
77 {
78         shared_ptr<const dcp::Reel> reel = dcp.cpls().front()->reels().front ();
79         shared_ptr<dcp::PictureAsset> picture = reel->main_picture()->asset ();
80         BOOST_CHECK (picture);
81
82         shared_ptr<const dcp::MonoPictureAsset> mono_picture = dynamic_pointer_cast<const dcp::MonoPictureAsset> (picture);
83         shared_ptr<const dcp::MonoPictureAssetReader> reader = mono_picture->start_read ();
84         shared_ptr<const dcp::MonoPictureFrame> j2k_frame = reader->get_frame (0);
85         shared_ptr<dcp::OpenJPEGImage> xyz = j2k_frame->xyz_image();
86
87         uint8_t* argb = new uint8_t[xyz->size().width * xyz->size().height * 4];
88         dcp::xyz_to_rgba (j2k_frame->xyz_image(), dcp::ColourConversion::srgb_to_xyz(), argb, xyz->size().width * 4);
89         return make_pair (argb, xyz->size ());
90 }
91
92 /** Decrypt an encrypted test DCP and check that its first frame is the same as the unencrypted version */
93 BOOST_AUTO_TEST_CASE (decryption_test1)
94 {
95         boost::filesystem::path plaintext_path = private_test;
96         plaintext_path /= "TONEPLATES-SMPTE-PLAINTEXT_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV";
97         dcp::DCP plaintext (plaintext_path.string ());
98         plaintext.read ();
99         BOOST_CHECK_EQUAL (plaintext.any_encrypted(), false);
100
101         boost::filesystem::path encrypted_path = private_test;
102         encrypted_path /= "TONEPLATES-SMPTE-ENCRYPTED_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV";
103         dcp::DCP encrypted (encrypted_path.string ());
104         encrypted.read ();
105         BOOST_CHECK_EQUAL (encrypted.any_encrypted(), true);
106
107         dcp::DecryptedKDM kdm (
108                 dcp::EncryptedKDM (
109                         dcp::file_to_string ("test/data/kdm_TONEPLATES-SMPTE-ENC_.smpte-430-2.ROOT.NOT_FOR_PRODUCTION_20130706_20230702_CAR_OV_t1_8971c838.xml")
110                         ),
111                 dcp::file_to_string ("test/data/private.key")
112                 );
113
114         encrypted.add (kdm);
115
116         pair<uint8_t *, dcp::Size> plaintext_frame = get_frame (plaintext);
117         pair<uint8_t *, dcp::Size> encrypted_frame = get_frame (encrypted);
118
119         /* Check that plaintext and encrypted are the same */
120
121         BOOST_CHECK_EQUAL (plaintext_frame.second, encrypted_frame.second);
122
123         BOOST_CHECK_EQUAL (
124                 memcmp (
125                         plaintext_frame.first,
126                         encrypted_frame.first,
127                         plaintext_frame.second.width * plaintext_frame.second.height * 4
128                         ),
129                 0
130                 );
131
132         delete[] plaintext_frame.first;
133         delete[] encrypted_frame.first;
134 }
135
136 /** Load in a KDM that didn't work at first */
137 BOOST_AUTO_TEST_CASE (failing_kdm_test)
138 {
139         dcp::DecryptedKDM kdm (
140                 dcp::EncryptedKDM (dcp::file_to_string ("test/data/target.pem.crt.de5d4eba-e683-41ca-bdda-aa4ad96af3f4.kdm.xml")),
141                 dcp::file_to_string ("test/data/private.key")
142                 );
143 }
144
145
146 /** Make an encrypted SMPTE DCP with picture, sound and subs and check that the keys get distributed to the assets
147  *  when we read it back in.
148  */
149 BOOST_AUTO_TEST_CASE (decryption_test2)
150 {
151         boost::filesystem::path dir = "build/test/decryption_test2";
152         boost::filesystem::create_directory(dir);
153
154         auto context_id = dcp::make_uuid();
155         dcp::Key key;
156
157         auto picture_asset = std::make_shared<dcp::MonoPictureAsset>(dcp::Fraction(24, 1), dcp::Standard::SMPTE);
158         picture_asset->set_key (key);
159         picture_asset->set_context_id (context_id);
160         auto picture_writer = picture_asset->start_write(dir / "picture.mxf", false);
161         dcp::ArrayData picture("test/data/flat_red.j2c");
162         for (int i = 0; i < 24; ++i) {
163                 picture_writer->write(picture);
164         }
165         picture_writer->finalize();
166
167         auto sound_asset = std::make_shared<dcp::SoundAsset>(dcp::Fraction(24, 1), 48000, 2, dcp::LanguageTag("en-GB"), dcp::Standard::SMPTE);
168         sound_asset->set_key (key);
169         sound_asset->set_context_id (context_id);
170         auto sound_writer = sound_asset->start_write(dir / "sound.mxf");
171         std::array<float, 48000> left;
172         std::array<float, 48000> right;
173         for (int i = 0; i < 48000; ++i) {
174                 left[i] = sin (2 * M_PI * i * 440 / 48000) * 0.25;
175                 right[i] = sin (2 * M_PI * i * 880 / 48000) * 0.25;
176         }
177         std::array<float*, 2> audio;
178         audio[0] = left.data();
179         audio[1] = right.data();
180         sound_writer->write (audio.data(), 48000);
181         sound_writer->finalize ();
182
183         auto subs_asset = std::make_shared<dcp::SMPTESubtitleAsset>();
184         subs_asset->set_key (key);
185         subs_asset->set_context_id (context_id);
186         subs_asset->add(std::make_shared<dcp::SubtitleString>(
187                 optional<string>(),
188                 false, false, false,
189                 dcp::Colour(255, 255, 255),
190                 42,
191                 1,
192                 dcp::Time(),
193                 dcp::Time(0, 0, 5, 0, 24),
194                 0.5, dcp::HAlign::CENTER,
195                 0.5, dcp::VAlign::CENTER,
196                 0,
197                 dcp::Direction::LTR,
198                 "Hello world",
199                 dcp::Effect::NONE,
200                 dcp::Colour(0, 0, 0),
201                 dcp::Time(), dcp::Time(), 0
202                 ));
203         subs_asset->write (dir / "subs.mxf");
204
205         auto reel = std::make_shared<dcp::Reel>();
206         auto reel_picture_asset = std::make_shared<dcp::ReelMonoPictureAsset>(picture_asset, 0);
207         auto reel_sound_asset = std::make_shared<dcp::ReelSoundAsset>(sound_asset, 0);
208         auto reel_subs_asset = std::make_shared<dcp::ReelSMPTESubtitleAsset>(subs_asset, dcp::Fraction(24, 1), 120, 0);
209         reel->add(reel_picture_asset);
210         reel->add(reel_sound_asset);
211         reel->add(reel_subs_asset);
212
213         auto cpl = std::make_shared<dcp::CPL>("My film", dcp::ContentKind::FEATURE, dcp::Standard::SMPTE);
214         cpl->add(reel);
215
216         dcp::DCP dcp (dir);
217         dcp.add (cpl);
218         dcp.write_xml ();
219
220         map<shared_ptr<const dcp::ReelFileAsset>, dcp::Key> keys;
221         keys[reel_picture_asset] = key;
222         keys[reel_sound_asset] = key;
223         keys[reel_subs_asset] = key;
224
225         dcp::DecryptedKDM kdm (cpl->id(), keys, dcp::LocalTime(), dcp::LocalTime(), "foo", "bar", "baz");
226
227         dcp::DCP dcp_read (dir);
228         dcp_read.read ();
229         dcp_read.add (kdm);
230
231         BOOST_REQUIRE_EQUAL (dcp_read.cpls().size(), 1U);
232         auto cpl_read = dcp_read.cpls()[0];
233         BOOST_REQUIRE_EQUAL (cpl_read->reels().size(), 1U);
234         auto reel_read = cpl_read->reels()[0];
235
236         BOOST_REQUIRE (reel_read->main_picture());
237         BOOST_CHECK (reel_read->main_picture()->asset()->key());
238         BOOST_REQUIRE (reel_read->main_sound());
239         BOOST_CHECK (reel_read->main_sound()->asset()->key());
240         BOOST_REQUIRE (reel_read->main_subtitle());
241         auto smpte_sub = dynamic_pointer_cast<dcp::SMPTESubtitleAsset>(reel_read->main_subtitle()->asset());
242         BOOST_REQUIRE (smpte_sub);
243         BOOST_CHECK (smpte_sub->key());
244 }
245