From e6c4f1fc98942b47096b79a9838cfedd93e22ab5 Mon Sep 17 00:00:00 2001 From: hashlag Date: Mon, 20 Jul 2026 02:20:54 +0300 Subject: [PATCH 1/6] Implement unpad for PKCS#7 padding. --- Chaos/Padding/Padder.hpp | 6 + Chaos/Padding/PadderPkcs7.hpp | 112 +++++++++++++ ChaosTests/Padding/PadderPkcs7Tests.cpp | 207 ++++++++++++++++++++++++ 3 files changed, 325 insertions(+) diff --git a/Chaos/Padding/Padder.hpp b/Chaos/Padding/Padder.hpp index 2f75e6e..5ae50e0 100644 --- a/Chaos/Padding/Padder.hpp +++ b/Chaos/Padding/Padder.hpp @@ -14,6 +14,12 @@ public: Impl().Pad(begin, end); } + template + auto ComputeUnpad(InputIt begin, InputIt end) const noexcept + { + return Impl().ComputeUnpad(begin, end); + } + protected: Padder() = default; diff --git a/Chaos/Padding/PadderPkcs7.hpp b/Chaos/Padding/PadderPkcs7.hpp index f94f43c..479e404 100644 --- a/Chaos/Padding/PadderPkcs7.hpp +++ b/Chaos/Padding/PadderPkcs7.hpp @@ -1,9 +1,12 @@ #ifndef CHAOS_PADDING_PADDERPKCS7_HPP #define CHAOS_PADDING_PADDERPKCS7_HPP +#include +#include #include #include #include +#include #include "Padding/Padder.hpp" #include "Service/ChaosException.hpp" @@ -19,6 +22,7 @@ public: { auto dist = std::distance(begin, end); + // TODO: dist > 0 if (dist >= 0 && dist <= std::numeric_limits::max()) { for (OutputIt it = begin; it != end; ++it) @@ -31,6 +35,114 @@ public: throw Service::ChaosException("PadderPkcs7::Pad(): invalid range"); } } + + struct ComputeUnpadResult + { + bool IsOkay_; + uint8_t PadSize_; + }; + + template + static ComputeUnpadResult ComputeUnpad(InputIt begin, InputIt end) noexcept + { + if (begin == end) + { + return { .IsOkay_ = false, .PadSize_ = 0 }; + } + + const uint8_t padSize = *std::prev(end); + uint8_t isOkay = ~BlIsZero(padSize); + + size_t suffixSize = 0; + InputIt it = end; + while (it != begin && suffixSize < std::numeric_limits::max()) + { + --it; + ++suffixSize; + + isOkay &= (BlEq(*it, padSize) | + BlGt(suffixSize, padSize)); + } + + isOkay &= BlGe(suffixSize, padSize); + + return + { + .IsOkay_ = static_cast(isOkay), + .PadSize_ = BlSel(isOkay, padSize, 0) + }; + } + +private: + template + static constexpr OutUInt BlMsb(InUInt in) noexcept + { + static_assert(std::is_unsigned_v && + std::is_unsigned_v); + + constexpr uint8_t shift = (sizeof(InUInt) * CHAR_BIT) - 1; + return static_cast(0) - (in >> shift); + } + + template + static constexpr OutUInt BlLt(InUInt lhs, InUInt rhs) noexcept + { + static_assert(std::is_unsigned_v && + std::is_unsigned_v); + static_assert(sizeof(InUInt) <= sizeof(uint64_t)); + + const uint64_t lhsEx = lhs; + const uint64_t rhsEx = rhs; + + return BlMsb(lhsEx ^ ((lhsEx ^ rhsEx) | ((lhsEx - rhsEx) ^ lhsEx))); + } + + template + static constexpr OutUInt BlIsZero(InUInt in) noexcept + { + static_assert(std::is_unsigned_v && + std::is_unsigned_v); + static_assert(sizeof(InUInt) <= sizeof(uint64_t)); + + const uint64_t inEx = in; + + return BlMsb(~inEx & (inEx - 1U)); + } + + template + static constexpr OutUInt BlEq(InUInt lhs, InUInt rhs) noexcept + { + static_assert(std::is_unsigned_v && + std::is_unsigned_v); + + return BlIsZero(lhs ^ rhs); + } + + template + static constexpr OutUInt BlGe(InUInt lhs, InUInt rhs) noexcept + { + static_assert(std::is_unsigned_v && + std::is_unsigned_v); + + return ~BlLt(lhs, rhs); + } + + template + static constexpr OutUInt BlGt(InUInt lhs, InUInt rhs) noexcept + { + static_assert(std::is_unsigned_v && + std::is_unsigned_v); + + return BlLt(rhs, lhs); + } + + template + static constexpr UInt BlSel(UInt mask, UInt onTrue, UInt onFalse) noexcept + { + static_assert(std::is_unsigned_v); + + return (mask & onTrue) | (~mask & onFalse); + } }; } // namespace Chaos::Padding diff --git a/ChaosTests/Padding/PadderPkcs7Tests.cpp b/ChaosTests/Padding/PadderPkcs7Tests.cpp index 874a704..eed60bd 100644 --- a/ChaosTests/Padding/PadderPkcs7Tests.cpp +++ b/ChaosTests/Padding/PadderPkcs7Tests.cpp @@ -141,3 +141,210 @@ TEST(PadPkcs7Tests, PadThroughBaseTest) ASSERT_EQ(expected, fact); } } + +TEST(PadPkcs7Tests, UnpadTest) +{ + { + std::array data = { 0x01 }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(1, result.PadSize_); + } + + { + std::array data = { 0xaa, 0xbb, 0x02, 0x02 }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(2, result.PadSize_); + } + + { + std::array data = { 0xaa, 0xbb, 0xcc, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07 }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(7, result.PadSize_); + } + + { + std::array data = { 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, + 0xa6, 0xa7, 0xa8, 0x01 }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(1, result.PadSize_); + } + + { + std::array data = { 0xa0, 0xa1, 0xa2, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07 }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(7, result.PadSize_); + } + + { + std::array data = { 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(10, result.PadSize_); + } + + { + std::array data = { 0x03, 0x03, 0x03, 0x03 }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(3, result.PadSize_); + } + + { + std::array data; + data.fill(0x41); + *std::prev(data.end()) = 1; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(1, result.PadSize_); + } + + { + std::array data; + data.fill(0x41); + std::fill(data.end() - 100, data.end(), 100); + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(100, result.PadSize_); + } + + { + std::array data; + data.fill(255); + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(255, result.PadSize_); + } + + { + std::array data; + data.fill(0x9a); + std::fill(data.end() - 255, data.end(), 255); + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(255, result.PadSize_); + } +} + +TEST(PadPkcs7Tests, UnpadErrorTest) +{ + { + std::array data = { }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0x00 }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0xa0, 0xa1, 0xa2, 0xa3, 0xff }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0xa0, 0xa1, 0xa2, 0xa3, 0x06 }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0xa0, 0xa1, 0xa2, 0xa3, 0x05 }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0xa0, 0xa1, 0x03, 0x02, 0x03 }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0xff }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0x03, 0x03 }; + + auto result = PadderPkcs7::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } +} + +template +auto ComputeUnpadThroughBase(const Padder & padder, OutputIt begin, OutputIt end) +{ + return padder.ComputeUnpad(begin, end); +} + +TEST(PadPkcs7Tests, ComputeUnpadThroughBaseTest) +{ + { + std::array data = { 0x05, 0x05, 0x05, 0x05, 0x05 }; + + const PadderPkcs7 padder; + auto result = ComputeUnpadThroughBase(padder, data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(5, result.PadSize_); + } +} From 5eb1aa2ece700b095f90f8d868ce18011210bea5 Mon Sep 17 00:00:00 2001 From: hashlag Date: Mon, 20 Jul 2026 02:34:31 +0300 Subject: [PATCH 2/6] Set clangd's unused includes diagnostic to strict explicitly. --- .clangd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.clangd b/.clangd index 2be4694..c7e9d1b 100644 --- a/.clangd +++ b/.clangd @@ -1,2 +1,5 @@ CompileFlags: CompilationDatabase: build/debug + +Diagnostics: + UnusedIncludes: Strict From 3560e321d73b82fb0160b28c0c98fecd3a6398fd Mon Sep 17 00:00:00 2001 From: hashlag Date: Mon, 20 Jul 2026 02:36:50 +0300 Subject: [PATCH 3/6] Enable clangd's missing includes diagnostic. --- .clangd | 1 + 1 file changed, 1 insertion(+) diff --git a/.clangd b/.clangd index c7e9d1b..24dac01 100644 --- a/.clangd +++ b/.clangd @@ -3,3 +3,4 @@ CompileFlags: Diagnostics: UnusedIncludes: Strict + MissingIncludes: Strict From 357f00d3e171a0ddf108227614e62690861caaf5 Mon Sep 17 00:00:00 2001 From: hashlag Date: Mon, 20 Jul 2026 02:53:13 +0300 Subject: [PATCH 4/6] Fix missing includes. --- Chaos/Cipher/Arc4/Arc4Crypt.hpp | 3 +++ Chaos/Cipher/Arc4/Arc4Gen.hpp | 1 + Chaos/Cipher/Block/Des/DesCrypt.hpp | 3 +++ Chaos/Hash/Md4.hpp | 2 ++ Chaos/Hash/Md5.hpp | 2 ++ Chaos/Hash/Sha1.hpp | 4 ++++ Chaos/Service/ChaosException.hpp | 1 + Chaos/Service/SeArray.hpp | 1 + ChaosTests/Cipher/Arc4CryptTests.cpp | 2 ++ ChaosTests/Cipher/Arc4GenTests.cpp | 5 +++++ ChaosTests/Cipher/DesCryptTests.cpp | 5 +++++ ChaosTests/Hash/Md4HasherTests.cpp | 2 ++ ChaosTests/Hash/Md5HasherTests.cpp | 2 ++ ChaosTests/Hash/Sha1HasherTests.cpp | 2 ++ ChaosTests/Mac/HmacTests.cpp | 4 ++++ ChaosTests/Padding/PadderIso7816Tests.cpp | 1 + ChaosTests/Padding/PadderPkcs7Tests.cpp | 1 + ChaosTests/Service/SeArrayTests.cpp | 1 + 18 files changed, 42 insertions(+) diff --git a/Chaos/Cipher/Arc4/Arc4Crypt.hpp b/Chaos/Cipher/Arc4/Arc4Crypt.hpp index 88ce26b..f7da4ab 100644 --- a/Chaos/Cipher/Arc4/Arc4Crypt.hpp +++ b/Chaos/Cipher/Arc4/Arc4Crypt.hpp @@ -1,6 +1,9 @@ #ifndef CHAOS_CIPHER_ARC4_ARC4CRYPT_HPP #define CHAOS_CIPHER_ARC4_ARC4CRYPT_HPP +#include +#include + #include "Arc4Gen.hpp" #include "Service/SeArray.hpp" #include "Service/ChaosException.hpp" diff --git a/Chaos/Cipher/Arc4/Arc4Gen.hpp b/Chaos/Cipher/Arc4/Arc4Gen.hpp index af2e833..f3f54f8 100644 --- a/Chaos/Cipher/Arc4/Arc4Gen.hpp +++ b/Chaos/Cipher/Arc4/Arc4Gen.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "Service/ChaosException.hpp" diff --git a/Chaos/Cipher/Block/Des/DesCrypt.hpp b/Chaos/Cipher/Block/Des/DesCrypt.hpp index a9e50c5..f303c50 100644 --- a/Chaos/Cipher/Block/Des/DesCrypt.hpp +++ b/Chaos/Cipher/Block/Des/DesCrypt.hpp @@ -3,6 +3,9 @@ #include #include +#include +#include +#include #include "Service/ChaosException.hpp" #include "Service/SeArray.hpp" diff --git a/Chaos/Hash/Md4.hpp b/Chaos/Hash/Md4.hpp index e4c1268..5387cae 100644 --- a/Chaos/Hash/Md4.hpp +++ b/Chaos/Hash/Md4.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "Hash.hpp" #include "Hasher.hpp" diff --git a/Chaos/Hash/Md5.hpp b/Chaos/Hash/Md5.hpp index 9ea28ce..2ef7149 100644 --- a/Chaos/Hash/Md5.hpp +++ b/Chaos/Hash/Md5.hpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include "Hash.hpp" #include "Hasher.hpp" diff --git a/Chaos/Hash/Sha1.hpp b/Chaos/Hash/Sha1.hpp index 1dd74a7..d8adf50 100644 --- a/Chaos/Hash/Sha1.hpp +++ b/Chaos/Hash/Sha1.hpp @@ -4,6 +4,10 @@ #include #include #include +#include +#include +#include +#include #include "Hash.hpp" #include "Hasher.hpp" diff --git a/Chaos/Service/ChaosException.hpp b/Chaos/Service/ChaosException.hpp index 761c406..888dedc 100644 --- a/Chaos/Service/ChaosException.hpp +++ b/Chaos/Service/ChaosException.hpp @@ -2,6 +2,7 @@ #define CHAOS_SERVICE_CHAOSEXCEPTION_HPP #include +#include namespace Chaos::Service { diff --git a/Chaos/Service/SeArray.hpp b/Chaos/Service/SeArray.hpp index 77a7f50..986e04e 100644 --- a/Chaos/Service/SeArray.hpp +++ b/Chaos/Service/SeArray.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace Chaos::Service { diff --git a/ChaosTests/Cipher/Arc4CryptTests.cpp b/ChaosTests/Cipher/Arc4CryptTests.cpp index 9375c38..200931f 100644 --- a/ChaosTests/Cipher/Arc4CryptTests.cpp +++ b/ChaosTests/Cipher/Arc4CryptTests.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include "Cipher/Arc4/Arc4Crypt.hpp" #include "Service/ChaosException.hpp" diff --git a/ChaosTests/Cipher/Arc4GenTests.cpp b/ChaosTests/Cipher/Arc4GenTests.cpp index 988d694..81fe1b1 100644 --- a/ChaosTests/Cipher/Arc4GenTests.cpp +++ b/ChaosTests/Cipher/Arc4GenTests.cpp @@ -1,6 +1,11 @@ #include +#include +#include +#include +#include #include "Cipher/Arc4/Arc4Gen.hpp" +#include "Service/ChaosException.hpp" using namespace Chaos::Cipher::Arc4; diff --git a/ChaosTests/Cipher/DesCryptTests.cpp b/ChaosTests/Cipher/DesCryptTests.cpp index 9a06d00..6d4e7f7 100644 --- a/ChaosTests/Cipher/DesCryptTests.cpp +++ b/ChaosTests/Cipher/DesCryptTests.cpp @@ -1,7 +1,12 @@ #include +#include +#include +#include #include "Cipher/Block/Des/DesCrypt.hpp" #include "Cipher/Block/Encryptor.hpp" +#include "Cipher/Block/Decryptor.hpp" +#include "Service/ChaosException.hpp" using namespace Chaos::Cipher::Block::Des; using namespace Chaos::Cipher::Block; diff --git a/ChaosTests/Hash/Md4HasherTests.cpp b/ChaosTests/Hash/Md4HasherTests.cpp index f234dd3..ab50e04 100644 --- a/ChaosTests/Hash/Md4HasherTests.cpp +++ b/ChaosTests/Hash/Md4HasherTests.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "Hash/Md4.hpp" diff --git a/ChaosTests/Hash/Md5HasherTests.cpp b/ChaosTests/Hash/Md5HasherTests.cpp index c17ef33..e2a4c6c 100644 --- a/ChaosTests/Hash/Md5HasherTests.cpp +++ b/ChaosTests/Hash/Md5HasherTests.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "Hash/Md5.hpp" diff --git a/ChaosTests/Hash/Sha1HasherTests.cpp b/ChaosTests/Hash/Sha1HasherTests.cpp index 2fce13a..38dccf5 100644 --- a/ChaosTests/Hash/Sha1HasherTests.cpp +++ b/ChaosTests/Hash/Sha1HasherTests.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "Hash/Sha1.hpp" diff --git a/ChaosTests/Mac/HmacTests.cpp b/ChaosTests/Mac/HmacTests.cpp index a782bd6..7882697 100644 --- a/ChaosTests/Mac/HmacTests.cpp +++ b/ChaosTests/Mac/HmacTests.cpp @@ -1,8 +1,12 @@ #include +#include +#include +#include #include "Hash/Md5.hpp" #include "Hash/Sha1.hpp" #include "Mac/Hmac.hpp" +#include "Service/ChaosException.hpp" using namespace Chaos::Mac::Hmac; using namespace Chaos::Hash::Md5; diff --git a/ChaosTests/Padding/PadderIso7816Tests.cpp b/ChaosTests/Padding/PadderIso7816Tests.cpp index e29b0c0..bd03976 100644 --- a/ChaosTests/Padding/PadderIso7816Tests.cpp +++ b/ChaosTests/Padding/PadderIso7816Tests.cpp @@ -4,6 +4,7 @@ #include #include "Padding/PadderIso7816.hpp" +#include "Padding/Padder.hpp" using namespace Chaos::Padding; diff --git a/ChaosTests/Padding/PadderPkcs7Tests.cpp b/ChaosTests/Padding/PadderPkcs7Tests.cpp index eed60bd..0e656e7 100644 --- a/ChaosTests/Padding/PadderPkcs7Tests.cpp +++ b/ChaosTests/Padding/PadderPkcs7Tests.cpp @@ -4,6 +4,7 @@ #include #include "Padding/PadderPkcs7.hpp" +#include "Padding/Padder.hpp" #include "Service/ChaosException.hpp" using namespace Chaos::Padding; diff --git a/ChaosTests/Service/SeArrayTests.cpp b/ChaosTests/Service/SeArrayTests.cpp index aa08a12..ae224c0 100644 --- a/ChaosTests/Service/SeArrayTests.cpp +++ b/ChaosTests/Service/SeArrayTests.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "Service/SeArray.hpp" From 442f7fbb290d9d479e00c2f1f00899e54cee32eb Mon Sep 17 00:00:00 2001 From: hashlag Date: Mon, 20 Jul 2026 02:53:46 +0300 Subject: [PATCH 5/6] Remove trailing whitespaces. --- ChaosTests/Service/SeArrayTests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChaosTests/Service/SeArrayTests.cpp b/ChaosTests/Service/SeArrayTests.cpp index ae224c0..9c703e0 100644 --- a/ChaosTests/Service/SeArrayTests.cpp +++ b/ChaosTests/Service/SeArrayTests.cpp @@ -17,7 +17,7 @@ TEST(SeArrayTests, InitializationTest) ASSERT_EQ(0, arr[i]); } } - + { SeArray arr; @@ -59,7 +59,7 @@ TEST(SeArrayTests, EraseTest) ASSERT_EQ(0, arr[i]); } } - + { SeArray arr; From eb178853e5c0f310186694c8d199213f99310b5c Mon Sep 17 00:00:00 2001 From: hashlag Date: Mon, 20 Jul 2026 02:54:15 +0300 Subject: [PATCH 6/6] Remove unused #include. --- ChaosTests/Cipher/Arc4CryptTests.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/ChaosTests/Cipher/Arc4CryptTests.cpp b/ChaosTests/Cipher/Arc4CryptTests.cpp index 200931f..8453504 100644 --- a/ChaosTests/Cipher/Arc4CryptTests.cpp +++ b/ChaosTests/Cipher/Arc4CryptTests.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include