mirror of
https://codeberg.org/anoncontributorxmr/monero.git
synced 2024-11-26 17:32:33 +00:00
Scrub keys from memory just before scope end.
Partially implements #74. Securely erases keys from memory after they are no longer needed. Might have a performance impact, which I haven't measured (perf measurements aren't generally reliable on laptops). Thanks to @stoffu for the suggestion to specialize the pod_to_hex/hex_to_pod functions. Using overloads + SFINAE instead generalizes it so other types can be marked as scrubbed without adding more boilerplate.
This commit is contained in:
parent
38ecd0526e
commit
7193b89fe5
6 changed files with 60 additions and 23 deletions
|
@ -108,7 +108,7 @@ namespace epee
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr bool has_padding() noexcept
|
constexpr bool has_padding() noexcept
|
||||||
{
|
{
|
||||||
return !std::is_pod<T>() || alignof(T) != 1;
|
return !std::is_pod<T>::value || alignof(T) != 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \return Cast data from `src` as `span<const std::uint8_t>`.
|
//! \return Cast data from `src` as `span<const std::uint8_t>`.
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
#include <array>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -39,3 +41,44 @@ void *memwipe(void *src, size_t n);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
namespace tools {
|
||||||
|
|
||||||
|
/// Scrubs data in the contained type upon destruction.
|
||||||
|
///
|
||||||
|
/// Primarily useful for making sure that private keys don't stick around in
|
||||||
|
/// memory after the objects that held them have gone out of scope.
|
||||||
|
template <class T>
|
||||||
|
struct scrubbed : public T {
|
||||||
|
using type = T;
|
||||||
|
|
||||||
|
~scrubbed() {
|
||||||
|
scrub();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Destroy the contents of the contained type.
|
||||||
|
void scrub() {
|
||||||
|
static_assert(std::is_pod<T>::value,
|
||||||
|
"T cannot be auto-scrubbed. T must be POD.");
|
||||||
|
static_assert(std::is_trivially_destructible<T>::value,
|
||||||
|
"T cannot be auto-scrubbed. T must be trivially destructable.");
|
||||||
|
memwipe(this, sizeof(T));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, size_t N>
|
||||||
|
using scrubbed_arr = scrubbed<std::array<T, N>>;
|
||||||
|
} // namespace tools
|
||||||
|
|
||||||
|
// Partial specialization for std::is_pod<tools::scrubbed<T>> so that it can
|
||||||
|
// pretend to be the containted type in those contexts.
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
template<class t_scrubbee>
|
||||||
|
struct is_pod<tools::scrubbed<t_scrubbee>> {
|
||||||
|
static const bool value = is_pod<t_scrubbee>::value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
|
@ -49,16 +49,9 @@ namespace crypto {
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using chacha8_key = tools::scrubbed_arr<uint8_t, CHACHA8_KEY_SIZE>;
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct chacha8_key {
|
|
||||||
uint8_t data[CHACHA8_KEY_SIZE];
|
|
||||||
|
|
||||||
~chacha8_key()
|
|
||||||
{
|
|
||||||
memwipe(data, sizeof(data));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// MS VC 2012 doesn't interpret `class chacha8_iv` as POD in spite of [9.0.10], so it is a struct
|
// MS VC 2012 doesn't interpret `class chacha8_iv` as POD in spite of [9.0.10], so it is a struct
|
||||||
struct chacha8_iv {
|
struct chacha8_iv {
|
||||||
uint8_t data[CHACHA8_IV_SIZE];
|
uint8_t data[CHACHA8_IV_SIZE];
|
||||||
|
@ -68,15 +61,14 @@ namespace crypto {
|
||||||
static_assert(sizeof(chacha8_key) == CHACHA8_KEY_SIZE && sizeof(chacha8_iv) == CHACHA8_IV_SIZE, "Invalid structure size");
|
static_assert(sizeof(chacha8_key) == CHACHA8_KEY_SIZE && sizeof(chacha8_iv) == CHACHA8_IV_SIZE, "Invalid structure size");
|
||||||
|
|
||||||
inline void chacha8(const void* data, std::size_t length, const chacha8_key& key, const chacha8_iv& iv, char* cipher) {
|
inline void chacha8(const void* data, std::size_t length, const chacha8_key& key, const chacha8_iv& iv, char* cipher) {
|
||||||
chacha8(data, length, reinterpret_cast<const uint8_t*>(&key), reinterpret_cast<const uint8_t*>(&iv), cipher);
|
chacha8(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void generate_chacha8_key(const void *data, size_t size, 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");
|
static_assert(sizeof(chacha8_key) <= sizeof(hash), "Size of hash must be at least that of chacha8_key");
|
||||||
char pwd_hash[HASH_SIZE];
|
tools::scrubbed_arr<char, HASH_SIZE> pwd_hash;
|
||||||
crypto::cn_slow_hash(data, size, pwd_hash);
|
crypto::cn_slow_hash(data, size, pwd_hash.data());
|
||||||
memcpy(&key, pwd_hash, sizeof(key));
|
memcpy(&key, pwd_hash.data(), sizeof(key));
|
||||||
memwipe(pwd_hash, sizeof(pwd_hash));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void generate_chacha8_key(std::string password, chacha8_key& key) {
|
inline void generate_chacha8_key(std::string password, chacha8_key& key) {
|
||||||
|
|
|
@ -36,9 +36,12 @@
|
||||||
#include <boost/thread/lock_guard.hpp>
|
#include <boost/thread/lock_guard.hpp>
|
||||||
#include <boost/utility/value_init.hpp>
|
#include <boost/utility/value_init.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "common/pod-class.h"
|
#include "common/pod-class.h"
|
||||||
|
#include "common/util.h"
|
||||||
|
#include "common/memwipe.h"
|
||||||
#include "generic-ops.h"
|
#include "generic-ops.h"
|
||||||
#include "hex.h"
|
#include "hex.h"
|
||||||
#include "span.h"
|
#include "span.h"
|
||||||
|
@ -65,9 +68,7 @@ namespace crypto {
|
||||||
friend class crypto_ops;
|
friend class crypto_ops;
|
||||||
};
|
};
|
||||||
|
|
||||||
POD_CLASS secret_key: ec_scalar {
|
using secret_key = tools::scrubbed<ec_scalar>;
|
||||||
friend class crypto_ops;
|
|
||||||
};
|
|
||||||
|
|
||||||
POD_CLASS public_keyV {
|
POD_CLASS public_keyV {
|
||||||
std::vector<public_key> keys;
|
std::vector<public_key> keys;
|
||||||
|
|
|
@ -57,6 +57,7 @@ using namespace epee;
|
||||||
#include "rapidjson/writer.h"
|
#include "rapidjson/writer.h"
|
||||||
#include "rapidjson/stringbuffer.h"
|
#include "rapidjson/stringbuffer.h"
|
||||||
#include "common/json_util.h"
|
#include "common/json_util.h"
|
||||||
|
#include "common/memwipe.h"
|
||||||
#include "common/base58.h"
|
#include "common/base58.h"
|
||||||
#include "ringct/rctSigs.h"
|
#include "ringct/rctSigs.h"
|
||||||
|
|
||||||
|
@ -2761,12 +2762,11 @@ bool wallet2::generate_chacha8_key_from_secret_keys(crypto::chacha8_key &key) co
|
||||||
const account_keys &keys = m_account.get_keys();
|
const account_keys &keys = m_account.get_keys();
|
||||||
const crypto::secret_key &view_key = keys.m_view_secret_key;
|
const crypto::secret_key &view_key = keys.m_view_secret_key;
|
||||||
const crypto::secret_key &spend_key = keys.m_spend_secret_key;
|
const crypto::secret_key &spend_key = keys.m_spend_secret_key;
|
||||||
char data[sizeof(view_key) + sizeof(spend_key) + 1];
|
tools::scrubbed_arr<char, sizeof(view_key) + sizeof(spend_key) + 1> data;
|
||||||
memcpy(data, &view_key, sizeof(view_key));
|
memcpy(data.data(), &view_key, sizeof(view_key));
|
||||||
memcpy(data + sizeof(view_key), &spend_key, sizeof(spend_key));
|
memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key));
|
||||||
data[sizeof(data) - 1] = CHACHA8_KEY_TAIL;
|
data[sizeof(data) - 1] = CHACHA8_KEY_TAIL;
|
||||||
crypto::generate_chacha8_key(data, sizeof(data), key);
|
crypto::generate_chacha8_key(data.data(), sizeof(data), key);
|
||||||
memset(data, 0, sizeof(data));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -42,6 +42,7 @@ add_executable(cncrypto-tests
|
||||||
${crypto_headers})
|
${crypto_headers})
|
||||||
target_link_libraries(cncrypto-tests
|
target_link_libraries(cncrypto-tests
|
||||||
PRIVATE
|
PRIVATE
|
||||||
|
common
|
||||||
${Boost_SYSTEM_LIBRARY}
|
${Boost_SYSTEM_LIBRARY}
|
||||||
${EXTRA_LIBRARIES})
|
${EXTRA_LIBRARIES})
|
||||||
set_property(TARGET cncrypto-tests
|
set_property(TARGET cncrypto-tests
|
||||||
|
|
Loading…
Reference in a new issue