Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wallet: encrypt the cache file #381

Merged
merged 2 commits into from
Aug 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/crypto/chacha8.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,17 @@ namespace crypto {
chacha8(data, length, reinterpret_cast<const uint8_t*>(&key), reinterpret_cast<const uint8_t*>(&iv), cipher);
}

inline void generate_chacha8_key(std::string password, chacha8_key& key) {
inline void generate_chacha8_key(const void *data, size_t size, chacha8_key& key) {
static_assert(sizeof(chacha8_key) <= sizeof(hash), "Size of hash must be at least that of chacha8_key");
char pwd_hash[HASH_SIZE];
crypto::cn_slow_hash(password.data(), password.size(), pwd_hash);
crypto::cn_slow_hash(data, size, pwd_hash);
memcpy(&key, pwd_hash, sizeof(key));
memset(pwd_hash, 0, sizeof(pwd_hash));
}

inline void generate_chacha8_key(std::string password, chacha8_key& key) {
return generate_chacha8_key(password.data(), password.size(), key);
}
}

#endif
66 changes: 64 additions & 2 deletions src/wallet/wallet2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ using namespace cryptonote;
// used to target a given block size (additional outputs may be added on top to build fee)
#define TX_SIZE_TARGET(bytes) (bytes*2/3)

// arbitrary, used to generate different hashes from the same input
#define CHACHA8_KEY_TAIL 0x8c

namespace
{
void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file)
Expand Down Expand Up @@ -853,6 +856,20 @@ bool wallet2::check_connection()
return m_http_client.connect(u.host, std::to_string(u.port), WALLET_RCP_CONNECTION_TIMEOUT);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::generate_chacha8_key_from_secret_keys(crypto::chacha8_key &key) const
{
const account_keys &keys = m_account.get_keys();
const crypto::secret_key &view_key = keys.m_view_secret_key;
const crypto::secret_key &spend_key = keys.m_spend_secret_key;
char data[sizeof(view_key) + sizeof(spend_key) + 1];
memcpy(data, &view_key, sizeof(view_key));
memcpy(data + sizeof(view_key), &spend_key, sizeof(spend_key));
data[sizeof(data) - 1] = CHACHA8_KEY_TAIL;
crypto::generate_chacha8_key(data, sizeof(data), key);
memset(data, 0, sizeof(data));
return true;
}
//----------------------------------------------------------------------------------------------------
void wallet2::load(const std::string& wallet_, const std::string& password)
{
clear();
Expand All @@ -874,8 +891,37 @@ void wallet2::load(const std::string& wallet_, const std::string& password)
}
else
{
bool r = tools::unserialize_obj_from_file(*this, m_wallet_file);
wallet2::cache_file_data cache_file_data;
std::string buf;
bool r = epee::file_io_utils::load_file_to_string(m_wallet_file, buf);
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, m_wallet_file);

// try to read it as an encrypted cache
try
{
LOG_PRINT_L1("Trying to decrypt cache data");

r = ::serialization::parse_binary(buf, cache_file_data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + m_wallet_file + '\"');
crypto::chacha8_key key;
generate_chacha8_key_from_secret_keys(key);
std::string cache_data;
cache_data.resize(cache_file_data.cache_data.size());
crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cache_data[0]);

std::stringstream iss;
iss << cache_data;
boost::archive::binary_iarchive ar(iss);
ar >> *this;
}
catch (...)
{
LOG_PRINT_L1("Failed to load encrypted cache, trying unencrypted");
std::stringstream iss;
iss << buf;
boost::archive::binary_iarchive ar(iss);
ar >> *this;
}
THROW_WALLET_EXCEPTION_IF(
m_account_public_address.m_spend_public_key != m_account.get_keys().m_account_address.m_spend_public_key ||
m_account_public_address.m_view_public_key != m_account.get_keys().m_account_address.m_view_public_key,
Expand Down Expand Up @@ -906,7 +952,23 @@ void wallet2::check_genesis(const crypto::hash& genesis_hash) const {
//----------------------------------------------------------------------------------------------------
void wallet2::store()
{
bool r = tools::serialize_obj_to_file(*this, m_wallet_file);
std::stringstream oss;
boost::archive::binary_oarchive ar(oss);
ar << *this;

wallet2::cache_file_data cache_file_data = boost::value_initialized<wallet2::cache_file_data>();
cache_file_data.cache_data = oss.str();
crypto::chacha8_key key;
generate_chacha8_key_from_secret_keys(key);
std::string cipher;
cipher.resize(cache_file_data.cache_data.size());
cache_file_data.iv = crypto::rand<crypto::chacha8_iv>();
crypto::chacha8(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), key, cache_file_data.iv, &cipher[0]);
cache_file_data.cache_data = cipher;

std::string buf;
bool r = ::serialization::dump_binary(cache_file_data, buf);
r = r && epee::file_io_utils::save_string_to_file(m_wallet_file, buf);
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file);
}
//----------------------------------------------------------------------------------------------------
Expand Down
12 changes: 12 additions & 0 deletions src/wallet/wallet2.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,17 @@ namespace tools
END_SERIALIZE()
};

struct cache_file_data
{
crypto::chacha8_iv iv;
std::string cache_data;

BEGIN_SERIALIZE_OBJECT()
FIELD(iv)
FIELD(cache_data)
END_SERIALIZE()
};

/*!
* \brief Generates a wallet or restores one.
* \param wallet_ Name of wallet file
Expand Down Expand Up @@ -307,6 +318,7 @@ namespace tools
void add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t change_amount);
void generate_genesis(cryptonote::block& b);
void check_genesis(const crypto::hash& genesis_hash) const; //throws
bool generate_chacha8_key_from_secret_keys(crypto::chacha8_key &key) const;

cryptonote::account_base m_account;
std::string m_daemon_address;
Expand Down