summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkleines Filmröllchen <filmroellchen@serenityos.org>2023-05-18 16:01:12 +0200
committerJelle Raaijmakers <jelle@gmta.nl>2023-05-18 22:23:15 +0200
commit3b8ccd123bdd70fcc7757fd7945f39861e34739c (patch)
tree5a8b19d12d79b3e2158476b8251ba49420e9382d
parent70ab4566f390ba85175147579b7f52cbc4e16b00 (diff)
downloadserenity-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.txt2
-rw-r--r--Userland/Libraries/LibAudio/FlacLoader.cpp19
-rw-r--r--Userland/Libraries/LibAudio/FlacTypes.h7
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