Update layer to 83.
GitOrigin-RevId: 2220a0399ed081441fefc06069b06efa11b8447b
This commit is contained in:
parent
7f62960ad3
commit
c9c2760173
@ -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.noPassword#5ea182f6 new_salt:bytes new_secure_salt:bytes secure_random:bytes email_unconfirmed_pattern:string = 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.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.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;
|
||||
|
||||
@ -900,6 +899,15 @@ savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:
|
||||
|
||||
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---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
|
Binary file not shown.
@ -14,14 +14,14 @@
|
||||
#include "td/telegram/ConfigShared.h"
|
||||
#include "td/telegram/ContactsManager.h"
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/misc.h"
|
||||
#include "td/telegram/net/DcId.h"
|
||||
#include "td/telegram/net/NetQueryDispatcher.h"
|
||||
#include "td/telegram/PasswordManager.h"
|
||||
#include "td/telegram/Td.h"
|
||||
#include "td/telegram/UpdatesManager.h"
|
||||
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
|
||||
#include "td/actor/PromiseFuture.h"
|
||||
|
||||
#include "td/utils/buffer.h"
|
||||
@ -613,13 +613,13 @@ void AuthManager::check_password(uint64 query_id, string password) {
|
||||
if (state_ != State::WaitPassword) {
|
||||
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_;
|
||||
sha256(password, buf.as_slice());
|
||||
|
||||
auto hash = PasswordManager::calc_password_hash(password, wait_password_state_.current_client_salt_,
|
||||
wait_password_state_.current_server_salt_);
|
||||
|
||||
on_new_query(query_id);
|
||||
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));
|
||||
}
|
||||
|
||||
@ -748,18 +748,30 @@ void AuthManager::on_get_password_result(NetQueryPtr &result) {
|
||||
return on_query_error(r_password.move_as_error());
|
||||
}
|
||||
auto password = r_password.move_as_ok();
|
||||
|
||||
wait_password_state_ = WaitPasswordState();
|
||||
if (password->get_id() == telegram_api::account_noPassword::ID) {
|
||||
auto no_password = move_tl_object_as<telegram_api::account_noPassword>(password);
|
||||
wait_password_state_.new_salt_ = no_password->new_salt_.as_slice().str();
|
||||
if (password->current_algo_ != nullptr) {
|
||||
switch (password->current_algo_->get_id()) {
|
||||
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 {
|
||||
CHECK(password->get_id() == telegram_api::account_password::ID);
|
||||
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_;
|
||||
// TODO we need to resend auth_signIn instead of going to WaitPassword state
|
||||
}
|
||||
|
||||
update_state(State::WaitPassword);
|
||||
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();
|
||||
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);
|
||||
on_query_ok();
|
||||
}
|
||||
|
@ -196,10 +196,10 @@ class AuthManager : public NetActor {
|
||||
};
|
||||
|
||||
struct WaitPasswordState {
|
||||
string current_salt_;
|
||||
string new_salt_;
|
||||
string current_client_salt_;
|
||||
string current_server_salt_;
|
||||
string hint_;
|
||||
bool has_recovery_;
|
||||
bool has_recovery_ = false;
|
||||
string email_address_pattern_;
|
||||
|
||||
template <class T>
|
||||
|
@ -57,8 +57,8 @@ void SendCodeHelper::parse(T &parser) {
|
||||
template <class T>
|
||||
void AuthManager::WaitPasswordState::store(T &storer) const {
|
||||
using td::store;
|
||||
store(current_salt_, storer);
|
||||
store(new_salt_, storer);
|
||||
store(current_client_salt_, storer);
|
||||
store(current_server_salt_, storer);
|
||||
store(hint_, storer);
|
||||
store(has_recovery_, storer);
|
||||
store(email_address_pattern_, storer);
|
||||
@ -67,8 +67,8 @@ void AuthManager::WaitPasswordState::store(T &storer) const {
|
||||
template <class T>
|
||||
void AuthManager::WaitPasswordState::parse(T &parser) {
|
||||
using td::parse;
|
||||
parse(current_salt_, parser);
|
||||
parse(new_salt_, parser);
|
||||
parse(current_client_salt_, parser);
|
||||
parse(current_server_salt_, parser);
|
||||
parse(hint_, parser);
|
||||
parse(has_recovery_, parser);
|
||||
parse(email_address_pattern_, parser);
|
||||
@ -78,8 +78,10 @@ template <class T>
|
||||
void AuthManager::DbState::store(T &storer) const {
|
||||
using td::store;
|
||||
bool has_terms_of_service = !terms_of_service_.get_id().empty();
|
||||
bool is_pbkdf2_supported = true;
|
||||
BEGIN_STORE_FLAGS();
|
||||
STORE_FLAG(has_terms_of_service);
|
||||
STORE_FLAG(is_pbkdf2_supported);
|
||||
END_STORE_FLAGS();
|
||||
store(state_, storer);
|
||||
store(api_id_, storer);
|
||||
@ -103,9 +105,11 @@ template <class T>
|
||||
void AuthManager::DbState::parse(T &parser) {
|
||||
using td::parse;
|
||||
bool has_terms_of_service = false;
|
||||
bool is_pbkdf2_supported = false;
|
||||
if (parser.version() >= static_cast<int32>(Version::AddTermsOfService)) {
|
||||
BEGIN_PARSE_FLAGS();
|
||||
PARSE_FLAG(has_terms_of_service);
|
||||
PARSE_FLAG(is_pbkdf2_supported);
|
||||
END_PARSE_FLAGS();
|
||||
}
|
||||
parse(state_, parser);
|
||||
@ -120,9 +124,12 @@ void AuthManager::DbState::parse(T &parser) {
|
||||
if (state_ == State::WaitCode) {
|
||||
parse(send_code_helper_, parser);
|
||||
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) {
|
||||
if (!is_pbkdf2_supported) {
|
||||
return parser.set_error("Need PBKDF2 support");
|
||||
}
|
||||
parse(wait_password_state_, parser);
|
||||
} else {
|
||||
parser.set_error(PSTRING() << "Unexpected " << tag("state", static_cast<int32>(state_)));
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "td/telegram/Global.h"
|
||||
#include "td/telegram/logevent/LogEvent.h"
|
||||
#include "td/telegram/net/NetQueryDispatcher.h"
|
||||
#include "td/telegram/SecureStorage.h"
|
||||
|
||||
#include "td/utils/buffer.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());
|
||||
}
|
||||
|
||||
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()) {
|
||||
return BufferSlice();
|
||||
}
|
||||
|
||||
BufferSlice buf(32);
|
||||
string salted_password = salt + password + salt;
|
||||
sha256(salted_password, buf.as_slice());
|
||||
return buf;
|
||||
hash_sha256(password, client_salt, buf.as_slice());
|
||||
hash_sha256(buf.as_slice(), server_salt, buf.as_slice());
|
||||
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,
|
||||
@ -152,20 +164,21 @@ void PasswordManager::drop_temp_password() {
|
||||
|
||||
void PasswordManager::do_create_temp_password(string password, int32 timeout, PasswordState &&password_state,
|
||||
Promise<TempPasswordState> promise) {
|
||||
send_with_promise(G()->net_query_creator().create(create_storer(telegram_api::account_getTmpPassword(
|
||||
calc_password_hash(password, password_state.current_salt), timeout))),
|
||||
PromiseCreator::lambda([promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
|
||||
auto r_result = fetch_result<telegram_api::account_getTmpPassword>(std::move(r_query));
|
||||
if (r_result.is_error()) {
|
||||
return promise.set_error(r_result.move_as_error());
|
||||
}
|
||||
auto result = r_result.move_as_ok();
|
||||
TempPasswordState res;
|
||||
res.has_temp_password = true;
|
||||
res.temp_password = result->tmp_password_.as_slice().str();
|
||||
res.valid_until = result->valid_until_;
|
||||
promise.set_value(std::move(res));
|
||||
}));
|
||||
auto hash = calc_password_hash(password, password_state);
|
||||
send_with_promise(
|
||||
G()->net_query_creator().create(create_storer(telegram_api::account_getTmpPassword(std::move(hash), timeout))),
|
||||
PromiseCreator::lambda([promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
|
||||
auto r_result = fetch_result<telegram_api::account_getTmpPassword>(std::move(r_query));
|
||||
if (r_result.is_error()) {
|
||||
return promise.set_error(r_result.move_as_error());
|
||||
}
|
||||
auto result = r_result.move_as_ok();
|
||||
TempPasswordState res;
|
||||
res.has_temp_password = true;
|
||||
res.temp_password = result->tmp_password_.as_slice().str();
|
||||
res.valid_until = result->valid_until_;
|
||||
promise.set_value(std::move(res));
|
||||
}));
|
||||
}
|
||||
|
||||
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) {
|
||||
auto current_salt = state.current_salt;
|
||||
auto hash = calc_password_hash(password, state);
|
||||
send_with_promise(
|
||||
G()->net_query_creator().create(
|
||||
create_storer(telegram_api::account_getPasswordSettings(calc_password_hash(password, current_salt)))),
|
||||
PromiseCreator::lambda([promise = std::move(promise), state = std::move(state),
|
||||
password](Result<NetQueryPtr> r_query) mutable {
|
||||
promise.set_result([&]() -> Result<PasswordFullState> {
|
||||
TRY_RESULT(result, fetch_result<telegram_api::account_getPasswordSettings>(std::move(r_query)));
|
||||
PasswordPrivateState private_state;
|
||||
private_state.email = result->email_;
|
||||
G()->net_query_creator().create(create_storer(telegram_api::account_getPasswordSettings(std::move(hash)))),
|
||||
PromiseCreator::lambda(
|
||||
[promise = std::move(promise), state = std::move(state), password](Result<NetQueryPtr> r_query) mutable {
|
||||
promise.set_result([&]() -> Result<PasswordFullState> {
|
||||
TRY_RESULT(result, fetch_result<telegram_api::account_getPasswordSettings>(std::move(r_query)));
|
||||
PasswordPrivateState private_state;
|
||||
private_state.email = std::move(result->email_);
|
||||
|
||||
auto r_secret = [&]() -> Result<secure_storage::Secret> {
|
||||
TRY_RESULT(encrypted_secret, secure_storage::EncryptedSecret::create(result->secure_secret_.as_slice()));
|
||||
auto r_secret = encrypted_secret.decrypt(PSLICE() << result->secure_salt_.as_slice() << password
|
||||
<< result->secure_salt_.as_slice());
|
||||
if (r_secret.is_ok() && result->secure_secret_id_ != r_secret.ok().get_hash()) {
|
||||
return Status::Error("Secret hash mismatch");
|
||||
}
|
||||
return r_secret;
|
||||
}();
|
||||
if (result->secure_settings_ != nullptr) {
|
||||
auto r_secret = decrypt_secure_secret(password, std::move(result->secure_settings_->secure_algo_),
|
||||
result->secure_settings_->secure_secret_.as_slice(),
|
||||
result->secure_settings_->secure_secret_id_);
|
||||
if (r_secret.is_ok()) {
|
||||
private_state.secret = r_secret.move_as_ok();
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
@ -329,15 +370,13 @@ void PasswordManager::update_password_settings(UpdateSettings update_settings, P
|
||||
}));
|
||||
}
|
||||
|
||||
namespace {
|
||||
BufferSlice create_salt(Slice server_salt) {
|
||||
static BufferSlice create_salt(Slice salt_prefix) {
|
||||
static constexpr size_t ADDED_SALT_SIZE = 32;
|
||||
BufferSlice new_salt(server_salt.size() + ADDED_SALT_SIZE);
|
||||
new_salt.as_slice().copy_from(server_salt);
|
||||
Random::secure_bytes(new_salt.as_slice().substr(server_salt.size()));
|
||||
BufferSlice new_salt(salt_prefix.size() + ADDED_SALT_SIZE);
|
||||
new_salt.as_slice().copy_from(salt_prefix);
|
||||
Random::secure_bytes(new_salt.as_slice().substr(salt_prefix.size()));
|
||||
return new_salt;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void PasswordManager::do_update_password_settings(UpdateSettings update_settings, PasswordFullState full_state,
|
||||
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>();
|
||||
if (update_settings.update_password) {
|
||||
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;
|
||||
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_ =
|
||||
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);
|
||||
if (private_state.secret) {
|
||||
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) {
|
||||
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SECRET_ID_MASK;
|
||||
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SALT_MASK;
|
||||
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SECRET_MASK;
|
||||
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 secret = private_state.secret ? std::move(private_state.secret.value()) : secure_storage::Secret::create_new();
|
||||
auto algorithm = make_tl_object<telegram_api::securePasswordKdfAlgoPBKDF2HMACSHA512iter100000>(
|
||||
create_salt(state.new_secure_salt));
|
||||
auto encrypted_secret = secret.encrypt(
|
||||
PSLICE() << new_secure_salt.as_slice()
|
||||
<< (update_settings.update_password ? update_settings.new_password : update_settings.current_password)
|
||||
<< new_secure_salt.as_slice());
|
||||
update_settings.update_password ? update_settings.new_password : update_settings.current_password,
|
||||
algorithm->salt_.as_slice(), secure_storage::EnryptionAlgorithm::Pbkdf2);
|
||||
|
||||
new_settings->new_secure_salt_ = std::move(new_secure_salt);
|
||||
new_settings->new_secure_secret_ = BufferSlice(encrypted_secret.as_slice());
|
||||
new_settings->new_secure_secret_id_ = secret.get_hash();
|
||||
new_settings->flags_ |= telegram_api::account_passwordInputSettings::NEW_SECURE_SETTINGS_MASK;
|
||||
new_settings->new_secure_settings_ = make_tl_object<telegram_api::secureSecretSettings>(
|
||||
std::move(algorithm), BufferSlice(encrypted_secret.as_slice()), secret.get_hash());
|
||||
}
|
||||
if (update_settings.update_recovery_email_address) {
|
||||
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;
|
||||
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(
|
||||
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) {
|
||||
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)](
|
||||
Result<NetQueryPtr> r_query) mutable {
|
||||
auto r_result = fetch_result<telegram_api::account_getPassword>(std::move(r_query));
|
||||
if (r_result.is_error()) {
|
||||
return promise.set_error(r_result.move_as_error());
|
||||
}
|
||||
auto result = r_result.move_as_ok();
|
||||
send_with_promise(
|
||||
std::move(query), PromiseCreator::lambda([actor_id = actor_id(this),
|
||||
promise = std::move(promise)](Result<NetQueryPtr> r_query) mutable {
|
||||
auto r_result = fetch_result<telegram_api::account_getPassword>(std::move(r_query));
|
||||
if (r_result.is_error()) {
|
||||
return promise.set_error(r_result.move_as_error());
|
||||
}
|
||||
auto password = r_result.move_as_ok();
|
||||
Random::add_seed(password->secure_random_.as_slice());
|
||||
|
||||
PasswordState state;
|
||||
string secure_random;
|
||||
if (result->get_id() == telegram_api::account_noPassword::ID) {
|
||||
auto no_password = move_tl_object_as<telegram_api::account_noPassword>(result);
|
||||
state.has_password = false;
|
||||
state.password_hint = "";
|
||||
state.current_salt = "";
|
||||
state.new_salt = no_password->new_salt_.as_slice().str();
|
||||
state.new_secure_salt = no_password->new_secure_salt_.as_slice().str();
|
||||
secure_random = no_password->secure_random_.as_slice().str();
|
||||
state.has_recovery_email_address = false;
|
||||
state.has_secure_values = false;
|
||||
state.unconfirmed_recovery_email_address_pattern = no_password->email_unconfirmed_pattern_;
|
||||
} else if (result->get_id() == telegram_api::account_password::ID) {
|
||||
auto password = move_tl_object_as<telegram_api::account_password>(result);
|
||||
state.has_password = true;
|
||||
state.password_hint = password->hint_;
|
||||
state.current_salt = password->current_salt_.as_slice().str();
|
||||
state.new_salt = password->new_salt_.as_slice().str();
|
||||
state.new_secure_salt = password->new_secure_salt_.as_slice().str();
|
||||
secure_random = password->secure_random_.as_slice().str();
|
||||
state.has_recovery_email_address =
|
||||
(password->flags_ & telegram_api::account_password::HAS_RECOVERY_MASK) != 0;
|
||||
state.has_secure_values =
|
||||
(password->flags_ & telegram_api::account_password::HAS_SECURE_VALUES_MASK) != 0;
|
||||
state.unconfirmed_recovery_email_address_pattern = password->email_unconfirmed_pattern_;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
Random::add_seed(secure_random);
|
||||
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_salt.size() < MIN_NEW_SALT_SIZE) {
|
||||
return promise.set_error(Status::Error(500, "New salt length too small"));
|
||||
}
|
||||
promise.set_value(std::move(state));
|
||||
}));
|
||||
PasswordState state;
|
||||
if (password->current_algo_ != nullptr) {
|
||||
state.has_password = true;
|
||||
|
||||
switch (password->current_algo_->get_id()) {
|
||||
case telegram_api::passwordKdfAlgoUnknown::ID:
|
||||
return promise.set_error(Status::Error(400, "Please update client to continue"));
|
||||
case telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000::ID: {
|
||||
auto algo = move_tl_object_as<telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000>(
|
||||
password->current_algo_);
|
||||
state.current_client_salt = algo->salt1_.as_slice().str();
|
||||
state.current_server_salt = algo->salt2_.as_slice().str();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
state.password_hint = std::move(password->hint_);
|
||||
state.has_recovery_email_address =
|
||||
(password->flags_ & telegram_api::account_password::HAS_RECOVERY_MASK) != 0;
|
||||
state.has_secure_values = (password->flags_ & telegram_api::account_password::HAS_SECURE_VALUES_MASK) != 0;
|
||||
} else {
|
||||
state.has_password = false;
|
||||
}
|
||||
state.unconfirmed_recovery_email_address_pattern = std::move(password->email_unconfirmed_pattern_);
|
||||
|
||||
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::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000::ID: {
|
||||
auto algo = move_tl_object_as<telegram_api::passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000>(
|
||||
password->new_algo_);
|
||||
state.new_client_salt = algo->salt1_.as_slice().str();
|
||||
state.new_server_salt = algo->salt2_.as_slice().str();
|
||||
break;
|
||||
}
|
||||
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) {
|
||||
|
@ -9,17 +9,19 @@
|
||||
#include "td/telegram/net/NetQuery.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/PromiseFuture.h"
|
||||
|
||||
#include "td/utils/Container.h"
|
||||
#include "td/utils/logging.h"
|
||||
#include "td/utils/optional.h"
|
||||
#include "td/utils/Slice.h"
|
||||
#include "td/utils/Status.h"
|
||||
#include "td/utils/tl_helpers.h"
|
||||
|
||||
#include "td/telegram/td_api.h"
|
||||
|
||||
namespace td {
|
||||
|
||||
struct TempPasswordState {
|
||||
@ -54,6 +56,8 @@ class PasswordManager : public NetQueryCallback {
|
||||
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 set_password(string current_password, string new_password, string new_hint, bool set_recovery_email_address,
|
||||
string recovery_email_address, Promise<State> promise);
|
||||
@ -88,10 +92,12 @@ class PasswordManager : public NetQueryCallback {
|
||||
string password_hint;
|
||||
bool has_recovery_email_address = false;
|
||||
bool has_secure_values = false;
|
||||
string unconfirmed_recovery_email_address_pattern = "";
|
||||
string unconfirmed_recovery_email_address_pattern;
|
||||
|
||||
string current_salt;
|
||||
string new_salt;
|
||||
string current_client_salt;
|
||||
string current_server_salt;
|
||||
string new_client_salt;
|
||||
string new_server_salt;
|
||||
|
||||
string new_secure_salt;
|
||||
|
||||
@ -130,6 +136,11 @@ class PasswordManager : public NetQueryCallback {
|
||||
|
||||
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 do_update_password_settings(UpdateSettings update_settings, PasswordFullState full_state, Promise<bool> promise);
|
||||
void do_get_state(Promise<PasswordState> promise);
|
||||
|
@ -859,7 +859,6 @@ Result<std::tuple<uint64, BufferSlice, int32>> SecretChatActor::decrypt(BufferSl
|
||||
}
|
||||
case mtproto::Transport::ReadResult::Nop: {
|
||||
return Status::Error("Got nop instead of a message");
|
||||
break;
|
||||
}
|
||||
case mtproto::Transport::ReadResult::Packet: {
|
||||
data = read_result.packet();
|
||||
|
@ -24,15 +24,27 @@ Result<ValueHash> ValueHash::create(Slice data) {
|
||||
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;
|
||||
auto hash_slice = as_slice(hash);
|
||||
sha512(seed, hash_slice);
|
||||
UInt256 key;
|
||||
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};
|
||||
return calc_aes_cbc_state_hash(hash_slice);
|
||||
}
|
||||
|
||||
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)) {
|
||||
}
|
||||
|
||||
int64 BufferSliceDataView::size() const {
|
||||
return narrow_cast<int64>(buffer_slice_.size());
|
||||
}
|
||||
|
||||
Result<BufferSlice> BufferSliceDataView::pread(int64 offset, int64 size) {
|
||||
auto end_offset = size + 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) {
|
||||
}
|
||||
|
||||
int64 ConcatDataView::size() const {
|
||||
return left_.size() + right_.size();
|
||||
}
|
||||
|
||||
Result<BufferSlice> ConcatDataView::pread(int64 offset, int64 size) {
|
||||
auto end_offset = size + offset;
|
||||
if (this->size() < end_offset) {
|
||||
@ -136,23 +152,20 @@ Result<BufferSlice> ConcatDataView::pread(int64 offset, int64 size) {
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
// Password
|
||||
Password::Password(std::string password) : password_(std::move(password)) {
|
||||
}
|
||||
|
||||
Slice Password::as_slice() const {
|
||||
return password_;
|
||||
}
|
||||
|
||||
// Secret
|
||||
namespace {
|
||||
uint8 secret_checksum(Slice secret) {
|
||||
static uint8 secret_checksum(Slice secret) {
|
||||
uint32 sum = 0;
|
||||
for (uint8 c : secret) {
|
||||
sum += c;
|
||||
}
|
||||
return static_cast<uint8>((255 + 239 - sum % 255) % 255);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Result<Secret> Secret::create(Slice secret) {
|
||||
if (secret.size() != 32) {
|
||||
@ -194,8 +207,19 @@ Secret Secret::clone() const {
|
||||
return {secret_, hash_};
|
||||
}
|
||||
|
||||
EncryptedSecret Secret::encrypt(Slice key) {
|
||||
auto aes_cbc_state = calc_aes_cbc_state(key);
|
||||
EncryptedSecret Secret::encrypt(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;
|
||||
aes_cbc_state.encrypt(as_slice(), td::as_slice(res));
|
||||
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) {
|
||||
}
|
||||
|
||||
//EncryptedSecret
|
||||
Result<EncryptedSecret> EncryptedSecret::create(Slice encrypted_secret) {
|
||||
if (encrypted_secret.size() != 32) {
|
||||
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);
|
||||
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;
|
||||
aes_cbc_state.decrypt(td::as_slice(encrypted_secret_), 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) {
|
||||
}
|
||||
|
||||
// Decryption
|
||||
Decryptor::Decryptor(AesCbcState aes_cbc_state) : aes_cbc_state_(std::move(aes_cbc_state)) {
|
||||
sha256_init(&sha256_state_);
|
||||
}
|
||||
|
||||
Result<BufferSlice> Decryptor::append(BufferSlice data) {
|
||||
if (data.empty()) {
|
||||
return BufferSlice();
|
||||
@ -251,6 +286,7 @@ Result<BufferSlice> Decryptor::append(BufferSlice data) {
|
||||
}
|
||||
return std::move(data);
|
||||
}
|
||||
|
||||
Result<ValueHash> Decryptor::finish() {
|
||||
if (!skipped_prefix_) {
|
||||
return Status::Error("No data was given");
|
||||
@ -263,7 +299,6 @@ Result<ValueHash> Decryptor::finish() {
|
||||
return ValueHash{res};
|
||||
}
|
||||
|
||||
// Encryptor
|
||||
Encryptor::Encryptor(AesCbcState aes_cbc_state, DataView &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));
|
||||
|
||||
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);
|
||||
TRY_RESULT(encrypted_data, encryptor.pread(0, encryptor.size()));
|
||||
return EncryptedValue{std::move(encrypted_data), std::move(hash)};
|
||||
}
|
||||
|
||||
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);
|
||||
TRY_RESULT(decrypted_value, decryptor.append(BufferSlice(data)));
|
||||
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));
|
||||
|
||||
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);
|
||||
TRY_STATUS(
|
||||
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 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);
|
||||
TRY_STATUS(data_view_for_each(src_file_view, [&decryptor, &dest_file](BufferSlice 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();
|
||||
}
|
||||
|
||||
} // namespace secure_storage
|
||||
} // namespace td
|
||||
|
@ -35,7 +35,6 @@ namespace td {
|
||||
// do_encrypt :: RandomPrefix -> Value -> AesCbcState -> EncryptedValue // async
|
||||
// encrypt :: (ValueSecret, RandomPrefix, Value) -> (EncryptedValue, ValueHash)
|
||||
//
|
||||
//
|
||||
// To decrypt data:
|
||||
// ValueSecret, ValueHash, EncryptedValue
|
||||
// do_decrypt :: EncryptedValue -> AesCbcState -> (RandomPrefix, Value, ValueHash) // async
|
||||
@ -102,7 +101,8 @@ class ConcatDataView : public DataView {
|
||||
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);
|
||||
ValueHash calc_value_hash(Slice data);
|
||||
BufferSlice gen_random_prefix(int64 data_size);
|
||||
@ -118,13 +118,15 @@ class Password {
|
||||
|
||||
class EncryptedSecret;
|
||||
|
||||
enum class EnryptionAlgorithm : int32 { Sha512, Pbkdf2 };
|
||||
|
||||
class Secret {
|
||||
public:
|
||||
static Result<Secret> create(Slice secret);
|
||||
static Secret create_new();
|
||||
|
||||
Slice as_slice() const;
|
||||
EncryptedSecret encrypt(Slice key);
|
||||
EncryptedSecret encrypt(Slice key, Slice salt, EnryptionAlgorithm algorithm);
|
||||
|
||||
int64 get_hash() const;
|
||||
Secret clone() const;
|
||||
@ -142,7 +144,7 @@ class Secret {
|
||||
class EncryptedSecret {
|
||||
public:
|
||||
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;
|
||||
|
||||
private:
|
||||
|
@ -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(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};
|
||||
key.set_value_hash(hash);
|
||||
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) {
|
||||
TRY_RESULT(hash, secure_storage::ValueHash::create(secure_data.hash));
|
||||
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));
|
||||
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;
|
||||
res.file = file;
|
||||
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(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 encrypted = encrypt_value(secret, data).move_as_ok();
|
||||
EncryptedSecureData res;
|
||||
res.encrypted_secret =
|
||||
secret.encrypt(PSLICE() << master_secret.as_slice() << encrypted.hash.as_slice()).as_slice().str();
|
||||
res.encrypted_secret = secret
|
||||
.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.hash = encrypted.hash.as_slice().str();
|
||||
to_hash.append(res.hash);
|
||||
|
@ -1323,7 +1323,7 @@ class CliClient final : public Actor {
|
||||
std::tie(password, args) = split(args);
|
||||
std::tie(passport_element_type, arg) = split(args);
|
||||
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") {
|
||||
string passport_element_type = args;
|
||||
send_request(make_tl_object<td_api::deletePassportElement>(as_passport_element_type(passport_element_type)));
|
||||
|
@ -19,7 +19,7 @@ class HeaderStorer {
|
||||
}
|
||||
template <class StorerT>
|
||||
void store(StorerT &storer) const {
|
||||
constexpr int32 LAYER = 82;
|
||||
constexpr int32 LAYER = 83;
|
||||
|
||||
using td::store;
|
||||
// invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
|
||||
|
@ -18,11 +18,11 @@ TEST(SecureStorage, secret) {
|
||||
using namespace td::secure_storage;
|
||||
auto secret = Secret::create_new();
|
||||
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());
|
||||
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(encrypted_secret.decrypt("notcucumber").is_error());
|
||||
ASSERT_TRUE(encrypted_secret.decrypt("notcucumber", "", secure_storage::EnryptionAlgorithm::Sha512).is_error());
|
||||
}
|
||||
|
||||
TEST(SecureStorage, simple) {
|
||||
@ -38,10 +38,11 @@ TEST(SecureStorage, simple) {
|
||||
auto full_value_view = ConcatDataView(prefix_view, value_view);
|
||||
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();
|
||||
|
||||
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 decrypted_hash = decryptor.finish().ok();
|
||||
ASSERT_TRUE(decrypted_hash.as_slice() == hash.as_slice());
|
||||
|
Loading…
Reference in New Issue
Block a user