1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

updated func and tonlib

This commit is contained in:
ton 2020-02-15 20:03:17 +04:00
parent 493ae2410c
commit a73d202ba2
50 changed files with 1340 additions and 271 deletions

View file

@ -154,30 +154,38 @@ TEST(Tonlib, InitClose) {
}
}
TEST(Tonlib, SimpleEncryption) {
template <class Encryption>
void test_encryption() {
std::string secret = "secret";
{
std::string data = "some private data";
std::string wrong_secret = "wrong secret";
auto encrypted_data = SimpleEncryption::encrypt_data(data, secret);
auto encrypted_data = Encryption::encrypt_data(data, secret);
LOG(ERROR) << encrypted_data.size();
auto decrypted_data = SimpleEncryption::decrypt_data(encrypted_data, secret).move_as_ok();
auto decrypted_data = Encryption::decrypt_data(encrypted_data, secret).move_as_ok();
CHECK(data == decrypted_data);
SimpleEncryption::decrypt_data(encrypted_data, wrong_secret).ensure_error();
SimpleEncryption::decrypt_data("", secret).ensure_error();
SimpleEncryption::decrypt_data(std::string(32, 'a'), secret).ensure_error();
SimpleEncryption::decrypt_data(std::string(33, 'a'), secret).ensure_error();
SimpleEncryption::decrypt_data(std::string(64, 'a'), secret).ensure_error();
SimpleEncryption::decrypt_data(std::string(128, 'a'), secret).ensure_error();
Encryption::decrypt_data(encrypted_data, wrong_secret).ensure_error();
Encryption::decrypt_data("", secret).ensure_error();
Encryption::decrypt_data(std::string(32, 'a'), secret).ensure_error();
Encryption::decrypt_data(std::string(33, 'a'), secret).ensure_error();
Encryption::decrypt_data(std::string(64, 'a'), secret).ensure_error();
Encryption::decrypt_data(std::string(128, 'a'), secret).ensure_error();
}
for (size_t i = 0; i < 255; i++) {
auto data = td::rand_string('a', 'z', static_cast<int>(i));
auto encrypted_data = SimpleEncryption::encrypt_data(data, secret);
auto decrypted_data = SimpleEncryption::decrypt_data(encrypted_data, secret).move_as_ok();
auto encrypted_data = Encryption::encrypt_data(data, secret);
auto decrypted_data = Encryption::decrypt_data(encrypted_data, secret).move_as_ok();
CHECK(data == decrypted_data);
}
}
TEST(Tonlib, SimpleEncryption) {
test_encryption<SimpleEncryption>();
}
TEST(Tonlib, SimpleEncryptionV2) {
test_encryption<SimpleEncryptionV2>();
}
TEST(Tonlib, SimpleEncryptionAsym) {
auto private_key = td::Ed25519::generate_private_key().move_as_ok();
@ -187,26 +195,26 @@ TEST(Tonlib, SimpleEncryptionAsym) {
auto wrong_private_key = td::Ed25519::generate_private_key().move_as_ok();
{
std::string data = "some private data";
auto encrypted_data = SimpleEncryption::encrypt_data(data, public_key, other_private_key).move_as_ok();
auto encrypted_data = SimpleEncryptionV2::encrypt_data(data, public_key, other_private_key).move_as_ok();
LOG(ERROR) << encrypted_data.size();
auto decrypted_data = SimpleEncryption::decrypt_data(encrypted_data, private_key).move_as_ok();
auto decrypted_data = SimpleEncryptionV2::decrypt_data(encrypted_data, private_key).move_as_ok();
CHECK(data == decrypted_data);
auto decrypted_data2 = SimpleEncryption::decrypt_data(encrypted_data, other_private_key).move_as_ok();
auto decrypted_data2 = SimpleEncryptionV2::decrypt_data(encrypted_data, other_private_key).move_as_ok();
CHECK(data == decrypted_data2);
SimpleEncryption::decrypt_data(encrypted_data, wrong_private_key).ensure_error();
SimpleEncryption::decrypt_data("", private_key).ensure_error();
SimpleEncryption::decrypt_data(std::string(32, 'a'), private_key).ensure_error();
SimpleEncryption::decrypt_data(std::string(33, 'a'), private_key).ensure_error();
SimpleEncryption::decrypt_data(std::string(64, 'a'), private_key).ensure_error();
SimpleEncryption::decrypt_data(std::string(128, 'a'), private_key).ensure_error();
SimpleEncryptionV2::decrypt_data(encrypted_data, wrong_private_key).ensure_error();
SimpleEncryptionV2::decrypt_data("", private_key).ensure_error();
SimpleEncryptionV2::decrypt_data(std::string(32, 'a'), private_key).ensure_error();
SimpleEncryptionV2::decrypt_data(std::string(33, 'a'), private_key).ensure_error();
SimpleEncryptionV2::decrypt_data(std::string(64, 'a'), private_key).ensure_error();
SimpleEncryptionV2::decrypt_data(std::string(128, 'a'), private_key).ensure_error();
}
for (size_t i = 0; i < 255; i++) {
auto data = td::rand_string('a', 'z', static_cast<int>(i));
auto encrypted_data = SimpleEncryption::encrypt_data(data, public_key, other_private_key).move_as_ok();
auto decrypted_data = SimpleEncryption::decrypt_data(encrypted_data, private_key).move_as_ok();
auto encrypted_data = SimpleEncryptionV2::encrypt_data(data, public_key, other_private_key).move_as_ok();
auto decrypted_data = SimpleEncryptionV2::decrypt_data(encrypted_data, private_key).move_as_ok();
CHECK(data == decrypted_data);
auto decrypted_data2 = SimpleEncryption::decrypt_data(encrypted_data, other_private_key).move_as_ok();
auto decrypted_data2 = SimpleEncryptionV2::decrypt_data(encrypted_data, other_private_key).move_as_ok();
CHECK(data == decrypted_data2);
}
}

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#include "KeyStorage.h"

View file

@ -14,7 +14,7 @@
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
Copyright 2017-2019 Telegram Systems LLP
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once

View file

@ -386,6 +386,15 @@ class AccountState {
{ton::HighloadWalletV2::get_init_code(wallet_revision_), ton::WalletV3::get_init_data(key, wallet_id_)});
return wallet_type_;
}
o_revision = ton::ManualDns::guess_revision(address_, key, wallet_id_);
if (o_revision) {
wallet_type_ = WalletType::ManualDns;
wallet_revision_ = o_revision.value();
LOG(ERROR) << "!!!" << wallet_revision_;
auto dns = ton::ManualDns::create(key, wallet_id_, wallet_revision_);
set_new_state(dns->get_state());
return wallet_type_;
}
if (ton::GenericAccount::get_address(address_.workchain, ton::TestWallet::get_init_state(key)).addr ==
address_.addr) {
set_new_state({ton::TestWallet::get_init_code(), ton::TestWallet::get_init_data(key)});
@ -399,12 +408,6 @@ class AccountState {
.addr == address_.addr) {
set_new_state({ton::HighloadWallet::get_init_code(), ton::HighloadWallet::get_init_data(key, wallet_id_)});
wallet_type_ = WalletType::HighloadWalletV1;
} else {
auto dns = ton::ManualDns::create(key, wallet_id_);
if (dns->get_address().addr == address_.addr) {
set_new_state(dns->get_state());
wallet_type_ = WalletType::ManualDns;
}
}
return wallet_type_;
}
@ -466,6 +469,12 @@ class AccountState {
wallet_revision_ = o_revision.value();
return wallet_type_;
}
o_revision = ton::ManualDns::guess_revision(code_hash);
if (o_revision) {
wallet_type_ = WalletType::ManualDns;
wallet_revision_ = o_revision.value();
return wallet_type_;
}
if (code_hash == ton::TestGiver::get_init_code_hash()) {
wallet_type_ = WalletType::Giver;
@ -475,8 +484,6 @@ class AccountState {
wallet_type_ = WalletType::Wallet;
} else if (code_hash == ton::HighloadWallet::get_init_code_hash()) {
wallet_type_ = WalletType::HighloadWalletV1;
} else if (code_hash == ton::SmartContractCode::dns_manual()->get_hash()) {
wallet_type_ = WalletType::ManualDns;
} else {
LOG(WARNING) << "Unknown code hash: " << td::base64_encode(code_hash.as_slice());
wallet_type_ = WalletType::Unknown;
@ -1308,7 +1315,7 @@ td::Result<block::StdAddress> get_account_address(const tonlib_api::dns_initialA
td::int32 revision) {
TRY_RESULT(key_bytes, get_public_key(dns_state.public_key_));
auto key = td::Ed25519::PublicKey(td::SecureString(key_bytes.key));
return ton::ManualDns::create(key, static_cast<td::uint32>(dns_state.wallet_id_))->get_address();
return ton::ManualDns::create(key, static_cast<td::uint32>(dns_state.wallet_id_), revision)->get_address();
}
td::Result<block::StdAddress> get_account_address(td::Slice account_address) {
@ -1621,6 +1628,7 @@ struct ToRawTransactions {
}
auto body_hash = vm::CellBuilder().append_cellslice(*body).finalize()->get_hash().as_slice().str();
std::string body_message;
bool is_encrypted = false;
if (body->size() >= 32 && body->prefetch_long(32) <= 1) {
auto type = body.write().fetch_long(32);
auto r_body_message = vm::CellString::load(body.write());
@ -1631,7 +1639,8 @@ struct ToRawTransactions {
if (!private_key_) {
return TonlibError::EmptyField("private_key");
}
TRY_RESULT(decrypted, SimpleEncryption::decrypt_data(message, private_key_.value()));
TRY_RESULT(decrypted, SimpleEncryptionV2::decrypt_data(message, private_key_.value()));
is_encrypted = true;
return decrypted.as_slice().str();
}();
}
@ -1644,7 +1653,7 @@ struct ToRawTransactions {
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), std::move(dest), balance, fwd_fee,
ihr_fee, created_lt, std::move(body_hash),
std::move(body_message));
std::move(body_message), is_encrypted);
}
case block::gen::CommonMsgInfo::ext_in_msg_info: {
block::gen::CommonMsgInfo::Record_ext_in_msg_info msg_info;
@ -1661,7 +1670,7 @@ struct ToRawTransactions {
}
auto body_hash = vm::CellBuilder().append_cellslice(*body).finalize()->get_hash().as_slice().str();
return tonlib_api::make_object<tonlib_api::raw_message>("", std::move(dest), 0, 0, 0, 0, std::move(body_hash),
"");
"", false);
}
case block::gen::CommonMsgInfo::ext_out_msg_info: {
block::gen::CommonMsgInfo::Record_ext_out_msg_info msg_info;
@ -1669,7 +1678,7 @@ struct ToRawTransactions {
return td::Status::Error("Failed to unpack CommonMsgInfo::ext_out_msg_info");
}
TRY_RESULT(src, to_std_address(msg_info.src));
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), "", 0, 0, 0, 0, "", "");
return tonlib_api::make_object<tonlib_api::raw_message>(std::move(src), "", 0, 0, 0, 0, "", "", false);
}
}
@ -2207,13 +2216,13 @@ class GenericCreateSendGrams : public TonlibQueryActor {
return TonlibError::EmptyField("private_key");
}
if (!destination->is_wallet()) {
return TonlibError::AccountActionUnsupported("Get public key (in destination)");
return TonlibError::MessageEncryption("Get public key (in destination)");
}
auto wallet = destination->get_wallet();
TRY_RESULT_PREFIX(public_key, wallet->get_public_key(),
TonlibError::AccountActionUnsupported("Get public key (in destination)"));
TRY_RESULT_PREFIX(encrypted_message,
SimpleEncryption::encrypt_data(action.message, public_key, private_key_.value()),
SimpleEncryptionV2::encrypt_data(action.message, public_key, private_key_.value()),
TonlibError::Internal());
gift.message = encrypted_message.as_slice().str();
gift.is_encrypted = true;

View file

@ -95,6 +95,9 @@ struct TonlibError {
static td::Status DangerousTransaction(td::Slice reason) {
return td::Status::Error(400, PSLICE() << "DANGEROUS_TRANSACTION: " << reason);
}
static td::Status MessageEncryption(td::Slice reason) {
return td::Status::Error(400, PSLICE() << "MESSAGE_ENCRYPTION: " << reason);
}
static td::Status AccountNotInited() {
return td::Status::Error(400, "ACCOUNT_NOT_INITED");
}

View file

@ -37,8 +37,8 @@ td::AesCbcState SimpleEncryption::calc_aes_cbc_state_sha512(td::Slice seed) {
return calc_aes_cbc_state_hash(hash.as_slice());
}
td::SecureString SimpleEncryption::gen_random_prefix(td::int64 data_size) {
td::SecureString buff(td::narrow_cast<size_t>(((32 + 15 + data_size) & -16) - data_size), 0);
td::SecureString SimpleEncryption::gen_random_prefix(td::int64 data_size, td::int64 min_padding) {
td::SecureString buff(td::narrow_cast<size_t>(((min_padding + 15 + data_size) & -16) - data_size), 0);
td::Random::secure_bytes(buff.as_mutable_slice());
buff.as_mutable_slice()[0] = td::narrow_cast<td::uint8>(buff.size());
CHECK((buff.size() + data_size) % 16 == 0);
@ -72,7 +72,7 @@ td::SecureString SimpleEncryption::encrypt_data_with_prefix(td::Slice data, td::
}
td::SecureString SimpleEncryption::encrypt_data(td::Slice data, td::Slice secret) {
auto prefix = gen_random_prefix(data.size());
auto prefix = gen_random_prefix(data.size(), 32);
td::SecureString combined(prefix.size() + data.size());
combined.as_mutable_slice().copy_from(prefix);
combined.as_mutable_slice().substr(prefix.size()).copy_from(data);
@ -106,7 +106,8 @@ td::Result<td::SecureString> SimpleEncryption::decrypt_data(td::Slice encrypted_
return td::SecureString(decrypted_data.as_slice().substr(prefix_size));
}
td::Result<td::SecureString> SimpleEncryption::encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key) {
td::Result<td::SecureString> SimpleEncryptionV2::encrypt_data(td::Slice data,
const td::Ed25519::PublicKey &public_key) {
TRY_RESULT(tmp_private_key, td::Ed25519::generate_private_key());
return encrypt_data(data, public_key, tmp_private_key);
}
@ -122,8 +123,8 @@ td::SecureString secure_xor(td::Slice a, td::Slice b) {
}
} // namespace
td::Result<td::SecureString> SimpleEncryption::encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key,
const td::Ed25519::PrivateKey &private_key) {
td::Result<td::SecureString> SimpleEncryptionV2::encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key,
const td::Ed25519::PrivateKey &private_key) {
TRY_RESULT(shared_secret, td::Ed25519::compute_shared_secret(public_key, private_key));
auto encrypted = encrypt_data(data, shared_secret.as_slice());
TRY_RESULT(tmp_public_key, private_key.get_public_key());
@ -135,8 +136,8 @@ td::Result<td::SecureString> SimpleEncryption::encrypt_data(td::Slice data, cons
return std::move(prefixed_encrypted);
}
td::Result<td::SecureString> SimpleEncryption::decrypt_data(td::Slice data,
const td::Ed25519::PrivateKey &private_key) {
td::Result<td::SecureString> SimpleEncryptionV2::decrypt_data(td::Slice data,
const td::Ed25519::PrivateKey &private_key) {
if (data.size() < td::Ed25519::PublicKey::LENGTH) {
return td::Status::Error("Failed to decrypte: data is too small");
}
@ -147,4 +148,53 @@ td::Result<td::SecureString> SimpleEncryption::decrypt_data(td::Slice data,
TRY_RESULT(decrypted, decrypt_data(data.substr(td::Ed25519::PublicKey::LENGTH), shared_secret.as_slice()));
return std::move(decrypted);
}
td::SecureString SimpleEncryptionV2::encrypt_data(td::Slice data, td::Slice secret) {
auto prefix = SimpleEncryption::gen_random_prefix(data.size(), 16);
td::SecureString combined(prefix.size() + data.size());
combined.as_mutable_slice().copy_from(prefix);
combined.as_mutable_slice().substr(prefix.size()).copy_from(data);
return encrypt_data_with_prefix(combined.as_slice(), secret);
}
td::Result<td::SecureString> SimpleEncryptionV2::decrypt_data(td::Slice encrypted_data, td::Slice secret) {
if (encrypted_data.size() < 17) {
return td::Status::Error("Failed to decrypt: data is too small");
}
if (encrypted_data.size() % 16 != 0) {
return td::Status::Error("Failed to decrypt: data size is not divisible by 16");
}
auto msg_key = encrypted_data.substr(0, 16);
encrypted_data = encrypted_data.substr(16);
auto cbc_state = SimpleEncryption::calc_aes_cbc_state_hash(SimpleEncryption::combine_secrets(secret, msg_key));
td::SecureString decrypted_data(encrypted_data.size(), 0);
cbc_state.decrypt(encrypted_data, decrypted_data.as_mutable_slice());
auto data_hash = SimpleEncryption::combine_secrets(decrypted_data, secret);
auto got_msg_key = data_hash.as_slice().substr(0, 16);
// check hash
if (msg_key != got_msg_key) {
return td::Status::Error("Failed to decrypt: hash mismatch");
}
td::uint8 prefix_size = static_cast<td::uint8>(decrypted_data[0]);
if (prefix_size > decrypted_data.size() || prefix_size < 16) {
return td::Status::Error("Failed to decrypt: invalid prefix size");
}
return td::SecureString(decrypted_data.as_slice().substr(prefix_size));
}
td::SecureString SimpleEncryptionV2::encrypt_data_with_prefix(td::Slice data, td::Slice secret) {
CHECK(data.size() % 16 == 0);
auto data_hash = SimpleEncryption::combine_secrets(data, secret);
auto msg_key = data_hash.as_slice().substr(0, 16);
td::SecureString res_buf(data.size() + 16, 0);
auto res = res_buf.as_mutable_slice();
res.copy_from(msg_key);
auto cbc_state = SimpleEncryption::calc_aes_cbc_state_hash(SimpleEncryption::combine_secrets(secret, msg_key));
cbc_state.encrypt(data, res.substr(16));
return res_buf;
}
} // namespace tonlib

View file

@ -31,16 +31,26 @@ class SimpleEncryption {
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, td::int64 min_padding);
static td::SecureString encrypt_data_with_prefix(td::Slice data, td::Slice secret);
friend class SimpleEncryptionV2;
};
class SimpleEncryptionV2 {
public:
static td::Result<td::SecureString> encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key);
static td::Result<td::SecureString> decrypt_data(td::Slice data, const td::Ed25519::PrivateKey &private_key);
static td::Result<td::SecureString> encrypt_data(td::Slice data, const td::Ed25519::PublicKey &public_key,
const td::Ed25519::PrivateKey &private_key);
static td::SecureString encrypt_data(td::Slice data, td::Slice secret);
static td::Result<td::SecureString> decrypt_data(td::Slice encrypted_data, td::Slice secret);
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 encrypt_data_with_prefix(td::Slice data, td::Slice secret);
};
} // namespace tonlib

View file

@ -1356,7 +1356,50 @@ class TonlibCli : public td::actor::Actor {
std::move(input_key), ton::move_tl_object_as<tonlib_api::accountAddress>(std::move(address.address)),
std::move(state->last_transaction_id_)),
promise.wrap([](auto res) {
td::TerminalIO::out() << to_string(res) << "\n";
td::StringBuilder sb;
for (tonlib_api::object_ptr<tonlib_api::raw_transaction>& t : res->transactions_) {
td::int64 balance = 0;
balance += t->in_msg_->value_;
for (auto& ot : t->out_msgs_) {
balance -= ot->value_;
}
if (balance >= 0) {
sb << Grams{td::uint64(balance)};
} else {
sb << "-" << Grams{td::uint64(-balance)};
}
sb << " Fee: " << Grams{td::uint64(t->fee_)};
if (t->in_msg_->source_.empty()) {
sb << " External ";
} else {
sb << " From " << t->in_msg_->source_;
}
if (!t->in_msg_->message_.empty()) {
sb << " ";
if (t->in_msg_->is_message_encrypted_) {
sb << "e";
}
sb << "msg{" << t->in_msg_->message_ << "}";
}
for (auto& ot : t->out_msgs_) {
sb << "\n\t";
if (ot->destination_.empty()) {
sb << " External ";
} else {
sb << " To " << ot->destination_;
}
sb << " " << Grams{td::uint64(ot->value_)};
if (!ot->message_.empty()) {
sb << " ";
if (ot->is_message_encrypted_) {
sb << "e";
}
sb << "msg{" << ot->message_ << "}";
}
}
sb << "\n";
}
td::TerminalIO::out() << sb.as_cslice() << "\n";
return td::Unit();
}));
}
@ -1364,6 +1407,7 @@ class TonlibCli : public td::actor::Actor {
void transfer(td::ConstParser& parser, td::Slice cmd, td::Promise<td::Unit> cmd_promise) {
bool from_file = false;
bool force = false;
bool use_encryption = false;
if (cmd != "init") {
td::ConstParser cmd_parser(cmd);
cmd_parser.advance(td::Slice("transfer").size());
@ -1374,6 +1418,8 @@ class TonlibCli : public td::actor::Actor {
from_file = true;
} else if (c == 'f') {
force = true;
} else if (c == 'e') {
use_encryption = true;
} else {
cmd_promise.set_error(td::Status::Error(PSLICE() << "Unknown suffix '" << c << "'"));
return;
@ -1394,13 +1440,21 @@ class TonlibCli : public td::actor::Actor {
auto add_message = [&](td::ConstParser& parser) {
auto to = parser.read_word();
auto grams = parser.read_word();
auto message = parser.read_word();
parser.skip_whitespaces();
auto message = parser.read_all();
Message res;
TRY_RESULT(address, to_account_address(to, false));
TRY_RESULT(amount, parse_grams(grams));
messages.push_back(tonlib_api::make_object<tonlib_api::msg_message>(
std::move(address.address), amount.nano, tonlib_api::make_object<tonlib_api::msg_dataText>(message.str())));
tonlib_api::object_ptr<tonlib_api::msg_Data> data;
if (use_encryption) {
data = tonlib_api::make_object<tonlib_api::msg_dataEncryptedText>(message.str());
} else {
data = tonlib_api::make_object<tonlib_api::msg_dataText>(message.str());
}
messages.push_back(
tonlib_api::make_object<tonlib_api::msg_message>(std::move(address.address), amount.nano, std::move(data)));
return td::Status::OK();
};