diff --git a/include/boost/crypt2/aes/cipher_mode.hpp b/include/boost/crypt2/aes/cipher_mode.hpp index 858a4fd0..99132600 100644 --- a/include/boost/crypt2/aes/cipher_mode.hpp +++ b/include/boost/crypt2/aes/cipher_mode.hpp @@ -5,13 +5,24 @@ #ifndef BOOST_CIPHER_MODE_HPP #define BOOST_CIPHER_MODE_HPP -namespace boost::crypt::aes { +#include -enum class cipher_mode -{ +namespace boost::crypt { + +enum class aes_cipher_mode { ecb, // Electronic Codebook + ctr, // Counter }; -} // namespace boost::crypt::aes +template +class aes128; + +template +class aes192; + +template +class aes256; + +} // namespace boost::crypt #endif //BOOST_CIPHER_MODE_HPP diff --git a/include/boost/crypt2/aes/detail/pkcs7.hpp b/include/boost/crypt2/aes/detail/pkcs7.hpp new file mode 100644 index 00000000..02c78ab1 --- /dev/null +++ b/include/boost/crypt2/aes/detail/pkcs7.hpp @@ -0,0 +1,40 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// +// See: https://datatracker.ietf.org/doc/html/rfc5652#section-6.3 + +#ifndef BOOST_CRYPT2_AES_DETAIL_PKCS7_HPP +#define BOOST_CRYPT2_AES_DETAIL_PKCS7_HPP + +#include +#include + +namespace boost::crypt::aes_detail { + +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto pkcs7( + compat::span message, + compat::array& padded_message) noexcept -> void +{ + const auto pad_num {static_cast(16U - message.size())}; + + auto message_begin {message.begin()}; + auto message_end {message.end()}; + auto padded_message_begin {padded_message.begin()}; + + while (message_begin != message_end) + { + *padded_message_begin++ = *message_begin++; + } + + const auto padded_message_end {padded_message.end()}; + while (padded_message_begin != padded_message_end) + { + *padded_message_begin++ = pad_num; + } +} + +} // namespace boost::crypt::aes_detail + +#endif //BOOST_CRYPT2_AES_DETAIL_PKCS7_HPP diff --git a/include/boost/crypt2/aes/ecb.hpp b/include/boost/crypt2/aes/ecb.hpp new file mode 100644 index 00000000..7ecebe16 --- /dev/null +++ b/include/boost/crypt2/aes/ecb.hpp @@ -0,0 +1,193 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CRYPT2_AES_ECB_HPP +#define BOOST_CRYPT2_AES_ECB_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost::crypt { + +namespace aes_detail { + +template +class ecb_impl { +private: + + static constexpr compat::size_t key_length_bytes {Nr == 10 ? 16 : + Nr == 12 ? 24 : + Nr == 14 ? 32 : 0}; + + static constexpr compat::size_t block_length_bytes {16U}; + + static_assert(key_length_bytes != 0, "Invalid key length"); + + cipher block_cipher; + + bool initialized {false}; + +public: + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR ecb_impl() noexcept = default; + + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR ~ecb_impl() noexcept = default; + + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto init(compat::span key) noexcept -> state; + + template + BOOST_CRYPT_GPU_ENABLED auto init(SizedRange&& key) noexcept -> state; + + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto + encrypt_no_padding(compat::span message) noexcept -> state; + + template + BOOST_CRYPT_GPU_ENABLED auto encrypt_no_padding(SizedRange&& message) noexcept -> state; + + template + BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto + decrypt_no_padding(compat::span ciphertext) noexcept -> state; + + template + BOOST_CRYPT_GPU_ENABLED auto decrypt_no_padding(SizedRange&& ciphertext) noexcept -> state; +}; + +template +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto ecb_impl::init( + compat::span key) noexcept -> state +{ + static_assert(Extent >= key_length_bytes, "Invalid key length"); + + if (key.size() < key_length_bytes) + { + return state::insufficient_key_length; + } + + const auto fixed_key {key.template first()}; + BOOST_CRYPT_ASSERT(fixed_key.size_bytes() == key_length_bytes); + + block_cipher.init(fixed_key); + + initialized = true; + + return state::success; +} + +template +template +BOOST_CRYPT_GPU_ENABLED auto ecb_impl::init(SizedRange&& key) noexcept -> state +{ + const auto key_span {compat::make_span(key)}; + if (key_span.size_bytes() < key_length_bytes) + { + return state::insufficient_key_length; + } + + const auto byte_key_span {compat::as_bytes(key_span)}; + const auto fixed_key {byte_key_span.template first()}; + + block_cipher.init(fixed_key); + + initialized = true; + + return state::success; +} + +template +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto ecb_impl::encrypt_no_padding( + compat::span message) noexcept -> state +{ + static_assert(Extent == compat::dynamic_extent || Extent % block_length_bytes == 0, "Invalid ciphertext length"); + + if (message.size() % block_length_bytes != 0 && !message.empty()) + { + return state::incorrect_message_length; + } + if (!initialized) + { + return state::uninitialized; + } + + auto message_begin {message.begin()}; + const auto message_end {message.end()}; + while (message_begin != message_end) + { + auto fixed_span {compat::span(message_begin, message_begin + block_length_bytes)}; + block_cipher.block_cipher(fixed_span); + message_begin += block_length_bytes; + } + + return state::success; +} + +template +template +BOOST_CRYPT_GPU_ENABLED auto ecb_impl::encrypt_no_padding( + SizedRange&& message) noexcept -> state +{ + auto message_span {compat::make_span(message)}; + return encrypt_no_padding(compat::as_writable_bytes(message_span)); +} + +template +template +BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto ecb_impl::decrypt_no_padding( + compat::span ciphertext) noexcept -> state +{ + static_assert(Extent == compat::dynamic_extent || Extent % block_length_bytes == 0, "Invalid ciphertext length"); + + if (ciphertext.size() % block_length_bytes != 0 && !ciphertext.empty()) + { + return state::incorrect_message_length; + } + if (!initialized) + { + return state::uninitialized; + } + + auto ciphertext_begin {ciphertext.begin()}; + const auto ciphertext_end {ciphertext.end()}; + while (ciphertext_begin != ciphertext_end) + { + auto fixed_span {compat::span(ciphertext_begin, ciphertext_begin + block_length_bytes)}; + block_cipher.inverse_block_cipher(fixed_span); + ciphertext_begin += block_length_bytes; + } + + return state::success; +} + +template +template +BOOST_CRYPT_GPU_ENABLED auto ecb_impl::decrypt_no_padding( + SizedRange&& ciphertext) noexcept -> state +{ + auto ciphertext_span {compat::make_span(ciphertext)}; + return decrypt_no_padding(compat::as_writable_bytes(ciphertext_span)); +} + +} // namespace aes_detail + +template <> +class aes128 : public aes_detail::ecb_impl<10> {}; + +template <> +class aes192 : public aes_detail::ecb_impl<12> {}; + +template <> +class aes256 : public aes_detail::ecb_impl<14> {}; + +} // namespace boost::crypt + +#endif // BOOST_CRYPT2_AES_ECB_HPP diff --git a/include/boost/crypt2/state.hpp b/include/boost/crypt2/state.hpp index 273f87f9..6bbd7915 100644 --- a/include/boost/crypt2/state.hpp +++ b/include/boost/crypt2/state.hpp @@ -21,6 +21,7 @@ BOOST_CRYPT_EXPORT enum class state requested_too_many_bits, // 2^19 bits is all that's allowed per request insufficient_key_length, // The key is not of proscribed length insufficient_output_length, // The output will not fit in the provided container + incorrect_message_length, // In non-padded AES modes the message must be a multiple of 128 bits state_error // added more input after get_digest without re-init }; diff --git a/test/Jamfile b/test/Jamfile index b336f163..9e821477 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -83,6 +83,8 @@ run test_hash_drbg.cpp ; run test_aes.cpp ; +run test_pkcs7.cpp ; + # NIST standard testing run test_nist_cavs_sha1_monte.cpp ; run test_nist_cavs_sha1_short_long.cpp ; @@ -150,9 +152,9 @@ run test_nist_cavs_shake256_short_long.cpp ; run test_nist_cavs_shake256_monte.cpp ; run test_nist_cavs_shake256_variable_output.cpp ; -#run test_nist_cavs_aes128_kat_ecb.cpp ; -#run test_nist_cavs_aes128_mmt_ecb.cpp ; -#run test_nist_cavs_aes128_mct_ecb.cpp ; +run test_nist_cavs_aes128_kat_ecb.cpp ; +run test_nist_cavs_aes128_mmt_ecb.cpp ; +run test_nist_cavs_aes128_mct_ecb.cpp ; #run test_nist_cavs_aes128_kat_cbc.cpp ; #run test_nist_cavs_aes128_mmt_cbc.cpp ; #run test_nist_cavs_aes128_mct_cbc.cpp ; diff --git a/test/test_aes.cpp b/test/test_aes.cpp index 102b4e42..81a55272 100644 --- a/test/test_aes.cpp +++ b/test/test_aes.cpp @@ -3,6 +3,7 @@ // https://www.boost.org/LICENSE_1_0.txt #include +#include #include #include #include @@ -53,6 +54,74 @@ void basic_block_cipher_test() BOOST_TEST(gen2.inverse_block_cipher(plaintext_span) == boost::crypt::state::uninitialized); } +void ecb_test() +{ + // AES-128 key from appendix A.1 + + constexpr std::array key = { + std::byte{0x2b}, std::byte{0x7e}, std::byte{0x15}, std::byte{0x16}, + std::byte{0x28}, std::byte{0xae}, std::byte{0xd2}, std::byte{0xa6}, + std::byte{0xab}, std::byte{0xf7}, std::byte{0x15}, std::byte{0x88}, + std::byte{0x09}, std::byte{0xcf}, std::byte{0x4f}, std::byte{0x3c} + }; + const std::span key_span {key}; + + std::array plaintext = { + std::byte{0x32}, std::byte{0x43}, std::byte{0xf6}, std::byte{0xa8}, + std::byte{0x88}, std::byte{0x5a}, std::byte{0x30}, std::byte{0x8d}, + std::byte{0x31}, std::byte{0x31}, std::byte{0x98}, std::byte{0xa2}, + std::byte{0xe0}, std::byte{0x37}, std::byte{0x07}, std::byte{0x34} + }; + std::span plaintext_span {plaintext}; + + const auto original_message {plaintext}; + + boost::crypt::aes128 gen; + BOOST_TEST(gen.init(key_span) == boost::crypt::state::success); + BOOST_TEST(gen.encrypt_no_padding(plaintext_span) == boost::crypt::state::success); + + + constexpr std::array validation_1 = { + std::byte{0x39}, std::byte{0x25}, std::byte{0x84}, std::byte{0x1d}, + std::byte{0x02}, std::byte{0xdc}, std::byte{0x09}, std::byte{0xfb}, + std::byte{0xdc}, std::byte{0x11}, std::byte{0x85}, std::byte{0x97}, + std::byte{0x19}, std::byte{0x6a}, std::byte{0x0b}, std::byte{0x32} + }; + + BOOST_TEST(plaintext == validation_1); + + BOOST_TEST(gen.decrypt_no_padding(plaintext_span) == boost::crypt::state::success); + + BOOST_TEST(plaintext == original_message); + + // Ranges + boost::crypt::aes128 gen3; + BOOST_TEST(gen3.init(key) == boost::crypt::state::success); + BOOST_TEST(gen3.encrypt_no_padding(plaintext) == boost::crypt::state::success); + BOOST_TEST(plaintext == validation_1); + BOOST_TEST(gen3.decrypt_no_padding(plaintext) == boost::crypt::state::success); + BOOST_TEST(plaintext == original_message); + + // Bad inputs + std::vector bad_key { std::byte{0x2b}, std::byte{0x7e}, std::byte{0x15}, std::byte{0x88} }; + std::span bad_key_span {bad_key}; + BOOST_TEST(gen.init(bad_key_span) == boost::crypt::state::insufficient_key_length); + BOOST_TEST(gen.init(bad_key) == boost::crypt::state::insufficient_key_length); + boost::crypt::aes128 gen2; + BOOST_TEST(gen2.encrypt_no_padding(plaintext_span) == boost::crypt::state::uninitialized); + BOOST_TEST(gen2.decrypt_no_padding(plaintext_span) == boost::crypt::state::uninitialized); + + auto bad_message = bad_key; + std::span bad_message_span {bad_message}; + BOOST_TEST(gen2.init(key_span) == boost::crypt::state::success); + BOOST_TEST(gen2.encrypt_no_padding(bad_message) == boost::crypt::state::incorrect_message_length); + BOOST_TEST(gen2.encrypt_no_padding(bad_message_span) == boost::crypt::state::incorrect_message_length); + + std::array incorrect_size {}; + std::span incorrect_size_span {incorrect_size}; + BOOST_TEST(gen2.decrypt_no_padding(incorrect_size_span) == boost::crypt::state::incorrect_message_length); +} + /* void cbc_test() { @@ -84,6 +153,36 @@ void cbc_test() BOOST_TEST(plaintext == plaintext_start); } +void cbc_test() +{ + // GFSbox test + constexpr boost::crypt::array key = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + constexpr boost::crypt::array iv {key}; + + constexpr boost::crypt::array plaintext_start = { + 0xf3, 0x44, 0x81, 0xec, 0x3c, 0xc6, 0x27, 0xba, + 0xcd, 0x5d, 0xc3, 0xfb, 0x08, 0xf2, 0x73, 0xe6 + }; + + auto plaintext {plaintext_start}; + + constexpr boost::crypt::array ciphertext = { + 0x03, 0x36, 0x76, 0x3e, 0x96, 0x6d, 0x92, 0x59, + 0x5a, 0x56, 0x7c, 0xc9, 0xce, 0x53, 0x7f, 0x5e + }; + + boost::crypt::aes128 gen; + BOOST_TEST(gen.init(key, key.size()) == boost::crypt::state::success); + BOOST_TEST(gen.encrypt(plaintext.begin(), plaintext.size(), iv.begin(), iv.size()) == boost::crypt::state::success); + BOOST_TEST(plaintext == ciphertext); + BOOST_TEST(gen.decrypt(plaintext.begin(), plaintext.size(), iv.begin(), iv.size()) == boost::crypt::state::success); + BOOST_TEST(plaintext == plaintext_start); +} + void cbc_mmt_test() { constexpr boost::crypt::array key = { @@ -323,6 +422,7 @@ void cfb128_test() int main() { basic_block_cipher_test(); + ecb_test(); /* cbc_test(); cbc_mmt_test(); diff --git a/test/test_nist_cavs_aes128_kat_ecb.cpp b/test/test_nist_cavs_aes128_kat_ecb.cpp index 683f2013..21a58c2c 100644 --- a/test/test_nist_cavs_aes128_kat_ecb.cpp +++ b/test/test_nist_cavs_aes128_kat_ecb.cpp @@ -3,7 +3,7 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include +#include #include "test_nist_cavs_detail.hpp" #include #include @@ -36,9 +36,15 @@ auto main() -> int // LCOV_EXCL_STOP } - result_is_ok = (nist::cavs::test_vectors_aes_kat(test_vectors) && result_is_ok); + result_is_ok = (nist::cavs::test_vectors_aes_kat>(test_vectors) && result_is_ok); - BOOST_TEST(result_is_ok); + if (!BOOST_TEST(result_is_ok)) + { + // LCOV_EXCL_START + std::cerr << "Failure from file: " << file << std::endl; + result_is_ok = true; + // LCOV_EXCL_STOP + } } return boost::report_errors(); diff --git a/test/test_nist_cavs_aes128_mct_ecb.cpp b/test/test_nist_cavs_aes128_mct_ecb.cpp index 827cb8c1..ab512741 100644 --- a/test/test_nist_cavs_aes128_mct_ecb.cpp +++ b/test/test_nist_cavs_aes128_mct_ecb.cpp @@ -3,7 +3,7 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include +#include #include "test_nist_cavs_detail.hpp" #include #include @@ -30,7 +30,7 @@ auto main() -> int // LCOV_EXCL_STOP } - result_is_ok = (nist::cavs::test_vectors_aes_mct(test_vectors) && result_is_ok); + result_is_ok = (nist::cavs::test_vectors_aes_mct>(test_vectors) && result_is_ok); BOOST_TEST(result_is_ok); } diff --git a/test/test_nist_cavs_aes128_mmt_ecb.cpp b/test/test_nist_cavs_aes128_mmt_ecb.cpp index 821dd966..30185f56 100644 --- a/test/test_nist_cavs_aes128_mmt_ecb.cpp +++ b/test/test_nist_cavs_aes128_mmt_ecb.cpp @@ -3,7 +3,7 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt -#include +#include #include "test_nist_cavs_detail.hpp" #include #include @@ -30,7 +30,7 @@ auto main() -> int // LCOV_EXCL_STOP } - result_is_ok = (nist::cavs::test_vectors_aes_mmt(test_vectors) && result_is_ok); + result_is_ok = (nist::cavs::test_vectors_aes_mmt>(test_vectors) && result_is_ok); BOOST_TEST(result_is_ok); } diff --git a/test/test_nist_cavs_detail.hpp b/test/test_nist_cavs_detail.hpp index afb8a018..ddc8868e 100644 --- a/test/test_nist_cavs_detail.hpp +++ b/test/test_nist_cavs_detail.hpp @@ -23,7 +23,7 @@ #endif #include -#include "boost/crypt/aes/detail/cipher_mode.hpp" +#include #include #include #include @@ -1619,18 +1619,34 @@ auto parse_file_aes(const std::string& test_vectors_filename, std::deque(plaintext.begin(), plaintext.size(), iv.begin(), iv.size()); - aes.template decrypt(plaintext.begin(), plaintext.size(), iv.begin(), iv.size()); + aes.template encrypt(plaintext.begin(), plaintext.size(), iv.begin(), iv.size()); + aes.template decrypt(plaintext.begin(), plaintext.size(), iv.begin(), iv.size()); if (plaintext != test_vector.plaintext) { - result_is_ok = false; std::cerr << "Error with vector: " << count << std::endl; - } ++count; @@ -2369,10 +2383,10 @@ auto test_vectors_aes_ctr(const nist::cavs::test_vector_container_aes &test_vect } // namespace detail -template +template auto test_vectors_aes_kat(const nist::cavs::test_vector_container_aes& test_vectors) -> bool { - BOOST_CRYPT_IF_CONSTEXPR (mode == boost::crypt::aes::cipher_mode::ctr) + if constexpr (mode == boost::crypt::aes_cipher_mode::ctr) { return detail::test_vectors_aes_ctr(test_vectors); } @@ -2391,6 +2405,7 @@ auto test_vectors_aes_kat(const nist::cavs::test_vector_container_aes& test_vect auto iv {test_vector.iv}; auto key {test_vector.key}; + /* BOOST_CRYPT_IF_CONSTEXPR (mode == boost::crypt::aes::cipher_mode::cfb8 || mode == boost::crypt::aes::cipher_mode::cfb128) { if (plaintext.empty() || ciphertext.empty() || iv.empty() || key.empty()) @@ -2404,20 +2419,37 @@ auto test_vectors_aes_kat(const nist::cavs::test_vector_container_aes& test_vect iv.pop_back(); key.pop_back(); } + */ AESType aes; - aes.init(key.begin(), key.size()); + aes.init(key); - if (count < total_tests / 2U) + if constexpr (mode != boost::crypt::aes_cipher_mode::ecb) { - // Encrypt Path - aes.template encrypt(plaintext.begin(), plaintext.size(), iv.begin(), iv.size()); + if (count < total_tests / 2U) + { + // Encrypt Path + aes.encrypt_no_padding(plaintext, iv); + } + else + { + // Decrypt Path + aes.decrypt_no_padding(ciphertext, iv); + } } else { - // Decrypt Path - aes.template decrypt(ciphertext.begin(), ciphertext.size(), iv.begin(), iv.size()); + if (count < total_tests / 2U) + { + // Encrypt Path + aes.encrypt_no_padding(plaintext); + } + else + { + // Decrypt Path + aes.decrypt_no_padding(ciphertext); + } } if (plaintext != ciphertext) @@ -2435,10 +2467,10 @@ auto test_vectors_aes_kat(const nist::cavs::test_vector_container_aes& test_vect } } -template +template auto test_vectors_aes_mmt(const nist::cavs::test_vector_container_aes& test_vectors) -> bool { - BOOST_CRYPT_IF_CONSTEXPR (mode == boost::crypt::aes::cipher_mode::ctr) + if constexpr (mode == boost::crypt::aes_cipher_mode::ctr) { return detail::test_vectors_aes_ctr(test_vectors); } @@ -2457,7 +2489,8 @@ auto test_vectors_aes_mmt(const nist::cavs::test_vector_container_aes& test_vect auto iv {test_vector.iv}; auto key {test_vector.key}; - BOOST_CRYPT_IF_CONSTEXPR (mode == boost::crypt::aes::cipher_mode::cfb8 || mode == boost::crypt::aes::cipher_mode::cfb128) + /* + if constexpr (mode == boost::crypt::aes::cipher_mode::cfb8 || mode == boost::crypt::aes::cipher_mode::cfb128) { if (plaintext.empty() || ciphertext.empty() || iv.empty() || key.empty()) { @@ -2470,20 +2503,37 @@ auto test_vectors_aes_mmt(const nist::cavs::test_vector_container_aes& test_vect iv.pop_back(); key.pop_back(); } + */ AESType aes; - aes.init(key.begin(), key.size()); + aes.init(key); - if (count < total_tests / 2U) + if constexpr (mode != boost::crypt::aes_cipher_mode::ecb) { - // Encrypt Path - aes.template encrypt(plaintext.begin(), plaintext.size(), iv.begin(), iv.size()); + if (count < total_tests / 2U) + { + // Encrypt Path + aes.encrypt_no_padding(plaintext, iv); + } + else + { + // Decrypt Path + aes.decrypt_no_padding(ciphertext, iv); + } } else { - // Decrypt Path - aes.template decrypt(ciphertext.begin(), ciphertext.size(), iv.begin(), iv.size()); + if (count < total_tests / 2U) + { + // Encrypt Path + aes.encrypt_no_padding(plaintext); + } + else + { + // Decrypt Path + aes.decrypt_no_padding(ciphertext); + } } if (plaintext != ciphertext) @@ -2501,7 +2551,7 @@ auto test_vectors_aes_mmt(const nist::cavs::test_vector_container_aes& test_vect } } -template +template auto test_vectors_aes_mct(const nist::cavs::test_vector_container_aes& test_vectors) -> bool { BOOST_TEST(!test_vectors.empty()); @@ -2517,6 +2567,7 @@ auto test_vectors_aes_mct(const nist::cavs::test_vector_container_aes& test_vect auto iv {test_vector.iv}; auto key {test_vector.key}; + /* BOOST_CRYPT_IF_CONSTEXPR (mode == boost::crypt::aes::cipher_mode::cfb8 || mode == boost::crypt::aes::cipher_mode::cfb128) { if (plaintext.empty() || ciphertext.empty() || iv.empty() || key.empty()) @@ -2530,19 +2581,20 @@ auto test_vectors_aes_mct(const nist::cavs::test_vector_container_aes& test_vect iv.pop_back(); key.pop_back(); } + */ AESType aes; - aes.init(key.begin(), key.size()); + aes.init(key); if (count < total_tests / 2U) { // Encrypt Path - BOOST_CRYPT_IF_CONSTEXPR (mode == boost::crypt::aes::cipher_mode::ecb) + if constexpr (mode == boost::crypt::aes_cipher_mode::ecb) { for (int i {0}; i < 1000; ++i) { - aes.template encrypt(plaintext.begin(), plaintext.size()); + aes.encrypt_no_padding(plaintext); } } else @@ -2555,13 +2607,13 @@ auto test_vectors_aes_mct(const nist::cavs::test_vector_container_aes& test_vect { if (i == 0) { - aes.template encrypt(PT[0].begin(), PT[0].size(), iv.begin(), iv.size()); + aes.encrypt_no_padding(PT[0], iv); CT[0] = PT[0]; PT[1] = iv; } else { - aes.template encrypt(PT[i].begin(), PT[i].size()); + aes.encrypt_no_padding(PT[i]); CT[i] = PT[i]; if (i < 999) { @@ -2577,11 +2629,11 @@ auto test_vectors_aes_mct(const nist::cavs::test_vector_container_aes& test_vect else { // Decrypt Path - BOOST_CRYPT_IF_CONSTEXPR (mode == boost::crypt::aes::cipher_mode::ecb) + if constexpr (mode == boost::crypt::aes_cipher_mode::ecb) { for (int i {0}; i < 1000; ++i) { - aes.template decrypt(ciphertext.begin(), ciphertext.size()); + aes.decrypt_no_padding(ciphertext); } } else @@ -2594,13 +2646,13 @@ auto test_vectors_aes_mct(const nist::cavs::test_vector_container_aes& test_vect { if (i == 0) { - aes.template decrypt(PT[0].begin(), PT[0].size(), iv.begin(), iv.size()); + aes.decrypt_no_padding(PT[0], iv); CT[0] = PT[0]; PT[1] = iv; } else { - aes.template decrypt(PT[i].begin(), PT[i].size()); + aes.decrypt_no_padding(PT[i]); CT[i] = PT[i]; if (i < 999) { diff --git a/test/test_pkcs7.cpp b/test/test_pkcs7.cpp new file mode 100644 index 00000000..ea4728fb --- /dev/null +++ b/test/test_pkcs7.cpp @@ -0,0 +1,52 @@ +// Copyright 2025 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include + +void test(std::size_t length) +{ + std::array padded_message {}; + std::vector original_message {}; + + for (std::size_t i {}; i < length; ++i) + { + original_message.emplace_back(std::byte{42}); + } + + std::span original_message_span {original_message.begin(), original_message.end()}; + boost::crypt::aes_detail::pkcs7(original_message_span, padded_message); + + auto iter {padded_message.crbegin()}; + std::size_t counter {}; + while (iter != padded_message.crend()) + { + if (*iter++ == std::byte{42}) + { + break; + } + + counter++; + } + + BOOST_TEST_EQ(counter, 16U - length); + + for (std::size_t i {}; i < length; ++i) + { + BOOST_TEST(original_message[i] == padded_message[i]); + } +} + +int main() +{ + for (std::size_t i {}; i <= 16; ++i) + { + test(i); + } + + return boost::report_errors(); +}