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_); + } +}