Skip to content

Commit 5894397

Browse files
authored
Merge pull request #22 from cppalliance/sha1_cavs_testing
Fix #21 via finishing sha1 nist cavs testing
2 parents f2e49e7 + 2be2c7f commit 5894397

File tree

8 files changed

+281
-46
lines changed

8 files changed

+281
-46
lines changed

include/boost/crypt/hash/sha1.hpp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,6 @@ namespace crypt {
3232

3333
class sha1_hasher
3434
{
35-
private:
36-
37-
boost::crypt::array<boost::crypt::uint32_t, 5> intermediate_hash_ {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0};
38-
boost::crypt::array<boost::crypt::uint8_t, 64> buffer_ {};
39-
40-
boost::crypt::size_t buffer_index_ {};
41-
boost::crypt::size_t low_ {};
42-
boost::crypt::size_t high_ {};
43-
44-
bool computed {};
45-
bool corrupted {};
46-
47-
BOOST_CRYPT_GPU_ENABLED constexpr auto sha1_process_message_block() -> void;
48-
49-
template <typename ForwardIter>
50-
BOOST_CRYPT_GPU_ENABLED constexpr auto sha1_update(ForwardIter data, boost::crypt::size_t size) noexcept -> hasher_state;
51-
52-
BOOST_CRYPT_GPU_ENABLED constexpr auto pad_message() noexcept -> void;
53-
5435
public:
5536

5637
using return_type = boost::crypt::array<boost::crypt::uint8_t, 20>;
@@ -71,6 +52,25 @@ class sha1_hasher
7152

7253

7354
BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> return_type ;
55+
56+
private:
57+
58+
boost::crypt::array<boost::crypt::uint32_t, 5> intermediate_hash_ { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 };
59+
boost::crypt::array<boost::crypt::uint8_t, 64> buffer_ {};
60+
61+
boost::crypt::size_t buffer_index_ {};
62+
boost::crypt::size_t low_ {};
63+
boost::crypt::size_t high_ {};
64+
65+
bool computed {};
66+
bool corrupted {};
67+
68+
BOOST_CRYPT_GPU_ENABLED constexpr auto sha1_process_message_block() -> void;
69+
70+
template <typename ForwardIter>
71+
BOOST_CRYPT_GPU_ENABLED constexpr auto sha1_update(ForwardIter data, boost::crypt::size_t size) noexcept -> hasher_state;
72+
73+
BOOST_CRYPT_GPU_ENABLED constexpr auto pad_message() noexcept -> void;
7474
};
7575

7676
namespace detail {

test/Jamfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,6 @@ project : requirements
4545

4646
run quick.cpp ;
4747
run test_md5.cpp ;
48-
run test_nist_cavs_sha1_short.cpp ;
48+
run test_nist_cavs_sha1_monte.cpp ;
49+
run test_nist_cavs_sha1_short_long.cpp ;
4950
run test_sha1.cpp ;

test/nist_cavs/vectors/shavs.pdf

217 KB
Binary file not shown.

test/test_cavs_nist_detail.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ struct test_object_hash
7373

7474
using test_vector_container_type = std::deque<test_object_hash>;
7575

76-
auto where_file(const std::string& test_vectors_filename) -> std::string
76+
auto where_file_shabytesvectors(const std::string& test_vectors_filename) -> std::string
7777
{
7878
// Try to open the file in each of the known relative paths
7979
// in order to find out where it is located.
@@ -159,7 +159,7 @@ auto parse_file_vectors(const std::string& test_vectors_filename, test_vector_co
159159
{
160160
bool result_parse_is_ok { false };
161161

162-
const std::string test_vectors_filename_relative { where_file(test_vectors_filename) };
162+
const std::string test_vectors_filename_relative { where_file_shabytesvectors(test_vectors_filename) };
163163

164164
const bool result_filename_plausible_is_ok { (!test_vectors_filename_relative.empty()) };
165165

test/test_nist_cavs_detail.hpp

Lines changed: 187 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,23 @@ struct test_object_hash
4646

4747
test_object_hash() = delete;
4848

49+
// Construct this hash test object by setting the result only.
50+
// There is no message and there is no length available for
51+
// this hash test object.
52+
53+
explicit test_object_hash(const std::string& str_result)
54+
: my_result // LCOV_EXCL_LINE
55+
{
56+
[&str_result]()
57+
{
58+
const auto byte_data { detail::convert_hex_string_to_byte_container(str_result) };
59+
return message_type(byte_data.cbegin(), byte_data.cend());
60+
}()
61+
}
62+
{ }
63+
64+
// Construct this hash test object with all of message, length and result.
65+
4966
explicit test_object_hash(const std::string& str_data, const std::string& str_result)
5067
: my_length { str_data.size() / static_cast<size_type>(UINT8_C(2)) },
5168
my_msg
@@ -61,7 +78,7 @@ struct test_object_hash
6178
[&str_result]()
6279
{
6380
const auto byte_data { detail::convert_hex_string_to_byte_container(str_result) };
64-
return message_type(byte_data.cbegin(), byte_data.cend());
81+
return message_type(byte_data.cbegin(), byte_data.cend());
6582
}()
6683
}
6784
{ }
@@ -73,7 +90,7 @@ struct test_object_hash
7390

7491
using test_vector_container_type = std::deque<test_object_hash>;
7592

76-
auto where_file(const std::string& test_vectors_filename) -> std::string
93+
auto where_file_shabytesvectors(const std::string& test_vectors_filename) -> std::string
7794
{
7895
// Try to open the file in each of the known relative paths
7996
// in order to find out where it is located.
@@ -159,10 +176,12 @@ auto parse_file_vectors(const std::string& test_vectors_filename, test_vector_co
159176
{
160177
bool result_parse_is_ok { false };
161178

162-
const std::string test_vectors_filename_relative { where_file(test_vectors_filename) };
179+
const std::string test_vectors_filename_relative { where_file_shabytesvectors(test_vectors_filename) };
163180

164181
const bool result_filename_plausible_is_ok { (!test_vectors_filename_relative.empty()) };
165182

183+
BOOST_TEST(result_filename_plausible_is_ok);
184+
166185
if(result_filename_plausible_is_ok)
167186
{
168187
std::string str_message { };
@@ -232,6 +251,77 @@ auto parse_file_vectors(const std::string& test_vectors_filename, test_vector_co
232251
}
233252
}
234253

254+
BOOST_TEST(result_parse_is_ok);
255+
256+
return result_parse_is_ok;
257+
}
258+
259+
auto parse_file_monte(const std::string& test_monte_filename, test_vector_container_type& test_vectors_to_get) -> bool
260+
{
261+
bool result_parse_is_ok { false };
262+
263+
const std::string test_vectors_filename_relative { where_file_shabytesvectors(test_monte_filename) };
264+
265+
const bool result_filename_plausible_is_ok { (!test_vectors_filename_relative.empty()) };
266+
267+
BOOST_TEST(result_filename_plausible_is_ok);
268+
269+
if(result_filename_plausible_is_ok)
270+
{
271+
std::string str_result { };
272+
273+
// Read the file for creating the test cases.
274+
std::ifstream in(test_vectors_filename_relative.c_str());
275+
276+
const bool file_is_open = in.is_open();
277+
278+
unsigned count { };
279+
280+
if(file_is_open)
281+
{
282+
result_parse_is_ok = true;
283+
284+
std::string line { };
285+
std::string result { };
286+
287+
while(getline(in, line))
288+
{
289+
const std::string::size_type pos_cnt = line.find("COUNT =", 0U);
290+
const std::string::size_type pos_md = line.find("MD =", 0U);
291+
292+
const bool line_is_representation_is_cnt = (pos_cnt != std::string::npos);
293+
const bool line_is_representation_is_md = (pos_md != std::string::npos);
294+
295+
// Get the next count.
296+
if(line_is_representation_is_cnt)
297+
{
298+
const std::string str_cnt = line.substr(8U, line.length() - 8U);
299+
300+
const unsigned long count_from_file = std::strtoul(str_cnt.c_str(), nullptr, 10U);
301+
302+
count = static_cast<unsigned>(count_from_file);
303+
}
304+
305+
// Get the next (expected) result.
306+
if(line_is_representation_is_md)
307+
{
308+
result = line.substr(5U, line.length() - 5U);
309+
310+
// Add the new test object to v.
311+
const test_object_hash test_obj(result);
312+
313+
test_vectors_to_get.push_back(test_obj);
314+
}
315+
}
316+
317+
in.close();
318+
319+
result_parse_is_ok = ((!test_vectors_to_get.empty()) && (count == 99U) && result_parse_is_ok);
320+
}
321+
}
322+
323+
BOOST_TEST(result_parse_is_ok);
324+
235325
return result_parse_is_ok;
236326
}
237327

@@ -246,6 +336,8 @@ auto test_vectors_oneshot(const test_vector_container_type& test_vectors) -> boo
246336
using local_hasher_type = HasherType;
247337
using local_result_type = typename local_hasher_type::return_type;
248338

339+
BOOST_TEST((!test_vectors.empty()));
340+
249341
bool result_is_ok { true };
250342

251343
for(const auto& test_vector : test_vectors)
@@ -267,6 +359,9 @@ auto test_vectors_oneshot(const test_vector_container_type& test_vectors) -> boo
267359

268360
// Make pass 2 through the messages.
269361
// Use the triple-combination of init/process/get-result functions.
362+
// Even though this is not required in CAVS testing, it is
363+
// done in order to ensure that the init() function properly
364+
// puts the hasher-object into its initialized state.
270365

271366
this_hash.init();
272367

@@ -287,6 +382,95 @@ auto test_vectors_oneshot(const test_vector_container_type& test_vectors) -> boo
287382
return result_is_ok;
288383
}
289384

385+
template<typename HasherType>
386+
auto test_vectors_monte(const nist::cavs::test_vector_container_type& test_vectors_monte, const std::vector<std::uint8_t>& seed_init) -> bool
387+
{
388+
using local_hasher_type = HasherType;
389+
using local_result_type = typename local_hasher_type::return_type;
390+
391+
using local_array_type = local_result_type;
392+
393+
// Obtain the test-specific initial seed.
394+
local_array_type Seed { };
395+
396+
const std::size_t
397+
copy_len
398+
{
399+
(std::min)(static_cast<std::size_t>(Seed.size()), static_cast<std::size_t>(seed_init.size()))
400+
};
401+
402+
std::copy
403+
(
404+
seed_init.cbegin(),
405+
seed_init.cbegin() + static_cast<typename std::vector<std::uint8_t>::difference_type>(copy_len),
406+
Seed.begin()
407+
);
408+
409+
bool result_is_ok { (!test_vectors_monte.empty()) };
410+
411+
if(result_is_ok)
412+
{
413+
local_array_type MD[3U] { { }, { }, { } };
414+
415+
local_array_type MDi { };
416+
local_array_type MDj { };
417+
418+
constexpr local_array_type dummy_array { };
419+
420+
// See pseudocode on page 9 of "The Secure Hash Algorithm Validation System (SHAVS)".
421+
422+
for(std::size_t j { }; j < 100U; ++j)
423+
{
424+
MD[0U] = MD[1U] = MD[2U] = Seed;
425+
426+
for(std::size_t i { 3U } ; i < 1003U; ++i)
427+
{
428+
using local_wide_array_type = boost::crypt::array<std::uint8_t, dummy_array.size() * 3U>;
429+
430+
std::vector<std::uint8_t> result_vector;
431+
432+
result_vector.reserve(dummy_array.size() * 3U);
433+
434+
result_vector.insert(result_vector.end(), MD[0U].cbegin(), MD[0U].cend());
435+
result_vector.insert(result_vector.end(), MD[1U].cbegin(), MD[1U].cend());
436+
result_vector.insert(result_vector.end(), MD[2U].cbegin(), MD[2U].cend());
437+
438+
local_wide_array_type Mi { };
439+
440+
std::copy(result_vector.cbegin(), result_vector.cend(), Mi.begin());
441+
442+
local_hasher_type this_hash { };
443+
444+
this_hash.init();
445+
446+
this_hash.process_bytes(Mi.data(), Mi.size());
447+
448+
MDi = this_hash.get_digest();
449+
450+
MD[0U] = MD[1U];
451+
MD[1U] = MD[2U];
452+
MD[2U] = MDi;
453+
}
454+
455+
MDj = Seed = MDi;
456+
457+
const bool result_this_monte_step_is_ok =
458+
std::equal
459+
(
460+
MDj.cbegin(),
461+
MDj.cend(),
462+
test_vectors_monte[j].my_result.cbegin()
463+
);
464+
465+
result_is_ok = (result_this_monte_step_is_ok && result_is_ok);
466+
467+
BOOST_TEST(result_this_monte_step_is_ok);
468+
}
469+
}
470+
471+
return result_is_ok;
472+
}
473+
290474
} // namespace cavs
291475
} // namespace nist
292476

test/test_nist_cavs_sha1_monte.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2024 Matt Borland
2+
// Copyright 2024 Christopher Kormanyos
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// https://www.boost.org/LICENSE_1_0.txt
5+
6+
#include <boost/crypt/hash/sha1.hpp>
7+
8+
#include "test_nist_cavs_detail.hpp"
9+
10+
auto main() -> int
11+
{
12+
bool result_is_ok { true };
13+
14+
{
15+
nist::cavs::test_vector_container_type my_test_vectors_monte { };
16+
17+
std::vector<std::uint8_t>
18+
seed_init
19+
(
20+
{
21+
0xDDU, 0x4DU, 0xF6U, 0x44U, 0xEAU, 0xF3U, 0xD8U, 0x5BU,
22+
0xACU, 0xE2U, 0xB2U, 0x1AU, 0xCCU, 0xAAU, 0x22U, 0xB2U,
23+
0x88U, 0x21U, 0xF5U, 0xCDU
24+
}
25+
);
26+
27+
static_cast<void>(nist::cavs::detail::parse_file_monte("SHA1Monte.rsp", my_test_vectors_monte));
28+
29+
result_is_ok = (nist::cavs::test_vectors_monte<boost::crypt::sha1_hasher>(my_test_vectors_monte, seed_init) && result_is_ok);
30+
31+
BOOST_TEST(result_is_ok);
32+
}
33+
34+
return boost::report_errors();
35+
}

test/test_nist_cavs_sha1_short.cpp

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

0 commit comments

Comments
 (0)