@ -27,8 +27,8 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
# include "version.h"
# include "device_ledger.hpp"
# include "log.hpp"
# include "ringct/rctOps.h"
# include "cryptonote_basic/account.h"
# include "cryptonote_basic/subaddress_index.h"
@ -173,6 +173,7 @@ namespace hw {
# define INS_SET_SIGNATURE_MODE 0x72
# define INS_GET_ADDITIONAL_KEY 0x74
# define INS_STEALTH 0x76
# define INS_GEN_COMMITMENT_MASK 0x77
# define INS_BLIND 0x78
# define INS_UNBLIND 0x7A
# define INS_GEN_TXOUT_KEYS 0x7B
@ -180,6 +181,7 @@ namespace hw {
# define INS_MLSAG 0x7E
# define INS_CLOSE_TX 0x80
# define INS_GET_TX_PROOF 0xA0
# define INS_GET_RESPONSE 0xc0
@ -302,8 +304,24 @@ namespace hw {
}
bool device_ledger : : reset ( ) {
send_simple ( INS_RESET ) ;
return true ;
reset_buffer ( ) ;
int offset = set_command_header_noopt ( INS_RESET ) ;
memmove ( this - > buffer_send + offset , MONERO_VERSION , strlen ( MONERO_VERSION ) ) ;
offset + = strlen ( MONERO_VERSION ) ;
this - > buffer_send [ 4 ] = offset - 5 ;
this - > length_send = offset ;
this - > exchange ( ) ;
ASSERT_X ( this - > length_recv > = 3 , " Communication error, less than three bytes received. Check your application version. " ) ;
unsigned int device_version = 0 ;
device_version = VERSION ( this - > buffer_recv [ 0 ] , this - > buffer_recv [ 1 ] , this - > buffer_recv [ 2 ] ) ;
ASSERT_X ( device_version > = MINIMAL_APP_VERSION ,
" Unsupported device application version: " < < VERSION_MAJOR ( device_version ) < < " . " < < VERSION_MINOR ( device_version ) < < " . " < < VERSION_MICRO ( device_version ) < <
" At least " < < MINIMAL_APP_VERSION_MAJOR < < " . " < < MINIMAL_APP_VERSION_MINOR < < " . " < < MINIMAL_APP_VERSION_MICRO < < " is required. " ) ;
return true ;
}
unsigned int device_ledger : : exchange ( unsigned int ok , unsigned int mask ) {
@ -314,9 +332,9 @@ namespace hw {
this - > length_recv - = 2 ;
this - > sw = ( this - > buffer_recv [ length_recv ] < < 8 ) | this - > buffer_recv [ length_recv + 1 ] ;
logRESP ( ) ;
ASSERT_SW ( this - > sw , ok , msk ) ;
logRESP ( ) ;
return this - > sw ;
}
@ -790,7 +808,11 @@ namespace hw {
const crypto : : secret_key a_x = hw : : ledger : : decrypt ( a ) ;
const crypto : : secret_key b_x = hw : : ledger : : decrypt ( b ) ;
crypto : : secret_key r_x ;
rct : : key aG_x ;
log_hexbuffer ( " sc_secret_add: [[IN]] a " , ( char * ) a_x . data , 32 ) ;
log_hexbuffer ( " sc_secret_add: [[IN]] b " , ( char * ) b_x . data , 32 ) ;
this - > controle_device - > sc_secret_add ( r_x , a_x , b_x ) ;
log_hexbuffer ( " sc_secret_add: [[OUT]] aG " , ( char * ) r_x . data , 32 ) ;
# endif
int offset = set_command_header_noopt ( INS_SECRET_KEY_ADD ) ;
@ -825,6 +847,11 @@ namespace hw {
# ifdef DEBUG_HWDEVICE
crypto : : public_key pub_x ;
crypto : : secret_key sec_x ;
crypto : : secret_key recovery_key_x ;
if ( recover ) {
recovery_key_x = hw : : ledger : : decrypt ( recovery_key ) ;
log_hexbuffer ( " generate_keys: [[IN]] pub " , ( char * ) recovery_key_x . data , 32 ) ;
}
# endif
send_simple ( INS_GENERATE_KEYPAIR ) ;
@ -836,6 +863,9 @@ namespace hw {
# ifdef DEBUG_HWDEVICE
crypto : : secret_key sec_clear = hw : : ledger : : decrypt ( sec ) ;
sec_x = sec_clear ;
log_hexbuffer ( " generate_keys: [[OUT]] pub " , ( char * ) pub . data , 32 ) ;
log_hexbuffer ( " generate_keys: [[OUT]] sec " , ( char * ) sec_clear . data , 32 ) ;
crypto : : secret_key_to_public_key ( sec_x , pub_x ) ;
hw : : ledger : : check32 ( " generate_keys " , " pub " , pub_x . data , pub . data ) ;
# endif
@ -850,7 +880,7 @@ namespace hw {
# ifdef DEBUG_HWDEVICE
const crypto : : public_key pub_x = pub ;
const crypto : : secret_key sec_x = hw : : ledger : : decrypt ( sec ) ;
const crypto : : secret_key sec_x = ( sec = = rct : : rct2sk ( rct : : I ) ) ? sec : hw : : ledger : : decrypt ( sec ) ;
crypto : : key_derivation derivation_x ;
log_hexbuffer ( " generate_key_derivation: [[IN]] pub " , pub_x . data , 32 ) ;
log_hexbuffer ( " generate_key_derivation: [[IN]] sec " , sec_x . data , 32 ) ;
@ -866,7 +896,6 @@ namespace hw {
assert ( is_fake_view_key ( sec ) ) ;
r = crypto : : generate_key_derivation ( pub , this - > viewkey , derivation ) ;
} else {
int offset = set_command_header_noopt ( INS_GEN_KEY_DERIVATION ) ;
//pub
memmove ( this - > buffer_send + offset , pub . data , 32 ) ;
@ -885,11 +914,11 @@ namespace hw {
}
# ifdef DEBUG_HWDEVICE
crypto : : key_derivation derivation_clear ;
if ( ( this - > mode = = TRANSACTION_PARSE ) & & has_view_key ) {
derivation_clear = derivation ;
} else {
derivation_clear = hw : : ledger : : decrypt ( derivation ) ;
}
if ( ( this - > mode = = TRANSACTION_PARSE ) & & has_view_key ) {
derivation_clear = derivation ;
} else {
derivation_clear = hw : : ledger : : decrypt ( derivation ) ;
}
hw : : ledger : : check32 ( " generate_key_derivation " , " derivation " , derivation_x . data , derivation_clear . data ) ;
# endif
@ -1050,7 +1079,7 @@ namespace hw {
bool rc = this - > controle_device - > secret_key_to_public_key ( sec_x , pub_x ) ;
log_hexbuffer ( " secret_key_to_public_key: [[OUT]] pub " , pub_x . data , 32 ) ;
if ( ! rc ) {
log_message ( " secret_key_to_public_key" , " secret_key rejected " ) ;
log_message ( " FAIL secret_key_to_public_key" , " secret_key rejected " ) ;
}
# endif
@ -1112,6 +1141,75 @@ namespace hw {
/* TRANSACTION */
/* ======================================================================= */
void device_ledger : : generate_tx_proof ( const crypto : : hash & prefix_hash ,
const crypto : : public_key & R , const crypto : : public_key & A , const boost : : optional < crypto : : public_key > & B , const crypto : : public_key & D , const crypto : : secret_key & r ,
crypto : : signature & sig ) {
AUTO_LOCK_CMD ( ) ;
# ifdef DEBUG_HWDEVICE
const crypto : : hash prefix_hash_x = prefix_hash ;
const crypto : : public_key R_x = R ;
const crypto : : public_key A_x = A ;
const boost : : optional < crypto : : public_key > B_x = B ;
const crypto : : public_key D_x = D ;
const crypto : : secret_key r_x = hw : : ledger : : decrypt ( r ) ;
crypto : : signature sig_x ;
log_hexbuffer ( " generate_tx_proof: [[IN]] prefix_hash " , prefix_hash_x . data , 32 ) ;
log_hexbuffer ( " generate_tx_proof: [[IN]] R " , R_x . data , 32 ) ;
log_hexbuffer ( " generate_tx_proof: [[IN]] A " , A_x . data , 32 ) ;
if ( B_x ) {
log_hexbuffer ( " generate_tx_proof: [[IN]] B " , ( * B_x ) . data , 32 ) ;
}
log_hexbuffer ( " generate_tx_proof: [[IN]] D " , D_x . data , 32 ) ;
log_hexbuffer ( " generate_tx_proof: [[IN]] r " , r_x . data , 32 ) ;
# endif
int offset = set_command_header ( INS_GET_TX_PROOF ) ;
//options
this - > buffer_send [ offset ] = B ? 0x01 : 0x00 ;
offset + = 1 ;
//prefix_hash
memmove ( & this - > buffer_send [ offset ] , prefix_hash . data , 32 ) ;
offset + = 32 ;
// R
memmove ( & this - > buffer_send [ offset ] , R . data , 32 ) ;
offset + = 32 ;
// A
memmove ( & this - > buffer_send [ offset ] , A . data , 32 ) ;
offset + = 32 ;
// B
if ( B ) {
memmove ( & this - > buffer_send [ offset ] , ( * B ) . data , 32 ) ;
} else {
memset ( & this - > buffer_send [ offset ] , 0 , 32 ) ;
}
offset + = 32 ;
// D
memmove ( & this - > buffer_send [ offset ] , D . data , 32 ) ;
offset + = 32 ;
// r
memmove ( & this - > buffer_send [ offset ] , r . data , 32 ) ;
offset + = 32 ;
this - > buffer_send [ 4 ] = offset - 5 ;
this - > length_send = offset ;
this - > exchange ( ) ;
memmove ( sig . c . data , & this - > buffer_recv [ 0 ] , 32 ) ;
memmove ( sig . r . data , & this - > buffer_recv [ 32 ] , 32 ) ;
# ifdef DEBUG_HWDEVICE
log_hexbuffer ( " GENERATE_TX_PROOF: **c** " , sig . c . data , sizeof ( sig . c . data ) ) ;
log_hexbuffer ( " GENERATE_TX_PROOF: **r** " , sig . r . data , sizeof ( sig . r . data ) ) ;
this - > controle_device - > generate_tx_proof ( prefix_hash_x , R_x , A_x , B_x , D_x , r_x , sig_x ) ;
hw : : ledger : : check32 ( " generate_tx_proof " , " c " , sig_x . c . data , sig . c . data ) ;
hw : : ledger : : check32 ( " generate_tx_proof " , " r " , sig_x . r . data , sig . r . data ) ;
# endif
}
bool device_ledger : : open_tx ( crypto : : secret_key & tx_key ) {
AUTO_LOCK_CMD ( ) ;
@ -1130,7 +1228,11 @@ namespace hw {
this - > exchange ( ) ;
memmove ( tx_key . data , & this - > buffer_recv [ 32 ] , 32 ) ;
# ifdef DEBUG_HWDEVICE
const crypto : : secret_key r_x = hw : : ledger : : decrypt ( tx_key ) ;
log_hexbuffer ( " open_tx: [[OUT]] R " , ( char * ) & this - > buffer_recv [ 0 ] , 32 ) ;
log_hexbuffer ( " open_tx: [[OUT]] r " , r_x . data , 32 ) ;
# endif
return true ;
}
@ -1141,7 +1243,11 @@ namespace hw {
const crypto : : public_key public_key_x = public_key ;
const crypto : : secret_key secret_key_x = hw : : ledger : : decrypt ( secret_key ) ;
crypto : : hash8 payment_id_x = payment_id ;
log_hexbuffer ( " encrypt_payment_id: [[IN]] payment_id " , payment_id_x . data , 32 ) ;
log_hexbuffer ( " encrypt_payment_id: [[IN]] public_key " , public_key_x . data , 32 ) ;
log_hexbuffer ( " encrypt_payment_id: [[IN]] secret_key " , secret_key_x . data , 32 ) ;
this - > controle_device - > encrypt_payment_id ( payment_id_x , public_key_x , secret_key_x ) ;
log_hexbuffer ( " encrypt_payment_id: [[OUT]] payment_id " , payment_id_x . data , 32 ) ;
# endif
int offset = set_command_header_noopt ( INS_STEALTH ) ;
@ -1178,49 +1284,58 @@ namespace hw {
# ifdef DEBUG_HWDEVICE
const size_t & tx_version_x = tx_version ;
const cryptonote : : account_keys sender_account_keys_x = sender_account_keys;
const cryptonote : : account_keys sender_account_keys_x = hw: : ledger : : decrypt ( sender_account_keys) ;
memmove ( ( void * ) sender_account_keys_x . m_view_secret_key . data , dbg_viewkey . data , 32 ) ;
const crypto : : public_key & txkey_pub_x = txkey_pub ;
const crypto : : secret_key & tx_key_x = tx_key ;
const cryptonote : : tx_destination_entry & dst_entr_x = dst_entr ;
const boost : : optional < cryptonote : : account_public_address > & change_addr_x = change_addr ;
const size_t & output_index_x = output_index ;
const bool & need_additional_txkeys_x = need_additional_txkeys ;
const std : : vector < crypto : : secret_key > & additional_tx_keys_x = additional_tx_keys ;
const crypto : : public_key txkey_pub_x = txkey_pub ;
const crypto : : secret_key tx_key_x = hw : : ledger : : decrypt ( tx_key ) ;
const cryptonote : : tx_destination_entry dst_entr_x = dst_entr ;
const boost : : optional < cryptonote : : account_public_address > change_addr_x = change_addr ;
const size_t output_index_x = output_index ;
const bool need_additional_txkeys_x = need_additional_txkeys ;
std : : vector < crypto : : secret_key > additional_tx_keys_x ;
for ( const auto k : additional_tx_keys ) {
additional_tx_keys_x . push_back ( hw : : ledger : : decrypt ( k ) ) ;
}
std : : vector < crypto : : public_key > additional_tx_public_keys_x ;
std : : vector < rct : : key > amount_keys_x ;
crypto : : public_key out_eph_public_key_x ;
log_message ( " generate_output_ephemeral_keys: [[IN]] tx_version " , std : : to_string ( tx_version_x ) ) ;
//log_hexbuffer("generate_output_ephemeral_keys: [[IN]] sender_account_keys.view", sender_account_keys.m_sview_secret_key.data, 32);
//log_hexbuffer("generate_output_ephemeral_keys: [[IN]] sender_account_keys.spend", sender_account_keys.m_spend_secret_key.data, 32);
log_hexbuffer ( " generate_output_ephemeral_keys: [[IN]] txkey_pub " , txkey_pub_x . data , 32 ) ;
log_hexbuffer ( " generate_output_ephemeral_keys: [[IN]] tx_key " , tx_key_x . data , 32 ) ;
log_hexbuffer ( " generate_output_ephemeral_keys: [[IN]] dst_entr.view " , dst_entr_x . addr . m_view_public_key . data , 32 ) ;
log_hexbuffer ( " generate_output_ephemeral_keys: [[IN]] dst_entr.spend " , dst_entr_x . addr . m_spend_public_key . data , 32 ) ;
if ( change_addr ) {
log_hexbuffer ( " generate_output_ephemeral_keys: [[IN]] change_addr.view " , ( * change_addr_x ) . m_view_public_key . data , 32 ) ;
log_hexbuffer ( " generate_output_ephemeral_keys: [[IN]] change_addr.spend " , ( * change_addr_x ) . m_spend_public_key . data , 32 ) ;
}
log_message ( " generate_output_ephemeral_keys: [[IN]] output_index " , std : : to_string ( output_index_x ) ) ;
log_message ( " generate_output_ephemeral_keys: [[IN]] need_additional_txkeys " , std : : to_string ( need_additional_txkeys_x ) ) ;
if ( need_additional_txkeys_x ) {
log_hexbuffer ( " generate_output_ephemeral_keys: [[IN]] additional_tx_keys[oi] " , additional_tx_keys_x [ output_index ] . data , 32 ) ;
}
this - > controle_device - > generate_output_ephemeral_keys ( tx_version_x , sender_account_keys_x , txkey_pub_x , tx_key_x , dst_entr_x , change_addr_x , output_index_x , need_additional_txkeys_x , additional_tx_keys_x ,
additional_tx_public_keys_x , amount_keys_x , out_eph_public_key_x ) ;
if ( need_additional_txkeys_x ) {
log_hexbuffer ( " additional_tx_public_keys_x: [[OUT]] additional_tx_public_keys_x " , additional_tx_public_keys_x . back ( ) . data , 32 ) ;
}
log_hexbuffer ( " generate_output_ephemeral_keys: [[OUT]] amount_keys " , ( char * ) amount_keys_x . back ( ) . bytes , 32 ) ;
log_hexbuffer ( " generate_output_ephemeral_keys: [[OUT]] out_eph_public_key " , out_eph_public_key_x . data , 32 ) ;
# endif
ASSERT_X ( tx_version > 1 , " TX version not supported " < < tx_version ) ;
// make additional tx pubkey if necessary
cryptonote : : keypair additional_txkey ;
if ( need_additional_txkeys ) {
additional_txkey . sec = additional_tx_keys [ output_index ] ;
}
//compute derivation, out_eph_public_key, and amount key in one shot on device, to ensure checkable link
const crypto : : secret_key * sec ;
bool is_change ;
if ( change_addr & & dst_entr . addr = = * change_addr )
{
// sending change to yourself; derivation = a*R
is_change = true ;
sec = & sender_account_keys . m_view_secret_key ;
}
else
{
is_change = false ;
if ( dst_entr . is_subaddress & & need_additional_txkeys ) {
sec = & additional_txkey . sec ;
} else {
sec = & tx_key ;
}
}
int offset = set_command_header_noopt ( INS_GEN_TXOUT_KEYS ) ;
//tx_version
this - > buffer_send [ offset + 0 ] = tx_version > > 24 ;
@ -1228,8 +1343,11 @@ namespace hw {
this - > buffer_send [ offset + 2 ] = tx_version > > 8 ;
this - > buffer_send [ offset + 3 ] = tx_version > > 0 ;
offset + = 4 ;
//tx_sec
memmove ( & this - > buffer_send [ offset ] , sec - > data , 32 ) ;
//tx_key
memmove ( & this - > buffer_send [ offset ] , tx_key . data , 32 ) ;
offset + = 32 ;
//txkey_pub
memmove ( & this - > buffer_send [ offset ] , txkey_pub . data , 32 ) ;
offset + = 32 ;
//Aout
memmove ( & this - > buffer_send [ offset ] , dst_entr . addr . m_view_public_key . data , 32 ) ;
@ -1244,6 +1362,7 @@ namespace hw {
this - > buffer_send [ offset + 3 ] = output_index > > 0 ;
offset + = 4 ;
//is_change,
bool is_change = ( change_addr & & dst_entr . addr = = * change_addr ) ;
this - > buffer_send [ offset ] = is_change ;
offset + + ;
//is_subaddress
@ -1252,6 +1371,13 @@ namespace hw {
//need_additional_key
this - > buffer_send [ offset ] = need_additional_txkeys ;
offset + + ;
//additional_tx_key
if ( need_additional_txkeys ) {
memmove ( & this - > buffer_send [ offset ] , additional_txkey . sec . data , 32 ) ;
} else {
memset ( & this - > buffer_send [ offset ] , 0 , 32 ) ;
}
offset + = 32 ;
this - > buffer_send [ 4 ] = offset - 5 ;
this - > length_send = offset ;
@ -1259,15 +1385,8 @@ namespace hw {
offset = 0 ;
unsigned int recv_len = this - > length_recv ;
if ( need_additional_txkeys )
{
ASSERT_X ( recv_len > = 32 , " Not enought data from device " ) ;
memmove ( additional_txkey . pub . data , & this - > buffer_recv [ offset ] , 32 ) ;
additional_tx_public_keys . push_back ( additional_txkey . pub ) ;
offset + = 32 ;
recv_len - = 32 ;
}
if ( tx_version > 1 )
//if (tx_version > 1)
{
ASSERT_X ( recv_len > = 32 , " Not enought data from device " ) ;
crypto : : secret_key scalar1 ;
@ -1279,6 +1398,16 @@ namespace hw {
ASSERT_X ( recv_len > = 32 , " Not enought data from device " ) ;
memmove ( out_eph_public_key . data , & this - > buffer_recv [ offset ] , 32 ) ;
recv_len - = 32 ;
offset + = 32 ;
if ( need_additional_txkeys )
{
ASSERT_X ( recv_len > = 32 , " Not enought data from device " ) ;
memmove ( additional_txkey . pub . data , & this - > buffer_recv [ offset ] , 32 ) ;
additional_tx_public_keys . push_back ( additional_txkey . pub ) ;
offset + = 32 ;
recv_len - = 32 ;
}
// add ABPkeys
this - > add_output_key_mapping ( dst_entr . addr . m_view_public_key , dst_entr . addr . m_spend_public_key , dst_entr . is_subaddress , is_change ,
@ -1286,9 +1415,10 @@ namespace hw {
amount_keys . back ( ) , out_eph_public_key ) ;
# ifdef DEBUG_HWDEVICE
log_hexbuffer ( " generate_output_ephemeral_keys: clear amount_key " , ( const char * ) hw : : ledger : : decrypt ( amount_keys . back ( ) ) . bytes , 32 ) ;
hw : : ledger : : check32 ( " generate_output_ephemeral_keys " , " amount_key " , ( const char * ) amount_keys_x . back ( ) . bytes , ( const char * ) hw : : ledger : : decrypt ( amount_keys . back ( ) ) . bytes ) ;
if ( need_additional_txkeys ) {
hw : : ledger : : check32 ( " generate_output_ephemeral_keys " , " additional_tx_key " , additional_tx_ keys_x. back ( ) . data , additional_tx _keys. back ( ) . data ) ;
hw : : ledger : : check32 ( " generate_output_ephemeral_keys " , " additional_tx_key " , additional_tx_ public_ keys_x. back ( ) . data , additional_tx _public _keys. back ( ) . data ) ;
}
hw : : ledger : : check32 ( " generate_output_ephemeral_keys " , " out_eph_public_key " , out_eph_public_key_x . data , out_eph_public_key . data ) ;
# endif
@ -1303,6 +1433,32 @@ namespace hw {
return true ;
}
rct : : key device_ledger : : genCommitmentMask ( const rct : : key & AKout ) {
# ifdef DEBUG_HWDEVICE
const rct : : key AKout_x = hw : : ledger : : decrypt ( AKout ) ;
rct : : key mask_x ;
mask_x = this - > controle_device - > genCommitmentMask ( AKout_x ) ;
# endif
rct : : key mask ;
int offset = set_command_header_noopt ( INS_GEN_COMMITMENT_MASK ) ;
// AKout
memmove ( this - > buffer_send + offset , AKout . bytes , 32 ) ;
offset + = 32 ;
this - > buffer_send [ 4 ] = offset - 5 ;
this - > length_send = offset ;
this - > exchange ( ) ;
memmove ( mask . bytes , & this - > buffer_recv [ 0 ] , 32 ) ;
# ifdef DEBUG_HWDEVICE
hw : : ledger : : check32 ( " genCommitmentMask " , " mask " , ( const char * ) mask_x . bytes , ( const char * ) mask . bytes ) ;
# endif
return mask ;
}
bool device_ledger : : ecdhEncode ( rct : : ecdhTuple & unmasked , const rct : : key & AKout , bool short_amount ) {
AUTO_LOCK_CMD ( ) ;
@ -1334,6 +1490,7 @@ namespace hw {
memmove ( unmasked . mask . bytes , & this - > buffer_recv [ 32 ] , 32 ) ;
# ifdef DEBUG_HWDEVICE
MDEBUG ( " ecdhEncode: Akout: " < < AKout_x ) ;
hw : : ledger : : check32 ( " ecdhEncode " , " amount " , ( char * ) unmasked_x . amount . bytes , ( char * ) unmasked . amount . bytes ) ;
hw : : ledger : : check32 ( " ecdhEncode " , " mask " , ( char * ) unmasked_x . mask . bytes , ( char * ) unmasked . mask . bytes ) ;
@ -1374,6 +1531,7 @@ namespace hw {
memmove ( masked . mask . bytes , & this - > buffer_recv [ 32 ] , 32 ) ;
# ifdef DEBUG_HWDEVICE
MDEBUG ( " ecdhEncode: Akout: " < < AKout_x ) ;
hw : : ledger : : check32 ( " ecdhDecode " , " amount " , ( char * ) masked_x . amount . bytes , ( char * ) masked . amount . bytes ) ;
hw : : ledger : : check32 ( " ecdhDecode " , " mask " , ( char * ) masked_x . mask . bytes , ( char * ) masked . mask . bytes ) ;
# endif