#ifndef HASH_MD_BASE_2019_04_04_H #define HASH_MD_BASE_2019_04_04_H #include #include #if(__cplusplus >= 201703L) namespace al::crypto::stream::hash { #else namespace al { namespace crypto { namespace stream { namespace hash { #endif template class hash_md_base : public al::crypto::stream::hash::hash_base { private: using base_class_type = al::crypto::stream::hash::hash_base; static_assert(static_cast(MessageLengthTotalBitCount % 8U) == 0U, "Error: Wrong granularity of MessageLengthTotalBitCount. " "Must be multiple of 8."); static constexpr auto message_length_total_width() noexcept -> std::size_t { return static_cast ( MessageLengthTotalBitCount / static_cast(UINT8_C(8)) ); } public: ~hash_md_base() override = default; auto initialize() -> void override { base_class_type::initialize(); std::copy(al::crypto::math::constants::hash::hash_init.begin(), al::crypto::math::constants::hash::hash_init.end(), base_class_type::transform_context.begin()); } auto finalize() -> void override { // Create the padding. Begin by setting the leading padding byte to 0x80. base_class_type::message_buffer[base_class_type::message_index] = static_cast(0x80U); ++base_class_type::message_index; // We need an extra block because there are not enough bytes // available for storing the total bit count. So we must // transform the current block, then create and pad yet another // additional block. const auto buffer_top = static_cast ( base_class_type::message_buffer_static_size - message_length_total_width() ); if(base_class_type::message_index > static_cast(buffer_top)) { this->transform(); } // Encode the total number of bits in the final transform buffer. // Here, we can easily see the conversion of the number of bytes // to the number of bits. This is done by performing a left-shift // of 3 on "base_class_type::message_length_total". auto carry = static_cast(0U); for(auto fi = base_class_type::message_buffer.end() - message_length_total_width(); fi != base_class_type::message_buffer.end(); ++fi) { const auto the_word = static_cast ( static_cast(base_class_type::message_length_total) << 3U ); *fi = static_cast(the_word | carry); base_class_type::message_length_total >>= 8U; carry = ( static_cast(the_word >> 8U) & static_cast(0x07U)); } this->transform(); } AL_CRYPTO_NODISCARD auto get_result() const -> typename base_class_type::result_type override { using local_result_type = typename base_class_type::result_type; local_result_type result; // Extract the hash result this->copy_transform_context_forward(result.data()); return result; } auto finalize_and_get_result(typename base_class_type::result_type::pointer result_data) -> void override { finalize(); base_class_type::copy_transform_context_forward(result_data); } protected: hash_md_base() = default; hash_md_base(const hash_md_base& other) : base_class_type(static_cast(other)) { } hash_md_base(hash_md_base&& other) noexcept : base_class_type(static_cast(other)) { } auto operator=(const hash_md_base& other) -> hash_md_base& // NOLINT(cert-oop54-cpp) { if(this != &other) { static_cast(base_class_type::operator=(static_cast(other))); } return *this; } auto operator=(hash_md_base&& other) noexcept -> hash_md_base& { static_cast(base_class_type::operator=(static_cast(other))); return *this; } }; #if(__cplusplus >= 201703L) } // namespace al::crypto::stream::hash #else } // namespace hash } // namespace stream } // namespace crypto } // namespace al #endif #endif // HASH_MD_BASE_2019_04_04_H