diff --git a/auth/password_authenticator.cc b/auth/password_authenticator.cc index 4868ae55ad..f589aa6914 100644 --- a/auth/password_authenticator.cc +++ b/auth/password_authenticator.cc @@ -328,7 +328,7 @@ future password_authenticator::authenticate( } salted_hash = role->salted_hash; } - const bool password_match = passwords::check(password, *salted_hash); + const bool password_match = co_await passwords::check(password, *salted_hash); if (!password_match) { throw exceptions::authentication_exception("Username and/or password are incorrect"); } diff --git a/auth/passwords.cc b/auth/passwords.cc index f047648a3b..8effdc1505 100644 --- a/auth/passwords.cc +++ b/auth/passwords.cc @@ -7,6 +7,8 @@ */ #include "auth/passwords.hh" +#include "utils/crypt_sha512.hh" +#include #include @@ -45,6 +47,24 @@ sstring hash_with_salt(const sstring& pass, const sstring& salt) { return res; } +seastar::future hash_with_salt_async(const sstring& pass, const sstring& salt) { + sstring res; + // Only SHA-512 hashes for passphrases shorter than 256 bytes can be computed using + // the __crypt_sha512 method. For other computations, we fall back to the + // crypt_r implementation from ``, which can stall. + if (salt.starts_with(prefix_for_scheme(scheme::sha_512)) && pass.size() <= 255) { + char buf[128]; + const char * output_ptr = co_await __crypt_sha512(pass.c_str(), salt.c_str(), buf); + verify_hashing_output(output_ptr); + res = output_ptr; + } else { + const char * output_ptr = crypt_r(pass.c_str(), salt.c_str(), &tlcrypt); + verify_hashing_output(output_ptr); + res = output_ptr; + } + co_return res; +} + std::string_view prefix_for_scheme(scheme c) noexcept { switch (c) { case scheme::bcrypt_y: return "$2y$"; @@ -61,8 +81,9 @@ no_supported_schemes::no_supported_schemes() : std::runtime_error("No allowed hashing schemes are supported on this system") { } -bool check(const sstring& pass, const sstring& salted_hash) { - return detail::hash_with_salt(pass, salted_hash) == salted_hash; +seastar::future check(const sstring& pass, const sstring& salted_hash) { + const auto pwd_hash = co_await detail::hash_with_salt_async(pass, salted_hash); + co_return pwd_hash == salted_hash; } } // namespace auth::passwords diff --git a/auth/passwords.hh b/auth/passwords.hh index 617f55ac13..7b0c769f75 100644 --- a/auth/passwords.hh +++ b/auth/passwords.hh @@ -11,6 +11,7 @@ #include #include +#include #include #include "seastarx.hh" @@ -75,10 +76,18 @@ sstring generate_salt(RandomNumberEngine& g, scheme scheme) { /// /// Hash a password combined with an implementation-specific salt string. +/// Deprecated in favor of `hash_with_salt_async`. /// /// \throws \ref std::system_error when an unexpected implementation-specific error occurs. /// -sstring hash_with_salt(const sstring& pass, const sstring& salt); +[[deprecated("Use hash_with_salt_async instead")]] sstring hash_with_salt(const sstring& pass, const sstring& salt); + +/// +/// Async version of `hash_with_salt` that returns a future. +/// +/// \throws \ref std::system_error when an unexpected implementation-specific error occurs. +/// +seastar::future hash_with_salt_async(const sstring& pass, const sstring& salt); } // namespace detail @@ -107,6 +116,6 @@ sstring hash(const sstring& pass, RandomNumberEngine& g, scheme scheme) { /// /// \throws \ref std::system_error when an unexpected implementation-specific error occurs. /// -bool check(const sstring& pass, const sstring& salted_hash); +seastar::future check(const sstring& pass, const sstring& salted_hash); } // namespace auth::passwords diff --git a/test/boost/auth_passwords_test.cc b/test/boost/auth_passwords_test.cc index 32f50e336e..f3396a3411 100644 --- a/test/boost/auth_passwords_test.cc +++ b/test/boost/auth_passwords_test.cc @@ -54,9 +54,8 @@ SEASTAR_TEST_CASE(correct_passwords_authenticate) { }; for (const char* p : passwords) { - BOOST_REQUIRE(auth::passwords::check(p, auth::passwords::hash(p, rng_for_salt, auth::passwords::scheme::sha_512))); + BOOST_REQUIRE(co_await auth::passwords::check(p, auth::passwords::hash(p, rng_for_salt, auth::passwords::scheme::sha_512))); } - co_return; } // @@ -64,6 +63,5 @@ SEASTAR_TEST_CASE(correct_passwords_authenticate) { // SEASTAR_TEST_CASE(incorrect_passwords_do_not_authenticate) { const sstring hashed_password = auth::passwords::hash("actual_password", rng_for_salt,auth::passwords::scheme::sha_512); - BOOST_REQUIRE(!auth::passwords::check("password_guess", hashed_password)); - co_return; + BOOST_REQUIRE(!co_await auth::passwords::check("password_guess", hashed_password)); }