#ifndef CHAOS_PADDING_PADDERPKCS7_HPP #define CHAOS_PADDING_PADDERPKCS7_HPP #include #include #include #include #include #include #include "Padding/Padder.hpp" #include "Service/ChaosException.hpp" namespace Chaos::Padding { class PadderPkcs7 : public Padder { public: template static void Pad(OutputIt begin, OutputIt end) { auto dist = std::distance(begin, end); // TODO: dist > 0 if (dist >= 0 && dist <= std::numeric_limits::max()) { for (OutputIt it = begin; it != end; ++it) { *it = static_cast(dist); } } else { 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 #endif // CHAOS_PADDING_PADDERPKCS7_HPP