Result_t ASDCP::IntegrityPack::TestValues(const ASDCP::FrameBuffer& FB, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC) { ASDCP_TEST_NULL(AssetID); ASDCP_TEST_NULL(HMAC); // find the start of the intpack byte_t* p = (byte_t*)FB.RoData() + ( FB.Size() - klv_intpack_size ); // test the AssetID length if ( ! Kumu::read_test_BER(&p, UUIDlen) ) return RESULT_HMACFAIL; // test the AssetID if ( memcmp(p, AssetID, UUIDlen) != 0 ) { DefaultLogSink().Error("IntegrityPack failure: AssetID mismatch.\n"); return RESULT_HMACFAIL; } p += UUIDlen; // test the sequence length if ( ! Kumu::read_test_BER(&p, sizeof(ui64_t)) ) return RESULT_HMACFAIL; ui32_t test_sequence = (ui32_t)KM_i64_BE(Kumu::cp2i<ui64_t>(p)); // test the sequence value if ( test_sequence != sequence ) { DefaultLogSink().Error("IntegrityPack failure: sequence is %u, expecting %u.\n", test_sequence, sequence); return RESULT_HMACFAIL; } p += sizeof(ui64_t); // test the HMAC length if ( ! Kumu::read_test_BER(&p, HMAC_SIZE) ) return RESULT_HMACFAIL; // test the HMAC HMAC->Reset(); HMAC->Update(FB.RoData(), FB.Size() - HMAC_SIZE); HMAC->Finalize(); return HMAC->TestHMACValue(p); }
static bool string_is_xml(const ASDCP::FrameBuffer& buffer) { std::string ns_prefix, type_name, namespace_name; Kumu::AttributeList doc_attr_list; return GetXMLDocType(buffer.RoData(), buffer.Size(), ns_prefix, type_name, namespace_name, doc_attr_list); }
Result_t AS_02::h__AS02WriterClip::WriteClipBlock(const ASDCP::FrameBuffer& FrameBuf) { if ( m_ClipStart == 0 ) { DefaultLogSink().Error("Cannot write clip block, no clip open.\n"); return RESULT_STATE; } return m_File.Write(FrameBuf.RoData(), FrameBuf.Size()); }
Result_t ASDCP::IntegrityPack::CalcValues(const ASDCP::FrameBuffer& FB, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC) { ASDCP_TEST_NULL(AssetID); ASDCP_TEST_NULL(HMAC); byte_t* p = Data; HMAC->Reset(); static byte_t ber_4[MXF_BER_LENGTH] = {0x83, 0, 0, 0}; // update HMAC with essence data HMAC->Update(FB.RoData(), FB.Size()); // track file ID length memcpy(p, ber_4, MXF_BER_LENGTH); *(p+3) = UUIDlen;; p += MXF_BER_LENGTH; // track file ID memcpy(p, AssetID, UUIDlen); p += UUIDlen; // sequence length memcpy(p, ber_4, MXF_BER_LENGTH); *(p+3) = sizeof(ui64_t); p += MXF_BER_LENGTH; // sequence number Kumu::i2p<ui64_t>(KM_i64_BE(sequence), p); p += sizeof(ui64_t); // HMAC length memcpy(p, ber_4, MXF_BER_LENGTH); *(p+3) = HMAC_SIZE; p += MXF_BER_LENGTH; // update HMAC with intpack values HMAC->Update(Data, klv_intpack_size - HMAC_SIZE); // finish & write HMAC HMAC->Finalize(); HMAC->GetHMACValue(p); assert(p + HMAC_SIZE == Data + klv_intpack_size); return RESULT_OK; }
Result_t ASDCP::DecryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FBout, AESDecContext* Ctx) { ASDCP_TEST_NULL(Ctx); assert(FBout.Capacity() >= FBin.SourceLength()); ui32_t ct_size = FBin.SourceLength() - FBin.PlaintextOffset(); ui32_t diff = ct_size % CBC_BLOCK_SIZE; ui32_t block_size = ct_size - diff; assert(block_size); assert((block_size % CBC_BLOCK_SIZE) == 0); const byte_t* buf = FBin.RoData(); // get ivec Ctx->SetIVec(buf); buf += CBC_BLOCK_SIZE; // decrypt and test check value byte_t CheckValue[CBC_BLOCK_SIZE]; Result_t result = Ctx->DecryptBlock(buf, CheckValue, CBC_BLOCK_SIZE); buf += CBC_BLOCK_SIZE; if ( memcmp(CheckValue, ESV_CheckValue, CBC_BLOCK_SIZE) != 0 ) return RESULT_CHECKFAIL; // copy plaintext region if ( FBin.PlaintextOffset() > 0 ) { memcpy(FBout.Data(), buf, FBin.PlaintextOffset()); buf += FBin.PlaintextOffset(); } // decrypt all but last block if ( ASDCP_SUCCESS(result) ) { result = Ctx->DecryptBlock(buf, FBout.Data() + FBin.PlaintextOffset(), block_size); buf += block_size; } // decrypt last block if ( ASDCP_SUCCESS(result) ) { byte_t the_last_block[CBC_BLOCK_SIZE]; result = Ctx->DecryptBlock(buf, the_last_block, CBC_BLOCK_SIZE); if ( the_last_block[diff] != 0 ) { DefaultLogSink().Error("Unexpected non-zero padding value.\n"); return RESULT_FORMAT; } if ( diff > 0 ) memcpy(FBout.Data() + FBin.PlaintextOffset() + block_size, the_last_block, diff); } if ( ASDCP_SUCCESS(result) ) FBout.Size(FBin.SourceLength()); return result; }
Result_t ASDCP::EncryptFrameBuffer(const ASDCP::FrameBuffer& FBin, ASDCP::FrameBuffer& FBout, AESEncContext* Ctx) { ASDCP_TEST_NULL(Ctx); FBout.Size(0); // size the buffer Result_t result = FBout.Capacity(calc_esv_length(FBin.Size(), FBin.PlaintextOffset())); // write the IV byte_t* p = FBout.Data(); // write the IV to the frame buffer Ctx->GetIVec(p); p += CBC_BLOCK_SIZE; // encrypt the check value to the frame buffer if ( ASDCP_SUCCESS(result) ) { result = Ctx->EncryptBlock(ESV_CheckValue, p, CBC_BLOCK_SIZE); p += CBC_BLOCK_SIZE; } // write optional plaintext region if ( FBin.PlaintextOffset() > 0 ) { assert(FBin.PlaintextOffset() <= FBin.Size()); memcpy(p, FBin.RoData(), FBin.PlaintextOffset()); p += FBin.PlaintextOffset(); } ui32_t ct_size = FBin.Size() - FBin.PlaintextOffset(); ui32_t diff = ct_size % CBC_BLOCK_SIZE; ui32_t block_size = ct_size - diff; assert((block_size % CBC_BLOCK_SIZE) == 0); // encrypt the ciphertext region essence data if ( ASDCP_SUCCESS(result) ) { result = Ctx->EncryptBlock(FBin.RoData() + FBin.PlaintextOffset(), p, block_size); p += block_size; } // construct and encrypt the padding if ( ASDCP_SUCCESS(result) ) { byte_t the_last_block[CBC_BLOCK_SIZE]; if ( diff > 0 ) memcpy(the_last_block, FBin.RoData() + FBin.PlaintextOffset() + block_size, diff); for (ui32_t i = 0; diff < CBC_BLOCK_SIZE; diff++, i++ ) the_last_block[diff] = i; result = Ctx->EncryptBlock(the_last_block, p, CBC_BLOCK_SIZE); } if ( ASDCP_SUCCESS(result) ) FBout.Size(calc_esv_length(FBin.Size(), FBin.PlaintextOffset())); return result; }
ASDCP::Result_t ASDCP::RawEssenceType(const std::string& filename, EssenceType_t& type) { type = ESS_UNKNOWN; ASDCP::FrameBuffer FB; Kumu::FileReader Reader; ASDCP::Wav::SimpleWaveHeader WavHeader; ASDCP::RF64::SimpleRF64Header RF64Header; ASDCP::AIFF::SimpleAIFFHeader AIFFHeader; Kumu::XMLElement TmpElement("Tmp"); ui32_t data_offset; ui32_t read_count; Result_t result = FB.Capacity(Wav::MaxWavHeader); // using Wav max because everything else is much smaller if ( Kumu::PathIsFile(filename) ) { result = Reader.OpenRead(filename); if ( ASDCP_SUCCESS(result) ) { result = Reader.Read(FB.Data(), FB.Capacity(), &read_count); Reader.Close(); } if ( ASDCP_SUCCESS(result) ) { const byte_t* p = FB.RoData(); FB.Size(read_count); ui32_t i = 0; while ( p[i] == 0 ) i++; if ( i > 1 && p[i] == 1 && (p[i+1] == ASDCP::MPEG2::SEQ_START || p[i+1] == ASDCP::MPEG2::PIC_START) ) { type = ESS_MPEG2_VES; } else if ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 ) { type = ESS_JPEG_2000; } else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) { switch ( WavHeader.samplespersec ) { case 48000: type = ESS_PCM_24b_48k; break; case 96000: type = ESS_PCM_24b_96k; break; default: return RESULT_FORMAT; } } else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) { switch ( RF64Header.samplespersec ) { case 48000: type = ESS_PCM_24b_48k; break; case 96000: type = ESS_PCM_24b_96k; break; default: return RESULT_FORMAT; } } else if ( ASDCP_SUCCESS(AIFFHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) { type = ESS_PCM_24b_48k; } else if ( string_is_xml(FB) ) { type = ESS_TIMED_TEXT; } else if ( ASDCP::ATMOS::IsDolbyAtmos(filename) ) { type = ESS_DCDATA_DOLBY_ATMOS; } } } else if ( Kumu::PathIsDirectory(filename) ) { char next_file[Kumu::MaxFilePath]; Kumu::DirScanner Scanner; Result_t result = Scanner.Open(filename); if ( ASDCP_SUCCESS(result) ) { while ( ASDCP_SUCCESS(Scanner.GetNext(next_file)) ) { if ( next_file[0] == '.' ) // no hidden files or internal links continue; result = Reader.OpenRead(Kumu::PathJoin(filename, next_file)); if ( ASDCP_SUCCESS(result) ) { result = Reader.Read(FB.Data(), FB.Capacity(), &read_count); Reader.Close(); } if ( ASDCP_SUCCESS(result) ) { if ( memcmp(FB.RoData(), ASDCP::JP2K::Magic, sizeof(ASDCP::JP2K::Magic)) == 0 ) { type = ESS_JPEG_2000; } else if ( ASDCP_SUCCESS(WavHeader.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) { switch ( WavHeader.samplespersec ) { case 48000: type = ESS_PCM_24b_48k; break; case 96000: type = ESS_PCM_24b_96k; break; default: return RESULT_FORMAT; } } else if ( ASDCP_SUCCESS(RF64Header.ReadFromBuffer(FB.RoData(), read_count, &data_offset)) ) { switch ( RF64Header.samplespersec ) { case 48000: type = ESS_PCM_24b_48k; break; case 96000: type = ESS_PCM_24b_96k; break; default: return RESULT_FORMAT; } } else if ( ASDCP::ATMOS::IsDolbyAtmos(Kumu::PathJoin(filename, next_file)) ) { type = ESS_DCDATA_DOLBY_ATMOS; } else { type = ESS_DCDATA_UNKNOWN; } } break; } } } return result; }