From ac122f0f9fe93227693047116340dfd1cfe8bc40 Mon Sep 17 00:00:00 2001 From: hashlag Date: Thu, 13 Aug 2026 00:31:40 +0300 Subject: [PATCH 1/7] Implement unpad for ISO 7816 padding. --- Chaos/Padding/PadderIso7816.hpp | 49 +++++ ChaosTests/Padding/PadderIso7816Tests.cpp | 212 ++++++++++++++++++++++ 2 files changed, 261 insertions(+) diff --git a/Chaos/Padding/PadderIso7816.hpp b/Chaos/Padding/PadderIso7816.hpp index 113b838..4acd000 100644 --- a/Chaos/Padding/PadderIso7816.hpp +++ b/Chaos/Padding/PadderIso7816.hpp @@ -1,9 +1,12 @@ #ifndef CHAOS_PADDING_PADDERISO7816_HPP #define CHAOS_PADDING_PADDERISO7816_HPP +#include #include +#include #include "Padding/Padder.hpp" +#include "Service/Branchless.hpp" namespace Chaos::Padding { @@ -26,6 +29,52 @@ public: } } } + + struct ComputeUnpadResult + { + bool IsOkay_; + uint8_t PadSize_; + }; + + template + static ComputeUnpadResult ComputeUnpad(InputIt begin, InputIt end) noexcept + { + if (begin == end) + { + return { .IsOkay_ = false, .PadSize_ = 0 }; + } + + uint8_t padSizeIncrement = 1; + uint8_t padSize = 0; + + uint8_t encountered0x80 = 0x00; + uint8_t onlyZerosPast0x80 = 0xFF; + + InputIt it = end; + while (it != begin && padSize < std::numeric_limits::max()) + { + --it; + + const uint8_t byte = *it; + + padSizeIncrement = Branchless::Sel(encountered0x80, 0, 1); + encountered0x80 |= Branchless::Eq(byte, 0x80); + onlyZerosPast0x80 &= Branchless::IsZero(byte) | encountered0x80; + + padSize += padSizeIncrement; + } + + uint8_t isOkay = encountered0x80 & onlyZerosPast0x80; + + return + { + .IsOkay_ = static_cast(isOkay), + .PadSize_ = Branchless::Sel(isOkay, padSize, 0) + }; + } + +private: + using Branchless = Service::Branchless; }; } // namespace Chaos::Padding diff --git a/ChaosTests/Padding/PadderIso7816Tests.cpp b/ChaosTests/Padding/PadderIso7816Tests.cpp index 606a8a1..233ac6c 100644 --- a/ChaosTests/Padding/PadderIso7816Tests.cpp +++ b/ChaosTests/Padding/PadderIso7816Tests.cpp @@ -1,7 +1,9 @@ +#include #include #include #include +#include #include #include "Padding/PadderIso7816.hpp" @@ -131,3 +133,213 @@ TEST(PadIso7816Tests, PadThroughBaseTest) ASSERT_EQ(expected, fact); } } + +TEST(PadIso7816Tests, UnpadTest) +{ + { + std::array data = { 0x80 }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(1, result.PadSize_); + } + + { + std::array data = { 0xaa, 0xbb, 0x80, 0x00 }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(2, result.PadSize_); + } + + { + std::array data = { 0xaa, 0xbb, 0xcc, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 }; + + auto result = PadderIso7816::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, 0x80 }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(1, result.PadSize_); + } + + { + std::array data = { 0xa0, 0xa1, 0xa2, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(7, result.PadSize_); + } + + { + std::array data = { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(10, result.PadSize_); + } + + { + std::array data = { 0x80, 0x80, 0x00, 0x00 }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(3, result.PadSize_); + } + + { + std::array data; + data.fill(0x41); + *std::prev(data.end()) = 0x80; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(1, result.PadSize_); + } + + { + std::array data; + data.fill(0x41); + *std::prev(data.end(), 100) = 0x80; + std::fill(data.end() - 99, data.end(), 0); + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(100, result.PadSize_); + } + + { + std::array data; + data.fill(0); + *data.begin() = 0x80; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(255, result.PadSize_); + } + + { + std::array data; + data.fill(0x9a); + *std::prev(data.end(), 255) = 0x80; + std::fill(data.end() - 254, data.end(), 0); + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(255, result.PadSize_); + } +} + +TEST(PadIso7816Tests, UnpadErrorTest) +{ + { + std::array data = { }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0x00 }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0xa0, 0xa1, 0xa2, 0x80, 0xff }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0xa0, 0xa1, 0x00, 0x00, 0x00 }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0x80, 0x00, 0xa2, 0x00, 0x00 }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0xa0, 0x80, 0x03, 0x00, 0x00 }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0xff }; + + auto result = PadderIso7816::ComputeUnpad(data.begin(), data.end()); + + ASSERT_FALSE(result.IsOkay_); + ASSERT_EQ(0, result.PadSize_); + } + + { + std::array data = { 0x00, 0x00 }; + + auto result = PadderIso7816::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(PadIso7816Tests, ComputeUnpadThroughBaseTest) +{ + { + std::array data = { 0x80, 0x00, 0x00, 0x00, 0x00 }; + + const PadderIso7816 padder; + auto result = ComputeUnpadThroughBase(padder, data.begin(), data.end()); + + ASSERT_TRUE(result.IsOkay_); + ASSERT_EQ(5, result.PadSize_); + } +} From 8adc867a2e0d0a7706681d343de29d6e04fd93f1 Mon Sep 17 00:00:00 2001 From: hashlag Date: Thu, 13 Aug 2026 01:17:54 +0300 Subject: [PATCH 2/7] PadderIso7816: Do not allow to pad empty ranges. --- Chaos/Padding/PadderIso7816.hpp | 5 ++++ ChaosTests/Padding/PadderIso7816Tests.cpp | 33 +++++++++++------------ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Chaos/Padding/PadderIso7816.hpp b/Chaos/Padding/PadderIso7816.hpp index 4acd000..547f6e7 100644 --- a/Chaos/Padding/PadderIso7816.hpp +++ b/Chaos/Padding/PadderIso7816.hpp @@ -7,6 +7,7 @@ #include "Padding/Padder.hpp" #include "Service/Branchless.hpp" +#include "Service/ChaosException.hpp" namespace Chaos::Padding { @@ -28,6 +29,10 @@ public: *it = 0; } } + else + { + throw Service::ChaosException("PadderIso7816::Pad(): invalid range"); + } } struct ComputeUnpadResult diff --git a/ChaosTests/Padding/PadderIso7816Tests.cpp b/ChaosTests/Padding/PadderIso7816Tests.cpp index 233ac6c..c9c0a17 100644 --- a/ChaosTests/Padding/PadderIso7816Tests.cpp +++ b/ChaosTests/Padding/PadderIso7816Tests.cpp @@ -1,5 +1,6 @@ #include #include +#include "TestHelpers/AssertThrowEx.hpp" #include #include @@ -8,6 +9,7 @@ #include "Padding/PadderIso7816.hpp" #include "Padding/Padder.hpp" +#include "Service/ChaosException.hpp" using namespace Chaos::Padding; @@ -45,7 +47,7 @@ TEST(PadIso7816Tests, PadTest) ASSERT_EQ(expected, fact); } - for (int i = 0; i < 256; ++i) + for (int i = 1; i < 256; ++i) { std::vector fact(i, 0xff); @@ -58,6 +60,19 @@ TEST(PadIso7816Tests, PadTest) } } +TEST(PadIso7816Tests, PadInvalidRangeTest) +{ + { + std::array out = {}; + + ASSERT_THROW_EX(PadderIso7816::Pad(out.begin(), out.begin()), + Chaos::Service::ChaosException, + { + ASSERT_EQ("PadderIso7816::Pad(): invalid range", ex.GetMessage()); + }); + } +} + TEST(PadIso7816Tests, PadOutIteratorUsageTest) { { @@ -92,22 +107,6 @@ TEST(PadIso7816Tests, PadOutIteratorUsageTest) PadderIso7816::Pad(fact.begin() + 3, fact.end() - 3); ASSERT_EQ(expected, fact); } - - { - std::array fact = - { - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb - }; - std::array expected = - { - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, - 0xbb, 0xbb, 0xbb, 0xbb, 0xbb - }; - - PadderIso7816::Pad(fact.begin() + 5, fact.begin() + 5); - ASSERT_EQ(expected, fact); - } } template From 481a8baa58043a19dd0303ca2d2da7d58ccc992e Mon Sep 17 00:00:00 2001 From: hashlag Date: Thu, 13 Aug 2026 01:24:55 +0300 Subject: [PATCH 3/7] PadderIso7816Tests: Fix #include grouping. --- ChaosTests/Padding/PadderIso7816Tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChaosTests/Padding/PadderIso7816Tests.cpp b/ChaosTests/Padding/PadderIso7816Tests.cpp index c9c0a17..0118032 100644 --- a/ChaosTests/Padding/PadderIso7816Tests.cpp +++ b/ChaosTests/Padding/PadderIso7816Tests.cpp @@ -1,8 +1,8 @@ -#include #include #include "TestHelpers/AssertThrowEx.hpp" #include +#include #include #include #include From a282feeb0bd85b46912b3cad97a1d3f4ee030725 Mon Sep 17 00:00:00 2001 From: hashlag Date: Fri, 14 Aug 2026 00:42:49 +0300 Subject: [PATCH 4/7] PadderPkcs7Tests: Fix empty range pad testcase. --- ChaosTests/Padding/PadderPkcs7Tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChaosTests/Padding/PadderPkcs7Tests.cpp b/ChaosTests/Padding/PadderPkcs7Tests.cpp index 8111bf5..c42ac29 100644 --- a/ChaosTests/Padding/PadderPkcs7Tests.cpp +++ b/ChaosTests/Padding/PadderPkcs7Tests.cpp @@ -91,7 +91,7 @@ TEST(PadPkcs7Tests, PadInvalidRangeTest) { std::array out = {}; - ASSERT_THROW_EX(PadderPkcs7::Pad(out.end(), out.begin()), + ASSERT_THROW_EX(PadderPkcs7::Pad(out.begin(), out.end()), Chaos::Service::ChaosException, { ASSERT_EQ("PadderPkcs7::Pad(): invalid range", ex.GetMessage()); From 409b6aa48c46dd1edebb8a497b9ad20cae0d3642 Mon Sep 17 00:00:00 2001 From: hashlag Date: Fri, 14 Aug 2026 00:45:18 +0300 Subject: [PATCH 5/7] PadderPkcs7Tests: Remove reversed range testcase. There is not much we can do. --- ChaosTests/Padding/PadderPkcs7Tests.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/ChaosTests/Padding/PadderPkcs7Tests.cpp b/ChaosTests/Padding/PadderPkcs7Tests.cpp index c42ac29..112918b 100644 --- a/ChaosTests/Padding/PadderPkcs7Tests.cpp +++ b/ChaosTests/Padding/PadderPkcs7Tests.cpp @@ -78,16 +78,6 @@ TEST(PadPkcs7Tests, PadInvalidRangeTest) }); } - { - std::array out = {}; - - ASSERT_THROW_EX(PadderPkcs7::Pad(out.end(), out.begin()), - Chaos::Service::ChaosException, - { - ASSERT_EQ("PadderPkcs7::Pad(): invalid range", ex.GetMessage()); - }); - } - { std::array out = {}; From c472b55a9db449ed86537ee54e90b2b1b6b3ffbf Mon Sep 17 00:00:00 2001 From: hashlag Date: Thu, 13 Aug 2026 00:31:40 +0300 Subject: [PATCH 6/7] Implement unpad for ISO 7816 padding. --- ChaosTests/Padding/PadderIso7816Tests.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ChaosTests/Padding/PadderIso7816Tests.cpp b/ChaosTests/Padding/PadderIso7816Tests.cpp index 0118032..5bf8655 100644 --- a/ChaosTests/Padding/PadderIso7816Tests.cpp +++ b/ChaosTests/Padding/PadderIso7816Tests.cpp @@ -1,3 +1,4 @@ +#include #include #include "TestHelpers/AssertThrowEx.hpp" From bd94ff963f69136427dbd46291261106416615d2 Mon Sep 17 00:00:00 2001 From: hashlag Date: Fri, 14 Aug 2026 00:58:29 +0300 Subject: [PATCH 7/7] PadderIso7816Tests: Delete #include duplicate. --- ChaosTests/Padding/PadderIso7816Tests.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/ChaosTests/Padding/PadderIso7816Tests.cpp b/ChaosTests/Padding/PadderIso7816Tests.cpp index 5bf8655..0118032 100644 --- a/ChaosTests/Padding/PadderIso7816Tests.cpp +++ b/ChaosTests/Padding/PadderIso7816Tests.cpp @@ -1,4 +1,3 @@ -#include #include #include "TestHelpers/AssertThrowEx.hpp"