Update layer to 83.

GitOrigin-RevId: 2220a0399ed081441fefc06069b06efa11b8447b
This commit is contained in:
levlam 2018-08-04 09:55:49 +03:00
parent 7f62960ad3
commit c9c2760173
14 changed files with 332 additions and 184 deletions

View File

@ -468,12 +468,11 @@ authorization#7bf2e6f6 hash:long flags:int device_model:string platform:string s
account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations; account.authorizations#1250abde authorizations:Vector<Authorization> = account.Authorizations;
account.noPassword#5ea182f6 new_salt:bytes new_secure_salt:bytes secure_random:bytes email_unconfirmed_pattern:string = account.Password; account.password#68873ba5 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes = account.Password;
account.password#ca39b447 flags:# has_recovery:flags.0?true has_secure_values:flags.1?true current_salt:bytes new_salt:bytes new_secure_salt:bytes secure_random:bytes hint:string email_unconfirmed_pattern:string = account.Password;
account.passwordSettings#7bd9c3f1 email:string secure_salt:bytes secure_secret:bytes secure_secret_id:long = account.PasswordSettings; account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings;
account.passwordInputSettings#21ffa60d flags:# new_salt:flags.0?bytes new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_salt:flags.2?bytes new_secure_secret:flags.2?bytes new_secure_secret_id:flags.2?long = account.PasswordInputSettings; account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings;
auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery;
@ -900,6 +899,15 @@ savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:
account.takeout#4dba4501 id:long = account.Takeout; account.takeout#4dba4501 id:long = account.Takeout;
passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo;
passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000#b6425eaa salt1:bytes salt2:bytes = PasswordKdfAlgo;
securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo;
securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo;
securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo;
secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings;
---functions--- ---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;

Binary file not shown.

View File

@ -14,14 +14,14 @@
#include "td/telegram/ConfigShared.h" #include "td/telegram/ConfigShared.h"
#include "td/telegram/ContactsManager.h" #include "td/telegram/ContactsManager.h"
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/misc.h" #include "td/telegram/misc.h"
#include "td/telegram/net/DcId.h" #include "td/telegram/net/DcId.h"
#include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/PasswordManager.h"
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
#include "td/telegram/UpdatesManager.h" #include "td/telegram/UpdatesManager.h"
#include "td/telegram/logevent/LogEvent.h"
#include "td/actor/PromiseFuture.h" #include "td/actor/PromiseFuture.h"
#include "td/utils/buffer.h" #include "td/utils/buffer.h"
@ -613,13 +613,13 @@ void AuthManager::check_password(uint64 query_id, string password) {
if (state_ != State::WaitPassword) { if (state_ != State::WaitPassword) {
return on_query_error(query_id, Status::Error(8, "checkAuthenticationPassword unexpected")); return on_query_error(query_id, Status::Error(8, "checkAuthenticationPassword unexpected"));
} }
BufferSlice buf(32);
password = wait_password_state_.current_salt_ + password + wait_password_state_.current_salt_; auto hash = PasswordManager::calc_password_hash(password, wait_password_state_.current_client_salt_,
sha256(password, buf.as_slice()); wait_password_state_.current_server_salt_);
on_new_query(query_id); on_new_query(query_id);
start_net_query(NetQueryType::CheckPassword, start_net_query(NetQueryType::CheckPassword,
G()->net_query_creator().create(create_storer(telegram_api::auth_checkPassword(std::move(buf))), G()->net_query_creator().create(create_storer(telegram_api::auth_checkPassword(std::move(hash))),
DcId::main(), NetQuery::Type::Common, NetQuery::AuthFlag::Off)); DcId::main(), NetQuery::Type::Common, NetQuery::AuthFlag::Off));
} }
@ -748,18 +748,30 @@ void AuthManager::on_get_password_result(NetQueryPtr &result) {
return on_query_error(r_password.move_as_error()); return on_query_error(r_password.move_as_error());
} }
auto password = r_password.move_as_ok(); auto password = r_password.move_as_ok();
wait_password_state_ = WaitPasswordState(); wait_password_state_ = WaitPasswordState();
if (password->get_id() == telegram_api::account_noPassword::ID) { if (password->current_algo_ != nullptr) {
auto no_password = move_tl_object_as<telegram_api::account_noPassword>(password); switch (password->current_algo_->get_id()) {
wait_password_state_.new_salt_ = no_password->new_salt_.as_slice().str(); case telegram_api::passwordKdfAlgoUnknown::ID:
// TODO we need to abort authorization somehow
break;
case telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000::ID: {
auto algo = move_tl_object_as<telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000>(
password->current_algo_);
wait_password_state_.current_client_salt_ = algo->salt1_.as_slice().str();
wait_password_state_.current_server_salt_ = algo->salt2_.as_slice().str();
wait_password_state_.hint_ = std::move(password->hint_);
wait_password_state_.has_recovery_ =
(password->flags_ & telegram_api::account_password::HAS_RECOVERY_MASK) != 0;
break;
}
default:
UNREACHABLE();
}
} else { } else {
CHECK(password->get_id() == telegram_api::account_password::ID); // TODO we need to resend auth_signIn instead of going to WaitPassword state
auto password_info = move_tl_object_as<telegram_api::account_password>(password);
wait_password_state_.current_salt_ = password_info->current_salt_.as_slice().str();
wait_password_state_.new_salt_ = password_info->new_salt_.as_slice().str();
wait_password_state_.hint_ = password_info->hint_;
wait_password_state_.has_recovery_ = password_info->has_recovery_;
} }
update_state(State::WaitPassword); update_state(State::WaitPassword);
on_query_ok(); on_query_ok();
} }
@ -771,7 +783,7 @@ void AuthManager::on_request_password_recovery_result(NetQueryPtr &result) {
} }
auto email_address_pattern = r_email_address_pattern.move_as_ok(); auto email_address_pattern = r_email_address_pattern.move_as_ok();
CHECK(email_address_pattern->get_id() == telegram_api::auth_passwordRecovery::ID); CHECK(email_address_pattern->get_id() == telegram_api::auth_passwordRecovery::ID);
wait_password_state_.email_address_pattern_ = email_address_pattern->email_pattern_; wait_password_state_.email_address_pattern_ = std::move(email_address_pattern->email_pattern_);
update_state(State::WaitPassword, true); update_state(State::WaitPassword, true);
on_query_ok(); on_query_ok();
} }

View File

@ -196,10 +196,10 @@ class AuthManager : public NetActor {
}; };
struct WaitPasswordState { struct WaitPasswordState {
string current_salt_; string current_client_salt_;
string new_salt_; string current_server_salt_;
string hint_; string hint_;
bool has_recovery_; bool has_recovery_ = false;
string email_address_pattern_; string email_address_pattern_;
template <class T> template <class T>

View File

@ -57,8 +57,8 @@ void SendCodeHelper::parse(T &parser) {
template <class T> template <class T>
void AuthManager::WaitPasswordState::store(T &storer) const { void AuthManager::WaitPasswordState::store(T &storer) const {
using td::store; using td::store;
store(current_salt_, storer); store(current_client_salt_, storer);
store(new_salt_, storer); store(current_server_salt_, storer);
store(hint_, storer); store(hint_, storer);
store(has_recovery_, storer); store(has_recovery_, storer);
store(email_address_pattern_, storer); store(email_address_pattern_, storer);
@ -67,8 +67,8 @@ void AuthManager::WaitPasswordState::store(T &storer) const {
template <class T> template <class T>
void AuthManager::WaitPasswordState::parse(T &parser) { void AuthManager::WaitPasswordState::parse(T &parser) {
using td::parse; using td::parse;
parse(current_salt_, parser); parse(current_client_salt_, parser);
parse(new_salt_, parser); parse(current_server_salt_, parser);
parse(hint_, parser); parse(hint_, parser);
parse(has_recovery_, parser); parse(has_recovery_, parser);
parse(email_address_pattern_, parser); parse(email_address_pattern_, parser);
@ -78,8 +78,10 @@ template <class T>
void AuthManager::DbState::store(T &storer) const { void AuthManager::DbState::store(T &storer) const {
using td::store; using td::store;
bool has_terms_of_service = !terms_of_service_.get_id().empty(); bool has_terms_of_service = !terms_of_service_.get_id().empty();
bool is_pbkdf2_supported = true;
BEGIN_STORE_FLAGS(); BEGIN_STORE_FLAGS();
STORE_FLAG(has_terms_of_service); STORE_FLAG(has_terms_of_service);
STORE_FLAG(is_pbkdf2_supported);
END_STORE_FLAGS(); END_STORE_FLAGS();
store(state_, storer); store(state_, storer);
store(api_id_, storer); store(api_id_, storer);
@ -103,9 +105,11 @@ template <class T>
void AuthManager::DbState::parse(T &parser) { void AuthManager::DbState::parse(T &parser) {
using td::parse; using td::parse;
bool has_terms_of_service = false; bool has_terms_of_service = false;
bool is_pbkdf2_supported = false;
if (parser.version() >= static_cast<int32>(Version::AddTermsOfService)) { if (parser.version() >= static_cast<int32>(Version::AddTermsOfService)) {
BEGIN_PARSE_FLAGS(); BEGIN_PARSE_FLAGS();
PARSE_FLAG(has_terms_of_service); PARSE_FLAG(has_terms_of_service);
PARSE_FLAG(is_pbkdf2_supported);
END_PARSE_FLAGS(); END_PARSE_FLAGS();
} }
parse(state_, parser); parse(state_, parser);
@ -120,9 +124,12 @@ void AuthManager::DbState::parse(T &parser) {
if (state_ == State::WaitCode) { if (state_ == State::WaitCode) {
parse(send_code_helper_, parser); parse(send_code_helper_, parser);
if (parser.version() < static_cast<int32>(Version::AddTermsOfService)) { if (parser.version() < static_cast<int32>(Version::AddTermsOfService)) {
parser.set_error("Have no terms of service"); return parser.set_error("Have no terms of service");
} }
} else if (state_ == State::WaitPassword) { } else if (state_ == State::WaitPassword) {
if (!is_pbkdf2_supported) {
return parser.set_error("Need PBKDF2 support");
}
parse(wait_password_state_, parser); parse(wait_password_state_, parser);
} else { } else {
parser.set_error(PSTRING() << "Unexpected " << tag("state", static_cast<int32>(state_))); parser.set_error(PSTRING() << "Unexpected " << tag("state", static_cast<int32>(state_)));

View File

@ -9,6 +9,7 @@
#include "td/telegram/Global.h" #include "td/telegram/Global.h"
#include "td/telegram/logevent/LogEvent.h" #include "td/telegram/logevent/LogEvent.h"
#include "td/telegram/net/NetQueryDispatcher.h" #include "td/telegram/net/NetQueryDispatcher.h"
#include "td/telegram/SecureStorage.h"
#include "td/utils/buffer.h" #include "td/utils/buffer.h"
#include "td/utils/crypto.h" #include "td/utils/crypto.h"
@ -28,14 +29,25 @@ tl_object_ptr<td_api::temporaryPasswordState> TempPasswordState::as_td_api() con
return make_tl_object<td_api::temporaryPasswordState>(true, valid_until - G()->unix_time_cached()); return make_tl_object<td_api::temporaryPasswordState>(true, valid_until - G()->unix_time_cached());
} }
static BufferSlice calc_password_hash(const string &password, const string &salt) { static void hash_sha256(Slice data, Slice salt, MutableSlice dest) {
sha256(PSLICE() << salt << data << salt, dest);
}
BufferSlice PasswordManager::calc_password_hash(Slice password, Slice client_salt, Slice server_salt) {
if (password.empty()) { if (password.empty()) {
return BufferSlice(); return BufferSlice();
} }
BufferSlice buf(32); BufferSlice buf(32);
string salted_password = salt + password + salt; hash_sha256(password, client_salt, buf.as_slice());
sha256(salted_password, buf.as_slice()); hash_sha256(buf.as_slice(), server_salt, buf.as_slice());
return buf; BufferSlice hash(64);
pbkdf2_sha512(buf.as_slice(), client_salt, 100000, hash.as_slice());
return hash;
}
BufferSlice PasswordManager::calc_password_hash(Slice password, const PasswordState &state) const {
return calc_password_hash(password, state.current_client_salt, state.current_server_salt);
} }
void PasswordManager::set_password(string current_password, string new_password, string new_hint, void PasswordManager::set_password(string current_password, string new_password, string new_hint,
@ -152,20 +164,21 @@ void PasswordManager::drop_temp_password() {
void PasswordManager::do_create_temp_password(string password, int32 timeout, PasswordState &&password_state, void PasswordManager::do_create_temp_password(string password, int32 timeout, PasswordState &&password_state,
Promise<TempPasswordState> promise) { Promise<TempPasswordState> promise) {
send_with_promise(G()->net_query_creator().create(create_storer(telegram_api::account_getTmpPassword( auto hash = calc_password_hash(password, password_state);
calc_password_hash(password, password_state.current_salt), timeout))), send_with_promise(
PromiseCreator::lambda([promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable { G()->net_query_creator().create(create_storer(telegram_api::account_getTmpPassword(std::move(hash), timeout))),
auto r_result = fetch_result<telegram_api::account_getTmpPassword>(std::move(r_query)); PromiseCreator::lambda([promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
if (r_result.is_error()) { auto r_result = fetch_result<telegram_api::account_getTmpPassword>(std::move(r_query));
return promise.set_error(r_result.move_as_error()); if (r_result.is_error()) {
} return promise.set_error(r_result.move_as_error());
auto result = r_result.move_as_ok(); }
TempPasswordState res; auto result = r_result.move_as_ok();
res.has_temp_password = true; TempPasswordState res;
res.temp_password = result->tmp_password_.as_slice().str(); res.has_temp_password = true;
res.valid_until = result->valid_until_; res.temp_password = result->tmp_password_.as_slice().str();
promise.set_value(std::move(res)); res.valid_until = result->valid_until_;
})); promise.set_value(std::move(res));
}));
} }
void PasswordManager::on_finish_create_temp_password(Result<TempPasswordState> result, bool /*dummy*/) { void PasswordManager::on_finish_create_temp_password(Result<TempPasswordState> result, bool /*dummy*/) {
@ -190,32 +203,60 @@ void PasswordManager::get_full_state(string password, Promise<PasswordFullState>
})); }));
} }
Result<secure_storage::Secret> PasswordManager::decrypt_secure_secret(
Slice password, tl_object_ptr<telegram_api::SecurePasswordKdfAlgo> algo_ptr, Slice secret, int64 secret_id) {
TRY_RESULT(encrypted_secret, secure_storage::EncryptedSecret::create(secret));
CHECK(algo_ptr != nullptr);
BufferSlice salt;
secure_storage::EnryptionAlgorithm algorithm = secure_storage::EnryptionAlgorithm::Pbkdf2;
switch (algo_ptr->get_id()) {
case telegram_api::securePasswordKdfAlgoUnknown::ID:
return Status::Error(400, "Unsupported algorithm");
case telegram_api::securePasswordKdfAlgoSHA512::ID: {
auto algo = move_tl_object_as<telegram_api::securePasswordKdfAlgoSHA512>(algo_ptr);
salt = std::move(algo->salt_);
algorithm = secure_storage::EnryptionAlgorithm::Sha512;
break;
}
case telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000::ID: {
auto algo = move_tl_object_as<telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000>(algo_ptr);
salt = std::move(algo->salt_);
break;
}
default:
UNREACHABLE();
}
TRY_RESULT(result, encrypted_secret.decrypt(password, salt.as_slice(), algorithm));
if (secret_id != result.get_hash()) {
return Status::Error("Secret hash mismatch");
}
return result;
}
void PasswordManager::do_get_full_state(string password, PasswordState state, Promise<PasswordFullState> promise) { void PasswordManager::do_get_full_state(string password, PasswordState state, Promise<PasswordFullState> promise) {
auto current_salt = state.current_salt; auto hash = calc_password_hash(password, state);
send_with_promise( send_with_promise(
G()->net_query_creator().create( G()->net_query_creator().create(create_storer(telegram_api::account_getPasswordSettings(std::move(hash)))),
create_storer(telegram_api::account_getPasswordSettings(calc_password_hash(password, current_salt)))), PromiseCreator::lambda(
PromiseCreator::lambda([promise = std::move(promise), state = std::move(state), [promise = std::move(promise), state = std::move(state), password](Result<NetQueryPtr> r_query) mutable {
password](Result<NetQueryPtr> r_query) mutable { promise.set_result([&]() -> Result<PasswordFullState> {
promise.set_result([&]() -> Result<PasswordFullState> { TRY_RESULT(result, fetch_result<telegram_api::account_getPasswordSettings>(std::move(r_query)));
TRY_RESULT(result, fetch_result<telegram_api::account_getPasswordSettings>(std::move(r_query))); PasswordPrivateState private_state;
PasswordPrivateState private_state; private_state.email = std::move(result->email_);
private_state.email = result->email_;
auto r_secret = [&]() -> Result<secure_storage::Secret> { if (result->secure_settings_ != nullptr) {
TRY_RESULT(encrypted_secret, secure_storage::EncryptedSecret::create(result->secure_secret_.as_slice())); auto r_secret = decrypt_secure_secret(password, std::move(result->secure_settings_->secure_algo_),
auto r_secret = encrypted_secret.decrypt(PSLICE() << result->secure_salt_.as_slice() << password result->secure_settings_->secure_secret_.as_slice(),
<< result->secure_salt_.as_slice()); result->secure_settings_->secure_secret_id_);
if (r_secret.is_ok() && result->secure_secret_id_ != r_secret.ok().get_hash()) { if (r_secret.is_ok()) {
return Status::Error("Secret hash mismatch"); private_state.secret = r_secret.move_as_ok();
} }
return r_secret; }
}();
private_state.secret = std::move(r_secret); return PasswordFullState{std::move(state), std::move(private_state)};
return PasswordFullState{std::move(state), std::move(private_state)}; }());
}()); }));
}));
} }
void PasswordManager::get_recovery_email_address(string password, void PasswordManager::get_recovery_email_address(string password,
@ -329,15 +370,13 @@ void PasswordManager::update_password_settings(UpdateSettings update_settings, P
})); }));
} }
namespace { static BufferSlice create_salt(Slice salt_prefix) {
BufferSlice create_salt(Slice server_salt) {
static constexpr size_t ADDED_SALT_SIZE = 32; static constexpr size_t ADDED_SALT_SIZE = 32;
BufferSlice new_salt(server_salt.size() + ADDED_SALT_SIZE); BufferSlice new_salt(salt_prefix.size() + ADDED_SALT_SIZE);
new_salt.as_slice().copy_from(server_salt); new_salt.as_slice().copy_from(salt_prefix);
Random::secure_bytes(new_salt.as_slice().substr(server_salt.size())); Random::secure_bytes(new_salt.as_slice().substr(salt_prefix.size()));
return new_salt; return new_salt;
} }
} // namespace
void PasswordManager::do_update_password_settings(UpdateSettings update_settings, PasswordFullState full_state, void PasswordManager::do_update_password_settings(UpdateSettings update_settings, PasswordFullState full_state,
Promise<bool> promise) { Promise<bool> promise) {
@ -346,18 +385,21 @@ void PasswordManager::do_update_password_settings(UpdateSettings update_settings
auto new_settings = make_tl_object<telegram_api::account_passwordInputSettings>(); auto new_settings = make_tl_object<telegram_api::account_passwordInputSettings>();
if (update_settings.update_password) { if (update_settings.update_password) {
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_PASSWORD_HASH_MASK; new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_PASSWORD_HASH_MASK;
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SALT_MASK; new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_ALGO_MASK;
new_settings->flags_ |= telegram_api::account_passwordInputSettings::HINT_MASK; new_settings->flags_ |= telegram_api::account_passwordInputSettings::HINT_MASK;
if (!update_settings.new_password.empty()) { if (!update_settings.new_password.empty()) {
auto new_salt = create_salt(state.new_salt); auto new_client_salt = create_salt(state.new_client_salt);
new_settings->new_salt_ = std::move(new_salt);
new_settings->new_password_hash_ = new_settings->new_password_hash_ =
calc_password_hash(update_settings.new_password, new_settings->new_salt_.as_slice().str()); calc_password_hash(update_settings.new_password, new_client_salt.as_slice(), state.new_server_salt);
new_settings->new_algo_ = make_tl_object<telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000>(
std::move(new_client_salt), BufferSlice(state.new_server_salt));
new_settings->hint_ = std::move(update_settings.new_hint); new_settings->hint_ = std::move(update_settings.new_hint);
if (private_state.secret) { if (private_state.secret) {
update_settings.update_secure_secret = true; update_settings.update_secure_secret = true;
} }
} else {
new_settings->new_algo_ = make_tl_object<telegram_api::passwordKdfAlgoUnknown>();
} }
} }
@ -372,24 +414,16 @@ void PasswordManager::do_update_password_settings(UpdateSettings update_settings
} }
if (update_settings.update_secure_secret) { if (update_settings.update_secure_secret) {
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SECRET_ID_MASK; auto secret = private_state.secret ? std::move(private_state.secret.value()) : secure_storage::Secret::create_new();
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SALT_MASK; auto algorithm = make_tl_object<telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000>(
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SECRET_MASK; create_salt(state.new_secure_salt));
auto secret = [&]() {
if (private_state.secret) {
return std::move(private_state.secret.value());
}
return secure_storage::Secret::create_new();
}();
auto new_secure_salt = create_salt(state.new_secure_salt);
auto encrypted_secret = secret.encrypt( auto encrypted_secret = secret.encrypt(
PSLICE() << new_secure_salt.as_slice() update_settings.update_password ? update_settings.new_password : update_settings.current_password,
<< (update_settings.update_password ? update_settings.new_password : update_settings.current_password) algorithm->salt_.as_slice(), secure_storage::EnryptionAlgorithm::Pbkdf2);
<< new_secure_salt.as_slice());
new_settings->new_secure_salt_ = std::move(new_secure_salt); new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SETTINGS_MASK;
new_settings->new_secure_secret_ = BufferSlice(encrypted_secret.as_slice()); new_settings->new_secure_settings_ = make_tl_object<telegram_api::secureSecretSettings>(
new_settings->new_secure_secret_id_ = secret.get_hash(); std::move(algorithm), BufferSlice(encrypted_secret.as_slice()), secret.get_hash());
} }
if (update_settings.update_recovery_email_address) { if (update_settings.update_recovery_email_address) {
new_settings->flags_ |= telegram_api::account_passwordInputSettings::EMAIL_MASK; new_settings->flags_ |= telegram_api::account_passwordInputSettings::EMAIL_MASK;
@ -397,7 +431,7 @@ void PasswordManager::do_update_password_settings(UpdateSettings update_settings
} }
BufferSlice current_hash; BufferSlice current_hash;
if (state.has_password) { if (state.has_password) {
current_hash = calc_password_hash(update_settings.current_password, state.current_salt); current_hash = calc_password_hash(update_settings.current_password, state);
} }
auto query = G()->net_query_creator().create( auto query = G()->net_query_creator().create(
create_storer(telegram_api::account_updatePasswordSettings(std::move(current_hash), std::move(new_settings)))); create_storer(telegram_api::account_updatePasswordSettings(std::move(current_hash), std::move(new_settings))));
@ -426,52 +460,81 @@ void PasswordManager::get_state(Promise<State> promise) {
void PasswordManager::do_get_state(Promise<PasswordState> promise) { void PasswordManager::do_get_state(Promise<PasswordState> promise) {
auto query = G()->net_query_creator().create(create_storer(telegram_api::account_getPassword())); auto query = G()->net_query_creator().create(create_storer(telegram_api::account_getPassword()));
send_with_promise(std::move(query), PromiseCreator::lambda([actor_id = actor_id(this), promise = std::move(promise)]( send_with_promise(
Result<NetQueryPtr> r_query) mutable { std::move(query), PromiseCreator::lambda([actor_id = actor_id(this),
auto r_result = fetch_result<telegram_api::account_getPassword>(std::move(r_query)); promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
if (r_result.is_error()) { auto r_result = fetch_result<telegram_api::account_getPassword>(std::move(r_query));
return promise.set_error(r_result.move_as_error()); if (r_result.is_error()) {
} return promise.set_error(r_result.move_as_error());
auto result = r_result.move_as_ok(); }
auto password = r_result.move_as_ok();
Random::add_seed(password->secure_random_.as_slice());
PasswordState state; PasswordState state;
string secure_random; if (password->current_algo_ != nullptr) {
if (result->get_id() == telegram_api::account_noPassword::ID) { state.has_password = true;
auto no_password = move_tl_object_as<telegram_api::account_noPassword>(result);
state.has_password = false; switch (password->current_algo_->get_id()) {
state.password_hint = ""; case telegram_api::passwordKdfAlgoUnknown::ID:
state.current_salt = ""; return promise.set_error(Status::Error(400, "Please update client to continue"));
state.new_salt = no_password->new_salt_.as_slice().str(); case telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000::ID: {
state.new_secure_salt = no_password->new_secure_salt_.as_slice().str(); auto algo = move_tl_object_as<telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000>(
secure_random = no_password->secure_random_.as_slice().str(); password->current_algo_);
state.has_recovery_email_address = false; state.current_client_salt = algo->salt1_.as_slice().str();
state.has_secure_values = false; state.current_server_salt = algo->salt2_.as_slice().str();
state.unconfirmed_recovery_email_address_pattern = no_password->email_unconfirmed_pattern_; break;
} else if (result->get_id() == telegram_api::account_password::ID) { }
auto password = move_tl_object_as<telegram_api::account_password>(result); default:
state.has_password = true; UNREACHABLE();
state.password_hint = password->hint_; }
state.current_salt = password->current_salt_.as_slice().str(); state.password_hint = std::move(password->hint_);
state.new_salt = password->new_salt_.as_slice().str(); state.has_recovery_email_address =
state.new_secure_salt = password->new_secure_salt_.as_slice().str(); (password->flags_ & telegram_api::account_password::HAS_RECOVERY_MASK) != 0;
secure_random = password->secure_random_.as_slice().str(); state.has_secure_values = (password->flags_ & telegram_api::account_password::HAS_SECURE_VALUES_MASK) != 0;
state.has_recovery_email_address = } else {
(password->flags_ & telegram_api::account_password::HAS_RECOVERY_MASK) != 0; state.has_password = false;
state.has_secure_values = }
(password->flags_ & telegram_api::account_password::HAS_SECURE_VALUES_MASK) != 0; state.unconfirmed_recovery_email_address_pattern = std::move(password->email_unconfirmed_pattern_);
state.unconfirmed_recovery_email_address_pattern = password->email_unconfirmed_pattern_;
} else { CHECK(password->new_algo_ != nullptr);
UNREACHABLE(); switch (password->new_algo_->get_id()) {
} case telegram_api::passwordKdfAlgoUnknown::ID:
Random::add_seed(secure_random); return promise.set_error(Status::Error(400, "Please update client to continue"));
if (state.new_secure_salt.size() < MIN_NEW_SECURE_SALT_SIZE) { case telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000::ID: {
return promise.set_error(Status::Error(500, "New secure salt length too small")); auto algo = move_tl_object_as<telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000>(
} password->new_algo_);
if (state.new_salt.size() < MIN_NEW_SALT_SIZE) { state.new_client_salt = algo->salt1_.as_slice().str();
return promise.set_error(Status::Error(500, "New salt length too small")); state.new_server_salt = algo->salt2_.as_slice().str();
} break;
promise.set_value(std::move(state)); }
})); default:
UNREACHABLE();
}
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<telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000>(
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));
}));
} }
void PasswordManager::cache_secret(secure_storage::Secret secret) { void PasswordManager::cache_secret(secure_storage::Secret secret) {

View File

@ -9,17 +9,19 @@
#include "td/telegram/net/NetQuery.h" #include "td/telegram/net/NetQuery.h"
#include "td/telegram/SecureStorage.h" #include "td/telegram/SecureStorage.h"
#include "td/telegram/td_api.h"
#include "td/telegram/telegram_api.h"
#include "td/actor/actor.h" #include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h" #include "td/actor/PromiseFuture.h"
#include "td/utils/Container.h" #include "td/utils/Container.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/optional.h" #include "td/utils/optional.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include "td/utils/tl_helpers.h" #include "td/utils/tl_helpers.h"
#include "td/telegram/td_api.h"
namespace td { namespace td {
struct TempPasswordState { struct TempPasswordState {
@ -54,6 +56,8 @@ class PasswordManager : public NetQueryCallback {
explicit PasswordManager(ActorShared<> parent) : parent_(std::move(parent)) { explicit PasswordManager(ActorShared<> parent) : parent_(std::move(parent)) {
} }
static BufferSlice calc_password_hash(Slice password, Slice client_salt, Slice server_salt);
void get_state(Promise<State> promise); void get_state(Promise<State> promise);
void set_password(string current_password, string new_password, string new_hint, bool set_recovery_email_address, void set_password(string current_password, string new_password, string new_hint, bool set_recovery_email_address,
string recovery_email_address, Promise<State> promise); string recovery_email_address, Promise<State> promise);
@ -88,10 +92,12 @@ class PasswordManager : public NetQueryCallback {
string password_hint; string password_hint;
bool has_recovery_email_address = false; bool has_recovery_email_address = false;
bool has_secure_values = false; bool has_secure_values = false;
string unconfirmed_recovery_email_address_pattern = ""; string unconfirmed_recovery_email_address_pattern;
string current_salt; string current_client_salt;
string new_salt; string current_server_salt;
string new_client_salt;
string new_server_salt;
string new_secure_salt; string new_secure_salt;
@ -130,6 +136,11 @@ class PasswordManager : public NetQueryCallback {
string last_verified_email_address_; string last_verified_email_address_;
static Result<secure_storage::Secret> decrypt_secure_secret(
Slice password, tl_object_ptr<telegram_api::SecurePasswordKdfAlgo> algo_ptr, Slice secret, int64 secret_id);
BufferSlice calc_password_hash(Slice password, const PasswordState &state) const;
void update_password_settings(UpdateSettings update_settings, Promise<State> promise); void update_password_settings(UpdateSettings update_settings, Promise<State> promise);
void do_update_password_settings(UpdateSettings update_settings, PasswordFullState full_state, Promise<bool> promise); void do_update_password_settings(UpdateSettings update_settings, PasswordFullState full_state, Promise<bool> promise);
void do_get_state(Promise<PasswordState> promise); void do_get_state(Promise<PasswordState> promise);

View File

@ -859,7 +859,6 @@ Result<std::tuple<uint64, BufferSlice, int32>> SecretChatActor::decrypt(BufferSl
} }
case mtproto::Transport::ReadResult::Nop: { case mtproto::Transport::ReadResult::Nop: {
return Status::Error("Got nop instead of a message"); return Status::Error("Got nop instead of a message");
break;
} }
case mtproto::Transport::ReadResult::Packet: { case mtproto::Transport::ReadResult::Packet: {
data = read_result.packet(); data = read_result.packet();

View File

@ -24,15 +24,27 @@ Result<ValueHash> ValueHash::create(Slice data) {
return ValueHash{hash}; return ValueHash{hash};
} }
AesCbcState calc_aes_cbc_state(Slice seed) { static AesCbcState calc_aes_cbc_state_hash(Slice hash) {
CHECK(hash.size() == 64);
UInt256 key;
as_slice(key).copy_from(hash.substr(0, 32));
UInt128 iv;
as_slice(iv).copy_from(hash.substr(32, 16));
return AesCbcState{key, iv};
}
AesCbcState calc_aes_cbc_state_pbkdf2(Slice secret, Slice salt) {
UInt<512> hash;
auto hash_slice = as_slice(hash);
pbkdf2_sha512(secret, salt, 100000, hash_slice);
return calc_aes_cbc_state_hash(hash_slice);
}
AesCbcState calc_aes_cbc_state_sha512(Slice seed) {
UInt<512> hash; UInt<512> hash;
auto hash_slice = as_slice(hash); auto hash_slice = as_slice(hash);
sha512(seed, hash_slice); sha512(seed, hash_slice);
UInt256 key; return calc_aes_cbc_state_hash(hash_slice);
as_slice(key).copy_from(hash_slice.substr(0, 32));
UInt128 iv;
as_slice(iv).copy_from(hash_slice.substr(32, 16));
return AesCbcState{key, iv};
} }
template <class F> template <class F>
@ -89,9 +101,11 @@ Result<BufferSlice> FileDataView::pread(int64 offset, int64 size) {
BufferSliceDataView::BufferSliceDataView(BufferSlice buffer_slice) : buffer_slice_(std::move(buffer_slice)) { BufferSliceDataView::BufferSliceDataView(BufferSlice buffer_slice) : buffer_slice_(std::move(buffer_slice)) {
} }
int64 BufferSliceDataView::size() const { int64 BufferSliceDataView::size() const {
return narrow_cast<int64>(buffer_slice_.size()); return narrow_cast<int64>(buffer_slice_.size());
} }
Result<BufferSlice> BufferSliceDataView::pread(int64 offset, int64 size) { Result<BufferSlice> BufferSliceDataView::pread(int64 offset, int64 size) {
auto end_offset = size + offset; auto end_offset = size + offset;
if (this->size() < end_offset) { if (this->size() < end_offset) {
@ -102,9 +116,11 @@ Result<BufferSlice> BufferSliceDataView::pread(int64 offset, int64 size) {
ConcatDataView::ConcatDataView(DataView &left, DataView &right) : left_(left), right_(right) { ConcatDataView::ConcatDataView(DataView &left, DataView &right) : left_(left), right_(right) {
} }
int64 ConcatDataView::size() const { int64 ConcatDataView::size() const {
return left_.size() + right_.size(); return left_.size() + right_.size();
} }
Result<BufferSlice> ConcatDataView::pread(int64 offset, int64 size) { Result<BufferSlice> ConcatDataView::pread(int64 offset, int64 size) {
auto end_offset = size + offset; auto end_offset = size + offset;
if (this->size() < end_offset) { if (this->size() < end_offset) {
@ -136,23 +152,20 @@ Result<BufferSlice> ConcatDataView::pread(int64 offset, int64 size) {
return std::move(res); return std::move(res);
} }
// Password
Password::Password(std::string password) : password_(std::move(password)) { Password::Password(std::string password) : password_(std::move(password)) {
} }
Slice Password::as_slice() const { Slice Password::as_slice() const {
return password_; return password_;
} }
// Secret static uint8 secret_checksum(Slice secret) {
namespace {
uint8 secret_checksum(Slice secret) {
uint32 sum = 0; uint32 sum = 0;
for (uint8 c : secret) { for (uint8 c : secret) {
sum += c; sum += c;
} }
return static_cast<uint8>((255 + 239 - sum % 255) % 255); return static_cast<uint8>((255 + 239 - sum % 255) % 255);
} }
} // namespace
Result<Secret> Secret::create(Slice secret) { Result<Secret> Secret::create(Slice secret) {
if (secret.size() != 32) { if (secret.size() != 32) {
@ -194,8 +207,19 @@ Secret Secret::clone() const {
return {secret_, hash_}; return {secret_, hash_};
} }
EncryptedSecret Secret::encrypt(Slice key) { EncryptedSecret Secret::encrypt(Slice key, Slice salt, EnryptionAlgorithm algorithm) {
auto aes_cbc_state = calc_aes_cbc_state(key); auto aes_cbc_state = [&]() {
switch (algorithm) {
case EnryptionAlgorithm::Sha512:
return calc_aes_cbc_state_sha512(PSLICE() << salt << key << salt);
case EnryptionAlgorithm::Pbkdf2:
return calc_aes_cbc_state_pbkdf2(key, salt);
default:
UNREACHABLE();
return AesCbcState(UInt256(), UInt128());
}
}();
UInt256 res; UInt256 res;
aes_cbc_state.encrypt(as_slice(), td::as_slice(res)); aes_cbc_state.encrypt(as_slice(), td::as_slice(res));
return EncryptedSecret::create(td::as_slice(res)).move_as_ok(); return EncryptedSecret::create(td::as_slice(res)).move_as_ok();
@ -204,7 +228,6 @@ EncryptedSecret Secret::encrypt(Slice key) {
Secret::Secret(UInt256 secret, int64 hash) : secret_(secret), hash_(hash) { Secret::Secret(UInt256 secret, int64 hash) : secret_(secret), hash_(hash) {
} }
//EncryptedSecret
Result<EncryptedSecret> EncryptedSecret::create(Slice encrypted_secret) { Result<EncryptedSecret> EncryptedSecret::create(Slice encrypted_secret) {
if (encrypted_secret.size() != 32) { if (encrypted_secret.size() != 32) {
return Status::Error("Wrong encrypted secret size"); return Status::Error("Wrong encrypted secret size");
@ -213,8 +236,20 @@ Result<EncryptedSecret> EncryptedSecret::create(Slice encrypted_secret) {
td::as_slice(res).copy_from(encrypted_secret); td::as_slice(res).copy_from(encrypted_secret);
return EncryptedSecret{res}; return EncryptedSecret{res};
} }
Result<Secret> EncryptedSecret::decrypt(Slice key) {
auto aes_cbc_state = calc_aes_cbc_state(key); Result<Secret> EncryptedSecret::decrypt(Slice key, Slice salt, EnryptionAlgorithm algorithm) {
auto aes_cbc_state = [&]() {
switch (algorithm) {
case EnryptionAlgorithm::Sha512:
return calc_aes_cbc_state_sha512(PSLICE() << salt << key << salt);
case EnryptionAlgorithm::Pbkdf2:
return calc_aes_cbc_state_pbkdf2(key, salt);
default:
UNREACHABLE();
return AesCbcState(UInt256(), UInt128());
}
}();
UInt256 res; UInt256 res;
aes_cbc_state.decrypt(td::as_slice(encrypted_secret_), td::as_slice(res)); aes_cbc_state.decrypt(td::as_slice(encrypted_secret_), td::as_slice(res));
return Secret::create(td::as_slice(res)); return Secret::create(td::as_slice(res));
@ -227,10 +262,10 @@ Slice EncryptedSecret::as_slice() const {
EncryptedSecret::EncryptedSecret(UInt256 encrypted_secret) : encrypted_secret_(encrypted_secret) { EncryptedSecret::EncryptedSecret(UInt256 encrypted_secret) : encrypted_secret_(encrypted_secret) {
} }
// Decryption
Decryptor::Decryptor(AesCbcState aes_cbc_state) : aes_cbc_state_(std::move(aes_cbc_state)) { Decryptor::Decryptor(AesCbcState aes_cbc_state) : aes_cbc_state_(std::move(aes_cbc_state)) {
sha256_init(&sha256_state_); sha256_init(&sha256_state_);
} }
Result<BufferSlice> Decryptor::append(BufferSlice data) { Result<BufferSlice> Decryptor::append(BufferSlice data) {
if (data.empty()) { if (data.empty()) {
return BufferSlice(); return BufferSlice();
@ -251,6 +286,7 @@ Result<BufferSlice> Decryptor::append(BufferSlice data) {
} }
return std::move(data); return std::move(data);
} }
Result<ValueHash> Decryptor::finish() { Result<ValueHash> Decryptor::finish() {
if (!skipped_prefix_) { if (!skipped_prefix_) {
return Status::Error("No data was given"); return Status::Error("No data was given");
@ -263,7 +299,6 @@ Result<ValueHash> Decryptor::finish() {
return ValueHash{res}; return ValueHash{res};
} }
// Encryptor
Encryptor::Encryptor(AesCbcState aes_cbc_state, DataView &data_view) Encryptor::Encryptor(AesCbcState aes_cbc_state, DataView &data_view)
: aes_cbc_state_(std::move(aes_cbc_state)), data_view_(data_view) { : aes_cbc_state_(std::move(aes_cbc_state)), data_view_(data_view) {
} }
@ -292,14 +327,14 @@ Result<EncryptedValue> encrypt_value(const Secret &secret, Slice data) {
TRY_RESULT(hash, calc_value_hash(full_view)); TRY_RESULT(hash, calc_value_hash(full_view));
auto aes_cbc_state = calc_aes_cbc_state(PSLICE() << secret.as_slice() << hash.as_slice()); auto aes_cbc_state = calc_aes_cbc_state_sha512(PSLICE() << secret.as_slice() << hash.as_slice());
Encryptor encryptor(aes_cbc_state, full_view); Encryptor encryptor(aes_cbc_state, full_view);
TRY_RESULT(encrypted_data, encryptor.pread(0, encryptor.size())); TRY_RESULT(encrypted_data, encryptor.pread(0, encryptor.size()));
return EncryptedValue{std::move(encrypted_data), std::move(hash)}; return EncryptedValue{std::move(encrypted_data), std::move(hash)};
} }
Result<BufferSlice> decrypt_value(const Secret &secret, const ValueHash &hash, Slice data) { Result<BufferSlice> decrypt_value(const Secret &secret, const ValueHash &hash, Slice data) {
auto aes_cbc_state = calc_aes_cbc_state(PSLICE() << secret.as_slice() << hash.as_slice()); auto aes_cbc_state = calc_aes_cbc_state_sha512(PSLICE() << secret.as_slice() << hash.as_slice());
Decryptor decryptor(aes_cbc_state); Decryptor decryptor(aes_cbc_state);
TRY_RESULT(decrypted_value, decryptor.append(BufferSlice(data))); TRY_RESULT(decrypted_value, decryptor.append(BufferSlice(data)));
TRY_RESULT(got_hash, decryptor.finish()); TRY_RESULT(got_hash, decryptor.finish());
@ -321,7 +356,7 @@ Result<ValueHash> encrypt_file(const Secret &secret, std::string src, std::strin
TRY_RESULT(hash, calc_value_hash(full_view)); TRY_RESULT(hash, calc_value_hash(full_view));
auto aes_cbc_state = calc_aes_cbc_state(PSLICE() << secret.as_slice() << hash.as_slice()); auto aes_cbc_state = calc_aes_cbc_state_sha512(PSLICE() << secret.as_slice() << hash.as_slice());
Encryptor encryptor(aes_cbc_state, full_view); Encryptor encryptor(aes_cbc_state, full_view);
TRY_STATUS( TRY_STATUS(
data_view_for_each(encryptor, [&dest_file](BufferSlice bytes) { return dest_file.write(bytes.as_slice()); })); data_view_for_each(encryptor, [&dest_file](BufferSlice bytes) { return dest_file.write(bytes.as_slice()); }));
@ -335,7 +370,7 @@ Status decrypt_file(const Secret &secret, const ValueHash &hash, std::string src
auto src_file_view = FileDataView(src_file, src_file_size); auto src_file_view = FileDataView(src_file, src_file_size);
auto aes_cbc_state = calc_aes_cbc_state(PSLICE() << secret.as_slice() << hash.as_slice()); auto aes_cbc_state = calc_aes_cbc_state_sha512(PSLICE() << secret.as_slice() << hash.as_slice());
Decryptor decryptor(aes_cbc_state); Decryptor decryptor(aes_cbc_state);
TRY_STATUS(data_view_for_each(src_file_view, [&decryptor, &dest_file](BufferSlice bytes) { TRY_STATUS(data_view_for_each(src_file_view, [&decryptor, &dest_file](BufferSlice bytes) {
TRY_RESULT(decrypted_bytes, decryptor.append(std::move(bytes))); TRY_RESULT(decrypted_bytes, decryptor.append(std::move(bytes)));
@ -351,5 +386,6 @@ Status decrypt_file(const Secret &secret, const ValueHash &hash, std::string src
return Status::OK(); return Status::OK();
} }
} // namespace secure_storage } // namespace secure_storage
} // namespace td } // namespace td

View File

@ -35,7 +35,6 @@ namespace td {
// do_encrypt :: RandomPrefix -> Value -> AesCbcState -> EncryptedValue // async // do_encrypt :: RandomPrefix -> Value -> AesCbcState -> EncryptedValue // async
// encrypt :: (ValueSecret, RandomPrefix, Value) -> (EncryptedValue, ValueHash) // encrypt :: (ValueSecret, RandomPrefix, Value) -> (EncryptedValue, ValueHash)
// //
//
// To decrypt data: // To decrypt data:
// ValueSecret, ValueHash, EncryptedValue // ValueSecret, ValueHash, EncryptedValue
// do_decrypt :: EncryptedValue -> AesCbcState -> (RandomPrefix, Value, ValueHash) // async // do_decrypt :: EncryptedValue -> AesCbcState -> (RandomPrefix, Value, ValueHash) // async
@ -102,7 +101,8 @@ class ConcatDataView : public DataView {
DataView &right_; DataView &right_;
}; };
AesCbcState calc_aes_cbc_state(Slice seed); AesCbcState calc_aes_cbc_state_pbkdf2(Slice secret, Slice salt);
AesCbcState calc_aes_cbc_state_sha512(Slice seed);
Result<ValueHash> calc_value_hash(DataView &data_view); Result<ValueHash> calc_value_hash(DataView &data_view);
ValueHash calc_value_hash(Slice data); ValueHash calc_value_hash(Slice data);
BufferSlice gen_random_prefix(int64 data_size); BufferSlice gen_random_prefix(int64 data_size);
@ -118,13 +118,15 @@ class Password {
class EncryptedSecret; class EncryptedSecret;
enum class EnryptionAlgorithm : int32 { Sha512, Pbkdf2 };
class Secret { class Secret {
public: public:
static Result<Secret> create(Slice secret); static Result<Secret> create(Slice secret);
static Secret create_new(); static Secret create_new();
Slice as_slice() const; Slice as_slice() const;
EncryptedSecret encrypt(Slice key); EncryptedSecret encrypt(Slice key, Slice salt, EnryptionAlgorithm algorithm);
int64 get_hash() const; int64 get_hash() const;
Secret clone() const; Secret clone() const;
@ -142,7 +144,7 @@ class Secret {
class EncryptedSecret { class EncryptedSecret {
public: public:
static Result<EncryptedSecret> create(Slice encrypted_secret); static Result<EncryptedSecret> create(Slice encrypted_secret);
Result<Secret> decrypt(Slice key); Result<Secret> decrypt(Slice key, Slice salt, EnryptionAlgorithm algorithm);
Slice as_slice() const; Slice as_slice() const;
private: private:

View File

@ -1088,7 +1088,8 @@ static Result<std::pair<DatedFile, SecureFileCredentials>> decrypt_secure_file(
} }
TRY_RESULT(hash, secure_storage::ValueHash::create(secure_file.file_hash)); TRY_RESULT(hash, secure_storage::ValueHash::create(secure_file.file_hash));
TRY_RESULT(encrypted_secret, secure_storage::EncryptedSecret::create(secure_file.encrypted_secret)); TRY_RESULT(encrypted_secret, secure_storage::EncryptedSecret::create(secure_file.encrypted_secret));
TRY_RESULT(secret, encrypted_secret.decrypt(PSLICE() << master_secret.as_slice() << hash.as_slice())); TRY_RESULT(secret, encrypted_secret.decrypt(PSLICE() << master_secret.as_slice() << hash.as_slice(), "",
secure_storage::EnryptionAlgorithm::Sha512));
FileEncryptionKey key{secret}; FileEncryptionKey key{secret};
key.set_value_hash(hash); key.set_value_hash(hash);
file_manager->set_encryption_key(secure_file.file.file_id, std::move(key)); file_manager->set_encryption_key(secure_file.file.file_id, std::move(key));
@ -1114,7 +1115,8 @@ static Result<std::pair<string, SecureDataCredentials>> decrypt_secure_data(cons
const EncryptedSecureData &secure_data) { const EncryptedSecureData &secure_data) {
TRY_RESULT(hash, secure_storage::ValueHash::create(secure_data.hash)); TRY_RESULT(hash, secure_storage::ValueHash::create(secure_data.hash));
TRY_RESULT(encrypted_secret, secure_storage::EncryptedSecret::create(secure_data.encrypted_secret)); TRY_RESULT(encrypted_secret, secure_storage::EncryptedSecret::create(secure_data.encrypted_secret));
TRY_RESULT(secret, encrypted_secret.decrypt(PSLICE() << master_secret.as_slice() << hash.as_slice())); TRY_RESULT(secret, encrypted_secret.decrypt(PSLICE() << master_secret.as_slice() << hash.as_slice(), "",
secure_storage::EnryptionAlgorithm::Sha512));
TRY_RESULT(value, secure_storage::decrypt_value(secret, hash, secure_data.data)); TRY_RESULT(value, secure_storage::decrypt_value(secret, hash, secure_data.data));
return std::make_pair(value.as_slice().str(), SecureDataCredentials{secret.as_slice().str(), hash.as_slice().str()}); return std::make_pair(value.as_slice().str(), SecureDataCredentials{secret.as_slice().str(), hash.as_slice().str()});
} }
@ -1206,7 +1208,11 @@ static EncryptedSecureFile encrypt_secure_file(FileManager *file_manager, const
EncryptedSecureFile res; EncryptedSecureFile res;
res.file = file; res.file = file;
res.file_hash = value_hash.as_slice().str(); res.file_hash = value_hash.as_slice().str();
res.encrypted_secret = secret.encrypt(PSLICE() << master_secret.as_slice() << value_hash.as_slice()).as_slice().str(); res.encrypted_secret = secret
.encrypt(PSLICE() << master_secret.as_slice() << value_hash.as_slice(), "",
secure_storage::EnryptionAlgorithm::Sha512)
.as_slice()
.str();
to_hash.append(res.file_hash); to_hash.append(res.file_hash);
to_hash.append(secret.as_slice().str()); to_hash.append(secret.as_slice().str());
@ -1236,8 +1242,11 @@ static EncryptedSecureData encrypt_secure_data(const secure_storage::Secret &mas
auto secret = secure_storage::Secret::create_new(); auto secret = secure_storage::Secret::create_new();
auto encrypted = encrypt_value(secret, data).move_as_ok(); auto encrypted = encrypt_value(secret, data).move_as_ok();
EncryptedSecureData res; EncryptedSecureData res;
res.encrypted_secret = res.encrypted_secret = secret
secret.encrypt(PSLICE() << master_secret.as_slice() << encrypted.hash.as_slice()).as_slice().str(); .encrypt(PSLICE() << master_secret.as_slice() << encrypted.hash.as_slice(), "",
secure_storage::EnryptionAlgorithm::Sha512)
.as_slice()
.str();
res.data = encrypted.data.as_slice().str(); res.data = encrypted.data.as_slice().str();
res.hash = encrypted.hash.as_slice().str(); res.hash = encrypted.hash.as_slice().str();
to_hash.append(res.hash); to_hash.append(res.hash);

View File

@ -1323,7 +1323,7 @@ class CliClient final : public Actor {
std::tie(password, args) = split(args); std::tie(password, args) = split(args);
std::tie(passport_element_type, arg) = split(args); std::tie(passport_element_type, arg) = split(args);
send_request(make_tl_object<td_api::setPassportElement>( send_request(make_tl_object<td_api::setPassportElement>(
as_input_passport_element(passport_element_type, arg, op == "spds"), password)); as_input_passport_element(passport_element_type, arg, op == "spes"), password));
} else if (op == "dpe") { } else if (op == "dpe") {
string passport_element_type = args; string passport_element_type = args;
send_request(make_tl_object<td_api::deletePassportElement>(as_passport_element_type(passport_element_type))); send_request(make_tl_object<td_api::deletePassportElement>(as_passport_element_type(passport_element_type)));

View File

@ -19,7 +19,7 @@ class HeaderStorer {
} }
template <class StorerT> template <class StorerT>
void store(StorerT &storer) const { void store(StorerT &storer) const {
constexpr int32 LAYER = 82; constexpr int32 LAYER = 83;
using td::store; using td::store;
// invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; // invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;

View File

@ -18,11 +18,11 @@ TEST(SecureStorage, secret) {
using namespace td::secure_storage; using namespace td::secure_storage;
auto secret = Secret::create_new(); auto secret = Secret::create_new();
std::string key = "cucumber"; std::string key = "cucumber";
auto encrypted_secret = secret.encrypt(key); auto encrypted_secret = secret.encrypt(key, "", secure_storage::EnryptionAlgorithm::Sha512);
ASSERT_TRUE(encrypted_secret.as_slice() != secret.as_slice()); ASSERT_TRUE(encrypted_secret.as_slice() != secret.as_slice());
auto decrypted_secret = encrypted_secret.decrypt(key).ok(); auto decrypted_secret = encrypted_secret.decrypt(key, "", secure_storage::EnryptionAlgorithm::Sha512).ok();
ASSERT_TRUE(secret.as_slice() == decrypted_secret.as_slice()); ASSERT_TRUE(secret.as_slice() == decrypted_secret.as_slice());
ASSERT_TRUE(encrypted_secret.decrypt("notcucumber").is_error()); ASSERT_TRUE(encrypted_secret.decrypt("notcucumber", "", secure_storage::EnryptionAlgorithm::Sha512).is_error());
} }
TEST(SecureStorage, simple) { TEST(SecureStorage, simple) {
@ -38,10 +38,11 @@ TEST(SecureStorage, simple) {
auto full_value_view = ConcatDataView(prefix_view, value_view); auto full_value_view = ConcatDataView(prefix_view, value_view);
auto hash = calc_value_hash(full_value_view).move_as_ok(); auto hash = calc_value_hash(full_value_view).move_as_ok();
Encryptor encryptor(calc_aes_cbc_state(PSLICE() << value_secret.as_slice() << hash.as_slice()), full_value_view); Encryptor encryptor(calc_aes_cbc_state_sha512(PSLICE() << value_secret.as_slice() << hash.as_slice()),
full_value_view);
auto encrypted_value = encryptor.pread(0, encryptor.size()).move_as_ok(); auto encrypted_value = encryptor.pread(0, encryptor.size()).move_as_ok();
Decryptor decryptor(calc_aes_cbc_state(PSLICE() << value_secret.as_slice() << hash.as_slice())); Decryptor decryptor(calc_aes_cbc_state_sha512(PSLICE() << value_secret.as_slice() << hash.as_slice()));
auto res = decryptor.append(encrypted_value.copy()).move_as_ok(); auto res = decryptor.append(encrypted_value.copy()).move_as_ok();
auto decrypted_hash = decryptor.finish().ok(); auto decrypted_hash = decryptor.finish().ok();
ASSERT_TRUE(decrypted_hash.as_slice() == hash.as_slice()); ASSERT_TRUE(decrypted_hash.as_slice() == hash.as_slice());