#ifndef CHAOS_PADDING_PADDERISO7816_HPP #define CHAOS_PADDING_PADDERISO7816_HPP #include #include #include #include "Padding/Padder.hpp" #include "Service/Branchless.hpp" #include "Service/ChaosException.hpp" namespace Chaos::Padding { class PadderIso7816 : public Padder { public: template static void Pad(OutputIt begin, OutputIt end) { OutputIt it = begin; if (it != end) { *it++ = static_cast(0x80); for (; it != end; ++it) { *it = 0; } } else { throw Service::ChaosException("PadderIso7816::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 }; } uint8_t padSizeIncrement = 1; uint8_t padSize = 0; uint8_t encountered0x80 = Branchless::FalseMask; uint8_t onlyZerosPast0x80 = Branchless::TrueMask; 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 #endif // CHAOS_PADDING_PADDERISO7816_HPP