diff --git a/crypto/fift/lib/Fift.fif b/crypto/fift/lib/Fift.fif index 65fecb31..f674be79 100644 --- a/crypto/fift/lib/Fift.fif +++ b/crypto/fift/lib/Fift.fif @@ -39,6 +39,34 @@ // { dup abs <# #s rot sign #> nip } : (.) // { (.) type } : ._ // { ._ space } : . +{ dup 10 < { 48 } { 55 } cond + } : Digit +{ dup 10 < { 48 } { 87 } cond + } : digit +// x s b -- x' s' +{ -rot swap rot /mod Digit rot swap hold } : B# +{ -rot swap rot /mod digit rot swap hold } : b# +{ 16 B# } : X# +{ 16 b# } : x# +// x s b -- 0 s' +{ -rot { 2 pick B# over 0<= } until rot drop } : B#s +{ -rot { 2 pick b# over 0<= } until rot drop } : b#s +{ 16 B#s } : X#s +{ 16 b#s } : x#s +variable base +{ 10 base ! } : decimal +{ 16 base ! } : hex +{ 8 base ! } : octal +{ 2 base ! } : binary +{ base @ B# } : Base# +{ base @ b# } : base# +{ base @ B#s } : Base#s +{ base @ b#s } : base#s +// x w -- s +{ over abs <# rot 1- ' X# swap times X#s rot sign #> nip } : (0X.) +{ over abs <# rot 1- ' x# swap times x#s rot sign #> nip } : (0x.) +{ (0X.) type } : 0X._ +{ 0X._ space } : 0X. +{ (0x.) type } : 0x._ +{ 0x._ space } : 0x. { bl (-trailing) } : -trailing { char 0 (-trailing) } : -trailing0 { char " word 1 ' $+ } ::_ +" diff --git a/crypto/fift/lib/TonUtil.fif b/crypto/fift/lib/TonUtil.fif index 2e2484ad..95353222 100644 --- a/crypto/fift/lib/TonUtil.fif +++ b/crypto/fift/lib/TonUtil.fif @@ -33,7 +33,7 @@ library TonUtil // TON Blockchain Fift Library } : parse-smc-addr // ( wc addr -- ) Show address in : form -{ swap ._ .":" x. } : .addr +{ swap ._ .":" 64 0x. } : .addr // ( wc addr flags -- ) Show address in base64url form { smca>$ type } : .Addr // ( wc addr fname -- ) Save address to file in 36-byte format diff --git a/tl/generate/scheme/tonlib_api.tl b/tl/generate/scheme/tonlib_api.tl index c0dc53c1..cf0ed2b8 100644 --- a/tl/generate/scheme/tonlib_api.tl +++ b/tl/generate/scheme/tonlib_api.tl @@ -85,6 +85,8 @@ logVerbosityLevel verbosity_level:int32 = LogVerbosityLevel; //@description Contains a list of available TDLib internal log tags @tags List of log tags logTags tags:vector = LogTags; +data bytes:secureBytes = Data; + ---functions--- init options:options = Ok; @@ -103,6 +105,10 @@ importPemKey local_password:secureBytes key_password:secureBytes exported_key:ex importEncryptedKey local_password:secureBytes key_password:secureBytes exported_encrypted_key:exportedEncryptedKey = Key; changeLocalPassword input_key:inputKey new_local_password:secureBytes = Key; +encrypt decrypted_data:secureBytes secret:secureBytes = Data; +decrypt encrypted_data:secureBytes secret:secureBytes = Data; +kdf password:secureBytes salt:secureBytes iterations:int32 = Data; + unpackAccountAddress account_address:string = UnpackedAccountAddress; packAccountAddress account_address:unpackedAccountAddress = AccountAddress; diff --git a/tl/generate/scheme/tonlib_api.tlo b/tl/generate/scheme/tonlib_api.tlo index 1050a59c..1af5d79a 100644 Binary files a/tl/generate/scheme/tonlib_api.tlo and b/tl/generate/scheme/tonlib_api.tlo differ diff --git a/tonlib/test/offline.cpp b/tonlib/test/offline.cpp index a956eecf..04b55c78 100644 --- a/tonlib/test/offline.cpp +++ b/tonlib/test/offline.cpp @@ -430,6 +430,34 @@ TEST(Tonlib, ParseAddres) { ASSERT_EQ("Uf9Tj6fMJP-OqhAdhKXxq36DL-HYSzCc3-9O6UNzqsgPfdyS", addr_str2->account_address_); } +TEST(Tonlib, EncryptionApi) { + using tonlib_api::make_object; + Client client; + + // init + sync_send(client, make_object( + make_object(nullptr, make_object(".")))) + .ensure(); + + std::string password = "hello world"; + std::string data = "very secret data"; + auto key = std::move( + sync_send(client, make_object(td::SecureString(password), td::SecureString("salt"), 100000)) + .move_as_ok() + ->bytes_); + auto encrypted = std::move( + sync_send(client, make_object(td::SecureString(data), key.copy())).move_as_ok()->bytes_); + auto decrypted = + std::move(sync_send(client, make_object(encrypted.copy(), key.copy())).move_as_ok()->bytes_); + ASSERT_EQ(data, decrypted); + + auto bad_key = std::move(sync_send(client, make_object(td::SecureString(password + "BAD"), + td::SecureString("salt"), 100000)) + .move_as_ok() + ->bytes_); + sync_send(client, make_object(encrypted.copy(), bad_key.copy())).ensure_error(); +} + TEST(Tonlib, KeysApi) { using tonlib_api::make_object; Client client; diff --git a/tonlib/tonlib/TonlibClient.cpp b/tonlib/tonlib/TonlibClient.cpp index 63203df8..ccf44df6 100644 --- a/tonlib/tonlib/TonlibClient.cpp +++ b/tonlib/tonlib/TonlibClient.cpp @@ -28,6 +28,7 @@ #include "tonlib/TestGiver.h" #include "tonlib/utils.h" #include "tonlib/keys/Mnemonic.h" +#include "tonlib/keys/SimpleEncryption.h" #include "tonlib/TonlibError.h" @@ -444,7 +445,7 @@ tonlib_api::object_ptr TonlibClient::static_request( tonlib_api::object_ptr response; downcast_call(*function, [&response](auto& request) { response = TonlibClient::do_static_request(request); }); - VLOG(tonlib_query) << " answer static query " << to_string(function); + VLOG(tonlib_query) << " answer static query " << to_string(response); return response; } @@ -466,6 +467,9 @@ bool TonlibClient::is_static_request(td::int32 id) { case tonlib_api::setLogTagVerbosityLevel::ID: case tonlib_api::getLogTagVerbosityLevel::ID: case tonlib_api::addLogMessage::ID: + case tonlib_api::encrypt::ID: + case tonlib_api::decrypt::ID: + case tonlib_api::kdf::ID: return true; default: return false; @@ -1633,4 +1637,28 @@ tonlib_api::object_ptr TonlibClient::do_static_request(const return tonlib_api::make_object(); } +tonlib_api::object_ptr TonlibClient::do_static_request(const tonlib_api::encrypt& request) { + return tonlib_api::make_object( + SimpleEncryption::encrypt_data(request.decrypted_data_, request.secret_)); +} + +tonlib_api::object_ptr TonlibClient::do_static_request(const tonlib_api::decrypt& request) { + auto r_data = SimpleEncryption::decrypt_data(request.encrypted_data_, request.secret_); + if (r_data.is_ok()) { + return tonlib_api::make_object(r_data.move_as_ok()); + } else { + return status_to_tonlib_api(r_data.error().move_as_error_prefix(TonlibError::KeyDecrypt())); + } +} + +tonlib_api::object_ptr TonlibClient::do_static_request(const tonlib_api::kdf& request) { + auto max_iterations = 10000000; + if (request.iterations_ < 0 || request.iterations_ > max_iterations) { + return status_to_tonlib_api( + TonlibError::InvalidField("iterations", PSLICE() << "must be between 0 and " << max_iterations)); + } + return tonlib_api::make_object( + SimpleEncryption::kdf(request.password_, request.salt_, request.iterations_)); +} + } // namespace tonlib diff --git a/tonlib/tonlib/TonlibClient.h b/tonlib/tonlib/TonlibClient.h index 649df52d..e2ea77d1 100644 --- a/tonlib/tonlib/TonlibClient.h +++ b/tonlib/tonlib/TonlibClient.h @@ -117,6 +117,10 @@ class TonlibClient : public td::actor::Actor { static object_ptr do_static_request(const tonlib_api::getLogTags& request); static object_ptr do_static_request(const tonlib_api::addLogMessage& request); + static object_ptr do_static_request(const tonlib_api::encrypt& request); + static object_ptr do_static_request(const tonlib_api::decrypt& request); + static object_ptr do_static_request(const tonlib_api::kdf& request); + template td::Status do_request(const T& request, P&& promise) { return td::Status::Error(400, "Function is unsupported"); diff --git a/tonlib/tonlib/keys/DecryptedKey.cpp b/tonlib/tonlib/keys/DecryptedKey.cpp index 931b9f01..7aadf635 100644 --- a/tonlib/tonlib/keys/DecryptedKey.cpp +++ b/tonlib/tonlib/keys/DecryptedKey.cpp @@ -42,12 +42,10 @@ EncryptedKey DecryptedKey::encrypt(td::Slice local_password, td::Slice old_secre } else { td::Random::secure_bytes(secret.as_mutable_slice()); } - td::SecureString decrypted_secret(32); - hmac_sha256(secret, local_password, decrypted_secret.as_mutable_slice()); + td::SecureString decrypted_secret = SimpleEncryption::combine_secrets(secret, local_password); - td::SecureString encryption_secret(64); - pbkdf2_sha512(as_slice(decrypted_secret), "TON local key", EncryptedKey::PBKDF_ITERATIONS, - encryption_secret.as_mutable_slice()); + td::SecureString encryption_secret = + SimpleEncryption::kdf(as_slice(decrypted_secret), "TON local key", EncryptedKey::PBKDF_ITERATIONS); std::vector mnemonic_words_copy; for (auto &w : mnemonic_words) { diff --git a/tonlib/tonlib/keys/EncryptedKey.cpp b/tonlib/tonlib/keys/EncryptedKey.cpp index 65de8c8d..893b9587 100644 --- a/tonlib/tonlib/keys/EncryptedKey.cpp +++ b/tonlib/tonlib/keys/EncryptedKey.cpp @@ -28,19 +28,21 @@ td::Result EncryptedKey::decrypt(td::Slice local_password, bool ch if (secret.size() != 32) { return td::Status::Error("Failed to decrypt key: invalid secret size"); } - td::SecureString decrypted_secret(32); + td::SecureString decrypted_secret; if (old) { + decrypted_secret = td::SecureString(32); td::SecureString local_password_hash(32); sha256(local_password, local_password_hash.as_mutable_slice()); for (size_t i = 0; i < 32; i++) { decrypted_secret.as_mutable_slice()[i] = secret.as_slice()[i] ^ local_password_hash.as_slice()[i]; } } else { - hmac_sha256(secret, local_password, decrypted_secret.as_mutable_slice()); + decrypted_secret = SimpleEncryption::combine_secrets(secret, local_password); } - td::SecureString encryption_secret(64); - pbkdf2_sha512(as_slice(decrypted_secret), "TON local key", PBKDF_ITERATIONS, encryption_secret.as_mutable_slice()); + td::SecureString encryption_secret = + SimpleEncryption::kdf(as_slice(decrypted_secret), "TON local key", EncryptedKey::PBKDF_ITERATIONS); + TRY_RESULT(decrypted_data, SimpleEncryption::decrypt_data(as_slice(encrypted_data), as_slice(encryption_secret))); RawDecryptedKey raw_decrypted_key; diff --git a/tonlib/tonlib/keys/SimpleEncryption.cpp b/tonlib/tonlib/keys/SimpleEncryption.cpp index 026a3429..586070b0 100644 --- a/tonlib/tonlib/keys/SimpleEncryption.cpp +++ b/tonlib/tonlib/keys/SimpleEncryption.cpp @@ -50,6 +50,12 @@ td::SecureString SimpleEncryption::combine_secrets(td::Slice a, td::Slice b) { return res; } +td::SecureString SimpleEncryption::kdf(td::Slice secret, td::Slice password, int iterations) { + td::SecureString new_secret(64); + pbkdf2_sha512(secret, password, iterations, new_secret.as_mutable_slice()); + return new_secret; +} + td::SecureString SimpleEncryption::encrypt_data_with_prefix(td::Slice data, td::Slice secret) { CHECK(data.size() % 16 == 0); auto data_hash = sha256(data); diff --git a/tonlib/tonlib/keys/SimpleEncryption.h b/tonlib/tonlib/keys/SimpleEncryption.h index 981925b2..69d5629a 100644 --- a/tonlib/tonlib/keys/SimpleEncryption.h +++ b/tonlib/tonlib/keys/SimpleEncryption.h @@ -27,13 +27,14 @@ class SimpleEncryption { public: static td::SecureString encrypt_data(td::Slice data, td::Slice secret); static td::Result decrypt_data(td::Slice encrypted_data, td::Slice secret); + static td::SecureString combine_secrets(td::Slice a, td::Slice b); + static td::SecureString kdf(td::Slice secret, td::Slice password, int iterations); private: static td::AesCbcState calc_aes_cbc_state_hash(td::Slice hash); static td::AesCbcState calc_aes_cbc_state_sha512(td::Slice seed); static td::SecureString gen_random_prefix(td::int64 data_size); - static td::SecureString combine_secrets(td::Slice a, td::Slice b); static td::SecureString encrypt_data_with_prefix(td::Slice data, td::Slice secret); }; } // namespace tonlib diff --git a/tonlib/tonlib/tonlib-cli.cpp b/tonlib/tonlib/tonlib-cli.cpp index 8b3c94f8..f681474e 100644 --- a/tonlib/tonlib/tonlib-cli.cpp +++ b/tonlib/tonlib/tonlib-cli.cpp @@ -58,6 +58,9 @@ class TonlibCli : public td::actor::Actor { bool is_closing_{false}; td::uint32 ref_cnt_{1}; + td::int64 snd_bytes_{0}; + td::int64 rcv_bytes_{0}; + void start_up() override { class Cb : public td::TerminalIO::Callback { public: @@ -258,15 +261,21 @@ class TonlibCli : public td::actor::Actor { auto addr = parser.read_word(); auto bounceable = parser.read_word(); set_bounceable(addr, to_bool(bounceable, true)); + } else if (cmd == "netstats") { + dump_netstats(); } } + void dump_netstats() { + td::TerminalIO::out() << td::tag("snd", td::format::as_size(snd_bytes_)) << "\n"; + td::TerminalIO::out() << td::tag("rcv", td::format::as_size(rcv_bytes_)) << "\n"; + } void on_adnl_result(td::uint64 id, td::Result res) { using tonlib_api::make_object; if (res.is_ok()) { + rcv_bytes_ += res.ok().size(); send_query(make_object(id, res.move_as_ok().as_slice().str()), [](auto r_ok) { LOG_IF(ERROR, r_ok.is_error()) << r_ok.error(); }); - LOG(ERROR) << "!!!"; } else { send_query(make_object( id, make_object(res.error().code(), res.error().message().str())), @@ -279,6 +288,7 @@ class TonlibCli : public td::actor::Actor { if (result->get_id() == tonlib_api::updateSendLiteServerQuery::ID) { auto update = tonlib_api::move_object_as(std::move(result)); CHECK(!raw_client_.empty()); + snd_bytes_ += update->data_.size(); send_closure(raw_client_, &ton::adnl::AdnlExtClient::send_query, "query", td::BufferSlice(update->data_), td::Timestamp::in(5), [actor_id = actor_id(this), id = update->id_](td::Result res) { @@ -800,7 +810,7 @@ class TonlibCli : public td::actor::Actor { } void transfer(Address from, Address to, td::uint64 grams, td::Slice password, td::Slice message, bool allow_send_to_uninited) { - auto r_sz = td::to_integer_safe(message); + auto r_sz = td::to_integer_safe(message); auto msg = message.str(); if (r_sz.is_ok()) { msg = std::string(r_sz.ok(), 'Z');