Skip to content

Commit acac94f

Browse files
authored
Merge pull request #98 from cppalliance/pr
Add PR to HMAC_DRBG base class
2 parents 787fcc7 + 41b06d7 commit acac94f

File tree

3 files changed

+127
-39
lines changed

3 files changed

+127
-39
lines changed

include/boost/crypt/drbg/drbg_state.hpp

Lines changed: 0 additions & 34 deletions
This file was deleted.

include/boost/crypt/drbg/hmac_drbg.hpp

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,19 @@ class hmac_drbg
6464
template <typename ForwardIter>
6565
BOOST_CRYPT_GPU_ENABLED inline auto update(ForwardIter provided_data, boost::crypt::size_t size) noexcept -> state;
6666

67+
template <typename ForwardIter1, typename ForwardIter2 = const boost::crypt::uint8_t*, typename ForwardIter3 = const boost::crypt::uint8_t*>
68+
BOOST_CRYPT_GPU_ENABLED inline auto generate_impl(const boost::crypt::false_type&,
69+
ForwardIter1 data, boost::crypt::size_t requested_bits,
70+
ForwardIter2 additional_data = nullptr, boost::crypt::size_t additional_data_size = 0,
71+
ForwardIter3 additional_data_2 = nullptr, boost::crypt::size_t additional_data_2_size = 0) noexcept -> state;
72+
73+
// Provides prediction resistance
74+
template <typename ForwardIter1, typename ForwardIter2, typename ForwardIter3 = const boost::crypt::uint8_t*>
75+
BOOST_CRYPT_GPU_ENABLED inline auto generate_impl(const boost::crypt::true_type&,
76+
ForwardIter1 data, boost::crypt::size_t requested_bits,
77+
ForwardIter2 entropy, boost::crypt::size_t entropy_size,
78+
ForwardIter3 additional_data = nullptr, boost::crypt::size_t additional_data_size = 0) noexcept -> state;
79+
6780
public:
6881

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

80-
template <typename ForwardIter1, typename ForwardIter2 = const boost::crypt::uint8_t*, boost::crypt::enable_if_t<!prediction_resistance, bool> = true>
93+
template <typename ForwardIter1, typename ForwardIter2 = const boost::crypt::uint8_t*, typename ForwardIter3 = const boost::crypt::uint8_t*>
8194
BOOST_CRYPT_GPU_ENABLED inline auto generate(ForwardIter1 data, boost::crypt::size_t requested_bits,
82-
ForwardIter2 additional_data = nullptr, boost::crypt::size_t additional_data_size = 0) noexcept -> state;
95+
ForwardIter2 additional_data_1 = nullptr, boost::crypt::size_t additional_data_1_size = 0,
96+
ForwardIter3 additional_data_2 = nullptr, boost::crypt::size_t additional_data_2_size = 0) noexcept -> state;
97+
8398
};
8499

100+
template <typename HMACType, boost::crypt::size_t max_hasher_security, boost::crypt::size_t outlen, bool prediction_resistance>
101+
template <typename ForwardIter1, typename ForwardIter2, typename ForwardIter3>
102+
auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::generate(
103+
ForwardIter1 data, boost::crypt::size_t requested_bits,
104+
ForwardIter2 additional_data_1, boost::crypt::size_t additional_data_1_size,
105+
ForwardIter3 additional_data_2, boost::crypt::size_t additional_data_2_size) noexcept -> state
106+
{
107+
using impl_type = boost::crypt::integral_constant<bool, prediction_resistance>;
108+
return generate_impl(impl_type(), data, requested_bits, additional_data_1, additional_data_1_size, additional_data_2, additional_data_2_size);
109+
}
110+
85111
template <typename HMACType, boost::crypt::size_t max_hasher_security, boost::crypt::size_t outlen, bool prediction_resistance>
86112
template <typename ForwardIter1, typename ForwardIter2>
87113
auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::update_impl(
@@ -91,6 +117,14 @@ auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::up
91117
BOOST_CRYPT_ASSERT(value_.size() + 1U + provided_data_size <= storage_size);
92118
static_cast<void>(storage_size);
93119

120+
// GCC optimizes this to memcpy (like it should),
121+
// but then complains about theoretical array boundaries (provided_data_size can be 0)
122+
#if defined(__GNUC__) && __GNUC__ >= 5
123+
#pragma GCC diagnostic push
124+
#pragma GCC diagnostic ignored "-Warray-bounds="
125+
#pragma GCC diagnostic ignored "-Wrestrict"
126+
#endif
127+
94128
// Step 1: V || 0x00 || provided data
95129
boost::crypt::size_t offset {};
96130
for (boost::crypt::size_t i {}; i < value_.size(); ++i)
@@ -103,6 +137,10 @@ auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::up
103137
storage[offset++] = static_cast<boost::crypt::uint8_t>(provided_data[i]);
104138
}
105139

140+
#if defined(__GNUC__) && __GNUC__ >= 5
141+
#pragma GCC diagnostic pop
142+
#endif
143+
106144
HMACType hmac(key_);
107145
hmac.process_bytes(storage, offset);
108146
key_ = hmac.get_digest();
@@ -397,10 +435,12 @@ auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::re
397435
}
398436

399437
template <typename HMACType, boost::crypt::size_t max_hasher_security, boost::crypt::size_t outlen, bool prediction_resistance>
400-
template <typename ForwardIter1, typename ForwardIter2, boost::crypt::enable_if_t<!prediction_resistance, bool>>
401-
auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::generate(
438+
template <typename ForwardIter1, typename ForwardIter2, typename ForwardIter3>
439+
auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::generate_impl(
440+
const boost::crypt::false_type&,
402441
ForwardIter1 data, boost::crypt::size_t requested_bits,
403-
ForwardIter2 additional_data, boost::crypt::size_t additional_data_size) noexcept -> state
442+
ForwardIter2 additional_data, boost::crypt::size_t additional_data_size,
443+
ForwardIter3, boost::crypt::size_t) noexcept -> state
404444
{
405445
if (reseed_counter_ > reseed_interval)
406446
{
@@ -467,6 +507,37 @@ auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::ge
467507
return state::success;
468508
}
469509

510+
template <typename HMACType, boost::crypt::size_t max_hasher_security, boost::crypt::size_t outlen, bool prediction_resistance>
511+
template <typename ForwardIter1, typename ForwardIter2, typename ForwardIter3>
512+
auto hmac_drbg<HMACType, max_hasher_security, outlen, prediction_resistance>::generate_impl(
513+
const boost::crypt::true_type&,
514+
ForwardIter1 data, boost::crypt::size_t requested_bits,
515+
ForwardIter2 entropy, boost::crypt::size_t entropy_size,
516+
ForwardIter3 additional_data, boost::crypt::size_t additional_data_size) noexcept -> state
517+
{
518+
if (reseed_counter_ > reseed_interval)
519+
{
520+
return state::requires_reseed;
521+
}
522+
if (utility::is_null(data) || utility::is_null(entropy))
523+
{
524+
return state::null;
525+
}
526+
if (!initialized_)
527+
{
528+
return state::uninitialized;
529+
}
530+
531+
// 9.3.3 Reseed using the entropy and the additional data, then set additional data to NULL
532+
const auto reseed_return {reseed(entropy, entropy_size, additional_data, additional_data_size)};
533+
if (reseed_return != state::success)
534+
{
535+
return reseed_return;
536+
}
537+
538+
return generate_impl(boost::crypt::false_type(), data, requested_bits);
539+
}
540+
470541
template <bool prediction_resistance>
471542
BOOST_CRYPT_EXPORT using sha1_hmac_drbg_t = drbg::hmac_drbg<hmac<sha1_hasher>, 128U, 160U, prediction_resistance>;
472543

test/test_hmac_drbg.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,61 @@ void sha1_additional_input()
129129
}
130130
}
131131

132+
void sha1_pr()
133+
{
134+
boost::crypt::sha1_hmac_drbg_pr rng;
135+
constexpr boost::crypt::array<boost::crypt::uint8_t, 16> entropy = {
136+
0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f, 0xf7, 0x3e, 0x9c, 0x5b
137+
};
138+
constexpr boost::crypt::array<boost::crypt::uint8_t, 8> nonce = {
139+
0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11
140+
};
141+
142+
constexpr boost::crypt::array<boost::crypt::uint8_t, 16> entropy_gen_1 = {
143+
0x48, 0xa5, 0x84, 0xfe, 0x69, 0xab, 0x5a, 0xee, 0x42, 0xaa, 0x4d, 0x42, 0x17, 0x60, 0x99, 0xd4
144+
};
145+
146+
constexpr boost::crypt::array<boost::crypt::uint8_t, 16> entropy_gen_2 = {
147+
0x5e, 0x13, 0x97, 0xdc, 0x40, 0x4d, 0x86, 0xa3, 0x7b, 0xf5, 0x59, 0x54, 0x75, 0x69, 0x51, 0xe4
148+
};
149+
150+
constexpr boost::crypt::array<boost::crypt::uint8_t, 80> nist_return = {
151+
0x9a, 0x00, 0xa2, 0xd0, 0x0e, 0xd5, 0x9b, 0xfe, 0x31, 0xec,
152+
0xb1, 0x39, 0x9b, 0x60, 0x81, 0x48, 0xd1, 0x96, 0x9d, 0x25,
153+
0x0d, 0x3c, 0x1e, 0x94, 0x10, 0x10, 0x98, 0x12, 0x93, 0x25,
154+
0xca, 0xb8, 0xfc, 0xcc, 0x2d, 0x54, 0x73, 0x19, 0x70, 0xc0,
155+
0x10, 0x7a, 0xa4, 0x89, 0x25, 0x19, 0x95, 0x5e, 0x4b, 0xc6,
156+
0x00, 0x1d, 0x7f, 0x4e, 0x6a, 0x2b, 0xf8, 0xa3, 0x01, 0xab,
157+
0x46, 0x05, 0x5c, 0x09, 0xa6, 0x71, 0x88, 0xf1, 0xa7, 0x40,
158+
0xee, 0xf3, 0xe1, 0x5c, 0x02, 0x9b, 0x44, 0xaf, 0x03, 0x44
159+
};
160+
161+
boost::crypt::array<boost::crypt::uint8_t, 80> return_bits {};
162+
163+
BOOST_TEST(rng.init(entropy, entropy.size(), nonce, nonce.size()) == boost::crypt::state::success);
164+
165+
BOOST_TEST(rng.generate(return_bits.begin(), 640U, entropy_gen_1.begin(), entropy_gen_1.size()) == boost::crypt::state::success);
166+
167+
BOOST_TEST(rng.generate(return_bits.begin(), 640U, entropy_gen_2.begin(), entropy_gen_2.size()) == boost::crypt::state::success);
168+
169+
for (boost::crypt::size_t i {}; i < return_bits.size(); ++i)
170+
{
171+
if (!BOOST_TEST_EQ(return_bits[i], nist_return[i]))
172+
{
173+
// LCOV_EXCL_START
174+
std::cerr << std::hex
175+
<< "Got: " << static_cast<boost::crypt::uint32_t>(return_bits[i])
176+
<< "\nExpected: " << static_cast<boost::crypt::uint32_t>(nist_return[i]) << std::endl;
177+
// LCOV_EXCL_STOP
178+
}
179+
}
180+
}
181+
132182
int main()
133183
{
134184
sha1_basic_correctness();
135185
sha1_additional_input();
186+
sha1_pr();
136187

137188
return boost::report_errors();
138189
}

0 commit comments

Comments
 (0)