2019-04-12 06:36:43 +02:00
|
|
|
// Copyright (c) 2017-2019, The Monero Project
|
2018-04-10 06:49:20 +02:00
|
|
|
// Copyright (c) 2018, The Loki Project
|
2018-02-20 17:01:27 +01:00
|
|
|
//
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without modification, are
|
|
|
|
// permitted provided that the following conditions are met:
|
|
|
|
//
|
|
|
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
|
|
// conditions and the following disclaimer.
|
|
|
|
//
|
|
|
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
|
|
// of conditions and the following disclaimer in the documentation and/or other
|
|
|
|
// materials provided with the distribution.
|
|
|
|
//
|
|
|
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
|
|
|
// used to endorse or promote products derived from this software without specific
|
|
|
|
// prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
|
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
|
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
//
|
|
|
|
|
2018-12-11 10:20:21 +01:00
|
|
|
#include "version.h"
|
2018-02-20 17:01:27 +01:00
|
|
|
#include "device_ledger.hpp"
|
|
|
|
#include "ringct/rctOps.h"
|
2018-03-05 08:16:30 +01:00
|
|
|
#include "cryptonote_basic/account.h"
|
|
|
|
#include "cryptonote_basic/subaddress_index.h"
|
2018-12-11 10:20:21 +01:00
|
|
|
#include "cryptonote_core/cryptonote_tx_utils.h"
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
#include "common/lock.h"
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
namespace hw {
|
|
|
|
|
|
|
|
namespace ledger {
|
|
|
|
|
|
|
|
#ifdef WITH_DEVICE_LEDGER
|
|
|
|
|
2018-04-10 06:49:20 +02:00
|
|
|
#undef LOKI_DEFAULT_LOG_CATEGORY
|
|
|
|
#define LOKI_DEFAULT_LOG_CATEGORY "device.ledger"
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
/* ===================================================================== */
|
|
|
|
/* === Debug ==== */
|
|
|
|
/* ===================================================================== */
|
2018-05-23 10:22:55 +02:00
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
void set_apdu_verbose(bool verbose) {
|
|
|
|
apdu_verbose = verbose;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define TRACKD MTRACE("hw")
|
2020-02-07 15:20:38 +01:00
|
|
|
#define ASSERT_SW(sw,ok,msk) CHECK_AND_ASSERT_THROW_MES(((sw)&(mask))==(ok), \
|
|
|
|
"Wrong Device Status: " << "0x" << std::hex << (sw) << " (" << Status::to_string(sw) << "), " << \
|
|
|
|
"EXPECTED 0x" << std::hex << (ok) << " (" << Status::to_string(ok) << "), " << \
|
|
|
|
"MASK 0x" << std::hex << (mask));
|
2018-02-20 17:01:27 +01:00
|
|
|
#define ASSERT_T0(exp) CHECK_AND_ASSERT_THROW_MES(exp, "Protocol assert failure: "#exp ) ;
|
2018-04-09 16:07:11 +02:00
|
|
|
#define ASSERT_X(exp,msg) CHECK_AND_ASSERT_THROW_MES(exp, msg);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
2018-03-26 12:55:48 +02:00
|
|
|
crypto::secret_key dbg_viewkey;
|
|
|
|
crypto::secret_key dbg_spendkey;
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2020-02-07 15:20:38 +01:00
|
|
|
struct Status
|
|
|
|
{
|
|
|
|
unsigned int code;
|
|
|
|
const char *string;
|
|
|
|
|
|
|
|
constexpr operator unsigned int() const
|
|
|
|
{
|
|
|
|
return this->code;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *to_string(unsigned int code);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Must be sorted in ascending order by the code
|
|
|
|
#define LEDGER_STATUS(status) {status, #status}
|
|
|
|
constexpr Status status_codes[] = {
|
|
|
|
LEDGER_STATUS(SW_BYTES_REMAINING_00),
|
|
|
|
LEDGER_STATUS(SW_WARNING_STATE_UNCHANGED),
|
|
|
|
LEDGER_STATUS(SW_STATE_TERMINATED),
|
|
|
|
LEDGER_STATUS(SW_MORE_DATA_AVAILABLE),
|
|
|
|
LEDGER_STATUS(SW_WRONG_LENGTH),
|
|
|
|
LEDGER_STATUS(SW_LOGICAL_CHANNEL_NOT_SUPPORTED),
|
|
|
|
LEDGER_STATUS(SW_SECURE_MESSAGING_NOT_SUPPORTED),
|
|
|
|
LEDGER_STATUS(SW_LAST_COMMAND_EXPECTED),
|
|
|
|
LEDGER_STATUS(SW_COMMAND_CHAINING_NOT_SUPPORTED),
|
|
|
|
LEDGER_STATUS(SW_SECURITY_LOAD_KEY),
|
|
|
|
LEDGER_STATUS(SW_SECURITY_COMMITMENT_CONTROL),
|
|
|
|
LEDGER_STATUS(SW_SECURITY_AMOUNT_CHAIN_CONTROL),
|
|
|
|
LEDGER_STATUS(SW_SECURITY_COMMITMENT_CHAIN_CONTROL),
|
|
|
|
LEDGER_STATUS(SW_SECURITY_OUTKEYS_CHAIN_CONTROL),
|
|
|
|
LEDGER_STATUS(SW_SECURITY_MAXOUTPUT_REACHED),
|
|
|
|
LEDGER_STATUS(SW_SECURITY_TRUSTED_INPUT),
|
|
|
|
LEDGER_STATUS(SW_CLIENT_NOT_SUPPORTED),
|
|
|
|
LEDGER_STATUS(SW_SECURITY_STATUS_NOT_SATISFIED),
|
|
|
|
LEDGER_STATUS(SW_FILE_INVALID),
|
|
|
|
LEDGER_STATUS(SW_PIN_BLOCKED),
|
|
|
|
LEDGER_STATUS(SW_DATA_INVALID),
|
|
|
|
LEDGER_STATUS(SW_CONDITIONS_NOT_SATISFIED),
|
|
|
|
LEDGER_STATUS(SW_COMMAND_NOT_ALLOWED),
|
|
|
|
LEDGER_STATUS(SW_APPLET_SELECT_FAILED),
|
|
|
|
LEDGER_STATUS(SW_WRONG_DATA),
|
|
|
|
LEDGER_STATUS(SW_FUNC_NOT_SUPPORTED),
|
|
|
|
LEDGER_STATUS(SW_FILE_NOT_FOUND),
|
|
|
|
LEDGER_STATUS(SW_RECORD_NOT_FOUND),
|
|
|
|
LEDGER_STATUS(SW_FILE_FULL),
|
|
|
|
LEDGER_STATUS(SW_INCORRECT_P1P2),
|
|
|
|
LEDGER_STATUS(SW_REFERENCED_DATA_NOT_FOUND),
|
|
|
|
LEDGER_STATUS(SW_WRONG_P1P2),
|
|
|
|
LEDGER_STATUS(SW_CORRECT_LENGTH_00),
|
|
|
|
LEDGER_STATUS(SW_INS_NOT_SUPPORTED),
|
|
|
|
LEDGER_STATUS(SW_CLA_NOT_SUPPORTED),
|
|
|
|
LEDGER_STATUS(SW_UNKNOWN),
|
|
|
|
LEDGER_STATUS(SW_OK),
|
|
|
|
LEDGER_STATUS(SW_ALGORITHM_UNSUPPORTED)
|
|
|
|
};
|
|
|
|
|
|
|
|
const char *Status::to_string(unsigned int code)
|
|
|
|
{
|
|
|
|
constexpr size_t status_codes_size = sizeof(status_codes) / sizeof(status_codes[0]);
|
|
|
|
constexpr const Status *status_codes_end = &status_codes[status_codes_size];
|
|
|
|
|
|
|
|
const Status *item = std::lower_bound(&status_codes[0], status_codes_end, code);
|
|
|
|
return (item == status_codes_end || code < *item) ? "UNKNOWN" : item->string;
|
|
|
|
}
|
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
/* ===================================================================== */
|
|
|
|
/* === 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();
|
|
|
|
}
|
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
/* ===================================================================== */
|
|
|
|
/* === Keymap ==== */
|
|
|
|
/* ===================================================================== */
|
|
|
|
|
2018-12-11 10:20:21 +01:00
|
|
|
ABPkeys::ABPkeys(const rct::key& A, const rct::key& B, const bool is_subaddr, const bool is_change, const bool need_additional_txkeys, const size_t real_output_index, const rct::key& P, const rct::key& AK) {
|
2018-02-20 17:01:27 +01:00
|
|
|
Aout = A;
|
|
|
|
Bout = B;
|
2018-03-05 14:46:15 +01:00
|
|
|
is_subaddress = is_subaddr;
|
2018-12-11 10:20:21 +01:00
|
|
|
is_change_address = is_change;
|
|
|
|
additional_key = need_additional_txkeys;
|
2018-02-20 17:01:27 +01:00
|
|
|
index = real_output_index;
|
|
|
|
Pout = P;
|
|
|
|
AKout = AK;
|
|
|
|
}
|
|
|
|
|
|
|
|
ABPkeys::ABPkeys(const ABPkeys& keys) {
|
2018-03-05 14:46:15 +01:00
|
|
|
Aout = keys.Aout;
|
|
|
|
Bout = keys.Bout;
|
|
|
|
is_subaddress = keys.is_subaddress;
|
2018-12-11 10:20:21 +01:00
|
|
|
is_change_address = keys.is_change_address;
|
|
|
|
additional_key = keys.additional_key;
|
2018-02-20 17:01:27 +01:00
|
|
|
index = keys.index;
|
2018-03-05 14:46:15 +01:00
|
|
|
Pout = keys.Pout;
|
2018-02-20 17:01:27 +01:00
|
|
|
AKout = keys.AKout;
|
|
|
|
}
|
|
|
|
|
2019-06-08 17:58:33 +02:00
|
|
|
ABPkeys &ABPkeys::operator=(const ABPkeys& keys) {
|
|
|
|
if (&keys == this)
|
|
|
|
return *this;
|
|
|
|
Aout = keys.Aout;
|
|
|
|
Bout = keys.Bout;
|
|
|
|
is_subaddress = keys.is_subaddress;
|
|
|
|
is_change_address = keys.is_change_address;
|
|
|
|
additional_key = keys.additional_key;
|
|
|
|
index = keys.index;
|
|
|
|
Pout = keys.Pout;
|
|
|
|
AKout = keys.AKout;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
bool Keymap::find(const rct::key& P, ABPkeys& keys) const {
|
|
|
|
size_t sz = ABP.size();
|
|
|
|
for (size_t i=0; i<sz; i++) {
|
|
|
|
if (ABP[i].Pout == P) {
|
|
|
|
keys = ABP[i];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Keymap::add(const ABPkeys& keys) {
|
|
|
|
ABP.push_back(keys);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Keymap::clear() {
|
|
|
|
ABP.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
void Keymap::log() {
|
|
|
|
log_message("keymap", "content");
|
|
|
|
size_t sz = ABP.size();
|
|
|
|
for (size_t i=0; i<sz; i++) {
|
|
|
|
log_message(" keymap", std::to_string(i));
|
|
|
|
log_hexbuffer(" Aout", (char*)ABP[i].Aout.bytes, 32);
|
|
|
|
log_hexbuffer(" Bout", (char*)ABP[i].Bout.bytes, 32);
|
2018-03-05 14:46:15 +01:00
|
|
|
log_message (" is_sub", std::to_string(ABP[i].is_subaddress));
|
2018-02-20 17:01:27 +01:00
|
|
|
log_message (" index", std::to_string(ABP[i].index));
|
|
|
|
log_hexbuffer(" Pout", (char*)ABP[i].Pout.bytes, 32);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* ===================================================================== */
|
2018-03-26 12:55:48 +02:00
|
|
|
/* === Internal Helpers ==== */
|
|
|
|
/* ===================================================================== */
|
|
|
|
static bool is_fake_view_key(const crypto::secret_key &sec) {
|
|
|
|
return sec == crypto::null_skey;
|
|
|
|
}
|
|
|
|
|
2018-04-09 16:07:11 +02:00
|
|
|
bool operator==(const crypto::key_derivation &d0, const crypto::key_derivation &d1) {
|
2018-06-13 19:23:06 +02:00
|
|
|
static_assert(sizeof(crypto::key_derivation) == 32, "key_derivation must be 32 bytes");
|
|
|
|
return !crypto_verify_32((const unsigned char*)&d0, (const unsigned char*)&d1);
|
2018-04-09 16:07:11 +02:00
|
|
|
}
|
|
|
|
|
2018-03-26 12:55:48 +02:00
|
|
|
/* ===================================================================== */
|
|
|
|
/* === Device ==== */
|
2018-02-20 17:01:27 +01:00
|
|
|
/* ===================================================================== */
|
|
|
|
|
|
|
|
static int device_id = 0;
|
|
|
|
|
2020-04-03 22:56:55 +02:00
|
|
|
#define PROTOCOL_VERSION 3
|
2018-12-11 10:20:21 +01:00
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
#define INS_NONE 0x00
|
|
|
|
#define INS_RESET 0x02
|
|
|
|
|
|
|
|
#define INS_GET_KEY 0x20
|
2019-09-28 14:03:51 +02:00
|
|
|
#define INS_DISPLAY_ADDRESS 0x21
|
2018-02-20 17:01:27 +01:00
|
|
|
#define INS_PUT_KEY 0x22
|
|
|
|
#define INS_GET_CHACHA8_PREKEY 0x24
|
|
|
|
#define INS_VERIFY_KEY 0x26
|
2019-09-28 14:03:51 +02:00
|
|
|
#define INS_MANAGE_SEEDWORDS 0x28
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#define INS_SECRET_KEY_TO_PUBLIC_KEY 0x30
|
|
|
|
#define INS_GEN_KEY_DERIVATION 0x32
|
|
|
|
#define INS_DERIVATION_TO_SCALAR 0x34
|
|
|
|
#define INS_DERIVE_PUBLIC_KEY 0x36
|
|
|
|
#define INS_DERIVE_SECRET_KEY 0x38
|
|
|
|
#define INS_GEN_KEY_IMAGE 0x3A
|
|
|
|
#define INS_SECRET_KEY_ADD 0x3C
|
|
|
|
#define INS_SECRET_KEY_SUB 0x3E
|
|
|
|
#define INS_GENERATE_KEYPAIR 0x40
|
|
|
|
#define INS_SECRET_SCAL_MUL_KEY 0x42
|
|
|
|
#define INS_SECRET_SCAL_MUL_BASE 0x44
|
|
|
|
|
|
|
|
#define INS_DERIVE_SUBADDRESS_PUBLIC_KEY 0x46
|
|
|
|
#define INS_GET_SUBADDRESS 0x48
|
|
|
|
#define INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY 0x4A
|
|
|
|
#define INS_GET_SUBADDRESS_SECRET_KEY 0x4C
|
|
|
|
|
|
|
|
#define INS_OPEN_TX 0x70
|
|
|
|
#define INS_SET_SIGNATURE_MODE 0x72
|
|
|
|
#define INS_GET_ADDITIONAL_KEY 0x74
|
|
|
|
#define INS_STEALTH 0x76
|
2018-12-11 10:20:21 +01:00
|
|
|
#define INS_GEN_COMMITMENT_MASK 0x77
|
2018-02-20 17:01:27 +01:00
|
|
|
#define INS_BLIND 0x78
|
|
|
|
#define INS_UNBLIND 0x7A
|
2018-12-11 10:20:21 +01:00
|
|
|
#define INS_GEN_TXOUT_KEYS 0x7B
|
2020-04-03 22:56:55 +02:00
|
|
|
#define INS_PREFIX_HASH 0x7D
|
2018-02-20 17:01:27 +01:00
|
|
|
#define INS_VALIDATE 0x7C
|
|
|
|
#define INS_MLSAG 0x7E
|
|
|
|
#define INS_CLOSE_TX 0x80
|
|
|
|
|
2019-03-21 17:22:43 +01:00
|
|
|
#define INS_GET_TX_PROOF 0xA0
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#define INS_GET_RESPONSE 0xc0
|
|
|
|
|
|
|
|
|
2019-01-09 09:20:53 +01:00
|
|
|
device_ledger::device_ledger(): hw_device(0x0101, 0x05, 64, 2000) {
|
2018-02-20 17:01:27 +01:00
|
|
|
this->id = device_id++;
|
|
|
|
this->reset_buffer();
|
2018-03-26 12:55:48 +02:00
|
|
|
this->mode = NONE;
|
|
|
|
this->has_view_key = false;
|
2019-09-25 14:31:14 +02:00
|
|
|
this->tx_in_progress = false;
|
2018-02-20 17:01:27 +01:00
|
|
|
MDEBUG( "Device "<<this->id <<" Created");
|
|
|
|
}
|
|
|
|
|
|
|
|
device_ledger::~device_ledger() {
|
|
|
|
this->release();
|
|
|
|
MDEBUG( "Device "<<this->id <<" Destroyed");
|
|
|
|
}
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
/* ======================================================================= */
|
|
|
|
/* LOCKER */
|
|
|
|
/* ======================================================================= */
|
|
|
|
|
|
|
|
//lock the device for a long sequence
|
|
|
|
void device_ledger::lock(void) {
|
|
|
|
MDEBUG( "Ask for LOCKING for device "<<this->name << " in thread ");
|
|
|
|
device_locker.lock();
|
|
|
|
MDEBUG( "Device "<<this->name << " LOCKed");
|
|
|
|
}
|
|
|
|
|
|
|
|
//lock the device for a long sequence
|
|
|
|
bool device_ledger::try_lock(void) {
|
|
|
|
MDEBUG( "Ask for LOCKING(try) for device "<<this->name << " in thread ");
|
|
|
|
bool r = device_locker.try_lock();
|
|
|
|
if (r) {
|
|
|
|
MDEBUG( "Device "<<this->name << " LOCKed(try)");
|
|
|
|
} else {
|
|
|
|
MDEBUG( "Device "<<this->name << " not LOCKed(try)");
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
//lock the device for a long sequence
|
|
|
|
void device_ledger::unlock(void) {
|
|
|
|
try {
|
|
|
|
MDEBUG( "Ask for UNLOCKING for device "<<this->name << " in thread ");
|
|
|
|
} catch (...) {
|
|
|
|
}
|
|
|
|
device_locker.unlock();
|
|
|
|
MDEBUG( "Device "<<this->name << " UNLOCKed");
|
|
|
|
}
|
2018-02-20 17:01:27 +01:00
|
|
|
|
2018-08-01 09:24:53 +02:00
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
/* ======================================================================= */
|
2018-08-01 09:24:53 +02:00
|
|
|
/* IO */
|
2018-02-20 17:01:27 +01:00
|
|
|
/* ======================================================================= */
|
2018-08-01 09:24:53 +02:00
|
|
|
|
2019-01-09 09:20:53 +01:00
|
|
|
#define IO_SW_DENY 0x6982
|
|
|
|
#define IO_SECRET_KEY 0x02
|
|
|
|
|
2018-08-01 09:24:53 +02:00
|
|
|
void device_ledger::logCMD() {
|
|
|
|
if (apdu_verbose) {
|
|
|
|
char strbuffer[1024];
|
|
|
|
snprintf(strbuffer, sizeof(strbuffer), "%.02x %.02x %.02x %.02x %.02x ",
|
|
|
|
this->buffer_send[0],
|
|
|
|
this->buffer_send[1],
|
|
|
|
this->buffer_send[2],
|
|
|
|
this->buffer_send[3],
|
|
|
|
this->buffer_send[4]
|
|
|
|
);
|
|
|
|
const size_t len = strlen(strbuffer);
|
|
|
|
buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_send+5), this->length_send-5);
|
|
|
|
MDEBUG( "CMD : " << strbuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void device_ledger::logRESP() {
|
|
|
|
if (apdu_verbose) {
|
|
|
|
char strbuffer[1024];
|
|
|
|
snprintf(strbuffer, sizeof(strbuffer), "%.04x ", this->sw);
|
|
|
|
const size_t len = strlen(strbuffer);
|
|
|
|
buffer_to_str(strbuffer+len, sizeof(strbuffer)-len, (char*)(this->buffer_recv), this->length_recv);
|
|
|
|
MDEBUG( "RESP : " << strbuffer);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int device_ledger::set_command_header(unsigned char ins, unsigned char p1, unsigned char p2) {
|
2018-06-20 11:40:09 +02:00
|
|
|
reset_buffer();
|
2018-12-11 10:20:21 +01:00
|
|
|
this->buffer_send[0] = PROTOCOL_VERSION;
|
2018-06-20 11:40:09 +02:00
|
|
|
this->buffer_send[1] = ins;
|
|
|
|
this->buffer_send[2] = p1;
|
|
|
|
this->buffer_send[3] = p2;
|
|
|
|
this->buffer_send[4] = 0x00;
|
|
|
|
return 5;
|
|
|
|
}
|
2018-02-20 17:01:27 +01:00
|
|
|
|
2018-08-01 09:24:53 +02:00
|
|
|
int device_ledger::set_command_header_noopt(unsigned char ins, unsigned char p1, unsigned char p2) {
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header(ins, p1, p2);
|
|
|
|
//options
|
|
|
|
this->buffer_send[offset++] = 0;
|
|
|
|
this->buffer_send[4] = offset - 5;
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2018-08-01 09:24:53 +02:00
|
|
|
void device_ledger::send_simple(unsigned char ins, unsigned char p1) {
|
2018-06-20 11:40:09 +02:00
|
|
|
this->length_send = set_command_header_noopt(ins, p1);
|
2019-01-09 09:20:53 +01:00
|
|
|
if (ins == INS_GET_KEY && p1 == IO_SECRET_KEY) {
|
|
|
|
// export view key user input
|
|
|
|
this->exchange_wait_on_input();
|
|
|
|
} else {
|
|
|
|
this->exchange();
|
|
|
|
}
|
2018-06-20 11:40:09 +02:00
|
|
|
}
|
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
void device_ledger::send_secret(const unsigned char sec[32], int &offset) {
|
|
|
|
MDEBUG("send_secret: " << this->tx_in_progress);
|
2019-10-25 15:13:23 +02:00
|
|
|
ASSERT_X(offset + 32 <= BUFFER_SEND_SIZE, "send_secret: out of bounds write (secret)");
|
2019-09-25 14:31:14 +02:00
|
|
|
memmove(this->buffer_send+offset, sec, 32);
|
|
|
|
offset +=32;
|
|
|
|
if (this->tx_in_progress) {
|
2019-10-25 15:13:23 +02:00
|
|
|
ASSERT_X(offset + 32 <= BUFFER_SEND_SIZE, "send_secret: out of bounds write (mac)");
|
2019-09-25 14:31:14 +02:00
|
|
|
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);
|
2019-10-25 15:13:23 +02:00
|
|
|
ASSERT_X(offset + 32 <= BUFFER_RECV_SIZE, "receive_secret: out of bounds read (secret)");
|
2019-09-25 14:31:14 +02:00
|
|
|
memmove(sec, this->buffer_recv+offset, 32);
|
|
|
|
offset += 32;
|
|
|
|
if (this->tx_in_progress) {
|
2019-10-25 15:13:23 +02:00
|
|
|
ASSERT_X(offset + 32 <= BUFFER_RECV_SIZE, "receive_secret: out of bounds read (mac)");
|
2019-09-25 14:31:14 +02:00
|
|
|
this->hmac_map.add_mac((uint8_t*)sec, this->buffer_recv+offset);
|
|
|
|
offset += 32;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
bool device_ledger::reset() {
|
2019-03-07 23:34:53 +01:00
|
|
|
reset_buffer();
|
|
|
|
int offset = set_command_header_noopt(INS_RESET);
|
2020-05-18 08:16:29 +02:00
|
|
|
const size_t verlen = strlen(LOKI_VERSION_STR);
|
|
|
|
ASSERT_X(offset + verlen <= BUFFER_SEND_SIZE, "LOKI_VERSION_STR is too long")
|
|
|
|
memmove(this->buffer_send+offset, LOKI_VERSION_STR, verlen);
|
2019-10-15 22:31:46 +02:00
|
|
|
offset += strlen(LOKI_VERSION_STR);
|
2019-03-07 23:34:53 +01:00
|
|
|
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;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int device_ledger::exchange(unsigned int ok, unsigned int mask) {
|
|
|
|
logCMD();
|
|
|
|
|
2019-01-09 09:20:53 +01:00
|
|
|
this->length_recv = hw_device.exchange(this->buffer_send, this->length_send, this->buffer_recv, BUFFER_SEND_SIZE, false);
|
2018-08-01 09:24:53 +02:00
|
|
|
ASSERT_X(this->length_recv>=2, "Communication error, less than tow bytes received");
|
|
|
|
|
|
|
|
this->length_recv -= 2;
|
|
|
|
this->sw = (this->buffer_recv[length_recv]<<8) | this->buffer_recv[length_recv+1];
|
2018-12-11 10:20:21 +01:00
|
|
|
logRESP();
|
2018-08-01 09:24:53 +02:00
|
|
|
ASSERT_SW(this->sw,ok,msk);
|
|
|
|
|
|
|
|
return this->sw;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-09 09:20:53 +01:00
|
|
|
unsigned int device_ledger::exchange_wait_on_input(unsigned int ok, unsigned int mask) {
|
|
|
|
logCMD();
|
|
|
|
unsigned int deny = 0;
|
|
|
|
this->length_recv = hw_device.exchange(this->buffer_send, this->length_send, this->buffer_recv, BUFFER_SEND_SIZE, true);
|
|
|
|
ASSERT_X(this->length_recv>=2, "Communication error, less than two bytes received");
|
|
|
|
|
|
|
|
this->length_recv -= 2;
|
|
|
|
this->sw = (this->buffer_recv[length_recv]<<8) | this->buffer_recv[length_recv+1];
|
|
|
|
if (this->sw == IO_SW_DENY) {
|
|
|
|
// cancel on device
|
|
|
|
deny = 1;
|
|
|
|
} else {
|
|
|
|
ASSERT_SW(this->sw,ok,msk);
|
|
|
|
}
|
|
|
|
|
|
|
|
logRESP();
|
|
|
|
return deny;
|
|
|
|
}
|
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
void device_ledger::reset_buffer() {
|
|
|
|
this->length_send = 0;
|
|
|
|
memset(this->buffer_send, 0, BUFFER_SEND_SIZE);
|
|
|
|
this->length_recv = 0;
|
|
|
|
memset(this->buffer_recv, 0, BUFFER_RECV_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ======================================================================= */
|
|
|
|
/* SETUP/TEARDOWN */
|
|
|
|
/* ======================================================================= */
|
|
|
|
|
|
|
|
bool device_ledger::set_name(const std::string & name) {
|
|
|
|
this->name = name;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::string device_ledger::get_name() const {
|
2019-01-09 05:32:04 +01:00
|
|
|
if (!this->connected()) {
|
2018-02-20 17:01:27 +01:00
|
|
|
return std::string("<disconnected:").append(this->name).append(">");
|
|
|
|
}
|
2018-08-01 09:24:53 +02:00
|
|
|
return this->name;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::init(void) {
|
2018-03-05 14:46:15 +01:00
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
this->controle_device = &hw::get_device("default");
|
|
|
|
#endif
|
2018-02-20 17:01:27 +01:00
|
|
|
this->release();
|
2018-08-01 09:24:53 +02:00
|
|
|
hw_device.init();
|
|
|
|
MDEBUG( "Device "<<this->id <<" HIDUSB inited");
|
2018-02-20 17:01:27 +01:00
|
|
|
return true;
|
|
|
|
}
|
2019-03-28 17:14:24 +01:00
|
|
|
|
|
|
|
static const std::vector<hw::io::hid_conn_params> known_devices {
|
|
|
|
{0x2c97, 0x0001, 0, 0xffa0},
|
|
|
|
{0x2c97, 0x0004, 0, 0xffa0},
|
|
|
|
};
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
bool device_ledger::connect(void) {
|
|
|
|
this->disconnect();
|
2019-03-28 17:14:24 +01:00
|
|
|
hw_device.connect(known_devices);
|
2018-02-20 17:01:27 +01:00
|
|
|
this->reset();
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
cryptonote::account_public_address pubkey;
|
|
|
|
this->get_public_address(pubkey);
|
2019-10-01 15:52:47 +02:00
|
|
|
#endif
|
2018-02-20 17:01:27 +01:00
|
|
|
crypto::secret_key vkey;
|
|
|
|
crypto::secret_key skey;
|
|
|
|
this->get_secret_keys(vkey,skey);
|
|
|
|
|
2018-08-01 09:24:53 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::connected(void) const {
|
|
|
|
return hw_device.connected();
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::disconnect() {
|
2018-08-01 09:24:53 +02:00
|
|
|
hw_device.disconnect();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::release() {
|
|
|
|
this->disconnect();
|
|
|
|
hw_device.release();
|
2018-02-20 17:01:27 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-03-26 12:55:48 +02:00
|
|
|
bool device_ledger::set_mode(device_mode mode) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-03-26 12:55:48 +02:00
|
|
|
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
switch(mode) {
|
|
|
|
case TRANSACTION_CREATE_REAL:
|
|
|
|
case TRANSACTION_CREATE_FAKE:
|
2018-06-20 11:40:09 +02:00
|
|
|
offset = set_command_header_noopt(INS_SET_SIGNATURE_MODE, 1);
|
2018-03-26 12:55:48 +02:00
|
|
|
//account
|
|
|
|
this->buffer_send[offset] = mode;
|
|
|
|
offset += 1;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
this->mode = mode;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TRANSACTION_PARSE:
|
|
|
|
case NONE:
|
|
|
|
this->mode = mode;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
CHECK_AND_ASSERT_THROW_MES(false, " device_ledger::set_mode(unsigned int mode): invalid mode: "<<mode);
|
|
|
|
}
|
|
|
|
MDEBUG("Switch to mode: " <<mode);
|
2018-10-19 13:15:31 +02:00
|
|
|
return device::set_mode(mode);
|
2018-03-26 12:55:48 +02:00
|
|
|
}
|
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
/* ======================================================================= */
|
|
|
|
/* WALLET & ADDRESS */
|
|
|
|
/* ======================================================================= */
|
|
|
|
|
|
|
|
bool device_ledger::get_public_address(cryptonote::account_public_address &pubkey){
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
send_simple(INS_GET_KEY, 1);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
memmove(pubkey.m_view_public_key.data, this->buffer_recv, 32);
|
|
|
|
memmove(pubkey.m_spend_public_key.data, this->buffer_recv+32, 32);
|
2018-03-26 12:38:38 +02:00
|
|
|
|
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2018-03-26 12:55:48 +02:00
|
|
|
bool device_ledger::get_secret_keys(crypto::secret_key &vkey , crypto::secret_key &skey) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-03-05 14:46:15 +01:00
|
|
|
|
2018-03-26 12:55:48 +02:00
|
|
|
//secret key are represented as fake key on the wallet side
|
|
|
|
memset(vkey.data, 0x00, 32);
|
|
|
|
memset(skey.data, 0xFF, 32);
|
2018-03-05 14:46:15 +01:00
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
//spcialkey, normal conf handled in decrypt
|
2018-06-20 11:40:09 +02:00
|
|
|
send_simple(INS_GET_KEY, 0x02);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
2018-03-26 12:55:48 +02:00
|
|
|
//View key is retrievied, if allowed, to speed up blockchain parsing
|
|
|
|
memmove(this->viewkey.data, this->buffer_recv+0, 32);
|
|
|
|
if (is_fake_view_key(this->viewkey)) {
|
|
|
|
MDEBUG("Have Not view key");
|
|
|
|
this->has_view_key = false;
|
|
|
|
} else {
|
|
|
|
MDEBUG("Have view key");
|
|
|
|
this->has_view_key = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
2019-10-01 17:28:23 +02:00
|
|
|
send_simple(INS_GET_KEY, 0x04);
|
2018-03-26 12:55:48 +02:00
|
|
|
memmove(dbg_viewkey.data, this->buffer_recv+0, 32);
|
|
|
|
memmove(dbg_spendkey.data, this->buffer_recv+32, 32);
|
|
|
|
#endif
|
2018-03-26 12:38:38 +02:00
|
|
|
|
2018-03-26 12:55:48 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2018-07-06 08:42:08 +02:00
|
|
|
bool device_ledger::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
crypto::chacha_key key_x;
|
2018-03-05 14:46:15 +01:00
|
|
|
cryptonote::account_keys keys_x = hw::ledger::decrypt(keys);
|
2018-07-06 08:42:08 +02:00
|
|
|
this->controle_device->generate_chacha_key(keys_x, key_x, kdf_rounds);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
send_simple(INS_GET_CHACHA8_PREKEY);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
char prekey[200];
|
|
|
|
memmove(prekey, &this->buffer_recv[0], 200);
|
2018-07-06 08:42:08 +02:00
|
|
|
crypto::generate_chacha_key_prehashed(&prekey[0], sizeof(prekey), key, kdf_rounds);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
2018-03-05 10:24:11 +01:00
|
|
|
hw::ledger::check32("generate_chacha_key_prehashed", "key", (char*)key_x.data(), (char*)key.data());
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-22 02:17:04 +02:00
|
|
|
void device_ledger::display_address(const cryptonote::subaddress_index& index, const std::optional<crypto::hash8> &payment_id) {
|
2020-06-22 02:42:23 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2019-09-28 14:03:51 +02:00
|
|
|
|
|
|
|
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.");
|
|
|
|
}
|
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
/* ======================================================================= */
|
|
|
|
/* SUB ADDRESS */
|
|
|
|
/* ======================================================================= */
|
|
|
|
|
|
|
|
bool device_ledger::derive_subaddress_public_key(const crypto::public_key &pub, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_pub){
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const crypto::public_key pub_x = pub;
|
2018-03-26 12:55:48 +02:00
|
|
|
crypto::key_derivation derivation_x;
|
|
|
|
if ((this->mode == TRANSACTION_PARSE) && has_view_key) {
|
|
|
|
derivation_x = derivation;
|
|
|
|
} else {
|
|
|
|
derivation_x = hw::ledger::decrypt(derivation);
|
|
|
|
}
|
2018-02-20 17:01:27 +01:00
|
|
|
const std::size_t output_index_x = output_index;
|
|
|
|
crypto::public_key derived_pub_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("derive_subaddress_public_key: [[IN]] pub ", pub_x.data, 32);
|
|
|
|
log_hexbuffer("derive_subaddress_public_key: [[IN]] derivation", derivation_x.data, 32);
|
|
|
|
log_message ("derive_subaddress_public_key: [[IN]] index ", std::to_string((int)output_index_x));
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->derive_subaddress_public_key(pub_x, derivation_x,output_index_x,derived_pub_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("derive_subaddress_public_key: [[OUT]] derived_pub", derived_pub_x.data, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:55:48 +02:00
|
|
|
if ((this->mode == TRANSACTION_PARSE) && has_view_key) {
|
|
|
|
//If we are in TRANSACTION_PARSE, the given derivation has been retrieved uncrypted (wihtout the help
|
|
|
|
//of the device), so continue that way.
|
|
|
|
MDEBUG( "derive_subaddress_public_key : PARSE mode with known viewkey");
|
|
|
|
crypto::derive_subaddress_public_key(pub, derivation, output_index,derived_pub);
|
|
|
|
} else {
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_DERIVE_SUBADDRESS_PUBLIC_KEY);
|
2018-02-20 17:01:27 +01:00
|
|
|
//pub
|
|
|
|
memmove(this->buffer_send+offset, pub.data, 32);
|
|
|
|
offset += 32;
|
|
|
|
//derivation
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)derivation.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
//index
|
|
|
|
this->buffer_send[offset+0] = output_index>>24;
|
|
|
|
this->buffer_send[offset+1] = output_index>>16;
|
|
|
|
this->buffer_send[offset+2] = output_index>>8;
|
|
|
|
this->buffer_send[offset+3] = output_index>>0;
|
|
|
|
offset += 4;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
//pub key
|
|
|
|
memmove(derived_pub.data, &this->buffer_recv[0], 32);
|
|
|
|
}
|
2018-03-26 12:55:48 +02:00
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
hw::ledger::check32("derive_subaddress_public_key", "derived_pub", derived_pub_x.data, derived_pub.data);
|
|
|
|
#endif
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-03-05 06:24:48 +01:00
|
|
|
crypto::public_key device_ledger::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-03-26 12:38:38 +02:00
|
|
|
crypto::public_key D;
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys);
|
|
|
|
const cryptonote::subaddress_index index_x = index;
|
|
|
|
crypto::public_key D_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("get_subaddress_spend_public_key: [[IN]] keys.m_view_secret_key ", keys_x.m_view_secret_key.data,32);
|
|
|
|
log_hexbuffer("get_subaddress_spend_public_key: [[IN]] keys.m_spend_secret_key", keys_x.m_spend_secret_key.data,32);
|
|
|
|
log_message ("get_subaddress_spend_public_key: [[IN]] index ", std::to_string(index_x.major)+"."+std::to_string(index_x.minor));
|
2018-03-26 12:38:38 +02:00
|
|
|
D_x = this->controle_device->get_subaddress_spend_public_key(keys_x, index_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("get_subaddress_spend_public_key: [[OUT]] derivation ", D_x.data, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (index.is_zero()) {
|
|
|
|
D = keys.m_account_address.m_spend_public_key;
|
|
|
|
} else {
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY);
|
2018-02-20 17:01:27 +01:00
|
|
|
//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));
|
|
|
|
offset +=8 ;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
memmove(D.data, &this->buffer_recv[0], 32);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
hw::ledger::check32("get_subaddress_spend_public_key", "D", D_x.data, D.data);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return D;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2018-03-05 06:24:48 +01:00
|
|
|
std::vector<crypto::public_key> device_ledger::get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) {
|
|
|
|
std::vector<crypto::public_key> pkeys;
|
2018-02-20 17:01:27 +01:00
|
|
|
cryptonote::subaddress_index index = {account, begin};
|
|
|
|
crypto::public_key D;
|
|
|
|
for (uint32_t idx = begin; idx < end; ++idx) {
|
|
|
|
index.minor = idx;
|
2018-03-05 06:24:48 +01:00
|
|
|
D = this->get_subaddress_spend_public_key(keys, index);
|
2018-02-20 17:01:27 +01:00
|
|
|
pkeys.push_back(D);
|
|
|
|
}
|
2018-03-05 06:24:48 +01:00
|
|
|
return pkeys;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2018-03-05 06:24:48 +01:00
|
|
|
cryptonote::account_public_address device_ledger::get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-03-26 12:38:38 +02:00
|
|
|
cryptonote::account_public_address address;
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys);
|
|
|
|
const cryptonote::subaddress_index index_x = index;
|
|
|
|
cryptonote::account_public_address address_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("get_subaddress: [[IN]] keys.m_view_secret_key ", keys_x.m_view_secret_key.data, 32);
|
|
|
|
log_hexbuffer("get_subaddress: [[IN]] keys.m_view_public_key", keys_x.m_account_address.m_view_public_key.data, 32);
|
|
|
|
log_hexbuffer("get_subaddress: [[IN]] keys.m_view_secret_key ", keys_x.m_view_secret_key.data, 32);
|
|
|
|
log_hexbuffer("get_subaddress: [[IN]] keys.m_spend_public_key", keys_x.m_account_address.m_spend_public_key.data, 32);
|
|
|
|
log_message ("get_subaddress: [[IN]] index ", std::to_string(index_x.major)+"."+std::to_string(index_x.minor));
|
2018-03-26 12:38:38 +02:00
|
|
|
address_x = this->controle_device->get_subaddress(keys_x, index_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("get_subaddress: [[OUT]] keys.m_view_public_key ", address_x.m_view_public_key.data, 32);
|
|
|
|
log_hexbuffer("get_subaddress: [[OUT]] keys.m_spend_public_key", address_x.m_spend_public_key.data, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (index.is_zero()) {
|
|
|
|
address = keys.m_account_address;
|
|
|
|
} else {
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_GET_SUBADDRESS);
|
2018-02-20 17:01:27 +01:00
|
|
|
//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));
|
|
|
|
offset +=8 ;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
memmove(address.m_view_public_key.data, &this->buffer_recv[0], 32);
|
|
|
|
memmove(address.m_spend_public_key.data, &this->buffer_recv[32], 32);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
hw::ledger::check32("get_subaddress", "address.m_view_public_key.data", address_x.m_view_public_key.data, address.m_view_public_key.data);
|
|
|
|
hw::ledger::check32("get_subaddress", "address.m_spend_public_key.data", address_x.m_spend_public_key.data, address.m_spend_public_key.data);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return address;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2018-03-05 06:24:48 +01:00
|
|
|
crypto::secret_key device_ledger::get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-03-26 12:38:38 +02:00
|
|
|
crypto::secret_key sub_sec;
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
|
|
|
|
const cryptonote::subaddress_index index_x = index;
|
|
|
|
crypto::secret_key sub_sec_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_message ("get_subaddress_secret_key: [[IN]] index ", std::to_string(index.major)+"."+std::to_string(index.minor));
|
|
|
|
log_hexbuffer("get_subaddress_secret_key: [[IN]] sec ", sec_x.data, 32);
|
2018-03-26 12:38:38 +02:00
|
|
|
sub_sec_x = this->controle_device->get_subaddress_secret_key(sec_x, index_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("get_subaddress_secret_key: [[OUT]] sub_sec", sub_sec_x.data, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_GET_SUBADDRESS_SECRET_KEY);
|
2018-02-20 17:01:27 +01:00
|
|
|
//sec
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)sec.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
//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));
|
|
|
|
offset +=8 ;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
offset = 0;
|
|
|
|
this->receive_secret((unsigned char*)sub_sec.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
crypto::secret_key sub_sec_clear = hw::ledger::decrypt(sub_sec);
|
|
|
|
hw::ledger::check32("get_subaddress_secret_key", "sub_sec", sub_sec_x.data, sub_sec_clear.data);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return sub_sec;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ======================================================================= */
|
|
|
|
/* DERIVATION & KEY */
|
|
|
|
/* ======================================================================= */
|
|
|
|
|
|
|
|
bool device_ledger::verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-12-07 16:46:52 +01:00
|
|
|
int offset;
|
2018-03-26 12:38:38 +02:00
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
offset = set_command_header_noopt(INS_VERIFY_KEY);
|
2018-02-20 17:01:27 +01:00
|
|
|
//sec
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)secret_key.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
//pub
|
|
|
|
memmove(this->buffer_send+offset, public_key.data, 32);
|
|
|
|
offset += 32;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
uint32_t verified =
|
|
|
|
this->buffer_recv[0] << 24 |
|
|
|
|
this->buffer_recv[1] << 16 |
|
|
|
|
this->buffer_recv[2] << 8 |
|
|
|
|
this->buffer_recv[3] << 0 ;
|
|
|
|
|
|
|
|
return verified == 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
2018-03-05 14:46:15 +01:00
|
|
|
const rct::key P_x = P;
|
|
|
|
const rct::key a_x = hw::ledger::decrypt(a);
|
|
|
|
rct::key aP_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("scalarmultKey: [[IN]] P ", (char*)P_x.bytes, 32);
|
|
|
|
log_hexbuffer("scalarmultKey: [[IN]] a ", (char*)a_x.bytes, 32);
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->scalarmultKey(aP_x, P_x, a_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("scalarmultKey: [[OUT]] aP", (char*)aP_x.bytes, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_SECRET_SCAL_MUL_KEY);
|
2018-02-20 17:01:27 +01:00
|
|
|
//pub
|
|
|
|
memmove(this->buffer_send+offset, P.bytes, 32);
|
|
|
|
offset += 32;
|
|
|
|
//sec
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret(a.bytes, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
//pub key
|
|
|
|
memmove(aP.bytes, &this->buffer_recv[0], 32);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
2018-03-05 14:46:15 +01:00
|
|
|
hw::ledger::check32("scalarmultKey", "mulkey", (char*)aP_x.bytes, (char*)aP.bytes);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::scalarmultBase(rct::key &aG, const rct::key &a) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
2018-03-05 14:46:15 +01:00
|
|
|
const rct::key a_x = hw::ledger::decrypt(a);
|
|
|
|
rct::key aG_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("scalarmultKey: [[IN]] a ", (char*)a_x.bytes, 32);
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->scalarmultBase(aG_x, a_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("scalarmultKey: [[OUT]] aG", (char*)aG_x.bytes, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_SECRET_SCAL_MUL_BASE);
|
2018-02-20 17:01:27 +01:00
|
|
|
//sec
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret(a.bytes, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
//pub key
|
|
|
|
memmove(aG.bytes, &this->buffer_recv[0], 32);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
2018-03-05 14:46:15 +01:00
|
|
|
hw::ledger::check32("scalarmultBase", "mulkey", (char*)aG_x.bytes, (char*)aG.bytes);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2019-09-25 14:31:14 +02:00
|
|
|
int offset;
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
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;
|
2019-03-21 17:22:43 +01:00
|
|
|
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);
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->sc_secret_add(r_x, a_x, b_x);
|
2019-03-21 17:22:43 +01:00
|
|
|
log_hexbuffer("sc_secret_add: [[OUT]] aG", (char*)r_x.data, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
offset = set_command_header_noopt(INS_SECRET_KEY_ADD);
|
2018-02-20 17:01:27 +01:00
|
|
|
//sec key
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)a.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
//sec key
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)b.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
//sec key
|
|
|
|
offset = 0;
|
|
|
|
this->receive_secret((unsigned char*)r.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
crypto::secret_key r_clear = hw::ledger::decrypt(r);
|
|
|
|
hw::ledger::check32("sc_secret_add", "r", r_x.data, r_clear.data);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2018-03-05 06:24:48 +01:00
|
|
|
crypto::secret_key device_ledger::generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2019-09-25 14:31:14 +02:00
|
|
|
int offset;
|
2018-03-26 12:38:38 +02:00
|
|
|
if (recover) {
|
|
|
|
throw std::runtime_error("device generate key does not support recover");
|
|
|
|
}
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
crypto::public_key pub_x;
|
|
|
|
crypto::secret_key sec_x;
|
2019-03-21 17:22:43 +01:00
|
|
|
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);
|
|
|
|
}
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
send_simple(INS_GENERATE_KEYPAIR);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
offset = 0;
|
2018-02-20 17:01:27 +01:00
|
|
|
//pub key
|
|
|
|
memmove(pub.data, &this->buffer_recv[0], 32);
|
2019-09-25 14:31:14 +02:00
|
|
|
offset += 32;
|
|
|
|
this->receive_secret((unsigned char*)sec.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
crypto::secret_key sec_clear = hw::ledger::decrypt(sec);
|
|
|
|
sec_x = sec_clear;
|
2019-03-21 17:22:43 +01:00
|
|
|
log_hexbuffer("generate_keys: [[OUT]] pub", (char*)pub.data, 32);
|
|
|
|
log_hexbuffer("generate_keys: [[OUT]] sec", (char*)sec_clear.data, 32);
|
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
crypto::secret_key_to_public_key(sec_x,pub_x);
|
|
|
|
hw::ledger::check32("generate_keys", "pub", pub_x.data, pub.data);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return sec;
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-03-26 12:55:48 +02:00
|
|
|
bool r = false;
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const crypto::public_key pub_x = pub;
|
2019-03-21 17:22:43 +01:00
|
|
|
const crypto::secret_key sec_x = (sec == rct::rct2sk(rct::I)) ? sec: hw::ledger::decrypt(sec);
|
2018-02-20 17:01:27 +01:00
|
|
|
crypto::key_derivation derivation_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("generate_key_derivation: [[IN]] pub ", pub_x.data, 32);
|
|
|
|
log_hexbuffer("generate_key_derivation: [[IN]] sec ", sec_x.data, 32);
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->generate_key_derivation(pub_x, sec_x, derivation_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("generate_key_derivation: [[OUT]] derivation", derivation_x.data, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:55:48 +02:00
|
|
|
if ((this->mode == TRANSACTION_PARSE) && has_view_key) {
|
|
|
|
//A derivation is resquested in PASRE mode and we have the view key,
|
|
|
|
//so do that wihtout the device and return the derivation unencrypted.
|
|
|
|
MDEBUG( "generate_key_derivation : PARSE mode with known viewkey");
|
|
|
|
//Note derivation in PARSE mode can only happen with viewkey, so assert it!
|
|
|
|
assert(is_fake_view_key(sec));
|
|
|
|
r = crypto::generate_key_derivation(pub, this->viewkey, derivation);
|
|
|
|
} else {
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_GEN_KEY_DERIVATION);
|
2018-02-20 17:01:27 +01:00
|
|
|
//pub
|
|
|
|
memmove(this->buffer_send+offset, pub.data, 32);
|
|
|
|
offset += 32;
|
|
|
|
//sec
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)sec.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
offset = 0;
|
2018-02-20 17:01:27 +01:00
|
|
|
//derivattion data
|
2019-09-25 14:31:14 +02:00
|
|
|
this->receive_secret((unsigned char*)derivation.data, offset);
|
|
|
|
|
2018-03-26 12:55:48 +02:00
|
|
|
r = true;
|
|
|
|
}
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
crypto::key_derivation derivation_clear ;
|
2019-03-21 17:22:43 +01:00
|
|
|
if ((this->mode == TRANSACTION_PARSE) && has_view_key) {
|
|
|
|
derivation_clear = derivation;
|
|
|
|
} else {
|
|
|
|
derivation_clear = hw::ledger::decrypt(derivation);
|
|
|
|
}
|
2018-03-26 12:55:48 +02:00
|
|
|
hw::ledger::check32("generate_key_derivation", "derivation", derivation_x.data, derivation_clear.data);
|
|
|
|
#endif
|
2018-02-20 17:01:27 +01:00
|
|
|
|
2018-03-26 12:55:48 +02:00
|
|
|
return r;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2018-04-09 16:07:11 +02:00
|
|
|
bool device_ledger::conceal_derivation(crypto::key_derivation &derivation, const crypto::public_key &tx_pub_key, const std::vector<crypto::public_key> &additional_tx_pub_keys, const crypto::key_derivation &main_derivation, const std::vector<crypto::key_derivation> &additional_derivations) {
|
|
|
|
const crypto::public_key *pkey=NULL;
|
|
|
|
if (derivation == main_derivation) {
|
|
|
|
pkey = &tx_pub_key;
|
|
|
|
MDEBUG("conceal derivation with main tx pub key");
|
|
|
|
} else {
|
|
|
|
for(size_t n=0; n < additional_derivations.size();++n) {
|
|
|
|
if(derivation == additional_derivations[n]) {
|
|
|
|
pkey = &additional_tx_pub_keys[n];
|
|
|
|
MDEBUG("conceal derivation with additionnal tx pub key");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
2018-04-09 16:07:11 +02:00
|
|
|
ASSERT_X(pkey, "Mismatched derivation on scan info");
|
|
|
|
return this->generate_key_derivation(*pkey, crypto::null_skey, derivation);
|
|
|
|
}
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
bool device_ledger::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
|
|
|
|
const size_t output_index_x = output_index;
|
|
|
|
crypto::ec_scalar res_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("derivation_to_scalar: [[IN]] derivation ", derivation_x.data, 32);
|
|
|
|
log_message ("derivation_to_scalar: [[IN]] output_index ", std::to_string(output_index_x));
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->derivation_to_scalar(derivation_x, output_index_x, res_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("derivation_to_scalar: [[OUT]] res ", res_x.data, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_DERIVATION_TO_SCALAR);
|
2019-09-25 14:31:14 +02:00
|
|
|
//derivation
|
|
|
|
this->send_secret((unsigned char*)derivation.data, offset);
|
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
//index
|
|
|
|
this->buffer_send[offset+0] = output_index>>24;
|
|
|
|
this->buffer_send[offset+1] = output_index>>16;
|
|
|
|
this->buffer_send[offset+2] = output_index>>8;
|
|
|
|
this->buffer_send[offset+3] = output_index>>0;
|
|
|
|
offset += 4;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
//derivation data
|
|
|
|
offset = 0;
|
|
|
|
this->receive_secret((unsigned char*)res.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
crypto::ec_scalar res_clear = hw::ledger::decrypt(res);
|
|
|
|
hw::ledger::check32("derivation_to_scalar", "res", res_x.data, res_clear.data);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
|
|
|
|
const std::size_t output_index_x = output_index;
|
|
|
|
const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
|
|
|
|
crypto::secret_key derived_sec_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("derive_secret_key: [[IN]] derivation ", derivation_x.data, 32);
|
|
|
|
log_message ("derive_secret_key: [[IN]] index ", std::to_string(output_index_x));
|
|
|
|
log_hexbuffer("derive_secret_key: [[IN]] sec ", sec_x.data, 32);
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->derive_secret_key(derivation_x, output_index_x, sec_x, derived_sec_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("derive_secret_key: [[OUT]] derived_sec", derived_sec_x.data, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_DERIVE_SECRET_KEY);
|
2018-02-20 17:01:27 +01:00
|
|
|
//derivation
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)derivation.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
//index
|
|
|
|
this->buffer_send[offset+0] = output_index>>24;
|
|
|
|
this->buffer_send[offset+1] = output_index>>16;
|
|
|
|
this->buffer_send[offset+2] = output_index>>8;
|
|
|
|
this->buffer_send[offset+3] = output_index>>0;
|
|
|
|
offset += 4;
|
|
|
|
//sec
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)sec.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
offset = 0;
|
|
|
|
//sec key
|
|
|
|
this->receive_secret((unsigned char*)derived_sec.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
crypto::secret_key derived_sec_clear = hw::ledger::decrypt(derived_sec);
|
|
|
|
hw::ledger::check32("derive_secret_key", "derived_sec", derived_sec_x.data, derived_sec_clear.data);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub){
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-03-26 12:38:38 +02:00
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation);
|
|
|
|
const std::size_t output_index_x = output_index;
|
|
|
|
const crypto::public_key pub_x = pub;
|
|
|
|
crypto::public_key derived_pub_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("derive_public_key: [[IN]] derivation ", derivation_x.data, 32);
|
|
|
|
log_message ("derive_public_key: [[IN]] output_index", std::to_string(output_index_x));
|
|
|
|
log_hexbuffer("derive_public_key: [[IN]] pub ", pub_x.data, 32);
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->derive_public_key(derivation_x, output_index_x, pub_x, derived_pub_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("derive_public_key: [[OUT]] derived_pub ", derived_pub_x.data, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_DERIVE_PUBLIC_KEY);
|
2018-02-20 17:01:27 +01:00
|
|
|
//derivation
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)derivation.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
//index
|
|
|
|
this->buffer_send[offset+0] = output_index>>24;
|
|
|
|
this->buffer_send[offset+1] = output_index>>16;
|
|
|
|
this->buffer_send[offset+2] = output_index>>8;
|
|
|
|
this->buffer_send[offset+3] = output_index>>0;
|
|
|
|
offset += 4;
|
|
|
|
//pub
|
|
|
|
memmove(this->buffer_send+offset, pub.data, 32);
|
|
|
|
offset += 32;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
//pub key
|
|
|
|
memmove(derived_pub.data, &this->buffer_recv[0], 32);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
hw::ledger::check32("derive_public_key", "derived_pub", derived_pub_x.data, derived_pub.data);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
|
|
|
|
crypto::public_key pub_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("secret_key_to_public_key: [[IN]] sec ", sec_x.data, 32);
|
2018-03-05 14:46:15 +01:00
|
|
|
bool rc = this->controle_device->secret_key_to_public_key(sec_x, pub_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("secret_key_to_public_key: [[OUT]] pub", pub_x.data, 32);
|
2018-03-05 14:46:15 +01:00
|
|
|
if (!rc){
|
2019-03-21 17:22:43 +01:00
|
|
|
log_message("FAIL secret_key_to_public_key", "secret_key rejected");
|
2018-03-05 14:46:15 +01:00
|
|
|
}
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_SECRET_KEY_TO_PUBLIC_KEY);
|
2018-02-20 17:01:27 +01:00
|
|
|
//sec key
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)sec.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
//pub key
|
|
|
|
memmove(pub.data, &this->buffer_recv[0], 32);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
hw::ledger::check32("secret_key_to_public_key", "pub", pub_x.data, pub.data);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image){
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const crypto::public_key pub_x = pub;
|
|
|
|
const crypto::secret_key sec_x = hw::ledger::decrypt(sec);
|
|
|
|
crypto::key_image image_x;
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("generate_key_image: [[IN]] pub ", pub_x.data, 32);
|
|
|
|
log_hexbuffer("generate_key_image: [[IN]] sec ", sec_x.data, 32);
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->generate_key_image(pub_x, sec_x, image_x);
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("generate_key_image: [[OUT]] image ", image_x.data, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_GEN_KEY_IMAGE);
|
2018-02-20 17:01:27 +01:00
|
|
|
//pub
|
|
|
|
memmove(this->buffer_send+offset, pub.data, 32);
|
|
|
|
offset += 32;
|
|
|
|
//sec
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)sec.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
//pub key
|
|
|
|
memmove(image.data, &this->buffer_recv[0], 32);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
hw::ledger::check32("generate_key_image", "image", image_x.data, image.data);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ======================================================================= */
|
|
|
|
/* TRANSACTION */
|
|
|
|
/* ======================================================================= */
|
|
|
|
|
2019-03-21 17:22:43 +01:00
|
|
|
void device_ledger::generate_tx_proof(const crypto::hash &prefix_hash,
|
2020-06-02 00:30:19 +02:00
|
|
|
const crypto::public_key &R, const crypto::public_key &A, const std::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
|
2019-03-21 17:22:43 +01:00
|
|
|
crypto::signature &sig) {
|
|
|
|
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2019-03-21 17:22:43 +01:00
|
|
|
|
|
|
|
#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;
|
2020-06-02 00:30:19 +02:00
|
|
|
const std::optional<crypto::public_key> B_x = B;
|
2019-03-21 17:22:43 +01:00
|
|
|
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
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)r.data, offset);
|
2019-03-21 17:22:43 +01:00
|
|
|
|
|
|
|
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);
|
2019-10-01 17:28:23 +02:00
|
|
|
MDEBUG("FAIL is normal if random is not fixed in proof");
|
2019-03-21 17:22:43 +01:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
bool device_ledger::open_tx(crypto::secret_key &tx_key) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker, *this);
|
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
key_map.clear();
|
2019-09-25 14:31:14 +02:00
|
|
|
hmac_map.clear();
|
|
|
|
this->tx_in_progress = true;
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_OPEN_TX, 0x01);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
//account
|
|
|
|
this->buffer_send[offset+0] = 0x00;
|
|
|
|
this->buffer_send[offset+1] = 0x00;
|
|
|
|
this->buffer_send[offset+2] = 0x00;
|
|
|
|
this->buffer_send[offset+3] = 0x00;
|
|
|
|
offset += 4;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
//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);
|
|
|
|
|
2019-03-21 17:22:43 +01:00
|
|
|
#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
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:56:55 +02:00
|
|
|
void device_ledger::get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) {
|
2020-06-22 02:42:23 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2020-04-03 22:56:55 +02:00
|
|
|
|
|
|
|
int pref_length = 0, pref_offset = 0, offset = 0;
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
crypto::hash h_x;
|
|
|
|
this->controle_device->get_transaction_prefix_hash(tx,h_x);
|
|
|
|
MDEBUG("get_transaction_prefix_hash [[IN]] h_x/1 "<<h_x);
|
|
|
|
#endif
|
|
|
|
|
2020-06-22 03:38:09 +02:00
|
|
|
std::string tx_prefix;
|
|
|
|
try {
|
|
|
|
tx_prefix = serialization::dump_binary(const_cast<cryptonote::transaction_prefix&>(tx));
|
|
|
|
} catch (const std::exception& e) {
|
|
|
|
ASSERT_MES_AND_THROW("unable to serialize transaction prefix: " << e.what());
|
|
|
|
}
|
|
|
|
|
|
|
|
pref_length = tx_prefix.size();
|
|
|
|
const unsigned char* pref = reinterpret_cast<const unsigned char*>(tx_prefix.c_str());
|
2020-04-03 22:56:55 +02:00
|
|
|
|
|
|
|
offset = set_command_header_noopt(INS_PREFIX_HASH,1);
|
|
|
|
pref_offset = 0;
|
|
|
|
unsigned char v;
|
|
|
|
|
|
|
|
//version as varint
|
|
|
|
do {
|
|
|
|
v = pref[pref_offset];
|
|
|
|
this->buffer_send[offset] = v;
|
|
|
|
offset += 1;
|
|
|
|
pref_offset += 1;
|
|
|
|
} while (v&0x80);
|
|
|
|
|
|
|
|
//locktime as var int
|
|
|
|
do {
|
|
|
|
v = pref[pref_offset];
|
|
|
|
this->buffer_send[offset] = v;
|
|
|
|
offset += 1;
|
|
|
|
pref_offset += 1;
|
|
|
|
} while (v&0x80);
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange_wait_on_input();
|
|
|
|
|
|
|
|
//hash remains
|
|
|
|
int cnt = 0;
|
|
|
|
while (pref_offset < pref_length) {
|
|
|
|
int len;
|
|
|
|
cnt++;
|
|
|
|
offset = set_command_header(INS_PREFIX_HASH,2,cnt);
|
|
|
|
len = pref_length - pref_offset;
|
|
|
|
//options
|
|
|
|
if (len > (BUFFER_SEND_SIZE-7)) {
|
|
|
|
len = BUFFER_SEND_SIZE-7;
|
|
|
|
this->buffer_send[offset] = 0x80;
|
|
|
|
} else {
|
|
|
|
this->buffer_send[offset] = 0x00;
|
|
|
|
}
|
|
|
|
offset += 1;
|
|
|
|
//send chunk
|
|
|
|
memmove(&this->buffer_send[offset], pref+pref_offset, len);
|
|
|
|
offset += len;
|
|
|
|
pref_offset += len;
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
}
|
|
|
|
memmove(h.data, &this->buffer_recv[0], 32);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
hw::ledger::check8("prefix_hash", "h", h_x.data, h.data);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-03-05 06:24:48 +01:00
|
|
|
bool device_ledger::encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
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;
|
2019-03-21 17:22:43 +01:00
|
|
|
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);
|
2018-03-26 12:38:38 +02:00
|
|
|
this->controle_device->encrypt_payment_id(payment_id_x, public_key_x, secret_key_x);
|
2019-03-21 17:22:43 +01:00
|
|
|
log_hexbuffer("encrypt_payment_id: [[OUT]] payment_id ", payment_id_x.data, 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_STEALTH);
|
2018-02-20 17:01:27 +01:00
|
|
|
//pub
|
|
|
|
memmove(&this->buffer_send[offset], public_key.data, 32);
|
|
|
|
offset += 32;
|
|
|
|
//sec
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)secret_key.data, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
//id
|
|
|
|
memmove(&this->buffer_send[offset], payment_id.data, 8);
|
|
|
|
offset += 8;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
memmove(payment_id.data, &this->buffer_recv[0], 8);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
hw::ledger::check8("stealth", "payment_id", payment_id_x.data, payment_id.data);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2018-12-11 10:20:21 +01:00
|
|
|
|
|
|
|
bool device_ledger::generate_output_ephemeral_keys(const size_t tx_version, bool &found_change, const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key,
|
2020-06-02 00:30:19 +02:00
|
|
|
const cryptonote::tx_destination_entry &dst_entr, const std::optional<cryptonote::tx_destination_entry> &change_addr, const size_t output_index,
|
2018-12-11 10:20:21 +01:00
|
|
|
const bool &need_additional_txkeys, const std::vector<crypto::secret_key> &additional_tx_keys,
|
|
|
|
std::vector<crypto::public_key> &additional_tx_public_keys,
|
|
|
|
std::vector<rct::key> &amount_keys,
|
|
|
|
crypto::public_key &out_eph_public_key) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-12-11 10:20:21 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const size_t &tx_version_x = tx_version;
|
2019-03-21 17:22:43 +01:00
|
|
|
const cryptonote::account_keys sender_account_keys_x = hw::ledger::decrypt(sender_account_keys);
|
2018-12-11 10:20:21 +01:00
|
|
|
memmove((void*)sender_account_keys_x.m_view_secret_key.data, dbg_viewkey.data, 32);
|
|
|
|
|
2018-12-11 10:20:21 +01:00
|
|
|
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;
|
2020-06-02 00:30:19 +02:00
|
|
|
const std::optional<cryptonote::tx_destination_entry> change_addr_x = change_addr;
|
2018-12-11 10:20:21 +01:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2018-12-11 10:20:21 +01:00
|
|
|
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;
|
2019-03-21 17:22:43 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2018-12-11 10:20:21 +01:00
|
|
|
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,
|
2018-12-11 10:20:21 +01:00
|
|
|
additional_tx_public_keys_x, amount_keys_x, out_eph_public_key_x);
|
2019-03-21 17:22:43 +01:00
|
|
|
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);
|
2018-12-11 10:20:21 +01:00
|
|
|
#endif
|
|
|
|
|
2018-12-11 10:20:21 +01:00
|
|
|
ASSERT_X(tx_version > 1, "TX version not supported"<<tx_version);
|
|
|
|
|
2018-12-11 10:20:21 +01:00
|
|
|
// make additional tx pubkey if necessary
|
|
|
|
cryptonote::keypair additional_txkey;
|
|
|
|
if (need_additional_txkeys) {
|
|
|
|
additional_txkey.sec = additional_tx_keys[output_index];
|
|
|
|
}
|
|
|
|
|
|
|
|
bool &is_change = found_change; // NOTE(loki): Alias our param into theirs so we don't have to change much code.
|
|
|
|
|
2019-02-25 07:28:33 +01:00
|
|
|
if (change_addr && dst_entr == *change_addr && !is_change)
|
2019-07-01 02:10:03 +02:00
|
|
|
is_change = true; // sending change to yourself; derivation = a*R
|
2018-12-11 10:20:21 +01:00
|
|
|
|
|
|
|
int offset = set_command_header_noopt(INS_GEN_TXOUT_KEYS);
|
|
|
|
//tx_version
|
|
|
|
this->buffer_send[offset+0] = tx_version>>24;
|
|
|
|
this->buffer_send[offset+1] = tx_version>>16;
|
|
|
|
this->buffer_send[offset+2] = tx_version>>8;
|
|
|
|
this->buffer_send[offset+3] = tx_version>>0;
|
|
|
|
offset += 4;
|
2018-12-11 10:20:21 +01:00
|
|
|
//tx_key
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)tx_key.data, offset);
|
2018-12-11 10:20:21 +01:00
|
|
|
//txkey_pub
|
|
|
|
memmove(&this->buffer_send[offset], txkey_pub.data, 32);
|
2018-12-11 10:20:21 +01:00
|
|
|
offset += 32;
|
|
|
|
//Aout
|
|
|
|
memmove(&this->buffer_send[offset], dst_entr.addr.m_view_public_key.data, 32);
|
|
|
|
offset += 32;
|
|
|
|
//Bout
|
|
|
|
memmove(&this->buffer_send[offset], dst_entr.addr.m_spend_public_key.data, 32);
|
|
|
|
offset += 32;
|
|
|
|
//output index
|
|
|
|
this->buffer_send[offset+0] = output_index>>24;
|
|
|
|
this->buffer_send[offset+1] = output_index>>16;
|
|
|
|
this->buffer_send[offset+2] = output_index>>8;
|
|
|
|
this->buffer_send[offset+3] = output_index>>0;
|
|
|
|
offset += 4;
|
|
|
|
//is_change,
|
|
|
|
this->buffer_send[offset] = is_change;
|
|
|
|
offset++;
|
|
|
|
//is_subaddress
|
|
|
|
this->buffer_send[offset] = dst_entr.is_subaddress;
|
|
|
|
offset++;
|
|
|
|
//need_additional_key
|
|
|
|
this->buffer_send[offset] = need_additional_txkeys;
|
|
|
|
offset++;
|
2019-03-21 17:22:43 +01:00
|
|
|
//additional_tx_key
|
2018-12-11 10:20:21 +01:00
|
|
|
if (need_additional_txkeys) {
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret((unsigned char*)additional_txkey.sec.data, offset);
|
2018-12-11 10:20:21 +01:00
|
|
|
} else {
|
|
|
|
memset(&this->buffer_send[offset], 0, 32);
|
2019-09-25 14:31:14 +02:00
|
|
|
offset += 32;
|
2018-12-11 10:20:21 +01:00
|
|
|
}
|
2018-12-11 10:20:21 +01:00
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
offset = 0;
|
|
|
|
unsigned int recv_len = this->length_recv;
|
2018-12-11 10:20:21 +01:00
|
|
|
|
|
|
|
//if (tx_version > 1)
|
2018-12-11 10:20:21 +01:00
|
|
|
{
|
|
|
|
ASSERT_X(recv_len>=32, "Not enought data from device");
|
|
|
|
crypto::secret_key scalar1;
|
2019-09-25 14:31:14 +02:00
|
|
|
this->receive_secret((unsigned char*)scalar1.data, offset);
|
2018-12-11 10:20:21 +01:00
|
|
|
amount_keys.push_back(rct::sk2rct(scalar1));
|
|
|
|
recv_len -= 32;
|
|
|
|
}
|
|
|
|
ASSERT_X(recv_len>=32, "Not enought data from device");
|
|
|
|
memmove(out_eph_public_key.data, &this->buffer_recv[offset], 32);
|
|
|
|
recv_len -= 32;
|
2018-12-11 10:20:21 +01:00
|
|
|
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;
|
|
|
|
}
|
2018-12-11 10:20:21 +01:00
|
|
|
|
|
|
|
// 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,
|
|
|
|
need_additional_txkeys, output_index,
|
|
|
|
amount_keys.back(), out_eph_public_key);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
2018-12-11 10:20:21 +01:00
|
|
|
log_hexbuffer("generate_output_ephemeral_keys: clear amount_key", (const char*)hw::ledger::decrypt(amount_keys.back()).bytes, 32);
|
2018-12-11 10:20:21 +01:00
|
|
|
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) {
|
2018-12-11 10:20:21 +01:00
|
|
|
hw::ledger::check32("generate_output_ephemeral_keys", "additional_tx_key", additional_tx_public_keys_x.back().data, additional_tx_public_keys.back().data);
|
2018-12-11 10:20:21 +01:00
|
|
|
}
|
|
|
|
hw::ledger::check32("generate_output_ephemeral_keys", "out_eph_public_key", out_eph_public_key_x.data, out_eph_public_key.data);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::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) {
|
|
|
|
key_map.add(ABPkeys(rct::pk2rct(Aout),rct::pk2rct(Bout), is_subaddress, is_change, need_additional, real_output_index, rct::pk2rct(out_eph_public_key), amount_key));
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2018-12-11 10:20:21 +01:00
|
|
|
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
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret(AKout.bytes, offset);
|
2018-12-11 10:20:21 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-01-06 20:49:52 +01:00
|
|
|
bool device_ledger::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & AKout, bool short_amount) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const rct::key AKout_x = hw::ledger::decrypt(AKout);
|
|
|
|
rct::ecdhTuple unmasked_x = unmasked;
|
2019-01-06 20:49:52 +01:00
|
|
|
this->controle_device->ecdhEncode(unmasked_x, AKout_x, short_amount);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2019-02-08 16:11:51 +01:00
|
|
|
int offset = set_command_header(INS_BLIND);
|
|
|
|
//options
|
|
|
|
this->buffer_send[offset] = short_amount?0x02:0x00;
|
|
|
|
offset += 1;
|
2018-02-20 17:01:27 +01:00
|
|
|
// AKout
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret(AKout.bytes, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
//mask k
|
|
|
|
memmove(this->buffer_send+offset, unmasked.mask.bytes, 32);
|
|
|
|
offset += 32;
|
|
|
|
//value v
|
|
|
|
memmove(this->buffer_send+offset, unmasked.amount.bytes, 32);
|
|
|
|
offset += 32;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
memmove(unmasked.amount.bytes, &this->buffer_recv[0], 32);
|
|
|
|
memmove(unmasked.mask.bytes, &this->buffer_recv[32], 32);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
2018-12-11 10:20:21 +01:00
|
|
|
MDEBUG("ecdhEncode: Akout: "<<AKout_x);
|
2018-02-20 17:01:27 +01:00
|
|
|
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);
|
|
|
|
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("Blind AKV input", (char*)&this->buffer_recv[64], 3*32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
2019-01-06 20:49:52 +01:00
|
|
|
bool device_ledger::ecdhDecode(rct::ecdhTuple & masked, const rct::key & AKout, bool short_amount) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const rct::key AKout_x = hw::ledger::decrypt(AKout);
|
|
|
|
rct::ecdhTuple masked_x = masked;
|
2019-01-06 20:49:52 +01:00
|
|
|
this->controle_device->ecdhDecode(masked_x, AKout_x, short_amount);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
2019-02-08 16:11:51 +01:00
|
|
|
int offset = set_command_header(INS_UNBLIND);
|
|
|
|
//options
|
|
|
|
this->buffer_send[offset] = short_amount?0x02:0x00;
|
|
|
|
offset += 1;
|
2018-02-20 17:01:27 +01:00
|
|
|
// AKout
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret(AKout.bytes, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
//mask k
|
|
|
|
memmove(this->buffer_send+offset, masked.mask.bytes, 32);
|
|
|
|
offset += 32;
|
|
|
|
//value v
|
|
|
|
memmove(this->buffer_send+offset, masked.amount.bytes, 32);
|
|
|
|
offset += 32;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
memmove(masked.amount.bytes, &this->buffer_recv[0], 32);
|
|
|
|
memmove(masked.mask.bytes, &this->buffer_recv[32], 32);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
2018-12-11 10:20:21 +01:00
|
|
|
MDEBUG("ecdhEncode: Akout: "<<AKout_x);
|
2018-02-20 17:01:27 +01:00
|
|
|
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
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::mlsag_prehash(const std::string &blob, size_t inputs_size, size_t outputs_size,
|
|
|
|
const rct::keyV &hashes, const rct::ctkeyV &outPk,
|
|
|
|
rct::key &prehash) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
unsigned int data_offset, C_offset, kv_offset, i;
|
|
|
|
const char *data;
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const std::string blob_x = blob;
|
|
|
|
size_t inputs_size_x = inputs_size;
|
|
|
|
size_t outputs_size_x = outputs_size;
|
|
|
|
const rct::keyV hashes_x = hashes;
|
|
|
|
const rct::ctkeyV outPk_x = outPk;
|
|
|
|
rct::key prehash_x;
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->mlsag_prehash(blob_x, inputs_size_x, outputs_size_x, hashes_x, outPk_x, prehash_x);
|
2018-02-20 17:01:27 +01:00
|
|
|
if (inputs_size) {
|
|
|
|
log_message("mlsag_prehash", (std::string("inputs_size not null: ") + std::to_string(inputs_size)).c_str());
|
|
|
|
}
|
|
|
|
this->key_map.log();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
data = blob.data();
|
|
|
|
|
|
|
|
// ====== u8 type, varint txnfee ======
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header(INS_VALIDATE, 0x01, 0x01);
|
2018-02-20 17:01:27 +01:00
|
|
|
//options
|
|
|
|
this->buffer_send[offset] = (inputs_size == 0)?0x00:0x80;
|
|
|
|
offset += 1;
|
|
|
|
|
|
|
|
//type
|
2018-03-05 14:46:15 +01:00
|
|
|
uint8_t type = data[0];
|
2018-02-20 17:01:27 +01:00
|
|
|
this->buffer_send[offset] = data[0];
|
|
|
|
offset += 1;
|
|
|
|
|
|
|
|
//txnfee
|
|
|
|
data_offset = 1;
|
|
|
|
while (data[data_offset]&0x80) {
|
|
|
|
this->buffer_send[offset] = data[data_offset];
|
|
|
|
offset += 1;
|
|
|
|
data_offset += 1;
|
|
|
|
}
|
|
|
|
this->buffer_send[offset] = data[data_offset];
|
|
|
|
offset += 1;
|
|
|
|
data_offset += 1;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
2019-01-09 09:20:53 +01:00
|
|
|
// check fee user input
|
|
|
|
CHECK_AND_ASSERT_THROW_MES(this->exchange_wait_on_input() == 0, "Fee denied on device.");
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
//pseudoOuts
|
2018-07-30 10:16:13 +02:00
|
|
|
if (type == rct::RCTTypeSimple) {
|
2018-03-05 14:46:15 +01:00
|
|
|
for ( i = 0; i < inputs_size; i++) {
|
2018-06-20 11:40:09 +02:00
|
|
|
offset = set_command_header(INS_VALIDATE, 0x01, i+2);
|
2018-03-05 14:46:15 +01:00
|
|
|
//options
|
|
|
|
this->buffer_send[offset] = (i==inputs_size-1)? 0x00:0x80;
|
|
|
|
offset += 1;
|
|
|
|
//pseudoOut
|
|
|
|
memmove(this->buffer_send+offset, data+data_offset,32);
|
|
|
|
offset += 32;
|
|
|
|
data_offset += 32;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
}
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// ====== Aout, Bout, AKout, C, v, k ======
|
|
|
|
kv_offset = data_offset;
|
2019-06-09 15:02:16 +02:00
|
|
|
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG) {
|
2019-02-08 16:11:51 +01:00
|
|
|
C_offset = kv_offset+ (8)*outputs_size;
|
|
|
|
} else {
|
|
|
|
C_offset = kv_offset+ (32+32)*outputs_size;
|
|
|
|
}
|
2018-02-20 17:01:27 +01:00
|
|
|
for ( i = 0; i < outputs_size; i++) {
|
|
|
|
ABPkeys outKeys;
|
|
|
|
bool found;
|
|
|
|
|
|
|
|
found = this->key_map.find(outPk[i].dest, outKeys);
|
|
|
|
if (!found) {
|
|
|
|
log_hexbuffer("Pout not found", (char*)outPk[i].dest.bytes, 32);
|
|
|
|
CHECK_AND_ASSERT_THROW_MES(found, "Pout not found");
|
|
|
|
}
|
2018-06-20 11:40:09 +02:00
|
|
|
offset = set_command_header(INS_VALIDATE, 0x02, i+1);
|
2018-02-20 17:01:27 +01:00
|
|
|
//options
|
|
|
|
this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ;
|
2019-06-09 15:02:16 +02:00
|
|
|
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG)?0x02:0x00;
|
2018-02-20 17:01:27 +01:00
|
|
|
offset += 1;
|
2019-09-25 14:31:14 +02:00
|
|
|
//is_subaddress
|
|
|
|
this->buffer_send[offset] = outKeys.is_subaddress;
|
|
|
|
offset++;
|
|
|
|
//is_change_address
|
|
|
|
this->buffer_send[offset] = outKeys.is_change_address;
|
|
|
|
offset++;
|
|
|
|
//Aout
|
|
|
|
memmove(this->buffer_send+offset, outKeys.Aout.bytes, 32);
|
|
|
|
offset+=32;
|
|
|
|
//Bout
|
|
|
|
memmove(this->buffer_send+offset, outKeys.Bout.bytes, 32);
|
|
|
|
offset+=32;
|
|
|
|
//AKout
|
|
|
|
this->send_secret(outKeys.AKout.bytes, offset);
|
|
|
|
|
2018-02-20 17:01:27 +01:00
|
|
|
//C
|
|
|
|
memmove(this->buffer_send+offset, data+C_offset,32);
|
|
|
|
offset += 32;
|
|
|
|
C_offset += 32;
|
2019-06-09 15:02:16 +02:00
|
|
|
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG) {
|
2019-02-08 16:11:51 +01:00
|
|
|
//k
|
|
|
|
memset(this->buffer_send+offset, 0, 32);
|
|
|
|
offset += 32;
|
|
|
|
//v
|
|
|
|
memset(this->buffer_send+offset, 0, 32);
|
|
|
|
memmove(this->buffer_send+offset, data+kv_offset,8);
|
|
|
|
offset += 32;
|
|
|
|
kv_offset += 8;
|
|
|
|
} else {
|
|
|
|
//k
|
|
|
|
memmove(this->buffer_send+offset, data+kv_offset,32);
|
|
|
|
offset += 32;
|
|
|
|
kv_offset += 32;
|
|
|
|
//v
|
|
|
|
memmove(this->buffer_send+offset, data+kv_offset,32);
|
|
|
|
offset += 32;
|
|
|
|
kv_offset += 32;
|
|
|
|
}
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
2019-01-09 09:20:53 +01:00
|
|
|
// check transaction user input
|
|
|
|
CHECK_AND_ASSERT_THROW_MES(this->exchange_wait_on_input() == 0, "Transaction denied on device.");
|
2018-02-20 17:01:27 +01:00
|
|
|
#ifdef DEBUG_HWDEVICE
|
2019-02-06 15:05:06 +01:00
|
|
|
log_hexbuffer("Prehash AKV input", (char*)&this->buffer_recv[64], 3*32);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// ====== C[], message, proof======
|
|
|
|
C_offset = kv_offset;
|
|
|
|
for (i = 0; i < outputs_size; i++) {
|
2018-06-20 11:40:09 +02:00
|
|
|
offset = set_command_header(INS_VALIDATE, 0x03, i+1);
|
2018-02-20 17:01:27 +01:00
|
|
|
//options
|
|
|
|
this->buffer_send[offset] = 0x80 ;
|
|
|
|
offset += 1;
|
|
|
|
//C
|
|
|
|
memmove(this->buffer_send+offset, data+C_offset,32);
|
|
|
|
offset += 32;
|
|
|
|
C_offset += 32;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
offset = set_command_header_noopt(INS_VALIDATE, 0x03, i+1);
|
2018-02-20 17:01:27 +01:00
|
|
|
//message
|
|
|
|
memmove(this->buffer_send+offset, hashes[0].bytes,32);
|
|
|
|
offset += 32;
|
|
|
|
//proof
|
|
|
|
memmove(this->buffer_send+offset, hashes[2].bytes,32);
|
|
|
|
offset += 32;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
memmove(prehash.bytes, this->buffer_recv, 32);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
hw::ledger::check32("mlsag_prehash", "prehash", (char*)prehash_x.bytes, (char*)prehash.bytes);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool device_ledger::mlsag_prepare(const rct::key &H, const rct::key &xx,
|
|
|
|
rct::key &a, rct::key &aG, rct::key &aHP, rct::key &II) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const rct::key H_x = H;
|
|
|
|
const rct::key xx_x = hw::ledger::decrypt(xx);
|
|
|
|
rct::key a_x;
|
|
|
|
rct::key aG_x;
|
|
|
|
rct::key aHP_x;
|
|
|
|
rct::key II_x;
|
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header_noopt(INS_MLSAG, 0x01);
|
2018-02-20 17:01:27 +01:00
|
|
|
//value H
|
|
|
|
memmove(this->buffer_send+offset, H.bytes, 32);
|
|
|
|
offset += 32;
|
|
|
|
//mask xin
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret(xx.bytes, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
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);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
a_x = hw::ledger::decrypt(a);
|
|
|
|
|
|
|
|
rct::scalarmultBase(aG_x, a_x);
|
|
|
|
rct::scalarmultKey(aHP_x, H_x, a_x);
|
|
|
|
rct::scalarmultKey(II_x, H_x, xx_x);
|
|
|
|
hw::ledger::check32("mlsag_prepare", "AG", (char*)aG_x.bytes, (char*)aG.bytes);
|
|
|
|
hw::ledger::check32("mlsag_prepare", "aHP", (char*)aHP_x.bytes, (char*)aHP.bytes);
|
|
|
|
hw::ledger::check32("mlsag_prepare", "II", (char*)II_x.bytes, (char*)II.bytes);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::mlsag_prepare(rct::key &a, rct::key &aG) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2019-09-25 14:31:14 +02:00
|
|
|
int offset;
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
rct::key a_x;
|
|
|
|
rct::key aG_x;
|
|
|
|
#endif
|
|
|
|
|
2018-06-20 11:40:09 +02:00
|
|
|
send_simple(INS_MLSAG, 0x01);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
2019-09-25 14:31:14 +02:00
|
|
|
offset = 0;
|
|
|
|
this->receive_secret(a.bytes, offset);
|
|
|
|
memmove(aG.bytes, &this->buffer_recv[offset], 32);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
a_x = hw::ledger::decrypt(a);
|
|
|
|
rct::scalarmultBase(aG_x, a_x);
|
|
|
|
hw::ledger::check32("mlsag_prepare", "AG", (char*)aG_x.bytes, (char*)aG.bytes);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::mlsag_hash(const rct::keyV &long_message, rct::key &c) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
size_t cnt;
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const rct::keyV long_message_x = long_message;
|
|
|
|
rct::key c_x;
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->mlsag_hash(long_message_x, c_x);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
cnt = long_message.size();
|
|
|
|
for (size_t i = 0; i<cnt; i++) {
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header(INS_MLSAG, 0x02, i+1);
|
2018-02-20 17:01:27 +01:00
|
|
|
//options
|
|
|
|
this->buffer_send[offset] =
|
|
|
|
(i==(cnt-1))?0x00:0x80; //last
|
|
|
|
offset += 1;
|
|
|
|
//msg part
|
|
|
|
memmove(this->buffer_send+offset, long_message[i].bytes, 32);
|
|
|
|
offset += 32;
|
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
}
|
|
|
|
|
|
|
|
memmove(c.bytes, &this->buffer_recv[0], 32);
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
hw::ledger::check32("mlsag_hash", "c", (char*)c_x.bytes, (char*)c.bytes);
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
CHECK_AND_ASSERT_THROW_MES(dsRows<=rows, "dsRows greater than rows");
|
|
|
|
CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "xx size does not match rows");
|
|
|
|
CHECK_AND_ASSERT_THROW_MES(alpha.size() == rows, "alpha size does not match rows");
|
|
|
|
CHECK_AND_ASSERT_THROW_MES(ss.size() == rows, "ss size does not match rows");
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
const rct::key c_x = c;
|
|
|
|
const rct::keyV xx_x = hw::ledger::decrypt(xx);
|
|
|
|
const rct::keyV alpha_x = hw::ledger::decrypt(alpha);
|
|
|
|
const int rows_x = rows;
|
|
|
|
const int dsRows_x = dsRows;
|
|
|
|
rct::keyV ss_x(ss.size());
|
2018-03-05 14:46:15 +01:00
|
|
|
this->controle_device->mlsag_sign(c_x, xx_x, alpha_x, rows_x, dsRows_x, ss_x);
|
2018-02-20 17:01:27 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
for (size_t j = 0; j < dsRows; j++) {
|
2018-06-20 11:40:09 +02:00
|
|
|
int offset = set_command_header(INS_MLSAG, 0x03, j+1);
|
2018-02-20 17:01:27 +01:00
|
|
|
//options
|
|
|
|
this->buffer_send[offset] = 0x00;
|
|
|
|
if (j==(dsRows-1)) {
|
|
|
|
this->buffer_send[offset] |= 0x80; //last
|
|
|
|
}
|
|
|
|
offset += 1;
|
|
|
|
//xx
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret(xx[j].bytes, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
//alpa
|
2019-09-25 14:31:14 +02:00
|
|
|
this->send_secret(alpha[j].bytes, offset);
|
2018-02-20 17:01:27 +01:00
|
|
|
|
|
|
|
this->buffer_send[4] = offset-5;
|
|
|
|
this->length_send = offset;
|
|
|
|
this->exchange();
|
|
|
|
|
|
|
|
//ss
|
|
|
|
memmove(ss[j].bytes, &this->buffer_recv[0], 32);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t j = dsRows; j < rows; j++) {
|
|
|
|
sc_mulsub(ss[j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_HWDEVICE
|
|
|
|
for (size_t j = 0; j < rows; j++) {
|
|
|
|
hw::ledger::check32("mlsag_sign", "ss["+std::to_string(j)+"]", (char*)ss_x[j].bytes, (char*)ss[j].bytes);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool device_ledger::close_tx() {
|
C++17
Switch loki dev branch to C++17 compilation, and update the code with
various C++17 niceties.
- stop including the (deprecated) lokimq/string_view.h header and
instead switch everything to use std::string_view and `""sv` instead of
`""_sv`.
- std::string_view is much nicer than epee::span, so updated various
loki-specific code to use it instead.
- made epee "portable storage" serialization accept a std::string_view
instead of const lvalue std::string so that we can avoid copying.
- switched from mapbox::variant to std::variant
- use `auto [a, b] = whatever()` instead of `T1 a; T2 b; std::tie(a, b)
= whatever()` in a couple places (in the wallet code).
- switch to std::lock(...) instead of boost::lock(...) for simultaneous
lock acquisition. boost::lock() won't compile in C++17 mode when given
locks of different types.
- removed various pre-C++17 workarounds, e.g. for fold expressions,
unused argument attributes, and byte-spannable object detection.
- class template deduction means lock types no longer have to specify
the mutex, so `std::unique_lock<std::mutex> lock{mutex}` can become
`std::unique_lock lock{mutex}`. This will make switching any mutex
types (e.g. from boost to std mutexes) far easier as you just have to
update the type in the header and everything should work. This also
makes the tools::unique_lock and tools::shared_lock methods redundant
(which were a sort of poor-mans-pre-C++17 way to eliminate the
redundancy) so they are now gone and replaced with direct unique_lock or
shared_lock constructions.
- Redid the LNS validation using a string_view; instead of using raw
char pointers the code now uses a string view and chops off parts of the
view as it validates. So, for instance, it starts with "abcd.loki",
validates the ".loki" and chops the view to "abcd", then validates the
first character and chops to "bcd", validates the last and chops to
"bc", then can just check everything remaining for is-valid-middle-char.
- LNS validation gained a couple minor validation checks in the process:
- slightly tightened the requirement on lokinet addresses to require
that the last character of the mapped address is 'y' or 'o' (the
last base32z char holds only one significant bit).
- In parse_owner_to_generic_owner made sure that the owner value has
the correct size (otherwise we could up end not filling or
overfilling the pubkey buffer).
- Replaced base32z/base64/hex conversions with lokimq's versions which
have a nicer interface, are better optimized, and don't depend on epee.
2020-05-13 20:12:49 +02:00
|
|
|
auto locks = tools::unique_locks(device_locker, command_locker);
|
2018-06-20 11:40:09 +02:00
|
|
|
send_simple(INS_CLOSE_TX);
|
2019-09-25 14:31:14 +02:00
|
|
|
key_map.clear();
|
|
|
|
hmac_map.clear();
|
|
|
|
this->tx_in_progress = false;
|
|
|
|
this->unlock();
|
2018-03-26 12:38:38 +02:00
|
|
|
return true;
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------- */
|
|
|
|
|
|
|
|
static device_ledger *legder_device = NULL;
|
|
|
|
void register_all(std::map<std::string, std::unique_ptr<device>> ®istry) {
|
|
|
|
if (!legder_device) {
|
|
|
|
legder_device = new device_ledger();
|
|
|
|
legder_device->set_name("Ledger");
|
|
|
|
}
|
2018-03-04 19:56:48 +01:00
|
|
|
registry.insert(std::make_pair("Ledger", std::unique_ptr<device>(legder_device)));
|
2018-02-20 17:01:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#else //WITH_DEVICE_LEDGER
|
|
|
|
|
|
|
|
void register_all(std::map<std::string, std::unique_ptr<device>> ®istry) {
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif //WITH_DEVICE_LEDGER
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|