Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions include/boost/crypt2/aes/cipher_mode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,24 @@
#ifndef BOOST_CIPHER_MODE_HPP
#define BOOST_CIPHER_MODE_HPP

namespace boost::crypt::aes {
#include <boost/crypt2/detail/compat.hpp>

enum class cipher_mode
{
namespace boost::crypt {

enum class aes_cipher_mode {
ecb, // Electronic Codebook
ctr, // Counter
};

} // namespace boost::crypt::aes
template <aes_cipher_mode c>
class aes128;

template <aes_cipher_mode c>
class aes192;

template <aes_cipher_mode c>
class aes256;

} // namespace boost::crypt

#endif //BOOST_CIPHER_MODE_HPP
40 changes: 40 additions & 0 deletions include/boost/crypt2/aes/detail/pkcs7.hpp
Original file line number Diff line number Diff line change
@@ -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 <boost/crypt2/detail/config.hpp>
#include <boost/crypt2/detail/compat.hpp>

namespace boost::crypt::aes_detail {

template <compat::size_t Extent>
BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto pkcs7(
compat::span<const compat::byte, Extent> message,
compat::array<compat::byte, 16>& padded_message) noexcept -> void
{
const auto pad_num {static_cast<compat::byte>(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
193 changes: 193 additions & 0 deletions include/boost/crypt2/aes/ecb.hpp
Original file line number Diff line number Diff line change
@@ -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 <boost/crypt2/aes/cipher_mode.hpp>
#include <boost/crypt2/aes/detail/cipher.hpp>
#include <boost/crypt2/detail/config.hpp>
#include <boost/crypt2/detail/compat.hpp>
#include <boost/crypt2/detail/concepts.hpp>
#include <boost/crypt2/detail/clear_mem.hpp>
#include <boost/crypt2/detail/assert.hpp>
#include <boost/crypt2/state.hpp>

namespace boost::crypt {

namespace aes_detail {

template <compat::size_t Nr>
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<Nr> 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 <compat::size_t Extent>
BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto init(compat::span<const compat::byte, Extent> key) noexcept -> state;

template <concepts::sized_range SizedRange>
BOOST_CRYPT_GPU_ENABLED auto init(SizedRange&& key) noexcept -> state;

template <compat::size_t Extent>
BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto
encrypt_no_padding(compat::span<compat::byte, Extent> message) noexcept -> state;

template <concepts::sized_range SizedRange>
BOOST_CRYPT_GPU_ENABLED auto encrypt_no_padding(SizedRange&& message) noexcept -> state;

template <compat::size_t Extent>
BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto
decrypt_no_padding(compat::span<compat::byte, Extent> ciphertext) noexcept -> state;

template <concepts::sized_range SizedRange>
BOOST_CRYPT_GPU_ENABLED auto decrypt_no_padding(SizedRange&& ciphertext) noexcept -> state;
};

template <compat::size_t Nr>
template <compat::size_t Extent>
BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto ecb_impl<Nr>::init(
compat::span<const compat::byte, Extent> 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<key_length_bytes>()};
BOOST_CRYPT_ASSERT(fixed_key.size_bytes() == key_length_bytes);

block_cipher.init(fixed_key);

initialized = true;

return state::success;
}

template <compat::size_t Nr>
template <concepts::sized_range SizedRange>
BOOST_CRYPT_GPU_ENABLED auto ecb_impl<Nr>::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<key_length_bytes>()};

block_cipher.init(fixed_key);

initialized = true;

return state::success;
}

template <compat::size_t Nr>
template <compat::size_t Extent>
BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto ecb_impl<Nr>::encrypt_no_padding(
compat::span<compat::byte, Extent> 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<compat::byte, block_length_bytes>(message_begin, message_begin + block_length_bytes)};
block_cipher.block_cipher(fixed_span);
message_begin += block_length_bytes;
}

return state::success;
}

template <compat::size_t Nr>
template <concepts::sized_range SizedRange>
BOOST_CRYPT_GPU_ENABLED auto ecb_impl<Nr>::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 <compat::size_t Nr>
template <compat::size_t Extent>
BOOST_CRYPT_GPU_ENABLED_CONSTEXPR auto ecb_impl<Nr>::decrypt_no_padding(
compat::span<compat::byte, Extent> 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<compat::byte, block_length_bytes>(ciphertext_begin, ciphertext_begin + block_length_bytes)};
block_cipher.inverse_block_cipher(fixed_span);
ciphertext_begin += block_length_bytes;
}

return state::success;
}

template <compat::size_t Nr>
template <concepts::sized_range SizedRange>
BOOST_CRYPT_GPU_ENABLED auto ecb_impl<Nr>::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<aes_cipher_mode::ecb> : public aes_detail::ecb_impl<10> {};

template <>
class aes192<aes_cipher_mode::ecb> : public aes_detail::ecb_impl<12> {};

template <>
class aes256<aes_cipher_mode::ecb> : public aes_detail::ecb_impl<14> {};

} // namespace boost::crypt

#endif // BOOST_CRYPT2_AES_ECB_HPP
1 change: 1 addition & 0 deletions include/boost/crypt2/state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down
8 changes: 5 additions & 3 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -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 ;
Expand Down Expand Up @@ -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 ;
Expand Down
Loading
Loading