@ -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 ) ;