danicoin/src/WalletLegacy/WalletLegacySerializer.cpp
2016-01-18 15:33:29 +00:00

175 lines
5.2 KiB
C++
Executable file

// Copyright (c) 2011-2016 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#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);
loadKeys(serializer);
throwIfKeysMissmatch(account.getAccountKeys().viewSecretKey, account.getAccountKeys().address.viewPublicKey);
if (account.getAccountKeys().spendSecretKey != NULL_SECRET_KEY) {
throwIfKeysMissmatch(account.getAccountKeys().spendSecretKey, account.getAccountKeys().address.spendPublicKey);
} else {
if (!Crypto::check_key(account.getAccountKeys().address.spendPublicKey)) {
throw std::system_error(make_error_code(CryptoNote::error::WRONG_PASSWORD));
}
}
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);
}
}