Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PR to HMAC_DRBG base class #98

Merged
merged 6 commits into from
Nov 11, 2024
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
34 changes: 0 additions & 34 deletions include/boost/crypt/drbg/drbg_state.hpp

This file was deleted.

81 changes: 76 additions & 5 deletions include/boost/crypt/drbg/hmac_drbg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,19 @@ class hmac_drbg
template <typename ForwardIter>
BOOST_CRYPT_GPU_ENABLED inline auto update(ForwardIter provided_data, boost::crypt::size_t size) noexcept -> state;

template <typename ForwardIter1, typename ForwardIter2 = const boost::crypt::uint8_t*, typename ForwardIter3 = const boost::crypt::uint8_t*>
BOOST_CRYPT_GPU_ENABLED inline auto generate_impl(const boost::crypt::false_type&,
ForwardIter1 data, boost::crypt::size_t requested_bits,
ForwardIter2 additional_data = nullptr, boost::crypt::size_t additional_data_size = 0,
ForwardIter3 additional_data_2 = nullptr, boost::crypt::size_t additional_data_2_size = 0) noexcept -> state;

// Provides prediction resistance
template <typename ForwardIter1, typename ForwardIter2, typename ForwardIter3 = const boost::crypt::uint8_t*>
BOOST_CRYPT_GPU_ENABLED inline auto generate_impl(const boost::crypt::true_type&,
ForwardIter1 data, boost::crypt::size_t requested_bits,
ForwardIter2 entropy, boost::crypt::size_t entropy_size,
ForwardIter3 additional_data = nullptr, boost::crypt::size_t additional_data_size = 0) noexcept -> state;

public:

BOOST_CRYPT_GPU_ENABLED constexpr hmac_drbg() = default;
Expand All @@ -77,11 +90,24 @@ class hmac_drbg
BOOST_CRYPT_GPU_ENABLED inline auto reseed(ForwardIter1 entropy, boost::crypt::size_t entropy_size,
ForwardIter2 additional_input = nullptr, boost::crypt::size_t additional_input_size = 0) noexcept -> state;

template <typename ForwardIter1, typename ForwardIter2 = const boost::crypt::uint8_t*, boost::crypt::enable_if_t<!prediction_resistance, bool> = true>
template <typename ForwardIter1, typename ForwardIter2 = const boost::crypt::uint8_t*, typename ForwardIter3 = const boost::crypt::uint8_t*>
BOOST_CRYPT_GPU_ENABLED inline auto generate(ForwardIter1 data, boost::crypt::size_t requested_bits,
ForwardIter2 additional_data = nullptr, boost::crypt::size_t additional_data_size = 0) noexcept -> state;
ForwardIter2 additional_data_1 = nullptr, boost::crypt::size_t additional_data_1_size = 0,
ForwardIter3 additional_data_2 = nullptr, boost::crypt::size_t additional_data_2_size = 0) noexcept -> state;

};

template <typename HMACType, boost::crypt::size_t max_hasher_security, boost::crypt::size_t outlen, bool prediction_resistance>
template <typename ForwardIter1, typename ForwardIter2, typename ForwardIter3>
auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::generate(
ForwardIter1 data, boost::crypt::size_t requested_bits,
ForwardIter2 additional_data_1, boost::crypt::size_t additional_data_1_size,
ForwardIter3 additional_data_2, boost::crypt::size_t additional_data_2_size) noexcept -> state
{
using impl_type = boost::crypt::integral_constant<bool, prediction_resistance>;
return generate_impl(impl_type(), data, requested_bits, additional_data_1, additional_data_1_size, additional_data_2, additional_data_2_size);
}

template <typename HMACType, boost::crypt::size_t max_hasher_security, boost::crypt::size_t outlen, bool prediction_resistance>
template <typename ForwardIter1, typename ForwardIter2>
auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::update_impl(
Expand All @@ -91,6 +117,14 @@ auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::up
BOOST_CRYPT_ASSERT(value_.size() + 1U + provided_data_size <= storage_size);
static_cast<void>(storage_size);

// GCC optimizes this to memcpy (like it should),
// but then complains about theoretical array boundaries (provided_data_size can be 0)
#if defined(__GNUC__) && __GNUC__ >= 5
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds="
#pragma GCC diagnostic ignored "-Wrestrict"
#endif

// Step 1: V || 0x00 || provided data
boost::crypt::size_t offset {};
for (boost::crypt::size_t i {}; i < value_.size(); ++i)
Expand All @@ -103,6 +137,10 @@ auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::up
storage[offset++] = static_cast<boost::crypt::uint8_t>(provided_data[i]);
}

#if defined(__GNUC__) && __GNUC__ >= 5
#pragma GCC diagnostic pop
#endif

HMACType hmac(key_);
hmac.process_bytes(storage, offset);
key_ = hmac.get_digest();
Expand Down Expand Up @@ -397,10 +435,12 @@ auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::re
}

template <typename HMACType, boost::crypt::size_t max_hasher_security, boost::crypt::size_t outlen, bool prediction_resistance>
template <typename ForwardIter1, typename ForwardIter2, boost::crypt::enable_if_t<!prediction_resistance, bool>>
auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::generate(
template <typename ForwardIter1, typename ForwardIter2, typename ForwardIter3>
auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::generate_impl(
const boost::crypt::false_type&,
ForwardIter1 data, boost::crypt::size_t requested_bits,
ForwardIter2 additional_data, boost::crypt::size_t additional_data_size) noexcept -> state
ForwardIter2 additional_data, boost::crypt::size_t additional_data_size,
ForwardIter3, boost::crypt::size_t) noexcept -> state
{
if (reseed_counter_ > reseed_interval)
{
Expand Down Expand Up @@ -467,6 +507,37 @@ auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::ge
return state::success;
}

template <typename HMACType, boost::crypt::size_t max_hasher_security, boost::crypt::size_t outlen, bool prediction_resistance>
template <typename ForwardIter1, typename ForwardIter2, typename ForwardIter3>
auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::generate_impl(
const boost::crypt::true_type&,
ForwardIter1 data, boost::crypt::size_t requested_bits,
ForwardIter2 entropy, boost::crypt::size_t entropy_size,
ForwardIter3 additional_data, boost::crypt::size_t additional_data_size) noexcept -> state
{
if (reseed_counter_ > reseed_interval)
{
return state::requires_reseed;
}
if (utility::is_null(data) || utility::is_null(entropy))
{
return state::null;
}
if (!initialized_)
{
return state::uninitialized;
}

// 9.3.3 Reseed using the entropy and the additional data, then set additional data to NULL
const auto reseed_return {reseed(entropy, entropy_size, additional_data, additional_data_size)};
if (reseed_return != state::success)
{
return reseed_return;
}

return generate_impl(boost::crypt::false_type(), data, requested_bits);
}

template <bool prediction_resistance>
BOOST_CRYPT_EXPORT using sha1_hmac_drbg_t = drbg::hmac_drbg<hmac<sha1_hasher>, 128U, 160U, prediction_resistance>;

Expand Down
51 changes: 51 additions & 0 deletions test/test_hmac_drbg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,61 @@ void sha1_additional_input()
}
}

void sha1_pr()
{
boost::crypt::sha1_hmac_drbg_pr rng;
constexpr boost::crypt::array<boost::crypt::uint8_t, 16> entropy = {
0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f, 0xf7, 0x3e, 0x9c, 0x5b
};
constexpr boost::crypt::array<boost::crypt::uint8_t, 8> nonce = {
0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11
};

constexpr boost::crypt::array<boost::crypt::uint8_t, 16> entropy_gen_1 = {
0x48, 0xa5, 0x84, 0xfe, 0x69, 0xab, 0x5a, 0xee, 0x42, 0xaa, 0x4d, 0x42, 0x17, 0x60, 0x99, 0xd4
};

constexpr boost::crypt::array<boost::crypt::uint8_t, 16> entropy_gen_2 = {
0x5e, 0x13, 0x97, 0xdc, 0x40, 0x4d, 0x86, 0xa3, 0x7b, 0xf5, 0x59, 0x54, 0x75, 0x69, 0x51, 0xe4
};

constexpr boost::crypt::array<boost::crypt::uint8_t, 80> nist_return = {
0x9a, 0x00, 0xa2, 0xd0, 0x0e, 0xd5, 0x9b, 0xfe, 0x31, 0xec,
0xb1, 0x39, 0x9b, 0x60, 0x81, 0x48, 0xd1, 0x96, 0x9d, 0x25,
0x0d, 0x3c, 0x1e, 0x94, 0x10, 0x10, 0x98, 0x12, 0x93, 0x25,
0xca, 0xb8, 0xfc, 0xcc, 0x2d, 0x54, 0x73, 0x19, 0x70, 0xc0,
0x10, 0x7a, 0xa4, 0x89, 0x25, 0x19, 0x95, 0x5e, 0x4b, 0xc6,
0x00, 0x1d, 0x7f, 0x4e, 0x6a, 0x2b, 0xf8, 0xa3, 0x01, 0xab,
0x46, 0x05, 0x5c, 0x09, 0xa6, 0x71, 0x88, 0xf1, 0xa7, 0x40,
0xee, 0xf3, 0xe1, 0x5c, 0x02, 0x9b, 0x44, 0xaf, 0x03, 0x44
};

boost::crypt::array<boost::crypt::uint8_t, 80> return_bits {};

BOOST_TEST(rng.init(entropy, entropy.size(), nonce, nonce.size()) == boost::crypt::state::success);

BOOST_TEST(rng.generate(return_bits.begin(), 640U, entropy_gen_1.begin(), entropy_gen_1.size()) == boost::crypt::state::success);

BOOST_TEST(rng.generate(return_bits.begin(), 640U, entropy_gen_2.begin(), entropy_gen_2.size()) == boost::crypt::state::success);

for (boost::crypt::size_t i {}; i < return_bits.size(); ++i)
{
if (!BOOST_TEST_EQ(return_bits[i], nist_return[i]))
{
// LCOV_EXCL_START
std::cerr << std::hex
<< "Got: " << static_cast<boost::crypt::uint32_t>(return_bits[i])
<< "\nExpected: " << static_cast<boost::crypt::uint32_t>(nist_return[i]) << std::endl;
// LCOV_EXCL_STOP
}
}
}

int main()
{
sha1_basic_correctness();
sha1_additional_input();
sha1_pr();

return boost::report_errors();
}
Loading