|
1 | 1 | // Copyright 2024 Matt Borland
|
2 | 2 | // Distributed under the Boost Software License, Version 1.0.
|
3 | 3 | // https://www.boost.org/LICENSE_1_0.txt
|
| 4 | +// |
| 5 | +// See: https://www.ietf.org/rfc/rfc1321.txt |
4 | 6 |
|
5 | 7 | #ifndef BOOST_CRYPT_HASH_MD5_HPP
|
6 | 8 | #define BOOST_CRYPT_HASH_MD5_HPP
|
|
13 | 15 | #include <boost/crypt/utility/type_traits.hpp>
|
14 | 16 | #include <boost/crypt/utility/strlen.hpp>
|
15 | 17 | #include <boost/crypt/utility/cstddef.hpp>
|
| 18 | +#include <boost/crypt/utility/iterator.hpp> |
16 | 19 |
|
17 | 20 | #ifndef BOOST_CRYPT_BUILD_MODULE
|
| 21 | +#include <memory> |
18 | 22 | #include <string>
|
19 | 23 | #include <cstdint>
|
20 | 24 | #include <cstring>
|
@@ -54,7 +58,13 @@ class md5_hasher
|
54 | 58 | BOOST_CRYPT_GPU_ENABLED constexpr auto process_byte(ByteType byte) noexcept
|
55 | 59 | BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t);
|
56 | 60 |
|
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> |
58 | 68 | BOOST_CRYPT_GPU_ENABLED constexpr auto process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept;
|
59 | 69 |
|
60 | 70 | 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,
|
108 | 118 | low_ += input_bits;
|
109 | 119 | if (low_ < old_low)
|
110 | 120 | {
|
111 |
| - ++high_; |
| 121 | + // This should never happen as it indicates size_t roll over |
| 122 | + ++high_; // LCOV_EXCL_LINE |
112 | 123 | }
|
113 | 124 | high_ += size >> 29U;
|
114 | 125 |
|
@@ -196,15 +207,50 @@ template <typename ByteType>
|
196 | 207 | BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_byte(ByteType byte) noexcept
|
197 | 208 | BOOST_CRYPT_REQUIRES_CONVERSION(ByteType, boost::crypt::uint8_t)
|
198 | 209 | {
|
199 |
| - md5_update(&byte, 1UL); |
| 210 | + const auto value {static_cast<boost::crypt::uint8_t>(byte)}; |
| 211 | + md5_update(&value, 1UL); |
200 | 212 | }
|
201 | 213 |
|
202 |
| -template <typename ForwardIter> |
| 214 | +template <typename ForwardIter, boost::crypt::enable_if_t<sizeof(typename utility::iterator_traits<ForwardIter>::value_type) == 1, bool>> |
203 | 215 | BOOST_CRYPT_GPU_ENABLED constexpr auto md5_hasher::process_bytes(ForwardIter buffer, boost::crypt::size_t byte_count) noexcept
|
204 | 216 | {
|
205 | 217 | md5_update(buffer, byte_count);
|
206 | 218 | }
|
207 | 219 |
|
| 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 | + |
208 | 254 | // See: Applied Cryptography - Bruce Schneier
|
209 | 255 | // Section 18.5
|
210 | 256 | namespace md5_body_detail {
|
@@ -413,19 +459,120 @@ BOOST_CRYPT_GPU_ENABLED constexpr auto md5(const boost::crypt::uint8_t* str, boo
|
413 | 459 | return detail::md5(str, str + len);
|
414 | 460 | }
|
415 | 461 |
|
| 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 | + |
416 | 527 | // ----- String and String view aren't in the libcu++ STL so they so not have device markers -----
|
417 | 528 |
|
| 529 | +#ifndef BOOST_CRYPT_HAS_CUDA |
| 530 | + |
418 | 531 | inline auto md5(const std::string& str) noexcept -> boost::crypt::array<boost::crypt::uint8_t, 16>
|
419 | 532 | {
|
420 | 533 | return detail::md5(str.begin(), str.end());
|
421 | 534 | }
|
422 | 535 |
|
| 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 | + |
423 | 551 | #ifdef BOOST_CRYPT_HAS_STRING_VIEW
|
| 552 | + |
424 | 553 | inline auto md5(const std::string_view& str) -> boost::crypt::array<boost::crypt::uint8_t, 16>
|
425 | 554 | {
|
426 | 555 | return detail::md5(str.begin(), str.end());
|
427 | 556 | }
|
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 |
429 | 576 |
|
430 | 577 | } // namespace crypt
|
431 | 578 | } // namespace boost
|
|
0 commit comments