mirror of
https://github.com/monero-project/monero.git
synced 2025-05-03 00:54:48 -04:00
store secret keys encrypted where possible
The secret spend key is kept encrypted in memory, and decrypted on the fly when needed. Both spend and view secret keys are kept encrypted in a JSON field in the keys file. This avoids leaving the keys in memory due to being manipulated by the JSON I/O API.
This commit is contained in:
parent
ea37614efe
commit
e9ffa91257
16 changed files with 661 additions and 160 deletions
|
@ -44,6 +44,9 @@ extern "C"
|
|||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "account"
|
||||
|
||||
#define KEYS_ENCRYPTION_SALT 'k'
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
DISABLE_VS_WARNINGS(4244 4345)
|
||||
|
@ -60,7 +63,70 @@ DISABLE_VS_WARNINGS(4244 4345)
|
|||
m_device = &hwdev;
|
||||
MCDEBUG("device", "account_keys::set_device device type: "<<typeid(hwdev).name());
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
static void derive_key(const crypto::chacha_key &base_key, crypto::chacha_key &key)
|
||||
{
|
||||
static_assert(sizeof(base_key) == sizeof(crypto::hash), "chacha key and hash should be the same size");
|
||||
tools::scrubbed_arr<char, sizeof(base_key)+1> data;
|
||||
memcpy(data.data(), &base_key, sizeof(base_key));
|
||||
data[sizeof(base_key)] = KEYS_ENCRYPTION_SALT;
|
||||
crypto::generate_chacha_key(data.data(), sizeof(data), key, 1);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
static epee::wipeable_string get_key_stream(const crypto::chacha_key &base_key, const crypto::chacha_iv &iv, size_t bytes)
|
||||
{
|
||||
// derive a new key
|
||||
crypto::chacha_key key;
|
||||
derive_key(base_key, key);
|
||||
|
||||
// chacha
|
||||
epee::wipeable_string buffer0(std::string(bytes, '\0'));
|
||||
epee::wipeable_string buffer1 = buffer0;
|
||||
crypto::chacha20(buffer0.data(), buffer0.size(), key, iv, buffer1.data());
|
||||
return buffer1;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_keys::xor_with_key_stream(const crypto::chacha_key &key)
|
||||
{
|
||||
// encrypt a large enough byte stream with chacha20
|
||||
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (2 + m_multisig_keys.size()));
|
||||
const char *ptr = key_stream.data();
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
m_spend_secret_key.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
m_view_secret_key.data[i] ^= *ptr++;
|
||||
for (crypto::secret_key &k: m_multisig_keys)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
k.data[i] ^= *ptr++;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_keys::encrypt(const crypto::chacha_key &key)
|
||||
{
|
||||
m_encryption_iv = crypto::rand<crypto::chacha_iv>();
|
||||
xor_with_key_stream(key);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_keys::decrypt(const crypto::chacha_key &key)
|
||||
{
|
||||
xor_with_key_stream(key);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_keys::encrypt_viewkey(const crypto::chacha_key &key)
|
||||
{
|
||||
// encrypt a large enough byte stream with chacha20
|
||||
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * 2);
|
||||
const char *ptr = key_stream.data();
|
||||
ptr += sizeof(crypto::secret_key);
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
m_view_secret_key.data[i] ^= *ptr++;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_keys::decrypt_viewkey(const crypto::chacha_key &key)
|
||||
{
|
||||
encrypt_viewkey(key);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
account_base::account_base()
|
||||
{
|
||||
|
|
|
@ -44,18 +44,29 @@ namespace cryptonote
|
|||
crypto::secret_key m_view_secret_key;
|
||||
std::vector<crypto::secret_key> m_multisig_keys;
|
||||
hw::device *m_device = &hw::get_device("default");
|
||||
crypto::chacha_iv m_encryption_iv;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_account_address)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_secret_key)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_secret_key)
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys)
|
||||
const crypto::chacha_iv default_iv{{0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(m_encryption_iv, default_iv)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
account_keys& operator=(account_keys const&) = default;
|
||||
|
||||
void encrypt(const crypto::chacha_key &key);
|
||||
void decrypt(const crypto::chacha_key &key);
|
||||
void encrypt_viewkey(const crypto::chacha_key &key);
|
||||
void decrypt_viewkey(const crypto::chacha_key &key);
|
||||
|
||||
hw::device& get_device() const ;
|
||||
void set_device( hw::device &hwdev) ;
|
||||
|
||||
private:
|
||||
void xor_with_key_stream(const crypto::chacha_key &key);
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
|
@ -87,6 +98,11 @@ namespace cryptonote
|
|||
void forget_spend_key();
|
||||
const std::vector<crypto::secret_key> &get_multisig_keys() const { return m_keys.m_multisig_keys; }
|
||||
|
||||
void encrypt_keys(const crypto::chacha_key &key) { m_keys.encrypt(key); }
|
||||
void decrypt_keys(const crypto::chacha_key &key) { m_keys.decrypt(key); }
|
||||
void encrypt_viewkey(const crypto::chacha_key &key) { m_keys.encrypt_viewkey(key); }
|
||||
void decrypt_viewkey(const crypto::chacha_key &key) { m_keys.decrypt_viewkey(key); }
|
||||
|
||||
template <class t_archive>
|
||||
inline void serialize(t_archive &a, const unsigned int /*ver*/)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue