Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-17 08:51:25

0001 //
0002 // Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 
0008 #ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_MYSQL_NATIVE_PASSWORD_HPP
0009 #define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_MYSQL_NATIVE_PASSWORD_HPP
0010 
0011 #include <boost/mysql/client_errc.hpp>
0012 #include <boost/mysql/string_view.hpp>
0013 
0014 #include <boost/mysql/impl/internal/protocol/static_buffer.hpp>
0015 #include <boost/mysql/impl/internal/sansio/auth_plugin_common.hpp>
0016 
0017 #include <boost/config.hpp>
0018 #include <boost/core/span.hpp>
0019 #include <boost/system/result.hpp>
0020 
0021 #include <array>
0022 #include <cstddef>
0023 #include <cstdint>
0024 #include <openssl/sha.h>
0025 
0026 // Reference:
0027 // https://dev.mysql.com/doc/dev/mysql-server/8.4.4/page_protocol_connection_phase_authentication_methods_native_password_authentication.html
0028 
0029 namespace boost {
0030 namespace mysql {
0031 namespace detail {
0032 
0033 // Constants
0034 BOOST_INLINE_CONSTEXPR std::size_t mnp_hash_size = 20;
0035 BOOST_INLINE_CONSTEXPR const char* mnp_plugin_name = "mysql_native_password";
0036 static_assert(mnp_hash_size <= max_hash_size, "");
0037 static_assert(mnp_hash_size == SHA_DIGEST_LENGTH, "Buffer size mismatch");
0038 
0039 // SHA1( password ) XOR SHA1( "20-bytes random data from server" <concat> SHA1( SHA1( password ) ) )
0040 inline void mnp_hash_password_impl(
0041     string_view password,
0042     span<const std::uint8_t, scramble_size> scramble,
0043     span<std::uint8_t, mnp_hash_size> output
0044 )
0045 {
0046     // SHA1 (password)
0047     std::array<std::uint8_t, mnp_hash_size> password_sha1;
0048     SHA1(reinterpret_cast<const unsigned char*>(password.data()), password.size(), password_sha1.data());
0049 
0050     // Add server scramble (salt)
0051     std::array<std::uint8_t, scramble_size + mnp_hash_size> salted_buffer;
0052     std::memcpy(salted_buffer.data(), scramble.data(), scramble.size());
0053     SHA1(password_sha1.data(), password_sha1.size(), salted_buffer.data() + mnp_hash_size);
0054     std::array<std::uint8_t, mnp_hash_size> salted_sha1;
0055     SHA1(salted_buffer.data(), salted_buffer.size(), salted_sha1.data());
0056 
0057     // XOR
0058     for (std::size_t i = 0; i < mnp_hash_size; ++i)
0059     {
0060         output[i] = password_sha1[i] ^ salted_sha1[i];
0061     }
0062 }
0063 
0064 // The static buffer size is chosen so that every plugin uses the same size
0065 inline static_buffer<max_hash_size> mnp_hash_password(
0066     string_view password,
0067     span<const std::uint8_t, scramble_size> scramble
0068 )
0069 {
0070     // Empty passwords are not hashed
0071     if (password.empty())
0072         return {};
0073 
0074     // Run the algorithm
0075     static_buffer<max_hash_size> res(mnp_hash_size);
0076     mnp_hash_password_impl(password, scramble, span<std::uint8_t, mnp_hash_size>(res.data(), mnp_hash_size));
0077     return res;
0078 }
0079 
0080 }  // namespace detail
0081 }  // namespace mysql
0082 }  // namespace boost
0083 
0084 #endif