2016-01-18 15:33:29 +00:00
|
|
|
// Copyright (c) 2011-2016 The Cryptonote developers
|
2015-09-18 11:55:31 +00:00
|
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
2015-07-30 15:22:07 +00:00
|
|
|
|
|
|
|
#include "WalletLegacySerializer.h"
|
|
|
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
#include "Common/MemoryInputStream.h"
|
|
|
|
#include "Common/StdInputStream.h"
|
|
|
|
#include "Common/StdOutputStream.h"
|
|
|
|
#include "Serialization/BinaryOutputStreamSerializer.h"
|
|
|
|
#include "Serialization/BinaryInputStreamSerializer.h"
|
|
|
|
#include "CryptoNoteCore/Account.h"
|
|
|
|
#include "CryptoNoteCore/CryptoNoteSerialization.h"
|
|
|
|
#include "WalletLegacy/WalletUserTransactionsCache.h"
|
|
|
|
#include "Wallet/WalletErrors.h"
|
|
|
|
#include "WalletLegacy/KeysStorage.h"
|
|
|
|
|
|
|
|
using namespace Common;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
bool verifyKeys(const Crypto::SecretKey& sec, const Crypto::PublicKey& expected_pub) {
|
|
|
|
Crypto::PublicKey pub;
|
|
|
|
bool r = Crypto::secret_key_to_public_key(sec, pub);
|
|
|
|
return r && expected_pub == pub;
|
|
|
|
}
|
|
|
|
|
|
|
|
void throwIfKeysMissmatch(const Crypto::SecretKey& sec, const Crypto::PublicKey& expected_pub) {
|
|
|
|
if (!verifyKeys(sec, expected_pub))
|
|
|
|
throw std::system_error(make_error_code(CryptoNote::error::WRONG_PASSWORD));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace CryptoNote {
|
|
|
|
|
|
|
|
WalletLegacySerializer::WalletLegacySerializer(CryptoNote::AccountBase& account, WalletUserTransactionsCache& transactionsCache) :
|
|
|
|
account(account),
|
|
|
|
transactionsCache(transactionsCache),
|
|
|
|
walletSerializationVersion(1)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void WalletLegacySerializer::serialize(std::ostream& stream, const std::string& password, bool saveDetailed, const std::string& cache) {
|
|
|
|
std::stringstream plainArchive;
|
|
|
|
StdOutputStream plainStream(plainArchive);
|
|
|
|
CryptoNote::BinaryOutputStreamSerializer serializer(plainStream);
|
|
|
|
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;
|
|
|
|
StdOutputStream output(stream);
|
|
|
|
CryptoNote::BinaryOutputStreamSerializer s(output);
|
|
|
|
s.beginObject("wallet");
|
|
|
|
s(version, "version");
|
|
|
|
s(iv, "iv");
|
|
|
|
s(cipher, "data");
|
|
|
|
s.endObject();
|
|
|
|
|
|
|
|
stream.flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
void WalletLegacySerializer::saveKeys(CryptoNote::ISerializer& serializer) {
|
|
|
|
CryptoNote::KeysStorage keys;
|
|
|
|
CryptoNote::AccountKeys acc = account.getAccountKeys();
|
|
|
|
|
|
|
|
keys.creationTimestamp = account.get_createtime();
|
|
|
|
keys.spendPublicKey = acc.address.spendPublicKey;
|
|
|
|
keys.spendSecretKey = acc.spendSecretKey;
|
|
|
|
keys.viewPublicKey = acc.address.viewPublicKey;
|
|
|
|
keys.viewSecretKey = acc.viewSecretKey;
|
|
|
|
|
|
|
|
keys.serialize(serializer, "keys");
|
|
|
|
}
|
|
|
|
|
|
|
|
Crypto::chacha8_iv WalletLegacySerializer::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 WalletLegacySerializer::deserialize(std::istream& stream, const std::string& password, std::string& cache) {
|
|
|
|
StdInputStream stdStream(stream);
|
|
|
|
CryptoNote::BinaryInputStreamSerializer serializerEncrypted(stdStream);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
MemoryInputStream decryptedStream(plain.data(), plain.size());
|
|
|
|
CryptoNote::BinaryInputStreamSerializer serializer(decryptedStream);
|
|
|
|
|
2015-08-11 14:33:19 +00:00
|
|
|
loadKeys(serializer);
|
|
|
|
throwIfKeysMissmatch(account.getAccountKeys().viewSecretKey, account.getAccountKeys().address.viewPublicKey);
|
|
|
|
|
|
|
|
if (account.getAccountKeys().spendSecretKey != NULL_SECRET_KEY) {
|
2015-07-30 15:22:07 +00:00
|
|
|
throwIfKeysMissmatch(account.getAccountKeys().spendSecretKey, account.getAccountKeys().address.spendPublicKey);
|
2015-08-11 14:33:19 +00:00
|
|
|
} else {
|
|
|
|
if (!Crypto::check_key(account.getAccountKeys().address.spendPublicKey)) {
|
|
|
|
throw std::system_error(make_error_code(CryptoNote::error::WRONG_PASSWORD));
|
|
|
|
}
|
2015-07-30 15:22:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool detailsSaved;
|
|
|
|
|
|
|
|
serializer(detailsSaved, "has_details");
|
|
|
|
|
|
|
|
if (detailsSaved) {
|
|
|
|
serializer(transactionsCache, "details");
|
|
|
|
}
|
|
|
|
|
|
|
|
serializer.binary(cache, "cache");
|
|
|
|
}
|
|
|
|
|
|
|
|
void WalletLegacySerializer::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]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WalletLegacySerializer::loadKeys(CryptoNote::ISerializer& serializer) {
|
|
|
|
CryptoNote::KeysStorage keys;
|
|
|
|
|
|
|
|
keys.serialize(serializer, "keys");
|
|
|
|
|
|
|
|
CryptoNote::AccountKeys acc;
|
|
|
|
acc.address.spendPublicKey = keys.spendPublicKey;
|
|
|
|
acc.spendSecretKey = keys.spendSecretKey;
|
|
|
|
acc.address.viewPublicKey = keys.viewPublicKey;
|
|
|
|
acc.viewSecretKey = keys.viewSecretKey;
|
|
|
|
|
|
|
|
account.setAccountKeys(acc);
|
|
|
|
account.set_createtime(keys.creationTimestamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|