Skip to content

Commit

Permalink
Merge pull request #98 from cppalliance/pr
Browse files Browse the repository at this point in the history
Add PR to HMAC_DRBG base class
  • Loading branch information
mborland authored Nov 11, 2024
2 parents 787fcc7 + 41b06d7 commit acac94f
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 39 deletions.
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();
}

0 comments on commit acac94f

Please sign in to comment.