Skip to content

Commit 19737ff

Browse files
authored
Merge pull request #5 from cppalliance/wchar
Add native interfaces to wider character types for MD5
2 parents d00484e + c02afaa commit 19737ff

File tree

5 files changed

+335
-35
lines changed

5 files changed

+335
-35
lines changed

include/boost/crypt/hash/md5.hpp

Lines changed: 152 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright 2024 Matt Borland
22
// Distributed under the Boost Software License, Version 1.0.
33
// https://www.boost.org/LICENSE_1_0.txt
4+
//
5+
// See: https://www.ietf.org/rfc/rfc1321.txt
46

57
#ifndef BOOST_CRYPT_HASH_MD5_HPP
68
#define BOOST_CRYPT_HASH_MD5_HPP
@@ -13,8 +15,10 @@
1315
#include <boost/crypt/utility/type_traits.hpp>
1416
#include <boost/crypt/utility/strlen.hpp>
1517
#include <boost/crypt/utility/cstddef.hpp>
18+
#include <boost/crypt/utility/iterator.hpp>
1619

1720
#ifndef BOOST_CRYPT_BUILD_MODULE
21+
#include <memory>
1822
#include <string>
1923
#include <cstdint>
2024
#include <cstring>
@@ -54,7 +58,13 @@ class md5_hasher
5458
BOOST_CRYPT_GPU_ENABLED constexpr auto process_byte(ByteType byte) noexcept
5559
BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t);
5660

57-
template <typename ForwardIter>
61+
template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 1, bool> = true>
62+
BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept;
63+
64+
template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 2, bool> = true>
65+
BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept;
66+
67+
template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 4, bool> = true>
5868
BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept;
5969

6070
BOOST_CRYPT_GPU_ENABLED constexpr auto get_digest() noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>;
@@ -108,7 +118,8 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::md5_update(ForwardIter data,
108118
low_ += input_bits;
109119
if (low_ < old_low)
110120
{
111-
++high_;
121+
// This should never happen as it indicates size_t roll over
122+
++high_; // LCOV_EXCL_LINE
112123
}
113124
high_ += size >> 29U;
114125

@@ -196,15 +207,50 @@ template <typename ByteType>
196207
BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_byte(ByteType byte) noexcept
197208
BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t)
198209
{
199-
md5_update(&byte, 1UL);
210+
const auto value {static_cast<boost::crypt::uint8_t>(byte)};
211+
md5_update(&value, 1UL);
200212
}
201213

202-
template <typename ForwardIter>
214+
template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 1, bool>>
203215
BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept
204216
{
205217
md5_update(buffer, byte_count);
206218
}
207219

220+
template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 2, bool>>
221+
BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept
222+
{
223+
#ifndef BOOST_CRYPT_HAS_CUDA
224+
225+
const auto* char_ptr {reinterpret_cast<const char*>(std::addressof(*buffer))};
226+
const auto* data {reinterpret_cast<const unsigned char*>(char_ptr)};
227+
md5_update(data, byte_count * 2U);
228+
229+
#else
230+
231+
const auto* data {reinterpret_cast<const unsigned char*>(buffer)};
232+
md5_update(data, byte_count * 2U);
233+
234+
#endif
235+
}
236+
237+
template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 4, bool>>
238+
BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept
239+
{
240+
#ifndef BOOST_CRYPT_HAS_CUDA
241+
242+
const auto* char_ptr {reinterpret_cast<const char*>(std::addressof(*buffer))};
243+
const auto* data {reinterpret_cast<const unsigned char*>(char_ptr)};
244+
md5_update(data, byte_count * 4U);
245+
246+
#else
247+
248+
const auto* data {reinterpret_cast<const unsigned char*>(buffer)};
249+
md5_update(data, byte_count * 4U);
250+
251+
#endif
252+
}
253+
208254
// See: Applied Cryptography - Bruce Schneier
209255
// Section 18.5
210256
namespace md5_body_detail {
@@ -413,19 +459,120 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const boost::crypt::uint8_t* str, boo
413459
return detail::md5(str, str + len);
414460
}
415461

462+
BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
463+
{
464+
if (str == nullptr)
465+
{
466+
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
467+
}
468+
469+
const auto message_len {utility::strlen(str)};
470+
return detail::md5(str, str + message_len);
471+
}
472+
473+
BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char16_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
474+
{
475+
if (str == nullptr)
476+
{
477+
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
478+
}
479+
480+
return detail::md5(str, str + len);
481+
}
482+
483+
BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
484+
{
485+
if (str == nullptr)
486+
{
487+
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
488+
}
489+
490+
const auto message_len {utility::strlen(str)};
491+
return detail::md5(str, str + message_len);
492+
}
493+
494+
BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const char32_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
495+
{
496+
if (str == nullptr)
497+
{
498+
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
499+
}
500+
501+
return detail::md5(str, str + len);
502+
}
503+
504+
// On some platforms wchar_t is 16 bits and others it's 32
505+
// Since we check sizeof() the underlying with SFINAE in the actual implementation this is handled transparently
506+
BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
507+
{
508+
if (str == nullptr)
509+
{
510+
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
511+
}
512+
513+
const auto message_len {utility::strlen(str)};
514+
return detail::md5(str, str + message_len);
515+
}
516+
517+
BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const wchar_t* str, boost::crypt::size_t len) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
518+
{
519+
if (str == nullptr)
520+
{
521+
return boost::crypt::array<boost::crypt::uint8_t, 16>{}; // LCOV_EXCL_LINE
522+
}
523+
524+
return detail::md5(str, str + len);
525+
}
526+
416527
// ----- String and String view aren't in the libcu++ STL so they so not have device markers -----
417528

529+
#ifndef BOOST_CRYPT_HAS_CUDA
530+
418531
inline auto md5(const std::string& str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
419532
{
420533
return detail::md5(str.begin(), str.end());
421534
}
422535

536+
inline auto md5(const std::u16string& str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
537+
{
538+
return detail::md5(str.begin(), str.end());
539+
}
540+
541+
inline auto md5(const std::u32string& str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
542+
{
543+
return detail::md5(str.begin(), str.end());
544+
}
545+
546+
inline auto md5(const std::wstring& str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
547+
{
548+
return detail::md5(str.begin(), str.end());
549+
}
550+
423551
#ifdef BOOST_CRYPT_HAS_STRING_VIEW
552+
424553
inline auto md5(const std::string_view& str) -> boost::crypt::array<boost::crypt::uint8_t, 16>
425554
{
426555
return detail::md5(str.begin(), str.end());
427556
}
428-
#endif
557+
558+
inline auto md5(const std::u16string_view& str) -> boost::crypt::array<boost::crypt::uint8_t, 16>
559+
{
560+
return detail::md5(str.begin(), str.end());
561+
}
562+
563+
inline auto md5(const std::u32string_view& str) -> boost::crypt::array<boost::crypt::uint8_t, 16>
564+
{
565+
return detail::md5(str.begin(), str.end());
566+
}
567+
568+
inline auto md5(const std::wstring_view& str) -> boost::crypt::array<boost::crypt::uint8_t, 16>
569+
{
570+
return detail::md5(str.begin(), str.end());
571+
}
572+
573+
#endif // BOOST_CRYPT_HAS_STRING_VIEW
574+
575+
#endif // BOOST_CRYPT_HAS_CUDA
429576

430577
} // namespace crypt
431578
} // namespace boost
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
#ifndef BOOST_CRYPT_UTILITES_ITERATOR_HPP
6+
#define BOOST_CRYPT_UTILITES_ITERATOR_HPP
7+
8+
#include <boost/crypt/utility/config.hpp>
9+
10+
#ifdef BOOST_CRYPT_HAS_CUDA
11+
12+
#include <cuda/std/iterator>
13+
14+
namespace boost {
15+
namespace crypt {
16+
17+
template <typename Iter>
18+
struct iterator_traits : public cuda::std::iterator_traits<Iter> {};
19+
20+
template <typename T>
21+
struct iterator_traits<T*> : public cuda::std::iterator_traits<T*> {};
22+
23+
} // namespace crypt
24+
} // namespace boost
25+
26+
#else
27+
28+
#ifndef BOOST_CRYPT_BUILD_MODULE
29+
#include <iterator>
30+
#endif
31+
32+
namespace boost {
33+
namespace crypt {
34+
namespace utility {
35+
36+
template <typename Iter>
37+
struct iterator_traits : public std::iterator_traits<Iter> {};
38+
39+
template <typename T>
40+
struct iterator_traits<T*> : public std::iterator_traits<T*> {};
41+
42+
} // namespace utility
43+
} // namespace crypt
44+
} // namespace boost
45+
46+
#endif // BOOST_CRYPT_HAS_CUDA
47+
48+
#endif //BOOST_CRYPT_UTILITES_ITERATOR_HPP

include/boost/crypt/utility/type_traits.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,9 @@ using cuda::std::underlying_type_t;
161161

162162
#else // STD versions
163163

164+
#ifndef BOOST_CRYPT_BUILD_MODULE
164165
#include <type_traits>
166+
#endif
165167

166168
namespace boost {
167169
namespace crypt {

test/generate_random_strings.hpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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+
#ifndef BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS
6+
#define BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS
7+
8+
#include <random>
9+
#include <cstdlib>
10+
#include <ctime>
11+
#include <cstring>
12+
13+
namespace boost {
14+
namespace crypt {
15+
16+
inline void generate_random_string(char* str, std::size_t length)
17+
{
18+
19+
const char charset[] = "0123456789"
20+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
21+
"abcdefghijklmnopqrstuvwxyz";
22+
23+
const std::size_t charset_size = sizeof(charset) - 1;
24+
25+
std::mt19937_64 rng(42);
26+
std::uniform_int_distribution<std::size_t> dist(0, charset_size);
27+
28+
for (std::size_t i = 0; i < length - 1; ++i)
29+
{
30+
const auto index = dist(rng);
31+
str[i] = charset[index];
32+
}
33+
34+
str[length - 1] = '\0';
35+
}
36+
37+
inline void generate_random_string(char16_t* str, std::size_t length)
38+
{
39+
const char16_t charset[] = u"0123456789"
40+
u"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
41+
u"abcdefghijklmnopqrstuvwxyz";
42+
43+
const std::size_t charset_size = std::char_traits<char16_t>::length(charset);
44+
45+
std::mt19937_64 rng(42);
46+
std::uniform_int_distribution<std::size_t> dist(0, charset_size - 1);
47+
48+
for (std::size_t i = 0; i < length - 1; ++i)
49+
{
50+
const auto index = dist(rng);
51+
str[i] = charset[index];
52+
}
53+
54+
str[length - 1] = u'\0';
55+
}
56+
57+
inline void generate_random_string(char32_t* str, std::size_t length)
58+
{
59+
const char32_t charset[] = U"0123456789"
60+
U"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
61+
U"abcdefghijklmnopqrstuvwxyz";
62+
63+
const std::size_t charset_size = std::char_traits<char32_t>::length(charset);
64+
65+
std::mt19937_64 rng(42);
66+
std::uniform_int_distribution<std::size_t> dist(0, charset_size - 1);
67+
68+
for (std::size_t i = 0; i < length - 1; ++i)
69+
{
70+
const auto index = dist(rng);
71+
str[i] = charset[index];
72+
}
73+
74+
str[length - 1] = u'\0';
75+
}
76+
77+
inline void generate_random_string(wchar_t* str, std::size_t length)
78+
{
79+
const wchar_t charset[] = L"0123456789"
80+
L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
81+
L"abcdefghijklmnopqrstuvwxyz";
82+
83+
const std::size_t charset_size = std::char_traits<wchar_t>::length(charset);
84+
85+
std::mt19937_64 rng(42);
86+
std::uniform_int_distribution<std::size_t> dist(0, charset_size - 1);
87+
88+
for (std::size_t i = 0; i < length - 1; ++i)
89+
{
90+
const auto index = dist(rng);
91+
str[i] = charset[index];
92+
}
93+
94+
str[length - 1] = u'\0';
95+
}
96+
97+
} // Namespace crypt
98+
} // namespace boost
99+
100+
#endif // BOOST_CRYPT_TEST_GENERATE_RANDOM_STRINGS

0 commit comments

Comments
 (0)