Skip to content

Commit c2a5ff9

Browse files
committed
Add basic sha224 testing
1 parent e7d9f8d commit c2a5ff9

File tree

2 files changed

+353
-0
lines changed

2 files changed

+353
-0
lines changed

test/Jamfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ run link_1.cpp link_2.cpp link_3.cpp ;
5151
run quick.cpp ;
5252
run test_md5.cpp ;
5353
run test_sha1.cpp ;
54+
run test_sha224.cpp ;
5455
run test_sha256.cpp ;
5556

5657
# NIST standard testing

test/test_sha224.cpp

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
// Copyright 2024 Matt Borland
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// https://www.boost.org/LICENSE_1_0.txt
4+
5+
#include <boost/crypt/hash/sha224.hpp>
6+
#include <boost/core/lightweight_test.hpp>
7+
#include "generate_random_strings.hpp"
8+
#include <random>
9+
#include <iostream>
10+
#include <string>
11+
#include <array>
12+
#include <tuple>
13+
#include <fstream>
14+
#include <cstdlib>
15+
#include <ctime>
16+
#include <cstring>
17+
18+
constexpr std::array<std::tuple<const char*, boost::crypt::sha224_hasher::return_type>, 4> test_values =
19+
{
20+
std::make_tuple("a",
21+
boost::crypt::sha224_hasher::return_type{0xab, 0xd3, 0x75, 0x34, 0xc7, 0xd9, 0xa2, 0xef, 0xb9, 0x46, 0x5d, 0xe9, 0x31, 0xcd, 0x70, 0x55, 0xff, 0xdb, 0x88, 0x79, 0x56, 0x3a, 0xe9, 0x80, 0x78, 0xd6, 0xd6, 0xd5}),
22+
std::make_tuple("The quick brown fox jumps over the lazy dog",
23+
boost::crypt::sha224_hasher::return_type{0x73, 0x0e, 0x10, 0x9b, 0xd7, 0xa8, 0xa3, 0x2b, 0x1c, 0xb9, 0xd9, 0xa0, 0x9a, 0xa2, 0x32, 0x5d, 0x24, 0x30, 0x58, 0x7d, 0xdb, 0xc0, 0xc3, 0x8b, 0xad, 0x91, 0x15, 0x25}),
24+
std::make_tuple("The quick brown fox jumps over the lazy dog.",
25+
boost::crypt::sha224_hasher::return_type{0x61, 0x9c, 0xba, 0x8e, 0x8e, 0x05, 0x82, 0x6e, 0x9b, 0x8c, 0x51, 0x9c, 0x0a, 0x5c, 0x68, 0xf4, 0xfb, 0x65, 0x3e, 0x8a, 0x3d, 0x8a, 0xa0, 0x4b, 0xb2, 0xc8, 0xcd, 0x4c}),
26+
std::make_tuple("",
27+
boost::crypt::sha224_hasher::return_type {0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47, 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2, 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4, 0x2f})
28+
};
29+
30+
void basic_tests()
31+
{
32+
for (const auto& test_value : test_values)
33+
{
34+
const auto message_result {boost::crypt::sha224(std::get<0>(test_value))};
35+
const auto valid_result {std::get<1>(test_value)};
36+
for (std::size_t i {}; i < message_result.size(); ++i)
37+
{
38+
if (!BOOST_TEST_EQ(message_result[i], valid_result[i]))
39+
{
40+
// LCOV_EXCL_START
41+
std::cerr << "Failure with: " << std::get<0>(test_value) << '\n';
42+
break;
43+
// LCOV_EXCL_STOP
44+
}
45+
}
46+
}
47+
}
48+
49+
void string_test()
50+
{
51+
for (const auto& test_value : test_values)
52+
{
53+
const std::string string_message {std::get<0>(test_value)};
54+
const auto message_result {boost::crypt::sha224(string_message)};
55+
const auto valid_result {std::get<1>(test_value)};
56+
for (std::size_t i {}; i < message_result.size(); ++i)
57+
{
58+
if (!BOOST_TEST_EQ(message_result[i], valid_result[i]))
59+
{
60+
// LCOV_EXCL_START
61+
std::cerr << "Failure with: " << std::get<0>(test_value) << '\n';
62+
break;
63+
// LCOV_EXCL_STOP
64+
}
65+
}
66+
}
67+
}
68+
69+
void string_view_test()
70+
{
71+
#ifdef BOOST_CRYPT_HAS_STRING_VIEW
72+
for (const auto& test_value : test_values)
73+
{
74+
const std::string string_message {std::get<0>(test_value)};
75+
const std::string_view string_view_message {string_message};
76+
const auto message_result {boost::crypt::sha224(string_view_message)};
77+
const auto valid_result {std::get<1>(test_value)};
78+
for (std::size_t i {}; i < message_result.size(); ++i)
79+
{
80+
if (!BOOST_TEST_EQ(message_result[i], valid_result[i]))
81+
{
82+
// LCOV_EXCL_START
83+
std::cerr << "Failure with: " << std::get<0>(test_value) << '\n';
84+
break;
85+
// LCOV_EXCL_STOP
86+
}
87+
}
88+
}
89+
#endif
90+
}
91+
92+
void bad_input()
93+
{
94+
const auto null_message {boost::crypt::sha224(static_cast<const char*>(nullptr))};
95+
BOOST_TEST_EQ(null_message[0], 0x0);
96+
BOOST_TEST_EQ(null_message[1], 0x0);
97+
BOOST_TEST_EQ(null_message[2], 0x0);
98+
BOOST_TEST_EQ(null_message[3], 0x0);
99+
100+
const auto null_message_len {boost::crypt::sha224(static_cast<const char*>(nullptr), 100)};
101+
BOOST_TEST_EQ(null_message_len[0], 0x0);
102+
BOOST_TEST_EQ(null_message_len[1], 0x0);
103+
BOOST_TEST_EQ(null_message_len[2], 0x0);
104+
BOOST_TEST_EQ(null_message_len[3], 0x0);
105+
106+
const auto unsigned_null_message {boost::crypt::sha224(static_cast<const std::uint8_t*>(nullptr))};
107+
BOOST_TEST_EQ(unsigned_null_message[0], 0x0);
108+
BOOST_TEST_EQ(unsigned_null_message[1], 0x0);
109+
BOOST_TEST_EQ(unsigned_null_message[2], 0x0);
110+
BOOST_TEST_EQ(unsigned_null_message[3], 0x0);
111+
112+
const auto unsigned_null_message_len {boost::crypt::sha224(static_cast<const std::uint8_t*>(nullptr), 100)};
113+
BOOST_TEST_EQ(unsigned_null_message_len[0], 0x0);
114+
BOOST_TEST_EQ(unsigned_null_message_len[1], 0x0);
115+
BOOST_TEST_EQ(unsigned_null_message_len[2], 0x0);
116+
BOOST_TEST_EQ(unsigned_null_message_len[3], 0x0);
117+
118+
std::string test_str {"Test string"};
119+
const auto reveresed_input {boost::crypt::detail::sha224(test_str.end(), test_str.begin())};
120+
BOOST_TEST_EQ(reveresed_input[0], 0x0);
121+
BOOST_TEST_EQ(reveresed_input[1], 0x0);
122+
BOOST_TEST_EQ(reveresed_input[2], 0x0);
123+
BOOST_TEST_EQ(reveresed_input[3], 0x0);
124+
}
125+
126+
void test_class()
127+
{
128+
boost::crypt::sha224_hasher hasher;
129+
130+
for (const auto& test_value : test_values)
131+
{
132+
const auto msg {std::get<0>(test_value)};
133+
hasher.process_bytes(msg, std::strlen(msg));
134+
const auto message_result {hasher.get_digest()};
135+
136+
const auto valid_result {std::get<1>(test_value)};
137+
for (std::size_t i {}; i < message_result.size(); ++i)
138+
{
139+
if (!BOOST_TEST_EQ(message_result[i], valid_result[i]))
140+
{
141+
// LCOV_EXCL_START
142+
std::cerr << "Failure with: " << std::get<0>(test_value) << '\n';
143+
break;
144+
// LCOV_EXCL_STOP
145+
}
146+
}
147+
148+
hasher.init();
149+
}
150+
}
151+
152+
template <typename T>
153+
void test_file(T filename, const boost::crypt::sha224_hasher::return_type& res)
154+
{
155+
const auto crypt_res {boost::crypt::sha224_file(filename)};
156+
157+
for (std::size_t j {}; j < crypt_res.size(); ++j)
158+
{
159+
if (!BOOST_TEST_EQ(res[j], crypt_res[j]))
160+
{
161+
// LCOV_EXCL_START
162+
std::cerr << "Failure with file: " << filename << std::endl;
163+
break;
164+
// LCOV_EXCL_STOP
165+
}
166+
}
167+
}
168+
169+
template <typename T>
170+
void test_invalid_file(T filename)
171+
{
172+
constexpr boost::crypt::sha224_hasher::return_type res{};
173+
174+
const auto crypt_res {boost::crypt::sha224_file(filename)};
175+
176+
for (std::size_t j {}; j < crypt_res.size(); ++j)
177+
{
178+
if (!BOOST_TEST_EQ(res[j], crypt_res[j]))
179+
{
180+
// LCOV_EXCL_START
181+
std::cerr << "Failure with file: " << filename << std::endl;
182+
break;
183+
// LCOV_EXCL_STOP
184+
}
185+
}
186+
}
187+
188+
void files_test()
189+
{
190+
// Based off where we are testing from (test vs boost_root) we need to adjust our filepath
191+
const char* filename;
192+
const char* filename_2;
193+
194+
// Boost-root
195+
std::ifstream fd("libs/crypt/test/test_file_1.txt", std::ios::binary | std::ios::in);
196+
filename = "libs/crypt/test/test_file_1.txt";
197+
filename_2 = "libs/crypt/test/test_file_2.txt";
198+
199+
// LCOV_EXCL_START
200+
if (!fd.is_open())
201+
{
202+
// Local test directory or IDE
203+
std::ifstream fd2("test_file_1.txt", std::ios::binary | std::ios::in);
204+
filename = "test_file_1.txt";
205+
filename_2 = "test_file_2.txt";
206+
207+
if (!fd2.is_open())
208+
{
209+
// test/cover
210+
std::ifstream fd3("../test_file_1.txt", std::ios::binary | std::ios::in);
211+
filename = "../test_file_1.txt";
212+
filename_2 = "../test_file_2.txt";
213+
214+
if (!fd3.is_open())
215+
{
216+
std::cerr << "Test not run due to file system issues" << std::endl;
217+
return;
218+
}
219+
else
220+
{
221+
fd3.close();
222+
}
223+
}
224+
else
225+
{
226+
fd2.close();
227+
}
228+
}
229+
else
230+
{
231+
fd.close();
232+
}
233+
// LCOV_EXCL_STOP
234+
235+
// On macOS 15
236+
// sha224 test_file_1.txt
237+
// sha224 (test_file_1.txt) = e88799b0d0d5becc6791837fa95388d4056f1250a511d14829766663
238+
constexpr boost::crypt::sha224_hasher::return_type res{0xe8, 0x87, 0x99, 0xb0, 0xd0, 0xd5, 0xbe, 0xcc, 0x67, 0x91, 0x83, 0x7f, 0xa9, 0x53, 0x88, 0xd4, 0x05, 0x6f, 0x12, 0x50, 0xa5, 0x11, 0xd1, 0x48, 0x29, 0x76, 0x66, 0x63};
239+
240+
test_file(filename, res);
241+
242+
const std::string str_filename {filename};
243+
test_file(str_filename, res);
244+
245+
#ifdef BOOST_CRYPT_HAS_STRING_VIEW
246+
const std::string_view str_view_filename {str_filename};
247+
test_file(str_view_filename, res);
248+
#endif
249+
250+
const auto invalid_filename = "broken.bin";
251+
test_invalid_file(invalid_filename);
252+
253+
const std::string str_invalid_filename {invalid_filename};
254+
test_invalid_file(str_invalid_filename);
255+
256+
#ifdef BOOST_CRYPT_HAS_STRING_VIEW
257+
const std::string_view str_view_invalid_filename {str_invalid_filename};
258+
test_invalid_file(str_view_invalid_filename);
259+
#endif
260+
261+
// On macOS 15
262+
// sha224 test_file_2.txt
263+
// sha224 (test_file_2.txt) = c58605901d0923feb172e964ca6722378063574d18ff3efa7881bd91
264+
constexpr boost::crypt::sha224_hasher::return_type res_2{0xc5, 0x86, 0x05, 0x90, 0x1d, 0x09, 0x23, 0xfe, 0xb1, 0x72, 0xe9, 0x64, 0xca, 0x67, 0x22, 0x37, 0x80, 0x63, 0x57, 0x4d, 0x18, 0xff, 0x3e, 0xfa, 0x78, 0x81, 0xbd, 0x91};
265+
266+
test_file(filename_2, res_2);
267+
268+
const char* test_null_file = nullptr;
269+
test_invalid_file(test_null_file);
270+
}
271+
272+
void test_invalid_state()
273+
{
274+
boost::crypt::sha224_hasher hasher;
275+
auto current_state = hasher.process_bytes("test", 4);
276+
BOOST_TEST(current_state == boost::crypt::hasher_state::success);
277+
278+
hasher.get_digest();
279+
280+
const auto bad_state = hasher.process_bytes("test", 4);
281+
BOOST_TEST(bad_state == boost::crypt::hasher_state::state_error);
282+
283+
const auto digest = hasher.get_digest();
284+
285+
for (const auto& val : digest)
286+
{
287+
BOOST_TEST_EQ(val, static_cast<std::uint8_t>(0));
288+
}
289+
290+
hasher.init();
291+
292+
current_state = hasher.process_bytes("test", 4);
293+
BOOST_TEST(current_state == boost::crypt::hasher_state::success);
294+
current_state = hasher.process_byte(0x03);
295+
BOOST_TEST(current_state == boost::crypt::hasher_state::success);
296+
const char* ptr = nullptr;
297+
current_state = hasher.process_bytes(ptr, 4);
298+
BOOST_TEST(current_state == boost::crypt::hasher_state::null);
299+
300+
const char16_t* ptr16 = nullptr;
301+
current_state = hasher.process_bytes(ptr16, 4);
302+
BOOST_TEST(current_state == boost::crypt::hasher_state::null);
303+
304+
const char32_t* ptr32 = nullptr;
305+
current_state = hasher.process_bytes(ptr32, 4);
306+
BOOST_TEST(current_state == boost::crypt::hasher_state::null);
307+
308+
const wchar_t* wptr = nullptr;
309+
current_state = hasher.process_bytes(wptr, 4);
310+
BOOST_TEST(current_state == boost::crypt::hasher_state::null);
311+
}
312+
313+
// This ends up being completely calculated in a constexpr fashion so Codecov complains
314+
// LCOV_EXCL_START
315+
void test_span()
316+
{
317+
#ifdef BOOST_CRYPT_HAS_SPAN
318+
319+
// "abc" in hex
320+
const std::byte vals[] = {std::byte{0x61}, std::byte{0x62}, std::byte{0x63}};
321+
std::span<const std::byte> byte_span {vals};
322+
const auto expected_res = boost::crypt::sha224_hasher::return_type{0x23, 0x09, 0x7d, 0x22, 0x34, 0x05, 0xd8, 0x22, 0x86, 0x42, 0xa4, 0x77, 0xbd, 0xa2, 0x55, 0xb3, 0x2a, 0xad, 0xbc, 0xe4, 0xbd, 0xa0, 0xb3, 0xf7, 0xe3, 0x6c, 0x9d, 0xa7};
323+
const auto res = boost::crypt::sha224(byte_span);
324+
325+
for (std::size_t i {}; i < res.size(); ++i)
326+
{
327+
BOOST_TEST_EQ(res[i], expected_res[i]);
328+
}
329+
330+
#endif // BOOST_CRYPT_HAS_SPAN
331+
}
332+
// LCOV_EXCL_STOP
333+
334+
int main()
335+
{
336+
basic_tests();
337+
string_test();
338+
string_view_test();
339+
bad_input();
340+
test_class();
341+
342+
// The Windows file system returns a different result than on UNIX platforms
343+
#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
344+
files_test();
345+
#endif
346+
347+
test_invalid_state();
348+
349+
test_span();
350+
351+
return boost::report_errors();
352+
}

0 commit comments

Comments
 (0)