diff --git a/CMakeLists.txt b/CMakeLists.txt index ca567f451..8142f8825 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -371,6 +371,7 @@ set(TDLIB_SOURCE td/telegram/net/Session.cpp td/telegram/net/SessionProxy.cpp td/telegram/net/SessionMultiProxy.cpp + td/telegram/NewPasswordState.cpp td/telegram/NotificationManager.cpp td/telegram/NotificationSettings.cpp td/telegram/NotificationType.cpp @@ -564,6 +565,7 @@ set(TDLIB_SOURCE td/telegram/net/SessionProxy.h td/telegram/net/SessionMultiProxy.h td/telegram/net/TempAuthKeyWatchdog.h + td/telegram/NewPasswordState.h td/telegram/Notification.h td/telegram/NotificationGroupId.h td/telegram/NotificationGroupKey.h diff --git a/td/telegram/NewPasswordState.cpp b/td/telegram/NewPasswordState.cpp new file mode 100644 index 000000000..839b1b725 --- /dev/null +++ b/td/telegram/NewPasswordState.cpp @@ -0,0 +1,59 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/telegram/NewPasswordState.h" + +namespace td { + +Result get_new_password_state( + tl_object_ptr new_algo, + tl_object_ptr new_secure_algo) { + NewPasswordState state; + CHECK(new_algo != nullptr); + switch (new_algo->get_id()) { + case telegram_api::passwordKdfAlgoUnknown::ID: + return Status::Error(400, "Please update client to continue"); + case telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow::ID: { + auto algo = + move_tl_object_as(new_algo); + state.client_salt = algo->salt1_.as_slice().str(); + state.server_salt = algo->salt2_.as_slice().str(); + state.srp_g = algo->g_; + state.srp_p = algo->p_.as_slice().str(); + break; + } + default: + UNREACHABLE(); + } + + CHECK(new_secure_algo != nullptr); + switch (new_secure_algo->get_id()) { + case telegram_api::securePasswordKdfAlgoUnknown::ID: + return Status::Error(400, "Please update client to continue"); + case telegram_api::securePasswordKdfAlgoSHA512::ID: + return Status::Error(500, "Server has sent outdated secret encryption mode"); + case telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000::ID: { + auto algo = move_tl_object_as(new_secure_algo); + state.secure_salt = algo->salt_.as_slice().str(); + break; + } + default: + UNREACHABLE(); + } + + static constexpr size_t MIN_NEW_SECURE_SALT_SIZE = 8; + if (state.secure_salt.size() < MIN_NEW_SECURE_SALT_SIZE) { + return Status::Error(500, "New secure salt length too small"); + } + + static constexpr size_t MIN_NEW_SALT_SIZE = 8; + if (state.client_salt.size() < MIN_NEW_SALT_SIZE) { + return Status::Error(500, "New salt length too small"); + } + return state; +} + +} // namespace td \ No newline at end of file diff --git a/td/telegram/NewPasswordState.h b/td/telegram/NewPasswordState.h new file mode 100644 index 000000000..7c82ae20b --- /dev/null +++ b/td/telegram/NewPasswordState.h @@ -0,0 +1,28 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2021 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include "td/telegram/telegram_api.h" + +#include "td/utils/common.h" +#include "td/utils/Status.h" + +namespace td { + +struct NewPasswordState { + string client_salt; + string server_salt; + string srp_p; + string secure_salt; + int32 srp_g = 0; +}; + +Result get_new_password_state( + tl_object_ptr new_algo, + tl_object_ptr new_secure_algo); + +} // namespace td \ No newline at end of file diff --git a/td/telegram/PasswordManager.cpp b/td/telegram/PasswordManager.cpp index bba20c868..4eca47534 100644 --- a/td/telegram/PasswordManager.cpp +++ b/td/telegram/PasswordManager.cpp @@ -496,7 +496,9 @@ void PasswordManager::recover_password(string code, string new_password, string return promise.set_error(r_state.move_as_error()); } - TRY_RESULT_PROMISE(promise, new_settings, get_password_input_settings(update_settings, r_state.ok(), nullptr)); + TRY_RESULT_PROMISE( + promise, new_settings, + get_password_input_settings(update_settings, r_state.ok().has_password, r_state.ok().new_state, nullptr)); send_closure(actor_id, &PasswordManager::do_recover_password, std::move(code), std::move(new_settings), std::move(promise)); @@ -568,7 +570,8 @@ void PasswordManager::do_update_password_settings(UpdateSettings update_settings } Result PasswordManager::get_password_input_settings( - const UpdateSettings &update_settings, const PasswordState &state, const PasswordPrivateState *private_state) { + const UpdateSettings &update_settings, bool has_password, const NewPasswordState &state, + const PasswordPrivateState *private_state) { auto settings = make_tl_object(); bool have_secret = private_state != nullptr && private_state->secret; auto update_secure_secret = update_settings.update_secure_secret; @@ -577,18 +580,17 @@ Result PasswordManager::get_password_inp settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_ALGO_MASK; settings->flags_ |= telegram_api::account_passwordInputSettings::HINT_MASK; if (!update_settings.new_password.empty()) { - auto new_client_salt = create_salt(state.new_client_salt); + auto new_client_salt = create_salt(state.client_salt); auto new_hash = calc_password_srp_hash(update_settings.new_password, new_client_salt.as_slice(), - state.new_server_salt, state.new_srp_g, state.new_srp_p); + state.server_salt, state.srp_g, state.srp_p); if (new_hash.is_error()) { return Status::Error(400, "Unable to change password, because it may be unsafe"); } settings->new_password_hash_ = new_hash.move_as_ok(); settings->new_algo_ = make_tl_object( - std::move(new_client_salt), BufferSlice(state.new_server_salt), state.new_srp_g, - BufferSlice(state.new_srp_p)); + std::move(new_client_salt), BufferSlice(state.server_salt), state.srp_g, BufferSlice(state.srp_p)); settings->hint_ = std::move(update_settings.new_hint); if (have_secret) { update_secure_secret = true; @@ -599,7 +601,7 @@ Result PasswordManager::get_password_inp } // have no password and not setting one - if (!update_settings.update_password && !state.has_password) { + if (!update_settings.update_password && !has_password) { update_secure_secret = false; } @@ -610,8 +612,8 @@ Result PasswordManager::get_password_inp if (update_secure_secret) { auto secret = have_secret ? std::move(private_state->secret.value()) : secure_storage::Secret::create_new(); - auto algorithm = make_tl_object( - create_salt(state.new_secure_salt)); + auto algorithm = + make_tl_object(create_salt(state.secure_salt)); auto encrypted_secret = secret.encrypt( update_settings.update_password ? update_settings.new_password : update_settings.current_password, algorithm->salt_.as_slice(), secure_storage::EnryptionAlgorithm::Pbkdf2); @@ -629,7 +631,8 @@ Result PasswordManager::get_password_inp void PasswordManager::do_update_password_settings_impl(UpdateSettings update_settings, PasswordState state, PasswordPrivateState private_state, Promise promise) { - TRY_RESULT_PROMISE(promise, new_settings, get_password_input_settings(update_settings, state, &private_state)); + TRY_RESULT_PROMISE(promise, new_settings, + get_password_input_settings(update_settings, state.has_password, state.new_state, &private_state)); auto current_hash = get_input_check_password(state.has_password ? update_settings.current_password : Slice(), state); auto query = G()->net_query_creator().create( telegram_api::account_updatePasswordSettings(std::move(current_hash), std::move(new_settings))); @@ -718,46 +721,11 @@ void PasswordManager::do_get_state(Promise promise) { state.unconfirmed_recovery_email_address_pattern = std::move(password->email_unconfirmed_pattern_); state.code_length = code_length; - CHECK(password->new_algo_ != nullptr); - switch (password->new_algo_->get_id()) { - case telegram_api::passwordKdfAlgoUnknown::ID: - return promise.set_error(Status::Error(400, "Please update client to continue")); - case telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow::ID: { - auto algo = - move_tl_object_as( - password->new_algo_); - state.new_client_salt = algo->salt1_.as_slice().str(); - state.new_server_salt = algo->salt2_.as_slice().str(); - state.new_srp_g = algo->g_; - state.new_srp_p = algo->p_.as_slice().str(); - break; - } - default: - UNREACHABLE(); - } + auto &new_state = state.new_state; + TRY_RESULT_PROMISE_ASSIGN( + promise, new_state, + get_new_password_state(std::move(password->new_algo_), std::move(password->new_secure_algo_))); - CHECK(password->new_secure_algo_ != nullptr); - switch (password->new_secure_algo_->get_id()) { - case telegram_api::securePasswordKdfAlgoUnknown::ID: - return promise.set_error(Status::Error(400, "Please update client to continue")); - case telegram_api::securePasswordKdfAlgoSHA512::ID: - return promise.set_error(Status::Error(500, "Server has sent outdated secret encryption mode")); - case telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000::ID: { - auto algo = move_tl_object_as( - password->new_secure_algo_); - state.new_secure_salt = algo->salt_.as_slice().str(); - break; - } - default: - UNREACHABLE(); - } - - if (state.new_secure_salt.size() < MIN_NEW_SECURE_SALT_SIZE) { - return promise.set_error(Status::Error(500, "New secure salt length too small")); - } - if (state.new_client_salt.size() < MIN_NEW_SALT_SIZE) { - return promise.set_error(Status::Error(500, "New salt length too small")); - } promise.set_value(std::move(state)); })); } diff --git a/td/telegram/PasswordManager.h b/td/telegram/PasswordManager.h index 40bfe10c9..daff846cf 100644 --- a/td/telegram/PasswordManager.h +++ b/td/telegram/PasswordManager.h @@ -7,6 +7,7 @@ #pragma once #include "td/telegram/net/NetQuery.h" +#include "td/telegram/NewPasswordState.h" #include "td/telegram/SecureStorage.h" #include "td/telegram/td_api.h" #include "td/telegram/telegram_api.h" @@ -90,9 +91,6 @@ class PasswordManager : public NetQueryCallback { static TempPasswordState get_temp_password_state_sync(); private: - static constexpr size_t MIN_NEW_SALT_SIZE = 8; - static constexpr size_t MIN_NEW_SECURE_SALT_SIZE = 8; - ActorShared<> parent_; struct PasswordState { @@ -109,12 +107,8 @@ class PasswordManager : public NetQueryCallback { string current_srp_p; string current_srp_B; int64 current_srp_id; - string new_client_salt; - string new_server_salt; - int32 new_srp_g; - string new_srp_p; - string new_secure_salt; + NewPasswordState new_state; State get_password_state_object() const { td_api::object_ptr code_info; @@ -172,7 +166,7 @@ class PasswordManager : public NetQueryCallback { const PasswordState &state); static Result get_password_input_settings(const UpdateSettings &update_settings, - const PasswordState &state, + bool has_password, const NewPasswordState &state, const PasswordPrivateState *private_state); void do_recover_password(string code, PasswordInputSettings &&new_settings, Promise &&promise);