diff options
author | kleines Filmröllchen <filmroellchen@serenityos.org> | 2023-05-18 16:01:12 +0200 |
---|---|---|
committer | Jelle Raaijmakers <jelle@gmta.nl> | 2023-05-18 22:23:15 +0200 |
commit | 3b8ccd123bdd70fcc7757fd7945f39861e34739c (patch) | |
tree | 5a8b19d12d79b3e2158476b8251ba49420e9382d | |
parent | 70ab4566f390ba85175147579b7f52cbc4e16b00 (diff) | |
download | serenity-3b8ccd123bdd70fcc7757fd7945f39861e34739c.zip |
LibAudio: Compute and verify FLAC frame header checksums
This is currently not a failure condition, but we will print out a
message to the console informing the user of a potential corrupted file.
-rw-r--r-- | Userland/Libraries/LibAudio/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibAudio/FlacLoader.cpp | 19 | ||||
-rw-r--r-- | Userland/Libraries/LibAudio/FlacTypes.h | 7 |
3 files changed, 21 insertions, 7 deletions
diff --git a/Userland/Libraries/LibAudio/CMakeLists.txt b/Userland/Libraries/LibAudio/CMakeLists.txt index cf807e8ed1..4ef906945a 100644 --- a/Userland/Libraries/LibAudio/CMakeLists.txt +++ b/Userland/Libraries/LibAudio/CMakeLists.txt @@ -22,4 +22,4 @@ if (SERENITYOS) endif() serenity_lib(LibAudio audio) -target_link_libraries(LibAudio PRIVATE LibCore LibIPC LibThreading LibUnicode) +target_link_libraries(LibAudio PRIVATE LibCore LibIPC LibThreading LibUnicode LibCrypto) diff --git a/Userland/Libraries/LibAudio/FlacLoader.cpp b/Userland/Libraries/LibAudio/FlacLoader.cpp index 851fda7137..c5e20f656b 100644 --- a/Userland/Libraries/LibAudio/FlacLoader.cpp +++ b/Userland/Libraries/LibAudio/FlacLoader.cpp @@ -24,6 +24,8 @@ #include <LibAudio/Resampler.h> #include <LibAudio/VorbisComment.h> #include <LibCore/File.h> +#include <LibCrypto/Checksum/ChecksumFunction.h> +#include <LibCrypto/Checksum/ChecksummingStream.h> namespace Audio { @@ -367,9 +369,10 @@ LoaderSamples FlacLoaderPlugin::next_frame() dbgln("FLAC Warning: Inserting seek point for sample {} failed: {}", sample_index, maybe_error.release_error()); } - BigEndianInputBitStream bit_stream { MaybeOwned<Stream>(*m_stream) }; + auto checksum_stream = TRY(try_make<Crypto::Checksum::ChecksummingStream<FlacFrameHeaderCRC>>(MaybeOwned<Stream>(*m_stream))); + BigEndianInputBitStream bit_stream { MaybeOwned<Stream> { *checksum_stream } }; - // TODO: Check the CRC-16 checksum (and others) by keeping track of read data + // TODO: Check the CRC-16 checksum by keeping track of read data. // 11.22. FRAME_HEADER u16 sync_code = LOADER_TRY(bit_stream.read_bits<u16>(14)); @@ -393,7 +396,6 @@ LoaderSamples FlacLoaderPlugin::next_frame() FLAC_VERIFY(reserved_bit == 0, LoaderError::Category::Format, "Reserved frame header end bit"); // 11.22.8. CODED NUMBER - // FIXME: sample number can be 8-56 bits, frame number can be 8-48 bits m_current_sample_or_frame = LOADER_TRY(read_utf8_char(bit_stream)); // Conditional header variables @@ -413,17 +415,22 @@ LoaderSamples FlacLoaderPlugin::next_frame() frame_sample_rate = LOADER_TRY(bit_stream.read_bits<u32>(16)) * 10; } + // It does not matter whether we extract the checksum from the digest here, or extract the digest 0x00 after processing the checksum. + auto const calculated_checksum = checksum_stream->digest(); // 11.22.11. FRAME CRC - // TODO: check header checksum, see above - [[maybe_unused]] u8 checksum = LOADER_TRY(bit_stream.read_bits<u8>(8)); + u8 specified_checksum = LOADER_TRY(bit_stream.read_bits<u8>(8)); + VERIFY(bit_stream.is_aligned_to_byte_boundary()); + if (specified_checksum != calculated_checksum) + dbgln("FLAC frame {}: Calculated header checksum {:02x} is different from specified checksum {:02x}", m_current_sample_or_frame, calculated_checksum, specified_checksum); - dbgln_if(AFLACLOADER_DEBUG, "Frame: {} samples, {}bit {}Hz, channeltype {:x}, {} number {}, header checksum {}", sample_count, bit_depth, frame_sample_rate, channel_type_num, blocking_strategy ? "sample" : "frame", m_current_sample_or_frame, checksum); + dbgln_if(AFLACLOADER_DEBUG, "Frame: {} samples, {}bit {}Hz, channeltype {:x}, {} number {}, header checksum {:02x}{}", sample_count, bit_depth, frame_sample_rate, channel_type_num, blocking_strategy ? "sample" : "frame", m_current_sample_or_frame, specified_checksum, specified_checksum != calculated_checksum ? " (checksum error)"sv : ""sv); m_current_frame = FlacFrameHeader { sample_count, frame_sample_rate, channel_type, bit_depth, + specified_checksum, }; u8 subframe_count = frame_channel_type_to_channel_count(channel_type); diff --git a/Userland/Libraries/LibAudio/FlacTypes.h b/Userland/Libraries/LibAudio/FlacTypes.h index 8eb5851e47..36f9265e2b 100644 --- a/Userland/Libraries/LibAudio/FlacTypes.h +++ b/Userland/Libraries/LibAudio/FlacTypes.h @@ -11,6 +11,7 @@ #include <AK/ByteBuffer.h> #include <AK/Types.h> #include <AK/Variant.h> +#include <LibCrypto/Checksum/CRC8.h> namespace Audio { @@ -23,6 +24,11 @@ namespace Audio { #define FLAC_SAMPLERATE_AT_END_OF_HEADER_16 0xfffffffe #define FLAC_SAMPLERATE_AT_END_OF_HEADER_16X10 0xfffffffd +// 11.22.11. FRAME CRC +// The polynomial used here is known as CRC-8-CCITT. +static constexpr u8 flac_polynomial = 0x07; +using FlacFrameHeaderCRC = Crypto::Checksum::CRC8<flac_polynomial>; + // 11.8 BLOCK_TYPE (7 bits) enum class FlacMetadataBlockType : u8 { STREAMINFO = 0, // Important data about the audio format @@ -80,6 +86,7 @@ struct FlacFrameHeader { u32 sample_rate; FlacFrameChannelType channels; u8 bit_depth; + u8 checksum; }; // 11.25. SUBFRAME_HEADER |