Add option to ignore mismatched HMACs when reading MXFs.
authorCarl Hetherington <cth@carlh.net>
Fri, 4 Jun 2021 12:37:43 +0000 (14:37 +0200)
committerCarl Hetherington <cth@carlh.net>
Fri, 4 Jun 2021 12:37:43 +0000 (14:37 +0200)
src/asset_reader.h
src/frame.h
src/mono_picture_frame.cc
src/mono_picture_frame.h
src/sound_frame.cc
src/sound_frame.h
src/stereo_picture_frame.cc
src/stereo_picture_frame.h
tools/dcpdecryptmxf.cc

index 2da67bd82fb4531e3a48996e69aeb47fe4f783d0..8478b51fd94c4c45c531c36cca1e07f0f2c912fc 100644 (file)
@@ -72,13 +72,17 @@ public:
        std::shared_ptr<const F> get_frame (int n) const
        {
                /* Can't use make_shared here as the constructor is private */
-               return std::shared_ptr<const F> (new F(_reader, n, _crypto_context));
+               return std::shared_ptr<const F> (new F(_reader, n, _crypto_context, _check_hmac));
        }
 
        R* reader () const {
                return _reader;
        }
 
+       void set_check_hmac (bool check) {
+               _check_hmac = check;
+       }
+
 protected:
        R* _reader = nullptr;
        std::shared_ptr<DecryptionContext> _crypto_context;
@@ -100,6 +104,8 @@ private:
                        boost::throw_exception (FileError("could not open MXF file for reading", asset->file().get(), r));
                }
        }
+
+       bool _check_hmac = true;
 };
 
 
index 74bd616fc434cf6ff93853e2755d4aa195113d09..01dfe8b4ab1286ed6ccd630a9727e800c35d3f43 100644 (file)
@@ -54,12 +54,12 @@ template <class R, class B>
 class Frame
 {
 public:
-       Frame (R* reader, int n, std::shared_ptr<const DecryptionContext> c)
+       Frame (R* reader, int n, std::shared_ptr<const DecryptionContext> c, bool check_hmac)
        {
                /* XXX: unfortunate guesswork on this buffer size */
                _buffer = std::make_shared<B>(Kumu::Megabyte);
 
-               if (ASDCP_FAILURE(reader->ReadFrame(n, *_buffer, c->context(), c->hmac()))) {
+               if (ASDCP_FAILURE(reader->ReadFrame(n, *_buffer, c->context(), check_hmac ? c->hmac() : nullptr))) {
                        boost::throw_exception (ReadError ("could not read frame"));
                }
        }
index fb451e08bf9474b4167bd6e41f5490463e1e882a..df75126ce5b75eebe078afb35f70a1384c0458f4 100644 (file)
@@ -80,13 +80,14 @@ MonoPictureFrame::MonoPictureFrame (boost::filesystem::path path)
  *  @param reader Reader for the asset's MXF file.
  *  @param n Frame within the asset, not taking EntryPoint into account.
  *  @param c Context for decryption, or 0.
+ *  @param check_hmac true to check the HMAC and give an error if it is not as expected.
  */
-MonoPictureFrame::MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, shared_ptr<DecryptionContext> c)
+MonoPictureFrame::MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, shared_ptr<DecryptionContext> c, bool check_hmac)
 {
        /* XXX: unfortunate guesswork on this buffer size */
        _buffer = make_shared<ASDCP::JP2K::FrameBuffer>(4 * Kumu::Megabyte);
 
-       auto const r = reader->ReadFrame (n, *_buffer, c->context(), c->hmac());
+       auto const r = reader->ReadFrame (n, *_buffer, c->context(), check_hmac ? c->hmac() : nullptr);
 
        if (ASDCP_FAILURE(r)) {
                boost::throw_exception (ReadError(String::compose ("could not read video frame %1 (%2)", n, static_cast<int>(r))));
index 95b0d111d3ad22b6fc47655c0f431b7ffc5ea032..3ca16bf2bd6a65c6c2a88014c365babe21e2d893 100644 (file)
@@ -101,7 +101,7 @@ private:
        */
        friend class AssetReader<ASDCP::JP2K::MXFReader, MonoPictureFrame>;
 
-       MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, std::shared_ptr<DecryptionContext>);
+       MonoPictureFrame (ASDCP::JP2K::MXFReader* reader, int n, std::shared_ptr<DecryptionContext>, bool check_hmac);
 
        std::shared_ptr<ASDCP::JP2K::FrameBuffer> _buffer;
 };
index 9c8087c2bce23d26827557edf6d1aa9e4935ee33..25845d88332e0d02c73d1772fdeaecffc8f755b3 100644 (file)
@@ -46,8 +46,8 @@ using std::cout;
 using namespace dcp;
 
 
-SoundFrame::SoundFrame (ASDCP::PCM::MXFReader* reader, int n, std::shared_ptr<const DecryptionContext> c)
-       : Frame<ASDCP::PCM::MXFReader, ASDCP::PCM::FrameBuffer> (reader, n, c)
+SoundFrame::SoundFrame (ASDCP::PCM::MXFReader* reader, int n, std::shared_ptr<const DecryptionContext> c, bool check_hmac)
+       : Frame<ASDCP::PCM::MXFReader, ASDCP::PCM::FrameBuffer> (reader, n, c, check_hmac)
 {
        ASDCP::PCM::AudioDescriptor desc;
        reader->FillAudioDescriptor (desc);
index 85082299e957c0c7b5aa1a721fc2543f7bb02d07..0f5021e20d11fd53a2cd028585c8d9532fb447a2 100644 (file)
@@ -51,7 +51,7 @@ namespace dcp {
 class SoundFrame : public Frame<ASDCP::PCM::MXFReader, ASDCP::PCM::FrameBuffer>
 {
 public:
-       SoundFrame (ASDCP::PCM::MXFReader* reader, int n, std::shared_ptr<const DecryptionContext> c);
+       SoundFrame (ASDCP::PCM::MXFReader* reader, int n, std::shared_ptr<const DecryptionContext> c, bool check_hmac);
        int channels () const;
        int samples () const;
        int32_t get (int channel, int sample) const;
index 4cb9f2a120fe3d2cc10eb6888825bf7fb6e4a206..8d3a2757359b6325c09309436e667eab51845b98 100644 (file)
@@ -94,13 +94,14 @@ StereoPictureFrame::Part::size () const
 /** Make a picture frame from a 3D (stereoscopic) asset.
  *  @param reader Reader for the MXF file.
  *  @param n Frame within the asset, not taking EntryPoint into account.
+ *  @param check_hmac true to check the HMAC and give an error if it is not as expected.
  */
-StereoPictureFrame::StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, shared_ptr<DecryptionContext> c)
+StereoPictureFrame::StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, shared_ptr<DecryptionContext> c, bool check_hmac)
 {
        /* XXX: unfortunate guesswork on this buffer size */
        _buffer = make_shared<ASDCP::JP2K::SFrameBuffer>(4 * Kumu::Megabyte);
 
-       if (ASDCP_FAILURE (reader->ReadFrame (n, *_buffer, c->context(), c->hmac()))) {
+       if (ASDCP_FAILURE (reader->ReadFrame (n, *_buffer, c->context(), check_hmac ? c->hmac() : nullptr))) {
                boost::throw_exception (ReadError (String::compose ("could not read video frame %1 of %2", n)));
        }
 }
index 096c821a0d45dac88614e5560a05ffda5959b96f..09d684c4e0bd0075b9abecf42f471ab52c4847be 100644 (file)
@@ -105,7 +105,7 @@ private:
        */
        friend class AssetReader<ASDCP::JP2K::MXFSReader, StereoPictureFrame>;
 
-       StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, std::shared_ptr<DecryptionContext>);
+       StereoPictureFrame (ASDCP::JP2K::MXFSReader* reader, int n, std::shared_ptr<DecryptionContext>, bool check_hmac);
 
        std::shared_ptr<ASDCP::JP2K::SFrameBuffer> _buffer;
 };
index cf8df73568845da57b8fddad289cb8ac4fa60f84..4c615f9966eb869c45c00864e3d62aa0b5e439d8 100644 (file)
@@ -68,13 +68,15 @@ help (string n)
             << "  -o, --output       output filename\n"
             << "  -k, --kdm          KDM file\n"
             << "  -p, --private-key  private key file\n"
-            << "  -t, --type         MXF type: picture or atmos\n";
+            << "  -t, --type         MXF type: picture or atmos\n"
+            << "  -i, --ignore-hmac  don't raise an error if HMACs don't agree\n";
 }
 
 template <class T, class U>
-void copy (T const& in, shared_ptr<U> writer)
+void copy (T const& in, shared_ptr<U> writer, bool ignore_hmac)
 {
        auto reader = in.start_read();
+       reader->set_check_hmac (!ignore_hmac);
        for (int64_t i = 0; i < in.intrinsic_duration(); ++i) {
                auto frame = reader->get_frame (i);
                writer->write (frame->data(), frame->size());
@@ -92,6 +94,7 @@ main (int argc, char* argv[])
        optional<boost::filesystem::path> output_file;
        optional<boost::filesystem::path> kdm_file;
        optional<boost::filesystem::path> private_key_file;
+       bool ignore_hmac = false;
 
        enum class Type {
                PICTURE,
@@ -110,10 +113,11 @@ main (int argc, char* argv[])
                        { "kdm", required_argument, 0, 'k'},
                        { "private-key", required_argument, 0, 'p'},
                        { "type", required_argument, 0, 't' },
+                       { "ignore-hmac", no_argument, 0, 'i' },
                        { 0, 0, 0, 0 }
                };
 
-               int c = getopt_long (argc, argv, "Avho:k:p:t:", long_options, &option_index);
+               int c = getopt_long (argc, argv, "Avho:k:p:t:i", long_options, &option_index);
 
                if (c == -1) {
                        break;
@@ -148,6 +152,9 @@ main (int argc, char* argv[])
                                exit (EXIT_FAILURE);
                        }
                        break;
+               case 'i':
+                       ignore_hmac = true;
+                       break;
                }
        }
 
@@ -214,7 +221,7 @@ main (int argc, char* argv[])
                                in.atmos_version()
                                );
                        auto writer = out.start_write (output_file.get());
-                       copy (in, writer);
+                       copy (in, writer, ignore_hmac);
                        break;
                }
                case Type::PICTURE:
@@ -223,7 +230,7 @@ main (int argc, char* argv[])
                        add_key (in, decrypted_kdm);
                        dcp::MonoPictureAsset out (in.edit_rate(), dcp::Standard::SMPTE);
                        auto writer = out.start_write (output_file.get(), false);
-                       copy (in, writer);
+                       copy (in, writer, ignore_hmac);
                        break;
                }
                }