#ifndef HASH_MD5_2019_01_23_H #define HASH_MD5_2019_01_23_H #include #include #include #include // See also: https://tools.ietf.org/html/rfc1321 #if(__cplusplus >= 201703L) namespace al::crypto::stream::hash { #else namespace al { namespace crypto { namespace stream { namespace hash { #endif class hash_md5 : public al::crypto::stream::hash::hash_md_base<128U, 128U, std::uint32_t, 64U, 64U> { private: using base_class_type = al::crypto::stream::hash::hash_md_base<128U, 128U, std::uint32_t, 64U, 64U>; public: hash_md5() = default; hash_md5(const hash_md5& other) : base_class_type(static_cast(other)) { } hash_md5(hash_md5&& other) noexcept : base_class_type(static_cast(other)) { } ~hash_md5() override = default; auto operator=(const hash_md5& other) -> hash_md5& { if(this != &other) { static_cast(base_class_type::operator=(static_cast(other))); } return *this; } auto operator=(hash_md5&& other) noexcept -> hash_md5& { static_cast(base_class_type::operator=(static_cast(other))); return *this; } private: // Constants for the md5 transform routine. static constexpr std::uint_fast8_t S11 = UINT8_C( 7); static constexpr std::uint_fast8_t S12 = UINT8_C(12); static constexpr std::uint_fast8_t S13 = UINT8_C(17); static constexpr std::uint_fast8_t S14 = UINT8_C(22); static constexpr std::uint_fast8_t S21 = UINT8_C( 5); static constexpr std::uint_fast8_t S22 = UINT8_C( 9); static constexpr std::uint_fast8_t S23 = UINT8_C(14); static constexpr std::uint_fast8_t S24 = UINT8_C(20); static constexpr std::uint_fast8_t S31 = UINT8_C( 4); static constexpr std::uint_fast8_t S32 = UINT8_C(11); static constexpr std::uint_fast8_t S33 = UINT8_C(16); static constexpr std::uint_fast8_t S34 = UINT8_C(23); static constexpr std::uint_fast8_t S41 = UINT8_C( 6); static constexpr std::uint_fast8_t S42 = UINT8_C(10); static constexpr std::uint_fast8_t S43 = UINT8_C(15); static constexpr std::uint_fast8_t S44 = UINT8_C(21); // FF, GG, HH, and II are the transformations for rounds 1, 2, 3, and 4 of the md5. template static auto transformation_ff( std::uint32_t& a, const std::uint32_t& b, const std::uint32_t& c, const std::uint32_t& d, // NOLINT(bugprone-easily-swappable-parameters) const std::uint32_t& x) -> void // NOLINT(bugprone-easily-swappable-parameters) { const auto permutation_f = static_cast ( static_cast(b & c) | static_cast(static_cast(~b) & d) ); a = static_cast(al::crypto::math::utils::rotl(static_cast(a + permutation_f) + static_cast(x + my_ac), my_s) + b); } template static auto transformation_gg( std::uint32_t& a, const std::uint32_t& b, const std::uint32_t& c, const std::uint32_t& d, // NOLINT(bugprone-easily-swappable-parameters) const std::uint32_t& x) -> void // NOLINT(bugprone-easily-swappable-parameters) { const auto permutation_g = static_cast ( static_cast(b & d) | static_cast(c & static_cast(~d)) ); a = static_cast(al::crypto::math::utils::rotl(static_cast(a + permutation_g) + static_cast(x + my_ac), my_s) + b); } template static auto transformation_hh( std::uint32_t& a, const std::uint32_t& b, const std::uint32_t& c, const std::uint32_t& d, // NOLINT(bugprone-easily-swappable-parameters) const std::uint32_t& x) -> void // NOLINT(bugprone-easily-swappable-parameters) { const auto permutation_h = static_cast ( static_cast(b ^ c) ^ d ); a = static_cast(al::crypto::math::utils::rotl(static_cast(a + permutation_h) + static_cast(x + my_ac), my_s) + b); } template static auto transformation_ii( std::uint32_t& a, const std::uint32_t& b, const std::uint32_t& c, const std::uint32_t& d, // NOLINT(bugprone-easily-swappable-parameters) const std::uint32_t& x) -> void // NOLINT(bugprone-easily-swappable-parameters) { const auto permutation_i = static_cast ( c ^ static_cast(b | static_cast(~d)) ); a = static_cast(al::crypto::math::utils::rotl(static_cast(a + permutation_i) + static_cast(x + my_ac), my_s) + b); } auto transform() -> void override { // Apply the messsage digest transformation algorithm a full data block using message_transform_type = std::array::value / base_class_type::conversion_scale()>; message_transform_type message_transform_block = {{ 0U }}; this->copy_message_buffer_forward(message_transform_block.data()); base_class_type::transform_context_type hash_tmp = base_class_type::transform_context; // Perform transformation round 1. transformation_ff(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 0U]); // 1 transformation_ff(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 1U]); // 2 transformation_ff(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 2U]); // 3 transformation_ff(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[ 3U]); // 4 transformation_ff(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 4U]); // 5 transformation_ff(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 5U]); // 6 transformation_ff(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 6U]); // 7 transformation_ff(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[ 7U]); // 8 transformation_ff(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 8U]); // 9 transformation_ff(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 9U]); // 10 transformation_ff(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[10U]); // 11 transformation_ff(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[11U]); // 12 transformation_ff(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[12U]); // 13 transformation_ff(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[13U]); // 14 transformation_ff(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[14U]); // 15 transformation_ff(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[15U]); // 16 // Perform transformation round 2. transformation_gg(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 1U]); // 17 transformation_gg(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 6U]); // 18 transformation_gg(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[11U]); // 19 transformation_gg(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[ 0U]); // 20 transformation_gg(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 5U]); // 21 transformation_gg(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[10U]); // 22 transformation_gg(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[15U]); // 23 transformation_gg(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[ 4U]); // 24 transformation_gg(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 9U]); // 25 transformation_gg(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[14U]); // 26 transformation_gg(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 3U]); // 27 transformation_gg(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[ 8U]); // 28 transformation_gg(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[13U]); // 29 transformation_gg(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 2U]); // 30 transformation_gg(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 7U]); // 31 transformation_gg(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[12U]); // 32 // Perform transformation round 3. transformation_hh(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 5U]); // 33 transformation_hh(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 8U]); // 34 transformation_hh(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[11U]); // 35 transformation_hh(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[14U]); // 36 transformation_hh(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 1U]); // 37 transformation_hh(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 4U]); // 38 transformation_hh(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 7U]); // 39 transformation_hh(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[10U]); // 40 transformation_hh(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[13U]); // 41 transformation_hh(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 0U]); // 42 transformation_hh(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 3U]); // 43 transformation_hh(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[ 6U]); // 44 transformation_hh(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 9U]); // 45 transformation_hh(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[12U]); // 46 transformation_hh(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[15U]); // 47 transformation_hh(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[ 2U]); // 48 // Perform transformation round 4. transformation_ii(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 0U]); // 49 transformation_ii(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 7U]); // 50 transformation_ii(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[14U]); // 51 transformation_ii(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[ 5U]); // 52 transformation_ii(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[12U]); // 53 transformation_ii(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 3U]); // 54 transformation_ii(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[10U]); // 55 transformation_ii(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[ 1U]); // 56 transformation_ii(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 8U]); // 57 transformation_ii(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[15U]); // 58 transformation_ii(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 6U]); // 59 transformation_ii(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[13U]); // 60 transformation_ii(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 4U]); // 61 transformation_ii(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[11U]); // 62 transformation_ii(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 2U]); // 63 transformation_ii(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[ 9U]); // 64 // Update the hash state with the transformation results. std::transform(base_class_type::transform_context.cbegin(), base_class_type::transform_context.cend (), hash_tmp.cbegin (), base_class_type::transform_context.begin (), std::plus ()); // NOLINT(modernize-use-transparent-functors) base_class_type::message_buffer.fill(0U); base_class_type::message_index = 0U; } }; #if(__cplusplus >= 201703L) } // namespace al::crypto::stream::hash #else } // namespace hash } // namespace stream } // namespace crypto } // namespace al #endif #endif // HASH_MD5_2019_01_23_H