From 9c084dcb291c91655444f57448fa99228cdc8b7d Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Thu, 6 Jan 2022 17:36:07 +0000 Subject: [PATCH] codec.cpp: Fix alignment and endianness issues --- Source/codec.cpp | 56 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/Source/codec.cpp b/Source/codec.cpp index 5832e68d8..4501e7cba 100644 --- a/Source/codec.cpp +++ b/Source/codec.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -20,9 +21,10 @@ struct CodecSignature { uint32_t checksum; uint8_t error; uint8_t lastChunkSize; - uint16_t unused; }; +constexpr size_t SignatureSize = 8; + // https://stackoverflow.com/a/45172360 - helper to make up for not having an implicit initializer for std::byte template std::array make_bytes(Ts &&...args) noexcept @@ -40,7 +42,7 @@ void CodecInitKey(const char *pszPassword) pw[i] = static_cast(pszPassword[j]); } - byte digest[SHA1HashSize]; + alignas(alignof(uint32_t)) byte digest[SHA1HashSize]; SHA1Reset(0); SHA1Calculate(0, pw, digest); SHA1Clear(); @@ -64,17 +66,40 @@ void CodecInitKey(const char *pszPassword) } memset(key.data(), 0, sizeof(key)); } + +CodecSignature GetCodecSignature(byte *src) +{ + CodecSignature result; + result.checksum = LoadLE32(src); + src += 4; + result.error = static_cast(*src++); + result.lastChunkSize = static_cast(*src); + return result; +} + +void SetCodecSignature(byte *dst, CodecSignature sig) +{ + *dst++ = static_cast(sig.checksum); + *dst++ = static_cast(sig.checksum >> 8); + *dst++ = static_cast(sig.checksum >> 16); + *dst++ = static_cast(sig.checksum >> 24); + *dst++ = static_cast(sig.error); + *dst++ = static_cast(sig.lastChunkSize); + *dst++ = static_cast(0); + *dst++ = static_cast(0); +} + } // namespace std::size_t codec_decode(byte *pbSrcDst, std::size_t size, const char *pszPassword) { byte buf[BlockSize]; - byte dst[SHA1HashSize]; + alignas(alignof(uint32_t)) byte dst[SHA1HashSize]; CodecInitKey(pszPassword); - if (size <= sizeof(CodecSignature)) + if (size <= SignatureSize) return 0; - size -= sizeof(CodecSignature); + size -= SignatureSize; if (size % BlockSize != 0) return 0; for (auto i = size; i != 0; pbSrcDst += BlockSize, i -= BlockSize) { @@ -89,18 +114,18 @@ std::size_t codec_decode(byte *pbSrcDst, std::size_t size, const char *pszPasswo } memset(buf, 0, sizeof(buf)); - auto *sig = reinterpret_cast(pbSrcDst); - if (sig->error > 0) { + const CodecSignature sig = GetCodecSignature(pbSrcDst); + if (sig.error > 0) { goto error; } SHA1Result(0, dst); - if (sig->checksum != *reinterpret_cast(dst)) { + if (sig.checksum != *reinterpret_cast(dst)) { memset(dst, 0, sizeof(dst)); goto error; } - size += sig->lastChunkSize - BlockSize; + size += sig.lastChunkSize - BlockSize; SHA1Clear(); return size; error: @@ -112,13 +137,13 @@ std::size_t codec_get_encoded_len(std::size_t dwSrcBytes) { if (dwSrcBytes % BlockSize != 0) dwSrcBytes += BlockSize - (dwSrcBytes % BlockSize); - return dwSrcBytes + sizeof(CodecSignature); + return dwSrcBytes + SignatureSize; } void codec_encode(byte *pbSrcDst, std::size_t size, std::size_t size64, const char *pszPassword) { byte buf[BlockSize]; - byte tmp[SHA1HashSize]; + alignas(alignof(uint32_t)) byte tmp[SHA1HashSize]; byte dst[SHA1HashSize]; if (size64 != codec_get_encoded_len(size)) @@ -144,11 +169,10 @@ void codec_encode(byte *pbSrcDst, std::size_t size, std::size_t size64, const ch } memset(buf, 0, sizeof(buf)); SHA1Result(0, tmp); - auto *sig = reinterpret_cast(pbSrcDst); - sig->error = 0; - sig->unused = 0; - sig->checksum = *reinterpret_cast(tmp); - sig->lastChunkSize = static_cast(lastChunk); // lastChunk is at most 64 so will always fit in an 8 bit var + SetCodecSignature(pbSrcDst, CodecSignature { /*.checksum=*/*reinterpret_cast(tmp), + /*.error=*/0, + // lastChunk is at most 64 so will always fit in an 8 bit var + /*.lastChunkSize=*/static_cast(lastChunk) }); SHA1Clear(); }