mirror of
https://codeberg.org/anoncontributorxmr/monero.git
synced 2024-11-30 03:03:17 +00:00
ringdb: use a different iv for key and data in rings table
This is technically a record encrypted in two pieces, so the iv needs to be different. Some backward compatibility is added to read data written by existing code, but new data is written with the new code.
This commit is contained in:
parent
7b88208722
commit
0349347e6d
1 changed files with 37 additions and 18 deletions
|
@ -39,6 +39,8 @@
|
||||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||||
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.ringdb"
|
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.ringdb"
|
||||||
|
|
||||||
|
#define V1TAG ((uint64_t)798237759845202)
|
||||||
|
|
||||||
static const char zerokey[8] = {0};
|
static const char zerokey[8] = {0};
|
||||||
static const MDB_val zerokeyval = { sizeof(zerokey), (void *)zerokey };
|
static const MDB_val zerokeyval = { sizeof(zerokey), (void *)zerokey };
|
||||||
|
|
||||||
|
@ -63,15 +65,16 @@ static int compare_uint64(const MDB_val *a, const MDB_val *b)
|
||||||
return va < vb ? -1 : va > vb;
|
return va < vb ? -1 : va > vb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string compress_ring(const std::vector<uint64_t> &ring)
|
static std::string compress_ring(const std::vector<uint64_t> &ring, uint64_t tag)
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
|
s += tools::get_varint_data(tag);
|
||||||
for (uint64_t out: ring)
|
for (uint64_t out: ring)
|
||||||
s += tools::get_varint_data(out);
|
s += tools::get_varint_data(out);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<uint64_t> decompress_ring(const std::string &s)
|
static std::vector<uint64_t> decompress_ring(const std::string &s, uint64_t tag)
|
||||||
{
|
{
|
||||||
std::vector<uint64_t> ring;
|
std::vector<uint64_t> ring;
|
||||||
int read = 0;
|
int read = 0;
|
||||||
|
@ -81,6 +84,13 @@ static std::vector<uint64_t> decompress_ring(const std::string &s)
|
||||||
std::string tmp(i, s.cend());
|
std::string tmp(i, s.cend());
|
||||||
read = tools::read_varint(tmp.begin(), tmp.end(), out);
|
read = tools::read_varint(tmp.begin(), tmp.end(), out);
|
||||||
THROW_WALLET_EXCEPTION_IF(read <= 0 || read > 256, tools::error::wallet_internal_error, "Internal error decompressing ring");
|
THROW_WALLET_EXCEPTION_IF(read <= 0 || read > 256, tools::error::wallet_internal_error, "Internal error decompressing ring");
|
||||||
|
if (tag)
|
||||||
|
{
|
||||||
|
if (tag != out)
|
||||||
|
return {};
|
||||||
|
tag = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ring.push_back(out);
|
ring.push_back(out);
|
||||||
}
|
}
|
||||||
return ring;
|
return ring;
|
||||||
|
@ -93,25 +103,27 @@ std::string get_rings_filename(boost::filesystem::path filename)
|
||||||
return filename.string();
|
return filename.string();
|
||||||
}
|
}
|
||||||
|
|
||||||
static crypto::chacha_iv make_iv(const crypto::key_image &key_image, const crypto::chacha_key &key)
|
static crypto::chacha_iv make_iv(const crypto::key_image &key_image, const crypto::chacha_key &key, uint8_t field)
|
||||||
{
|
{
|
||||||
static const char salt[] = "ringdsb";
|
static const char salt[] = "ringdsb";
|
||||||
|
|
||||||
uint8_t buffer[sizeof(key_image) + sizeof(key) + sizeof(salt)];
|
uint8_t buffer[sizeof(key_image) + sizeof(key) + sizeof(salt) + sizeof(field)];
|
||||||
memcpy(buffer, &key_image, sizeof(key_image));
|
memcpy(buffer, &key_image, sizeof(key_image));
|
||||||
memcpy(buffer + sizeof(key_image), &key, sizeof(key));
|
memcpy(buffer + sizeof(key_image), &key, sizeof(key));
|
||||||
memcpy(buffer + sizeof(key_image) + sizeof(key), salt, sizeof(salt));
|
memcpy(buffer + sizeof(key_image) + sizeof(key), salt, sizeof(salt));
|
||||||
|
memcpy(buffer + sizeof(key_image) + sizeof(key) + sizeof(salt), &field, sizeof(field));
|
||||||
crypto::hash hash;
|
crypto::hash hash;
|
||||||
crypto::cn_fast_hash(buffer, sizeof(buffer), hash.data);
|
// if field is 0, backward compat mode: hash without the field
|
||||||
|
crypto::cn_fast_hash(buffer, sizeof(buffer) - !field, hash.data);
|
||||||
static_assert(sizeof(hash) >= CHACHA_IV_SIZE, "Incompatible hash and chacha IV sizes");
|
static_assert(sizeof(hash) >= CHACHA_IV_SIZE, "Incompatible hash and chacha IV sizes");
|
||||||
crypto::chacha_iv iv;
|
crypto::chacha_iv iv;
|
||||||
memcpy(&iv, &hash, CHACHA_IV_SIZE);
|
memcpy(&iv, &hash, CHACHA_IV_SIZE);
|
||||||
return iv;
|
return iv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string encrypt(const std::string &plaintext, const crypto::key_image &key_image, const crypto::chacha_key &key)
|
static std::string encrypt(const std::string &plaintext, const crypto::key_image &key_image, const crypto::chacha_key &key, uint8_t field)
|
||||||
{
|
{
|
||||||
const crypto::chacha_iv iv = make_iv(key_image, key);
|
const crypto::chacha_iv iv = make_iv(key_image, key, field);
|
||||||
std::string ciphertext;
|
std::string ciphertext;
|
||||||
ciphertext.resize(plaintext.size() + sizeof(iv));
|
ciphertext.resize(plaintext.size() + sizeof(iv));
|
||||||
crypto::chacha20(plaintext.data(), plaintext.size(), key, iv, &ciphertext[sizeof(iv)]);
|
crypto::chacha20(plaintext.data(), plaintext.size(), key, iv, &ciphertext[sizeof(iv)]);
|
||||||
|
@ -119,14 +131,14 @@ static std::string encrypt(const std::string &plaintext, const crypto::key_image
|
||||||
return ciphertext;
|
return ciphertext;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string encrypt(const crypto::key_image &key_image, const crypto::chacha_key &key)
|
static std::string encrypt(const crypto::key_image &key_image, const crypto::chacha_key &key, uint8_t field)
|
||||||
{
|
{
|
||||||
return encrypt(std::string((const char*)&key_image, sizeof(key_image)), key_image, key);
|
return encrypt(std::string((const char*)&key_image, sizeof(key_image)), key_image, key, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string decrypt(const std::string &ciphertext, const crypto::key_image &key_image, const crypto::chacha_key &key)
|
static std::string decrypt(const std::string &ciphertext, const crypto::key_image &key_image, const crypto::chacha_key &key, uint8_t field)
|
||||||
{
|
{
|
||||||
const crypto::chacha_iv iv = make_iv(key_image, key);
|
const crypto::chacha_iv iv = make_iv(key_image, key, field);
|
||||||
std::string plaintext;
|
std::string plaintext;
|
||||||
THROW_WALLET_EXCEPTION_IF(ciphertext.size() < sizeof(iv), tools::error::wallet_internal_error, "Bad ciphertext text");
|
THROW_WALLET_EXCEPTION_IF(ciphertext.size() < sizeof(iv), tools::error::wallet_internal_error, "Bad ciphertext text");
|
||||||
plaintext.resize(ciphertext.size() - sizeof(iv));
|
plaintext.resize(ciphertext.size() - sizeof(iv));
|
||||||
|
@ -137,11 +149,11 @@ static std::string decrypt(const std::string &ciphertext, const crypto::key_imag
|
||||||
static void store_relative_ring(MDB_txn *txn, MDB_dbi &dbi, const crypto::key_image &key_image, const std::vector<uint64_t> &relative_ring, const crypto::chacha_key &chacha_key)
|
static void store_relative_ring(MDB_txn *txn, MDB_dbi &dbi, const crypto::key_image &key_image, const std::vector<uint64_t> &relative_ring, const crypto::chacha_key &chacha_key)
|
||||||
{
|
{
|
||||||
MDB_val key, data;
|
MDB_val key, data;
|
||||||
std::string key_ciphertext = encrypt(key_image, chacha_key);
|
std::string key_ciphertext = encrypt(key_image, chacha_key, 0);
|
||||||
key.mv_data = (void*)key_ciphertext.data();
|
key.mv_data = (void*)key_ciphertext.data();
|
||||||
key.mv_size = key_ciphertext.size();
|
key.mv_size = key_ciphertext.size();
|
||||||
std::string compressed_ring = compress_ring(relative_ring);
|
std::string compressed_ring = compress_ring(relative_ring, V1TAG);
|
||||||
std::string data_ciphertext = encrypt(compressed_ring, key_image, chacha_key);
|
std::string data_ciphertext = encrypt(compressed_ring, key_image, chacha_key, 1);
|
||||||
data.mv_size = data_ciphertext.size();
|
data.mv_size = data_ciphertext.size();
|
||||||
data.mv_data = (void*)data_ciphertext.c_str();
|
data.mv_data = (void*)data_ciphertext.c_str();
|
||||||
int dbr = mdb_put(txn, dbi, &key, &data, 0);
|
int dbr = mdb_put(txn, dbi, &key, &data, 0);
|
||||||
|
@ -297,7 +309,7 @@ bool ringdb::remove_rings(const crypto::chacha_key &chacha_key, const std::vecto
|
||||||
for (const crypto::key_image &key_image: key_images)
|
for (const crypto::key_image &key_image: key_images)
|
||||||
{
|
{
|
||||||
MDB_val key, data;
|
MDB_val key, data;
|
||||||
std::string key_ciphertext = encrypt(key_image, chacha_key);
|
std::string key_ciphertext = encrypt(key_image, chacha_key, 0);
|
||||||
key.mv_data = (void*)key_ciphertext.data();
|
key.mv_data = (void*)key_ciphertext.data();
|
||||||
key.mv_size = key_ciphertext.size();
|
key.mv_size = key_ciphertext.size();
|
||||||
|
|
||||||
|
@ -349,7 +361,7 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
|
||||||
tx_active = true;
|
tx_active = true;
|
||||||
|
|
||||||
MDB_val key, data;
|
MDB_val key, data;
|
||||||
std::string key_ciphertext = encrypt(key_image, chacha_key);
|
std::string key_ciphertext = encrypt(key_image, chacha_key, 0);
|
||||||
key.mv_data = (void*)key_ciphertext.data();
|
key.mv_data = (void*)key_ciphertext.data();
|
||||||
key.mv_size = key_ciphertext.size();
|
key.mv_size = key_ciphertext.size();
|
||||||
dbr = mdb_get(txn, dbi_rings, &key, &data);
|
dbr = mdb_get(txn, dbi_rings, &key, &data);
|
||||||
|
@ -358,8 +370,15 @@ bool ringdb::get_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
|
||||||
return false;
|
return false;
|
||||||
THROW_WALLET_EXCEPTION_IF(data.mv_size <= 0, tools::error::wallet_internal_error, "Invalid ring data size");
|
THROW_WALLET_EXCEPTION_IF(data.mv_size <= 0, tools::error::wallet_internal_error, "Invalid ring data size");
|
||||||
|
|
||||||
std::string data_plaintext = decrypt(std::string((const char*)data.mv_data, data.mv_size), key_image, chacha_key);
|
bool try_v0 = false;
|
||||||
outs = decompress_ring(data_plaintext);
|
std::string data_plaintext = decrypt(std::string((const char*)data.mv_data, data.mv_size), key_image, chacha_key, 1);
|
||||||
|
try { outs = decompress_ring(data_plaintext, V1TAG); if (outs.empty()) try_v0 = true; }
|
||||||
|
catch(...) { try_v0 = true; }
|
||||||
|
if (try_v0)
|
||||||
|
{
|
||||||
|
data_plaintext = decrypt(std::string((const char*)data.mv_data, data.mv_size), key_image, chacha_key, 0);
|
||||||
|
outs = decompress_ring(data_plaintext, 0);
|
||||||
|
}
|
||||||
MDEBUG("Found ring for key image " << key_image << ":");
|
MDEBUG("Found ring for key image " << key_image << ":");
|
||||||
MDEBUG("Relative: " << boost::join(outs | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " "));
|
MDEBUG("Relative: " << boost::join(outs | boost::adaptors::transformed([](uint64_t out){return std::to_string(out);}), " "));
|
||||||
outs = cryptonote::relative_output_offsets_to_absolute(outs);
|
outs = cryptonote::relative_output_offsets_to_absolute(outs);
|
||||||
|
|
Loading…
Reference in a new issue