2015-05-27 12:08:46 +00:00
|
|
|
// Copyright (c) 2012-2015, The CryptoNote developers, The Bytecoin developers
|
2015-04-06 16:13:07 +00:00
|
|
|
//
|
|
|
|
// This file is part of Bytecoin.
|
|
|
|
//
|
|
|
|
// Bytecoin is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// Bytecoin is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with Bytecoin. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#include "WalletSerializer.h"
|
|
|
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
#include "serialization/BinaryOutputStreamSerializer.h"
|
|
|
|
#include "serialization/BinaryInputStreamSerializer.h"
|
|
|
|
#include "cryptonote_core/account.h"
|
|
|
|
#include "cryptonote_core/cryptonote_serialization.h"
|
|
|
|
#include "WalletUserTransactionsCache.h"
|
|
|
|
#include "WalletErrors.h"
|
|
|
|
#include "KeysStorage.h"
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
bool verifyKeys(const crypto::secret_key& sec, const crypto::public_key& expected_pub) {
|
|
|
|
crypto::public_key pub;
|
|
|
|
bool r = crypto::secret_key_to_public_key(sec, pub);
|
|
|
|
return r && expected_pub == pub;
|
|
|
|
}
|
|
|
|
|
|
|
|
void throwIfKeysMissmatch(const crypto::secret_key& sec, const crypto::public_key& expected_pub) {
|
|
|
|
if (!verifyKeys(sec, expected_pub))
|
2015-05-27 12:08:46 +00:00
|
|
|
throw std::system_error(make_error_code(CryptoNote::error::WRONG_PASSWORD));
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace CryptoNote {
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
WalletSerializer::WalletSerializer(CryptoNote::account_base& account, WalletUserTransactionsCache& transactionsCache) :
|
2015-04-06 16:13:07 +00:00
|
|
|
account(account),
|
|
|
|
transactionsCache(transactionsCache),
|
|
|
|
walletSerializationVersion(1)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void WalletSerializer::serialize(std::ostream& stream, const std::string& password, bool saveDetailed, const std::string& cache) {
|
|
|
|
std::stringstream plainArchive;
|
2015-05-27 12:08:46 +00:00
|
|
|
CryptoNote::BinaryOutputStreamSerializer serializer(plainArchive);
|
2015-04-06 16:13:07 +00:00
|
|
|
saveKeys(serializer);
|
|
|
|
|
|
|
|
serializer(saveDetailed, "has_details");
|
|
|
|
|
|
|
|
if (saveDetailed) {
|
|
|
|
serializer(transactionsCache, "details");
|
|
|
|
}
|
|
|
|
|
|
|
|
serializer.binary(const_cast<std::string&>(cache), "cache");
|
|
|
|
|
|
|
|
std::string plain = plainArchive.str();
|
|
|
|
std::string cipher;
|
|
|
|
|
|
|
|
crypto::chacha8_iv iv = encrypt(plain, password, cipher);
|
|
|
|
|
|
|
|
uint32_t version = walletSerializationVersion;
|
2015-05-27 12:08:46 +00:00
|
|
|
CryptoNote::BinaryOutputStreamSerializer s(stream);
|
2015-04-06 16:13:07 +00:00
|
|
|
s.beginObject("wallet");
|
|
|
|
s(version, "version");
|
|
|
|
s(iv, "iv");
|
|
|
|
s(cipher, "data");
|
|
|
|
s.endObject();
|
2015-05-27 12:08:46 +00:00
|
|
|
|
|
|
|
stream.flush();
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
void WalletSerializer::saveKeys(CryptoNote::ISerializer& serializer) {
|
|
|
|
CryptoNote::KeysStorage keys;
|
|
|
|
CryptoNote::account_keys acc = account.get_keys();
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
keys.creationTimestamp = account.get_createtime();
|
|
|
|
keys.spendPublicKey = acc.m_account_address.m_spendPublicKey;
|
|
|
|
keys.spendSecretKey = acc.m_spend_secret_key;
|
|
|
|
keys.viewPublicKey = acc.m_account_address.m_viewPublicKey;
|
|
|
|
keys.viewSecretKey = acc.m_view_secret_key;
|
|
|
|
|
|
|
|
keys.serialize(serializer, "keys");
|
|
|
|
}
|
|
|
|
|
|
|
|
crypto::chacha8_iv WalletSerializer::encrypt(const std::string& plain, const std::string& password, std::string& cipher) {
|
|
|
|
crypto::chacha8_key key;
|
|
|
|
crypto::cn_context context;
|
|
|
|
crypto::generate_chacha8_key(context, password, key);
|
|
|
|
|
|
|
|
cipher.resize(plain.size());
|
|
|
|
|
|
|
|
crypto::chacha8_iv iv = crypto::rand<crypto::chacha8_iv>();
|
|
|
|
crypto::chacha8(plain.data(), plain.size(), key, iv, &cipher[0]);
|
|
|
|
|
|
|
|
return iv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void WalletSerializer::deserialize(std::istream& stream, const std::string& password, std::string& cache) {
|
2015-05-27 12:08:46 +00:00
|
|
|
CryptoNote::BinaryInputStreamSerializer serializerEncrypted(stream);
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
serializerEncrypted.beginObject("wallet");
|
|
|
|
|
|
|
|
uint32_t version;
|
|
|
|
serializerEncrypted(version, "version");
|
|
|
|
|
|
|
|
crypto::chacha8_iv iv;
|
|
|
|
serializerEncrypted(iv, "iv");
|
|
|
|
|
|
|
|
std::string cipher;
|
|
|
|
serializerEncrypted(cipher, "data");
|
|
|
|
|
|
|
|
serializerEncrypted.endObject();
|
|
|
|
|
|
|
|
std::string plain;
|
|
|
|
decrypt(cipher, plain, iv, password);
|
|
|
|
|
|
|
|
std::stringstream decryptedStream(plain);
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
CryptoNote::BinaryInputStreamSerializer serializer(decryptedStream);
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
loadKeys(serializer);
|
|
|
|
throwIfKeysMissmatch(account.get_keys().m_view_secret_key, account.get_keys().m_account_address.m_viewPublicKey);
|
|
|
|
throwIfKeysMissmatch(account.get_keys().m_spend_secret_key, account.get_keys().m_account_address.m_spendPublicKey);
|
|
|
|
}
|
|
|
|
catch (std::exception&) {
|
2015-05-27 12:08:46 +00:00
|
|
|
throw std::system_error(make_error_code(CryptoNote::error::WRONG_PASSWORD));
|
2015-04-06 16:13:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool detailsSaved;
|
|
|
|
|
|
|
|
serializer(detailsSaved, "has_details");
|
|
|
|
|
|
|
|
if (detailsSaved) {
|
|
|
|
serializer(transactionsCache, "details");
|
|
|
|
}
|
|
|
|
|
|
|
|
serializer.binary(cache, "cache");
|
|
|
|
}
|
|
|
|
|
|
|
|
void WalletSerializer::decrypt(const std::string& cipher, std::string& plain, crypto::chacha8_iv iv, const std::string& password) {
|
|
|
|
crypto::chacha8_key key;
|
|
|
|
crypto::cn_context context;
|
|
|
|
crypto::generate_chacha8_key(context, password, key);
|
|
|
|
|
|
|
|
plain.resize(cipher.size());
|
|
|
|
|
|
|
|
crypto::chacha8(cipher.data(), cipher.size(), key, iv, &plain[0]);
|
|
|
|
}
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
void WalletSerializer::loadKeys(CryptoNote::ISerializer& serializer) {
|
|
|
|
CryptoNote::KeysStorage keys;
|
2015-04-06 16:13:07 +00:00
|
|
|
|
|
|
|
keys.serialize(serializer, "keys");
|
|
|
|
|
2015-05-27 12:08:46 +00:00
|
|
|
CryptoNote::account_keys acc;
|
2015-04-06 16:13:07 +00:00
|
|
|
acc.m_account_address.m_spendPublicKey = keys.spendPublicKey;
|
|
|
|
acc.m_spend_secret_key = keys.spendSecretKey;
|
|
|
|
acc.m_account_address.m_viewPublicKey = keys.viewPublicKey;
|
|
|
|
acc.m_view_secret_key = keys.viewSecretKey;
|
|
|
|
|
|
|
|
account.set_keys(acc);
|
|
|
|
account.set_createtime(keys.creationTimestamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|