Merge pull request

d25acd7 Add hmac over encrypted value during transaction (clashm)
34f28a7 Add display address (clashm)
235b94e Revert PR  (export view key) (clashm)
32febd2 Fix debug feature (clashm)
This commit is contained in:
luigi1111 2019-10-25 16:03:24 -05:00
commit 07c6789148
No known key found for this signature in database
GPG key ID: F4ACA0183641E010
3 changed files with 217 additions and 108 deletions

View file

@ -612,7 +612,7 @@ namespace cryptonote
{
hw::device &hwdev = sender_account_keys.get_device();
hwdev.open_tx(tx_key);
try {
// figure out if we need to make additional tx pubkeys
size_t num_stdaddresses = 0;
size_t num_subaddresses = 0;
@ -629,6 +629,10 @@ namespace cryptonote
bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, msout);
hwdev.close_tx();
return r;
} catch(...) {
hwdev.close_tx();
throw;
}
}
//---------------------------------------------------------------
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time)

View file

@ -64,6 +64,41 @@ namespace hw {
crypto::secret_key dbg_spendkey;
#endif
/* ===================================================================== */
/* === hmacmap ==== */
/* ===================================================================== */
SecHMAC::SecHMAC(const uint8_t s[32], const uint8_t h[32]) {
memcpy(this->sec, s, 32);
memcpy(this->hmac, h, 32);
}
void HMACmap::find_mac(const uint8_t sec[32], uint8_t hmac[32]) {
size_t sz = hmacs.size();
log_hexbuffer("find_mac: lookup for ", (char*)sec,32);
for (size_t i=0; i<sz; i++) {
log_hexbuffer("find_mac: - try ",(char*)hmacs[i].sec,32);
if (memcmp(sec, hmacs[i].sec, 32) == 0) {
memcpy(hmac, hmacs[i].hmac, 32);
log_hexbuffer("find_mac: - found ",(char*)hmacs[i].hmac,32);
return;
}
}
throw std::runtime_error("Protocol error: try to send untrusted secret");
}
void HMACmap::add_mac(const uint8_t sec[32], const uint8_t hmac[32]) {
log_hexbuffer("add_mac: sec ", (char*)sec,32);
log_hexbuffer("add_mac: hmac ", (char*)hmac,32);
hmacs.push_back(SecHMAC(sec,hmac));
}
void HMACmap::clear() {
hmacs.clear();
}
/* ===================================================================== */
/* === Keymap ==== */
/* ===================================================================== */
@ -162,9 +197,11 @@ namespace hw {
#define INS_RESET 0x02
#define INS_GET_KEY 0x20
#define INS_DISPLAY_ADDRESS 0x21
#define INS_PUT_KEY 0x22
#define INS_GET_CHACHA8_PREKEY 0x24
#define INS_VERIFY_KEY 0x26
#define INS_MANAGE_SEEDWORDS 0x28
#define INS_SECRET_KEY_TO_PUBLIC_KEY 0x30
#define INS_GEN_KEY_DERIVATION 0x32
@ -205,6 +242,7 @@ namespace hw {
this->reset_buffer();
this->mode = NONE;
this->has_view_key = false;
this->tx_in_progress = false;
MDEBUG( "Device "<<this->id <<" Created");
}
@ -317,6 +355,26 @@ namespace hw {
}
}
void device_ledger::send_secret(const unsigned char sec[32], int &offset) {
MDEBUG("send_secret: " << this->tx_in_progress);
memmove(this->buffer_send+offset, sec, 32);
offset +=32;
if (this->tx_in_progress) {
this->hmac_map.find_mac((uint8_t*)sec, this->buffer_send+offset);
offset += 32;
}
}
void device_ledger::receive_secret(unsigned char sec[32], int &offset) {
MDEBUG("receive_secret: " << this->tx_in_progress);
memmove(sec, this->buffer_recv+offset, 32);
offset += 32;
if (this->tx_in_progress) {
this->hmac_map.add_mac((uint8_t*)sec, this->buffer_recv+offset);
offset += 32;
}
}
bool device_ledger::reset() {
reset_buffer();
int offset = set_command_header_noopt(INS_RESET);
@ -418,10 +476,10 @@ namespace hw {
#ifdef DEBUG_HWDEVICE
cryptonote::account_public_address pubkey;
this->get_public_address(pubkey);
#endif
crypto::secret_key vkey;
crypto::secret_key skey;
this->get_secret_keys(vkey,skey);
#endif
return true;
}
@ -509,6 +567,7 @@ namespace hw {
}
#ifdef DEBUG_HWDEVICE
send_simple(INS_GET_KEY, 0x04);
memmove(dbg_viewkey.data, this->buffer_recv+0, 32);
memmove(dbg_spendkey.data, this->buffer_recv+32, 32);
#endif
@ -538,6 +597,27 @@ namespace hw {
return true;
}
void device_ledger::display_address(const cryptonote::subaddress_index& index, const boost::optional<crypto::hash8> &payment_id) {
AUTO_LOCK_CMD();
int offset = set_command_header_noopt(INS_DISPLAY_ADDRESS, payment_id?1:0);
//index
memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index));
offset +=8 ;
//payment ID
if (payment_id) {
memmove(this->buffer_send+offset, (*payment_id).data, 8);
} else {
memset(this->buffer_send+offset, 0, 8);
}
offset +=8;
this->buffer_send[4] = offset-5;
this->length_send = offset;
CHECK_AND_ASSERT_THROW_MES(this->exchange_wait_on_input() == 0, "Timeout/Error on display address.");
}
/* ======================================================================= */
/* SUB ADDRESS */
/* ======================================================================= */
@ -573,8 +653,7 @@ namespace hw {
memmove(this->buffer_send+offset, pub.data, 32);
offset += 32;
//derivation
memmove(this->buffer_send+offset, derivation.data, 32);
offset += 32;
this->send_secret((unsigned char*)derivation.data, offset);
//index
this->buffer_send[offset+0] = output_index>>24;
this->buffer_send[offset+1] = output_index>>16;
@ -706,8 +785,7 @@ namespace hw {
int offset = set_command_header_noopt(INS_GET_SUBADDRESS_SECRET_KEY);
//sec
memmove(this->buffer_send+offset, sec.data, 32);
offset += 32;
this->send_secret((unsigned char*)sec.data, offset);
//index
static_assert(sizeof(cryptonote::subaddress_index) == 8, "cryptonote::subaddress_index shall be 8 bytes length");
memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index));
@ -717,7 +795,8 @@ namespace hw {
this->length_send = offset;
this->exchange();
memmove(sub_sec.data, &this->buffer_recv[0], 32);
offset = 0;
this->receive_secret((unsigned char*)sub_sec.data, offset);
#ifdef DEBUG_HWDEVICE
crypto::secret_key sub_sec_clear = hw::ledger::decrypt(sub_sec);
@ -737,8 +816,7 @@ namespace hw {
offset = set_command_header_noopt(INS_VERIFY_KEY);
//sec
memmove(this->buffer_send+offset, secret_key.data, 32);
offset += 32;
this->send_secret((unsigned char*)secret_key.data, offset);
//pub
memmove(this->buffer_send+offset, public_key.data, 32);
offset += 32;
@ -774,9 +852,7 @@ namespace hw {
memmove(this->buffer_send+offset, P.bytes, 32);
offset += 32;
//sec
memmove(this->buffer_send+offset, a.bytes, 32);
offset += 32;
this->send_secret(a.bytes, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
@ -805,8 +881,7 @@ namespace hw {
int offset = set_command_header_noopt(INS_SECRET_SCAL_MUL_BASE);
//sec
memmove(this->buffer_send+offset, a.bytes, 32);
offset += 32;
this->send_secret(a.bytes, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
@ -824,6 +899,7 @@ namespace hw {
bool device_ledger::sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) {
AUTO_LOCK_CMD();
int offset;
#ifdef DEBUG_HWDEVICE
const crypto::secret_key a_x = hw::ledger::decrypt(a);
@ -836,20 +912,19 @@ namespace hw {
log_hexbuffer("sc_secret_add: [[OUT]] aG", (char*)r_x.data, 32);
#endif
int offset = set_command_header_noopt(INS_SECRET_KEY_ADD);
offset = set_command_header_noopt(INS_SECRET_KEY_ADD);
//sec key
memmove(this->buffer_send+offset, a.data, 32);
offset += 32;
this->send_secret((unsigned char*)a.data, offset);
//sec key
memmove(this->buffer_send+offset, b.data, 32);
offset += 32;
this->send_secret((unsigned char*)b.data, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
this->exchange();
//pub key
memmove(r.data, &this->buffer_recv[0], 32);
//sec key
offset = 0;
this->receive_secret((unsigned char*)r.data, offset);
#ifdef DEBUG_HWDEVICE
crypto::secret_key r_clear = hw::ledger::decrypt(r);
@ -861,6 +936,8 @@ namespace hw {
crypto::secret_key device_ledger::generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover) {
AUTO_LOCK_CMD();
int offset;
if (recover) {
throw std::runtime_error("device generate key does not support recover");
}
@ -877,9 +954,11 @@ namespace hw {
send_simple(INS_GENERATE_KEYPAIR);
offset = 0;
//pub key
memmove(pub.data, &this->buffer_recv[0], 32);
memmove(sec.data, &this->buffer_recv[32], 32);
offset += 32;
this->receive_secret((unsigned char*)sec.data, offset);
#ifdef DEBUG_HWDEVICE
crypto::secret_key sec_clear = hw::ledger::decrypt(sec);
@ -922,15 +1001,16 @@ namespace hw {
memmove(this->buffer_send+offset, pub.data, 32);
offset += 32;
//sec
memmove(this->buffer_send+offset, sec.data, 32);
offset += 32;
this->send_secret((unsigned char*)sec.data, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
this->exchange();
offset = 0;
//derivattion data
memmove(derivation.data, &this->buffer_recv[0], 32);
this->receive_secret((unsigned char*)derivation.data, offset);
r = true;
}
#ifdef DEBUG_HWDEVICE
@ -978,9 +1058,9 @@ namespace hw {
#endif
int offset = set_command_header_noopt(INS_DERIVATION_TO_SCALAR);
//derivattion
memmove(this->buffer_send+offset, derivation.data, 32);
offset += 32;
//derivation
this->send_secret((unsigned char*)derivation.data, offset);
//index
this->buffer_send[offset+0] = output_index>>24;
this->buffer_send[offset+1] = output_index>>16;
@ -992,8 +1072,9 @@ namespace hw {
this->length_send = offset;
this->exchange();
//derivattion data
memmove(res.data, &this->buffer_recv[0], 32);
//derivation data
offset = 0;
this->receive_secret((unsigned char*)res.data, offset);
#ifdef DEBUG_HWDEVICE
crypto::ec_scalar res_clear = hw::ledger::decrypt(res);
@ -1020,8 +1101,7 @@ namespace hw {
int offset = set_command_header_noopt(INS_DERIVE_SECRET_KEY);
//derivation
memmove(this->buffer_send+offset, derivation.data, 32);
offset += 32;
this->send_secret((unsigned char*)derivation.data, offset);
//index
this->buffer_send[offset+0] = output_index>>24;
this->buffer_send[offset+1] = output_index>>16;
@ -1029,15 +1109,15 @@ namespace hw {
this->buffer_send[offset+3] = output_index>>0;
offset += 4;
//sec
memmove(this->buffer_send+offset, sec.data, 32);
offset += 32;
this->send_secret((unsigned char*)sec.data, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
this->exchange();
//pub key
memmove(derived_sec.data, &this->buffer_recv[0], 32);
offset = 0;
//sec key
this->receive_secret((unsigned char*)derived_sec.data, offset);
#ifdef DEBUG_HWDEVICE
crypto::secret_key derived_sec_clear = hw::ledger::decrypt(derived_sec);
@ -1064,8 +1144,7 @@ namespace hw {
int offset = set_command_header_noopt(INS_DERIVE_PUBLIC_KEY);
//derivation
memmove(this->buffer_send+offset, derivation.data, 32);
offset += 32;
this->send_secret((unsigned char*)derivation.data, offset);
//index
this->buffer_send[offset+0] = output_index>>24;
this->buffer_send[offset+1] = output_index>>16;
@ -1106,8 +1185,7 @@ namespace hw {
int offset = set_command_header_noopt(INS_SECRET_KEY_TO_PUBLIC_KEY);
//sec key
memmove(this->buffer_send+offset, sec.data, 32);
offset += 32;
this->send_secret((unsigned char*)sec.data, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
@ -1141,8 +1219,7 @@ namespace hw {
memmove(this->buffer_send+offset, pub.data, 32);
offset += 32;
//sec
memmove(this->buffer_send+offset, sec.data, 32);
offset += 32;
this->send_secret((unsigned char*)sec.data, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
@ -1211,8 +1288,7 @@ namespace hw {
memmove(&this->buffer_send[offset], D.data, 32);
offset += 32;
// r
memmove(&this->buffer_send[offset], r.data, 32);
offset += 32;
this->send_secret((unsigned char*)r.data, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
@ -1225,6 +1301,7 @@ namespace hw {
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);
MDEBUG("FAIL is normal if random is not fixed in proof");
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);
@ -1233,8 +1310,10 @@ namespace hw {
bool device_ledger::open_tx(crypto::secret_key &tx_key) {
AUTO_LOCK_CMD();
this->lock();
key_map.clear();
hmac_map.clear();
this->tx_in_progress = true;
int offset = set_command_header_noopt(INS_OPEN_TX, 0x01);
//account
@ -1248,7 +1327,13 @@ namespace hw {
this->length_send = offset;
this->exchange();
memmove(tx_key.data, &this->buffer_recv[32], 32);
//skip R, receive: r, r_hmac, fake_a, a_hmac, fake_b, hmac_b
unsigned char tmp[32];
offset = 32;
this->receive_secret((unsigned char*)tx_key.data, offset);
this->receive_secret(tmp, offset);
this->receive_secret(tmp, offset);
#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);
@ -1276,8 +1361,7 @@ namespace hw {
memmove(&this->buffer_send[offset], public_key.data, 32);
offset += 32;
//sec
memmove(&this->buffer_send[offset], secret_key.data, 32);
offset += 32;
this->send_secret((unsigned char*)secret_key.data, offset);
//id
memmove(&this->buffer_send[offset], payment_id.data, 8);
offset += 8;
@ -1365,8 +1449,7 @@ namespace hw {
this->buffer_send[offset+3] = tx_version>>0;
offset += 4;
//tx_key
memmove(&this->buffer_send[offset], tx_key.data, 32);
offset += 32;
this->send_secret((unsigned char*)tx_key.data, offset);
//txkey_pub
memmove(&this->buffer_send[offset], txkey_pub.data, 32);
offset += 32;
@ -1394,11 +1477,11 @@ namespace hw {
offset++;
//additional_tx_key
if (need_additional_txkeys) {
memmove(&this->buffer_send[offset], additional_txkey.sec.data, 32);
this->send_secret((unsigned char*)additional_txkey.sec.data, offset);
} else {
memset(&this->buffer_send[offset], 0, 32);
}
offset += 32;
}
this->buffer_send[4] = offset-5;
this->length_send = offset;
@ -1411,9 +1494,8 @@ namespace hw {
{
ASSERT_X(recv_len>=32, "Not enought data from device");
crypto::secret_key scalar1;
memmove(scalar1.data, &this->buffer_recv[offset],32);
this->receive_secret((unsigned char*)scalar1.data, offset);
amount_keys.push_back(rct::sk2rct(scalar1));
offset += 32;
recv_len -= 32;
}
ASSERT_X(recv_len>=32, "Not enought data from device");
@ -1464,8 +1546,7 @@ namespace hw {
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->send_secret(AKout.bytes, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
@ -1494,8 +1575,7 @@ namespace hw {
this->buffer_send[offset] = short_amount?0x02:0x00;
offset += 1;
// AKout
memmove(this->buffer_send+offset, AKout.bytes, 32);
offset += 32;
this->send_secret(AKout.bytes, offset);
//mask k
memmove(this->buffer_send+offset, unmasked.mask.bytes, 32);
offset += 32;
@ -1535,8 +1615,7 @@ namespace hw {
this->buffer_send[offset] = short_amount?0x02:0x00;
offset += 1;
// AKout
memmove(this->buffer_send+offset, AKout.bytes, 32);
offset += 32;
this->send_secret(AKout.bytes, offset);
//mask k
memmove(this->buffer_send+offset, masked.mask.bytes, 32);
offset += 32;
@ -1649,7 +1728,6 @@ namespace hw {
this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ;
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2)?0x02:0x00;
offset += 1;
if (found) {
//is_subaddress
this->buffer_send[offset] = outKeys.is_subaddress;
offset++;
@ -1663,12 +1741,8 @@ namespace hw {
memmove(this->buffer_send+offset, outKeys.Bout.bytes, 32);
offset+=32;
//AKout
memmove(this->buffer_send+offset, outKeys.AKout.bytes, 32);
offset+=32;
} else {
// dummy: is_subaddress Aout Bout AKout
offset += 2+32*3;
}
this->send_secret(outKeys.AKout.bytes, offset);
//C
memmove(this->buffer_send+offset, data+C_offset,32);
offset += 32;
@ -1760,17 +1834,19 @@ namespace hw {
memmove(this->buffer_send+offset, H.bytes, 32);
offset += 32;
//mask xin
memmove(this->buffer_send+offset, xx.bytes, 32);
offset += 32;
this->send_secret(xx.bytes, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
this->exchange();
memmove(a.bytes, &this->buffer_recv[32*0], 32);
memmove(aG.bytes, &this->buffer_recv[32*1], 32);
memmove(aHP.bytes, &this->buffer_recv[32*2], 32);
memmove(II.bytes, &this->buffer_recv[32*3], 32);
offset = 0;
this->receive_secret(a.bytes, offset);
memmove(aG.bytes, &this->buffer_recv[offset], 32);
offset +=32;
memmove(aHP.bytes, &this->buffer_recv[offset], 32);
offset +=32;
memmove(II.bytes, &this->buffer_recv[offset], 32);
#ifdef DEBUG_HWDEVICE
a_x = hw::ledger::decrypt(a);
@ -1788,6 +1864,7 @@ namespace hw {
bool device_ledger::mlsag_prepare(rct::key &a, rct::key &aG) {
AUTO_LOCK_CMD();
int offset;
#ifdef DEBUG_HWDEVICE
rct::key a_x;
@ -1796,8 +1873,9 @@ namespace hw {
send_simple(INS_MLSAG, 0x01);
memmove(a.bytes, &this->buffer_recv[32*0], 32);
memmove(aG.bytes, &this->buffer_recv[32*1], 32);
offset = 0;
this->receive_secret(a.bytes, offset);
memmove(aG.bytes, &this->buffer_recv[offset], 32);
#ifdef DEBUG_HWDEVICE
a_x = hw::ledger::decrypt(a);
@ -1870,11 +1948,9 @@ namespace hw {
}
offset += 1;
//xx
memmove(this->buffer_send+offset, xx[j].bytes, 32);
offset += 32;
this->send_secret(xx[j].bytes, offset);
//alpa
memmove(this->buffer_send+offset, alpha[j].bytes, 32);
offset += 32;
this->send_secret(alpha[j].bytes, offset);
this->buffer_send[4] = offset-5;
this->length_send = offset;
@ -1900,6 +1976,10 @@ namespace hw {
bool device_ledger::close_tx() {
AUTO_LOCK_CMD();
send_simple(INS_CLOSE_TX);
key_map.clear();
hmac_map.clear();
this->tx_in_progress = false;
this->unlock();
return true;
}

View file

@ -90,6 +90,25 @@ namespace hw {
void log();
};
class SecHMAC {
public:
uint32_t sec[32];
uint32_t hmac[32];
SecHMAC(const uint8_t s[32], const uint8_t m[32]);
};
class HMACmap {
public:
std::vector<SecHMAC> hmacs;
void find_mac(const uint8_t sec[32], uint8_t hmac[32]) ;
void add_mac(const uint8_t sec[32], const uint8_t hmac[32]) ;
void clear() ;
};
#define BUFFER_SEND_SIZE 262
#define BUFFER_RECV_SIZE 262
@ -115,15 +134,21 @@ namespace hw {
int set_command_header(unsigned char ins, unsigned char p1 = 0x00, unsigned char p2 = 0x00);
int set_command_header_noopt(unsigned char ins, unsigned char p1 = 0x00, unsigned char p2 = 0x00);
void send_simple(unsigned char ins, unsigned char p1 = 0x00);
void send_secret(const unsigned char sec[32], int &offset);
void receive_secret(unsigned char sec[32], int &offset);
// hw running mode
device_mode mode;
bool tx_in_progress;
// map public destination key to ephemeral destination key
Keymap key_map;
bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, const bool is_subaddress, const bool is_change,
const bool need_additional, const size_t real_output_index,
const rct::key &amount_key, const crypto::public_key &out_eph_public_key);
//hmac for some encrypted value
HMACmap hmac_map;
// To speed up blockchain parsing the view key maybe handle here.
crypto::secret_key viewkey;
bool has_view_key;
@ -174,7 +199,7 @@ namespace hw {
bool get_public_address(cryptonote::account_public_address &pubkey) override;
bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override;
bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) override;
void display_address(const cryptonote::subaddress_index& index, const boost::optional<crypto::hash8> &payment_id) override;
/* ======================================================================= */
/* SUB ADDRESS */