#ifndef HASH_MD4_2019_03_29_H #define HASH_MD4_2019_03_29_H #include #include #include #include // See also: https://tools.ietf.org/html/rfc1320 #if(__cplusplus >= 201703L) namespace al::crypto::stream::hash { #else namespace al { namespace crypto { namespace stream { namespace hash { #endif class hash_md4 : 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_md4() = default; hash_md4(const hash_md4&) = default; hash_md4(hash_md4&&) noexcept = default; ~hash_md4() override = default; auto operator=(const hash_md4&) -> hash_md4& = default; auto operator=(hash_md4&&) noexcept -> hash_md4& = default; private: // Constants for the md4 transform routine. static constexpr auto S11 = static_cast(UINT8_C( 3)); static constexpr auto S12 = static_cast(UINT8_C( 7)); static constexpr auto S13 = static_cast(UINT8_C(11)); static constexpr auto S14 = static_cast(UINT8_C(19)); static constexpr auto S21 = static_cast(UINT8_C( 3)); static constexpr auto S22 = static_cast(UINT8_C( 5)); static constexpr auto S23 = static_cast(UINT8_C( 9)); static constexpr auto S24 = static_cast(UINT8_C(13)); static constexpr auto S31 = static_cast(UINT8_C( 3)); static constexpr auto S32 = static_cast(UINT8_C( 9)); static constexpr auto S33 = static_cast(UINT8_C(11)); static constexpr auto S34 = static_cast(UINT8_C(15)); // FF, GG, and HH are the transformations for rounds 1, 2, and 3 of the md4. template static void transformation_ff(std::uint32_t& a, const std::uint32_t& b, const std::uint32_t& c, const std::uint32_t& d, const std::uint32_t& x) // NOLINT(bugprone-easily-swappable-parameters) { const auto permutation_f = static_cast ( static_cast(b & static_cast(c ^ d)) ^ d ); a = al::crypto::math::utils::rotl(static_cast(a + permutation_f + x), my_s); } template static void transformation_gg(std::uint32_t& a, const std::uint32_t& b, const std::uint32_t& c, const std::uint32_t& d, const std::uint32_t& x) // NOLINT(bugprone-easily-swappable-parameters) { const std::uint32_t permutation_g = (static_cast(b & c) | static_cast((b | c) & d)); a = al::crypto::math::utils::rotl(static_cast((a + permutation_g) + (x + 0x5A827999UL)), my_s); } template static void transformation_hh(std::uint32_t& a, const std::uint32_t& b, const std::uint32_t& c, const std::uint32_t& d, const std::uint32_t& x) // NOLINT(bugprone-easily-swappable-parameters) { const auto permutation_h = static_cast ( static_cast(b ^ c) ^ d ); a = al::crypto::math::utils::rotl(static_cast(a + permutation_h + x + 0x6ED9EBA1U), my_s); } void transform() 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[ 0U]); // 17 transformation_gg(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 4U]); // 18 transformation_gg(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 8U]); // 19 transformation_gg(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[12U]); // 20 transformation_gg(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 1U]); // 21 transformation_gg(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 5U]); // 22 transformation_gg(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 9U]); // 23 transformation_gg(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[13U]); // 24 transformation_gg(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 2U]); // 25 transformation_gg(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 6U]); // 26 transformation_gg(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[10U]); // 27 transformation_gg(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[14U]); // 28 transformation_gg(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 3U]); // 29 transformation_gg(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 7U]); // 30 transformation_gg(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[11U]); // 31 transformation_gg(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[15U]); // 32 // Perform transformation round 3 transformation_hh(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 0U]); // 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[ 4U]); // 35 transformation_hh(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[12U]); // 36 transformation_hh(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 2U]); // 37 transformation_hh(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[10U]); // 38 transformation_hh(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 6U]); // 39 transformation_hh(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[14U]); // 40 transformation_hh(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 1U]); // 41 transformation_hh(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[ 9U]); // 42 transformation_hh(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 5U]); // 43 transformation_hh(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[13U]); // 44 transformation_hh(hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], message_transform_block[ 3U]); // 45 transformation_hh(hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], hash_tmp[2U], message_transform_block[11U]); // 46 transformation_hh(hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], hash_tmp[1U], message_transform_block[ 7U]); // 47 transformation_hh(hash_tmp[1U], hash_tmp[2U], hash_tmp[3U], hash_tmp[0U], message_transform_block[15U]); // 48 // 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_MD4_2019_03_29_H