diff options
author | Riccardo Spagni <ric@spagni.net> | 2018-03-04 19:03:41 +0200 |
---|---|---|
committer | Riccardo Spagni <ric@spagni.net> | 2018-03-04 19:03:41 +0200 |
commit | c7ace5fa3d412410312e21c55c28068dcd625fef (patch) | |
tree | fba40dea29a948b8a4904b4de189d4adc605ec6e /src | |
parent | Merge pull request #3245 (diff) | |
parent | Code modifications to integrate Ledger HW device into monero-wallet-cli. (diff) | |
download | monero-c7ace5fa3d412410312e21c55c28068dcd625fef.tar.xz |
Merge pull request #3303
e745c1e3 Code modifications to integrate Ledger HW device into monero-wallet-cli. (cslashm)
Diffstat (limited to 'src')
37 files changed, 4029 insertions, 191 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 357495960..3b71c38cd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -143,3 +143,5 @@ endif() if(PER_BLOCK_CHECKPOINT) add_subdirectory(blocks) endif() + +add_subdirectory(device) diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index 71dcedcab..35c099697 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -33,6 +33,7 @@ set(crypto_sources crypto-ops-data.c crypto-ops.c crypto.cpp + crypto_device.cpp groestl.c hash-extra-blake.c hash-extra-groestl.c @@ -77,6 +78,7 @@ monero_add_library(cncrypto target_link_libraries(cncrypto PUBLIC epee + device ${Boost_SYSTEM_LIBRARY} PRIVATE ${EXTRA_LIBRARIES}) diff --git a/src/crypto/chacha.h b/src/crypto/chacha.h index f74d0c352..b45c3d7c7 100644 --- a/src/crypto/chacha.h +++ b/src/crypto/chacha.h @@ -69,10 +69,10 @@ namespace crypto { chacha20(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher); } - inline void generate_chacha_key(const void *data, size_t size, chacha_key& key) { + inline void generate_chacha_key(const void *data, size_t size, chacha_key& key, bool prehashed=false) { static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key"); tools::scrubbed_arr<char, HASH_SIZE> pwd_hash; - crypto::cn_slow_hash(data, size, pwd_hash.data()); + crypto::cn_slow_hash_pre(data, size, pwd_hash.data(), prehashed); memcpy(&key, pwd_hash.data(), sizeof(key)); } diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index d9b8b6787..afac105e4 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -436,7 +436,7 @@ namespace crypto { return sc_isnonzero(&c2) == 0; } - static void hash_to_ec(const public_key &key, ge_p3 &res) { + void crypto_ops::hash_to_ec(const public_key &key, ge_p3 &res) { hash h; ge_p2 point; ge_p1p1 point2; diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 81ebfb9e2..75b333473 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -46,6 +46,10 @@ #include "hex.h" #include "span.h" #include "hash.h" +#include "device/device_declare.hpp" +extern "C" { + #include "crypto-ops.h" +} namespace crypto { @@ -113,6 +117,9 @@ namespace crypto { void operator=(const crypto_ops &); ~crypto_ops(); + static void hash_to_ec(const public_key &key, ge_p3 &res) ; + friend void hash_to_ec(const public_key &key, ge_p3 &res) ; + static secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false); friend secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover); static bool check_key(const public_key &); @@ -149,6 +156,17 @@ namespace crypto { const public_key *const *, std::size_t, const signature *); }; + secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover, hw::device &hwdev); + secret_key generate_keys(public_key &pub, secret_key &sec, hw::device &hwdev); + bool secret_key_to_public_key(const secret_key &sec, public_key &pub, hw::device &hwdev); + bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation, hw::device &hwdev); + void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res, hw::device &hwdev) ; + bool derive_public_key(const key_derivation &derivation, size_t output_index, const public_key &base, public_key &derived_key, hw::device &hwdev); + void derive_secret_key(const key_derivation &derivation, size_t output_index, const secret_key &base, secret_key &derived_key, hw::device &hwdev); + bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &derived_key, hw::device &hwdev); + void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image, hw::device &hwdev); + + /* Generate N random bytes */ inline void rand(size_t N, uint8_t *bytes) { @@ -166,6 +184,9 @@ namespace crypto { return res; } + inline void hash_to_ec(const public_key &key, ge_p3 &res) { + crypto_ops::hash_to_ec(key,res); + } /* Generate a new key pair */ inline secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false) { diff --git a/src/crypto/crypto_device.cpp b/src/crypto/crypto_device.cpp new file mode 100644 index 000000000..5536857c8 --- /dev/null +++ b/src/crypto/crypto_device.cpp @@ -0,0 +1,79 @@ +// Copyright (c) 2014-2018, The Monero Project +// +// 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. +// + + +#include "crypto.h" +#include "device/device.hpp" +#include "device/log.hpp" + +namespace crypto { + + secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover, hw::device &hwdev) { + secret_key rng; + hwdev.generate_keys(pub, sec, recovery_key, recover, rng); + return rng; + } + + secret_key generate_keys(public_key &pub, secret_key &sec, hw::device &hwdev) { + secret_key rng; + hwdev.generate_keys(pub, sec, secret_key(), false, rng); + return rng; + } + + + bool secret_key_to_public_key(const secret_key &sec, public_key &pub, hw::device &hwdev) { + return hwdev.secret_key_to_public_key(sec, pub); + } + + bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation, hw::device &hwdev) { + return hwdev.generate_key_derivation(key1, key2, derivation); + } + + void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res, hw::device &hwdev) { + hwdev.derivation_to_scalar(derivation, output_index, res); + } + + bool derive_public_key(const key_derivation &derivation, size_t output_index, + const public_key &base, public_key &derived_key, hw::device &hwdev) { + return hwdev.derive_public_key(derivation, output_index, base, derived_key); + } + + void derive_secret_key(const key_derivation &derivation, size_t output_index, + const secret_key &base, secret_key &derived_key, hw::device &hwdev) { + hwdev.derive_secret_key(derivation, output_index, base, derived_key); + } + + bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &derived_key, hw::device &hwdev) { + return hwdev.derive_subaddress_public_key(out_key, derivation, output_index, derived_key); + } + + void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image, hw::device &hwdev) { + hwdev.generate_key_image(pub,sec,image); + } +}
\ No newline at end of file diff --git a/src/crypto/hash-ops.h b/src/crypto/hash-ops.h index 47c6f6425..130bf02db 100644 --- a/src/crypto/hash-ops.h +++ b/src/crypto/hash-ops.h @@ -80,6 +80,7 @@ enum { void cn_fast_hash(const void *data, size_t length, char *hash); void cn_slow_hash(const void *data, size_t length, char *hash); +void cn_slow_hash_pre(const void *data, size_t length, char *hash, bool pre); void hash_extra_blake(const void *data, size_t length, char *hash); void hash_extra_groestl(const void *data, size_t length, char *hash); diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index f921b2455..36bfba9fd 100644 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -515,8 +515,11 @@ void slow_hash_free_state(void) * @param length the length in bytes of the data * @param hash a pointer to a buffer in which the final 256 bit hash will be stored */ +void cn_slow_hash(const void *data, size_t length, char *hash) { + cn_slow_hash_pre(data,length,hash,false); +} -void cn_slow_hash(const void *data, size_t length, char *hash) +void cn_slow_hash_pre(const void *data, size_t length, char *hash, bool prehashed) { RDATA_ALIGN16 uint8_t expandedKey[240]; /* These buffers are aligned to use later with SSE functions */ @@ -543,8 +546,11 @@ void cn_slow_hash(const void *data, size_t length, char *hash) slow_hash_allocate_state(); /* CryptoNight Step 1: Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */ - - hash_process(&state.hs, data, length); + if (prehashed) { + memcpy(&state.hs, data, length); + } else { + hash_process(&state.hs, data, length); + } memcpy(text, state.init, INIT_SIZE_BYTE); /* CryptoNight Step 2: Iteratively encrypt the results from Keccak to fill diff --git a/src/cryptonote_basic/CMakeLists.txt b/src/cryptonote_basic/CMakeLists.txt index de986b6aa..d50a9df67 100644 --- a/src/cryptonote_basic/CMakeLists.txt +++ b/src/cryptonote_basic/CMakeLists.txt @@ -68,6 +68,7 @@ target_link_libraries(cryptonote_basic common cncrypto checkpoints + device ${Boost_DATE_TIME_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} diff --git a/src/cryptonote_basic/account.cpp b/src/cryptonote_basic/account.cpp index 1b38d99b3..26c823c2a 100644 --- a/src/cryptonote_basic/account.cpp +++ b/src/cryptonote_basic/account.cpp @@ -40,6 +40,7 @@ extern "C" } #include "cryptonote_basic_impl.h" #include "cryptonote_format_utils.h" +#include "device/device.hpp" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "account" @@ -50,6 +51,17 @@ DISABLE_VS_WARNINGS(4244 4345) namespace cryptonote { + + //----------------------------------------------------------------- + hw::device& account_keys::get_device() const { + return *m_device; + } + //----------------------------------------------------------------- + void account_keys::set_device( hw::device &hwdev) { + m_device = &hwdev; + MCDEBUG("device", "account_keys::set_device device type: "<<typeid(hwdev).name()); + } + //----------------------------------------------------------------- account_base::account_base() { @@ -116,6 +128,34 @@ DISABLE_VS_WARNINGS(4244 4345) if (m_creation_timestamp == (uint64_t)-1) // failure m_creation_timestamp = 0; // lowest value } + + //----------------------------------------------------------------- + void account_base::create_from_device(const std::string &device_name) + { + + hw::device &hwdev = hw::get_device(device_name); + m_keys.set_device(hwdev); + hwdev.set_name(device_name); + MCDEBUG("ledger", "device type: "<<typeid(hwdev).name()); + hwdev.init(); + hwdev.connect(); + hwdev.get_public_address(m_keys.m_account_address); + #ifdef DEBUG_HWDEVICE + hwdev.get_secret_keys(m_keys.m_view_secret_key, m_keys.m_spend_secret_key); + #endif + struct tm timestamp = {0}; + timestamp.tm_year = 2014 - 1900; // year 2014 + timestamp.tm_mon = 4 - 1; // month april + timestamp.tm_mday = 15; // 15th of april + timestamp.tm_hour = 0; + timestamp.tm_min = 0; + timestamp.tm_sec = 0; + + m_creation_timestamp = mktime(×tamp); + if (m_creation_timestamp == (uint64_t)-1) // failure + m_creation_timestamp = 0; // lowest value + } + //----------------------------------------------------------------- void account_base::create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey) { diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h index 79601f99c..d734599a3 100644 --- a/src/cryptonote_basic/account.h +++ b/src/cryptonote_basic/account.h @@ -33,6 +33,7 @@ #include "cryptonote_basic.h" #include "crypto/crypto.h" #include "serialization/keyvalue_serialization.h" +#include "device/device_declare.hpp" namespace cryptonote { @@ -43,6 +44,7 @@ namespace cryptonote crypto::secret_key m_spend_secret_key; crypto::secret_key m_view_secret_key; std::vector<crypto::secret_key> m_multisig_keys; + hw::device *m_device = &hw::get_device("default"); BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(m_account_address) @@ -50,6 +52,11 @@ namespace cryptonote KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_secret_key) KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys) END_KV_SERIALIZE_MAP() + + account_keys& operator=(account_keys const&) = default; + + hw::device& get_device() const ; + void set_device( hw::device &hwdev) ; }; /************************************************************************/ @@ -60,6 +67,7 @@ namespace cryptonote public: account_base(); crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false); + void create_from_device(const std::string &device_name) ; void create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey); void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey); bool make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys); @@ -68,6 +76,9 @@ namespace cryptonote std::string get_public_address_str(bool testnet) const; std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const; + hw::device& get_device() const {return m_keys.get_device();} + void set_device( hw::device &hwdev) {m_keys.set_device(hwdev);} + uint64_t get_createtime() const { return m_creation_timestamp; } void set_createtime(uint64_t val) { m_creation_timestamp = val; } diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index 54227ad92..4c5f32a09 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -434,6 +434,12 @@ namespace cryptonote generate_keys(k.pub, k.sec); return k; } + static inline keypair generate(hw::device &hwdev) + { + keypair k; + generate_keys(k.pub, k.sec, hwdev); + return k; + } }; //--------------------------------------------------------------- diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index c668ceae5..f462d1ca9 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -41,6 +41,8 @@ using namespace epee; #include "crypto/crypto.h" #include "crypto/hash.h" #include "ringct/rctSigs.h" +#include "device/device.hpp" +#include "device/log.hpp" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "cn" @@ -104,6 +106,16 @@ namespace cryptonote ge_p1p1_to_p3(&A2, &tmp3); ge_p3_tobytes(&AB, &A2); } + + // a copy of rct::scalarmultKey, since we can't link to libringct to avoid circular dependencies + static void secret_key_mult_public_key(crypto::public_key & aP, const crypto::public_key &P, const crypto::secret_key &a) { + ge_p3 A; + ge_p2 R; + //CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&A, P.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__)); + ge_frombytes_vartime(&A, (const unsigned char*)P.data); + ge_scalarmult(&R, (const unsigned char*)a.data, &A); + ge_tobytes((unsigned char*)aP.data, &R); + } } namespace cryptonote @@ -171,6 +183,13 @@ namespace cryptonote crypto::hash_to_scalar(data, sizeof(data), m); return m; } + crypto::secret_key get_subaddress_secret_key(const crypto::secret_key& a, const subaddress_index& index, hw::device &hwdev) + { + crypto::secret_key m; + hwdev.get_subaddress_secret_key(a, index, m); + return m; + } + //--------------------------------------------------------------- std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end) { @@ -210,29 +229,37 @@ namespace cryptonote } return pkeys; } + + std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, hw::device &hwdev) + { + std::vector<crypto::public_key> pkeys; + hwdev.get_subaddress_spend_public_keys(keys, account, begin, end, pkeys); + return pkeys; + } + //--------------------------------------------------------------- - bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki) + bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev) { crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation); - bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation); + bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation, hwdev); CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")"); std::vector<crypto::key_derivation> additional_recv_derivations; for (size_t i = 0; i < additional_tx_public_keys.size(); ++i) { crypto::key_derivation additional_recv_derivation = AUTO_VAL_INIT(additional_recv_derivation); - r = crypto::generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation); + r = crypto::generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation, hwdev); CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", " << ack.m_view_secret_key << ")"); additional_recv_derivations.push_back(additional_recv_derivation); } - boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index); + boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index,hwdev); CHECK_AND_ASSERT_MES(subaddr_recv_info, false, "key image helper: given output pubkey doesn't seem to belong to this address"); - return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki); + return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev); } //--------------------------------------------------------------- - bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki) + bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev) { if (ack.m_spend_secret_key == crypto::null_skey) { @@ -244,7 +271,7 @@ namespace cryptonote { // derive secret key with subaddress - step 1: original CN derivation crypto::secret_key scalar_step1; - crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, scalar_step1); // computes Hs(a*R || idx) + b + crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, scalar_step1, hwdev); // computes Hs(a*R || idx) + b // step 2: add Hs(a || index_major || index_minor) crypto::secret_key subaddr_sk; @@ -255,8 +282,8 @@ namespace cryptonote } else { - subaddr_sk = get_subaddress_secret_key(ack.m_view_secret_key, received_index); - sc_add((unsigned char*)&scalar_step2, (unsigned char*)&scalar_step1, (unsigned char*)&subaddr_sk); + hwdev.get_subaddress_secret_key(ack.m_view_secret_key, received_index, subaddr_sk); + hwdev.sc_secret_add(scalar_step2, scalar_step1,subaddr_sk); } in_ephemeral.sec = scalar_step2; @@ -264,17 +291,17 @@ namespace cryptonote if (ack.m_multisig_keys.empty()) { // when not in multisig, we know the full spend secret key, so the output pubkey can be obtained by scalarmultBase - CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub), false, "Failed to derive public key"); + CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub, hwdev), false, "Failed to derive public key"); } else { // when in multisig, we only know the partial spend secret key. but we do know the full spend public key, so the output pubkey can be obtained by using the standard CN key derivation - CHECK_AND_ASSERT_MES(crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub), false, "Failed to derive public key"); + CHECK_AND_ASSERT_MES(crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub, hwdev), false, "Failed to derive public key"); // and don't forget to add the contribution from the subaddress part if (!received_index.is_zero()) { crypto::public_key subaddr_pk; - CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(subaddr_sk, subaddr_pk), false, "Failed to derive public key"); + CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(subaddr_sk, subaddr_pk, hwdev), false, "Failed to derive public key"); add_public_key(in_ephemeral.pub, in_ephemeral.pub, subaddr_pk); } } @@ -283,7 +310,7 @@ namespace cryptonote false, "key image helper precomp: given output pubkey doesn't match the derived one"); } - crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki); + crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki, hwdev); return true; } //--------------------------------------------------------------- @@ -570,6 +597,17 @@ namespace cryptonote // Encryption and decryption are the same operation (xor with a key) return encrypt_payment_id(payment_id, public_key, secret_key); } + + //--------------------------------------------------------------- + bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key,hw::device &hwdev) + { + return hwdev.encrypt_payment_id(public_key, secret_key, payment_id); + } + bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key, hw::device &hwdev) + { + // Encryption and decryption are the same operation (xor with a key) + return encrypt_payment_id(payment_id, public_key, secret_key, hwdev); + } //--------------------------------------------------------------- bool get_inputs_money_amount(const transaction& tx, uint64_t& money) { @@ -670,10 +708,10 @@ namespace cryptonote bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, const std::vector<crypto::public_key>& additional_tx_pub_keys, size_t output_index) { crypto::key_derivation derivation; - bool r = generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation); + bool r = generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation, acc.get_device()); CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation"); crypto::public_key pk; - r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk); + r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk, acc.get_device()); CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key"); if (pk == out_key.key) return true; @@ -681,20 +719,20 @@ namespace cryptonote if (!additional_tx_pub_keys.empty()) { CHECK_AND_ASSERT_MES(output_index < additional_tx_pub_keys.size(), false, "wrong number of additional tx pubkeys"); - r = generate_key_derivation(additional_tx_pub_keys[output_index], acc.m_view_secret_key, derivation); + r = generate_key_derivation(additional_tx_pub_keys[output_index], acc.m_view_secret_key, derivation, acc.get_device()); CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation"); - r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk); + r = derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk, acc.get_device()); CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key"); return pk == out_key.key; } return false; } //--------------------------------------------------------------- - boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index) + boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index, hw::device &hwdev) { // try the shared tx pubkey crypto::public_key subaddress_spendkey; - derive_subaddress_public_key(out_key, derivation, output_index, subaddress_spendkey); + derive_subaddress_public_key(out_key, derivation, output_index, subaddress_spendkey,hwdev); auto found = subaddresses.find(subaddress_spendkey); if (found != subaddresses.end()) return subaddress_receive_info{ found->second, derivation }; @@ -702,7 +740,7 @@ namespace cryptonote if (!additional_derivations.empty()) { CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations"); - derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey); + derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey, hwdev); found = subaddresses.find(subaddress_spendkey); if (found != subaddresses.end()) return subaddress_receive_info{ found->second, additional_derivations[output_index] }; @@ -1102,4 +1140,63 @@ namespace cryptonote return key; } + //--------------------------------------------------------------- + #define CHACHA8_KEY_TAIL 0x8c + bool generate_chacha_key_from_secret_keys(const account_keys &keys, crypto::chacha_key &key) + { + const crypto::secret_key &view_key = keys.m_view_secret_key; + const crypto::secret_key &spend_key = keys.m_spend_secret_key; + tools::scrubbed_arr<char, sizeof(view_key) + sizeof(spend_key) + 1> data; + memcpy(data.data(), &view_key, sizeof(view_key)); + memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key)); + data[sizeof(data) - 1] = CHACHA8_KEY_TAIL; + crypto::generate_chacha_key(data.data(), sizeof(data), key); + return true; + } + + //--------------------------------------------------------------- + crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) + { + if (index.is_zero()) + return keys.m_account_address.m_spend_public_key; + + // m = Hs(a || index_major || index_minor) + crypto::secret_key m = cryptonote::get_subaddress_secret_key(keys.m_view_secret_key, index); + + // M = m*G + crypto::public_key M; + crypto::secret_key_to_public_key(m, M); + + // D = B + M + crypto::public_key D; + add_public_key(D, keys.m_account_address.m_spend_public_key, M); // could have defined add_public_key() under src/crypto + return D; + } + + //--------------------------------------------------------------- + cryptonote::account_public_address get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index) + { + if (index.is_zero()) + return keys.m_account_address; + + crypto::public_key D = get_subaddress_spend_public_key(keys, index); + + // C = a*D + crypto::public_key C; + secret_key_mult_public_key(C, D, keys.m_view_secret_key); // could have defined secret_key_mult_public_key() under src/crypto + + // result: (C, D) + cryptonote::account_public_address address; + address.m_view_public_key = C; + address.m_spend_public_key = D; + return address; + } + + //--------------------------------------------------------------- + bool verify_keys(const crypto::secret_key& sec, const crypto::public_key& expected_pub) + { + crypto::public_key pub; + bool r = crypto::secret_key_to_public_key(sec, pub); + return r && expected_pub == pub; + } } diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index 07a3ac92a..7bd34ea87 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -37,6 +37,7 @@ #include "crypto/crypto.h" #include "crypto/hash.h" #include <unordered_map> +#include "device/device_declare.hpp" namespace epee { @@ -52,7 +53,9 @@ namespace cryptonote bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx); bool parse_and_validate_tx_base_from_blob(const blobdata& tx_blob, transaction& tx); bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); + bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key, hw::device &hwdev); bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); + bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key, hw::device &hwdev); template<typename T> bool find_tx_extra_field_by_type(const std::vector<tx_extra_field>& tx_extra_fields, T& field, size_t index = 0) @@ -87,15 +90,17 @@ namespace cryptonote subaddress_index index; crypto::key_derivation derivation; }; - boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index); + boost::optional<subaddress_receive_info> is_out_to_acc_precomp(const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector<crypto::key_derivation>& additional_derivations, size_t output_index, hw::device &hwdev); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, const std::vector<crypto::public_key>& additional_tx_public_keys, std::vector<size_t>& outs, uint64_t& money_transfered); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered); bool get_tx_fee(const transaction& tx, uint64_t & fee); uint64_t get_tx_fee(const transaction& tx); crypto::secret_key get_subaddress_secret_key(const crypto::secret_key& a, const subaddress_index& index); + crypto::secret_key get_subaddress_secret_key(const crypto::secret_key& a, const subaddress_index& index, hw::device &hwdev); std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end); - bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki); - bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki); + std::vector<crypto::public_key> get_subaddress_spend_public_keys(const cryptonote::account_keys &keys, uint32_t account, uint32_t begin, uint32_t end, hw::device &hwdev); + bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); + bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); void get_blob_hash(const blobdata& blob, crypto::hash& res); crypto::hash get_blob_hash(const blobdata& blob); std::string short_hash_str(const crypto::hash& h); @@ -238,4 +243,9 @@ namespace cryptonote CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \ specific_type& variable_name = boost::get<specific_type>(variant_var); + cryptonote::account_public_address get_subaddress(const cryptonote::account_keys &keys, const cryptonote::subaddress_index& index); + crypto::public_key get_subaddress_spend_public_key(const cryptonote::account_keys &keys, const cryptonote::subaddress_index& index); + bool generate_chacha_key_from_secret_keys(const cryptonote::account_keys &keys, crypto::chacha_key &key); + bool verify_keys(const crypto::secret_key& sec, const crypto::public_key& expected_pub); + } diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index d8a21ae31..72844db66 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -61,6 +61,7 @@ target_link_libraries(cryptonote_core blockchain_db multisig ringct + device ${Boost_DATE_TIME_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 4a10f7133..d641caf80 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -41,6 +41,7 @@ using namespace epee; #include "crypto/hash.h" #include "ringct/rctSigs.h" #include "multisig/multisig.h" +#include "device/device.hpp" using namespace crypto; @@ -194,6 +195,8 @@ namespace cryptonote //--------------------------------------------------------------- bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout) { + hw::device &hwdev = sender_account_keys.get_device(); + if (sources.empty()) { LOG_ERROR("Empty sources"); @@ -232,7 +235,7 @@ namespace cryptonote return false; } - if (!encrypt_payment_id(payment_id, view_key_pub, tx_key)) + if (!encrypt_payment_id(payment_id, view_key_pub, tx_key, hwdev)) { LOG_ERROR("Failed to encrypt payment id"); return false; @@ -280,7 +283,7 @@ namespace cryptonote keypair& in_ephemeral = in_contexts.back().in_ephemeral; crypto::key_image img; const auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest); - if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral, img)) + if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev)) { LOG_ERROR("Key image generation failed!"); return false; @@ -338,11 +341,11 @@ namespace cryptonote // if this is a single-destination transfer to a subaddress, we set the tx pubkey to R=s*D if (num_stdaddresses == 0 && num_subaddresses == 1) { - txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(single_dest_subaddress.m_spend_public_key), rct::sk2rct(tx_key))); + txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(single_dest_subaddress.m_spend_public_key), rct::sk2rct(tx_key), hwdev)); } else { - txkey_pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(tx_key))); + txkey_pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(tx_key), hwdev)); } remove_field_from_tx_extra(tx.extra, typeid(tx_extra_pub_key)); add_tx_pub_key_to_extra(tx, txkey_pub); @@ -371,22 +374,22 @@ namespace cryptonote { additional_txkey.sec = additional_tx_keys[output_index]; if (dst_entr.is_subaddress) - additional_txkey.pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(dst_entr.addr.m_spend_public_key), rct::sk2rct(additional_txkey.sec))); + additional_txkey.pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(dst_entr.addr.m_spend_public_key), rct::sk2rct(additional_txkey.sec),hwdev)); else - additional_txkey.pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(additional_txkey.sec))); + additional_txkey.pub = rct::rct2pk(rct::scalarmultBase(rct::sk2rct(additional_txkey.sec), hwdev)); } bool r; if (change_addr && dst_entr.addr == *change_addr) { // sending change to yourself; derivation = a*R - r = crypto::generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation); + r = crypto::generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation, hwdev); CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")"); } else { // sending to the recipient; derivation = r*A (or s*C in the subaddress scheme) - r = crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key, derivation); + r = crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key, derivation, hwdev); CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_view_public_key << ", " << (dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key) << ")"); } @@ -398,12 +401,14 @@ namespace cryptonote if (tx.version > 1) { crypto::secret_key scalar1; - crypto::derivation_to_scalar(derivation, output_index, scalar1); + crypto::derivation_to_scalar(derivation, output_index, scalar1, hwdev); amount_keys.push_back(rct::sk2rct(scalar1)); } - r = crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key); + r = crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key, hwdev); CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to derive_public_key(" << derivation << ", " << output_index << ", "<< dst_entr.addr.m_spend_public_key << ")"); + hwdev.add_output_key_mapping(dst_entr.addr.m_view_public_key, dst_entr.addr.m_spend_public_key, output_index, amount_keys.back(), out_eph_public_key); + tx_out out; out.amount = dst_entr.amount; txout_to_key tk; @@ -579,9 +584,9 @@ namespace cryptonote get_transaction_prefix_hash(tx, tx_prefix_hash); rct::ctkeyV outSk; if (use_simple_rct) - tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, bulletproof); + tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, bulletproof, hwdev); else - tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, bulletproof); // same index assumption + tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, bulletproof, hwdev); // same index assumption CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout"); @@ -595,8 +600,8 @@ namespace cryptonote //--------------------------------------------------------------- bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout) { - keypair txkey = keypair::generate(); - tx_key = txkey.sec; + hw::device &hwdev = sender_account_keys.get_device(); + hwdev.open_tx(tx_key); // figure out if we need to make additional tx pubkeys size_t num_stdaddresses = 0; @@ -608,10 +613,12 @@ namespace cryptonote { additional_tx_keys.clear(); for (const auto &d: destinations) - additional_tx_keys.push_back(keypair::generate().sec); + additional_tx_keys.push_back(keypair::generate(sender_account_keys.get_device()).sec); } - return construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, bulletproof, msout); + bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, bulletproof, msout); + hwdev.close_tx(); + return r; } //--------------------------------------------------------------- bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time) diff --git a/src/device/CMakeLists.txt b/src/device/CMakeLists.txt new file mode 100644 index 000000000..26389220f --- /dev/null +++ b/src/device/CMakeLists.txt @@ -0,0 +1,77 @@ +# Copyright (c) 2014-2017, The Monero Project +# +# 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. + +set(device_sources + device.cpp + device_default.cpp + log.cpp + ) + +if(PCSC_FOUND) + set(device_sources ${device_sources} device_ledger.cpp) +endif() + +set(device_headers + device_declare.hpp + device.hpp + device_default.hpp + log.hpp + ) + +if(PCSC_FOUND) + set(device_headers ${device_headers} device_ledger.hpp) +endif() + +set(device_private_headers) + + +if(PER_BLOCK_CHECKPOINT) + set(Blocks "blocks") +else() + set(Blocks "") +endif() + +monero_private_headers(device + ${device_private_headers}) + +monero_add_library(device + ${device_sources} + ${device_headers} + ${device_private_headers}) + +target_link_libraries(device + PUBLIC + ${PCSC_LIBRARIES} + cncrypto + ringct + ${OPENSSL_CRYPTO_LIBRARIES} + ${GNU_READLINE_LIBRARY} + ${EPEE_READLINE} + PRIVATE + ${Blocks} + ${EXTRA_LIBRARIES}) diff --git a/src/device/device.cpp b/src/device/device.cpp new file mode 100644 index 000000000..080d83c7e --- /dev/null +++ b/src/device/device.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// + +#include "device.hpp" +#include "device_default.hpp" +#ifdef HAVE_PCSC +#include "device_ledger.hpp" +#endif +#include "common/scoped_message_writer.h" + + +namespace hw { + + /* ======================================================================= */ + /* SETUP */ + /* ======================================================================= */ + device& get_device(const std::string device_descriptor) { + + struct s_devices { + std::map<std::string, std::unique_ptr<device>> registry; + s_devices() : registry() { + hw::core::register_all(registry); + #ifdef HAVE_PCSC + hw::ledger::register_all(registry); + #endif + }; + }; + + static const s_devices devices; + + auto device = devices.registry.find(device_descriptor); + if (device == devices.registry.end()) { + auto logger = tools::fail_msg_writer(); + logger << "device not found in registry '"<<device_descriptor<<"'\n" << + "known devices:"<<device_descriptor<<"'"; + + for( const auto& sm_pair : devices.registry ) { + logger<< " - " << sm_pair.first ; + } + throw std::runtime_error("device not found: "+ device_descriptor); + } + return *device->second; + } + +}
\ No newline at end of file diff --git a/src/device/device.hpp b/src/device/device.hpp new file mode 100644 index 000000000..bdea7b8f6 --- /dev/null +++ b/src/device/device.hpp @@ -0,0 +1,146 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// + + +#pragma once + +#include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/account.h" +#include "cryptonote_basic/subaddress_index.h" + +#ifndef USE_DEVICE_LEDGER +#define USE_DEVICE_LEDGER 1 +#endif + +#if !defined(HAVE_PCSC) +#undef USE_DEVICE_LEDGER +#define USE_DEVICE_LEDGER 0 +#endif + +#if USE_DEVICE_LEDGER +#define WITH_DEVICE_LEDGER +#endif + +namespace hw { + namespace { + //device funcion not supported + #define dfns() \ + throw std::runtime_error(std::string("device function not supported: ")+ std::string(__FUNCTION__) + \ + std::string(" (device.hpp line ")+std::to_string(__LINE__)+std::string(").")); \ + return false; + } + + + class device { + public: + + device() {} + device(const device &hwdev) {} + virtual ~device() {} + + explicit virtual operator bool() const = 0; + + static const int SIGNATURE_REAL = 0; + static const int SIGNATURE_FAKE = 1; + + + std::string name; + + /* ======================================================================= */ + /* SETUP/TEARDOWN */ + /* ======================================================================= */ + virtual bool set_name(const std::string &name) = 0; + virtual const std::string get_name() const = 0; + + virtual bool init(void) = 0; + virtual bool release() = 0; + + virtual bool connect(void) = 0; + virtual bool disconnect() = 0; + + /* ======================================================================= */ + /* WALLET & ADDRESS */ + /* ======================================================================= */ + virtual bool get_public_address(cryptonote::account_public_address &pubkey) = 0; + virtual bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) = 0; + virtual bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) = 0; + + /* ======================================================================= */ + /* SUB ADDRESS */ + /* ======================================================================= */ + virtual bool 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) = 0; + virtual bool get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index, crypto::public_key &D) = 0; + virtual bool 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) = 0; + virtual bool get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) = 0; + virtual bool get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) = 0; + + /* ======================================================================= */ + /* DERIVATION & KEY */ + /* ======================================================================= */ + virtual bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) = 0; + virtual bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) = 0; + virtual bool scalarmultBase(rct::key &aG, const rct::key &a) = 0; + virtual bool sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) = 0; + virtual bool generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) = 0; + virtual bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) = 0; + virtual bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) = 0; + virtual bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) = 0; + virtual bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) = 0; + virtual bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) = 0; + virtual bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) = 0; + + /* ======================================================================= */ + /* TRANSACTION */ + /* ======================================================================= */ + + virtual bool open_tx(crypto::secret_key &tx_key) = 0; + + virtual bool set_signature_mode(unsigned int sig_mode) = 0; + + virtual bool encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) = 0; + + virtual bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) = 0; + virtual bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) = 0; + + virtual bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index, + const rct::key &amount_key, const crypto::public_key &out_eph_public_key) = 0; + + + virtual bool 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) = 0; + virtual bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) = 0; + virtual bool mlsag_prepare(rct::key &a, rct::key &aG) = 0; + virtual bool mlsag_hash(const rct::keyV &long_message, rct::key &c) = 0; + virtual bool 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) = 0; + + virtual bool close_tx(void) = 0; + } ; + + device& get_device(const std::string device_descriptor) ; +} + diff --git a/src/device/device_declare.hpp b/src/device/device_declare.hpp new file mode 100644 index 000000000..799052ad2 --- /dev/null +++ b/src/device/device_declare.hpp @@ -0,0 +1,42 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// + +#pragma once + + +//#define DEBUG_HWDEVICE +//#define IODUMMYCRYPT 1 +//#define IONOCRYPT 1 + +namespace hw { + class device; + + device& get_device(std::string device_descriptor); +} + diff --git a/src/device/device_default.cpp b/src/device/device_default.cpp new file mode 100644 index 000000000..a38d96c15 --- /dev/null +++ b/src/device/device_default.cpp @@ -0,0 +1,263 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// + + + + +#include "device_default.hpp" + +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "ringct/rctOps.h" + +namespace hw { + + namespace core { + + device_default::device_default() { } + + device_default::~device_default() { } + + /* ===================================================================== */ + /* === Misc ==== */ + /* ===================================================================== */ + static inline unsigned char *operator &(crypto::ec_scalar &scalar) { + return &reinterpret_cast<unsigned char &>(scalar); + } + static inline const unsigned char *operator &(const crypto::ec_scalar &scalar) { + return &reinterpret_cast<const unsigned char &>(scalar); + } + + /* ======================================================================= */ + /* SETUP/TEARDOWN */ + /* ======================================================================= */ + bool device_default::set_name(const std::string &name) { + this->name = name; + return true; + } + const std::string device_default::get_name() const { + return this->name; + } + + bool device_default::init(void) { + dfns(); + } + bool device_default::release() { + dfns(); + } + + bool device_default::connect(void) { + dfns(); + } + bool device_default::disconnect() { + dfns(); + } + + /* ======================================================================= */ + /* WALLET & ADDRESS */ + /* ======================================================================= */ + + bool device_default::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) { + return cryptonote::generate_chacha_key_from_secret_keys(keys, key); + } + bool device_default::get_public_address(cryptonote::account_public_address &pubkey) { + dfns(); + } + bool device_default::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) { + dfns(); + } + /* ======================================================================= */ + /* SUB ADDRESS */ + /* ======================================================================= */ + + bool device_default::derive_subaddress_public_key(const crypto::public_key &out_key, const crypto::key_derivation &derivation, const std::size_t output_index, crypto::public_key &derived_key) { + return crypto::derive_subaddress_public_key(out_key, derivation, output_index,derived_key); + } + + bool device_default::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, crypto::public_key &D) { + D = cryptonote::get_subaddress_spend_public_key(keys,index); + return true; + } + + bool device_default::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) { + pkeys = cryptonote::get_subaddress_spend_public_keys(keys, account, begin, end); + return true; + } + + bool device_default::get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) { + address = cryptonote::get_subaddress(keys,index); + return true; + } + + bool device_default::get_subaddress_secret_key(const crypto::secret_key &a, const cryptonote::subaddress_index &index, crypto::secret_key &m) { + m = cryptonote::get_subaddress_secret_key(a,index); + return true; + } + + /* ======================================================================= */ + /* DERIVATION & KEY */ + /* ======================================================================= */ + + bool device_default::verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) { + return cryptonote::verify_keys(secret_key, public_key); + } + + bool device_default::scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) { + rct::scalarmultKey(aP, P,a); + return true; + } + + bool device_default::scalarmultBase(rct::key &aG, const rct::key &a) { + rct::scalarmultBase(aG,a); + return true; + } + + bool device_default::sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) { + sc_add(&r, &a, &b); + return true; + } + + bool device_default::generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) { + rng = crypto::generate_keys(pub, sec, recovery_key, recover); + return true; + } + + bool device_default::generate_key_derivation(const crypto::public_key &key1, const crypto::secret_key &key2, crypto::key_derivation &derivation) { + return crypto::generate_key_derivation(key1, key2, derivation); + } + + bool device_default::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res){ + crypto::derivation_to_scalar(derivation,output_index, res); + return true; + } + + bool device_default::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &base, crypto::secret_key &derived_key){ + crypto::derive_secret_key(derivation, output_index, base, derived_key); + return true; + } + + bool device_default::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &base, crypto::public_key &derived_key){ + return crypto::derive_public_key(derivation, output_index, base, derived_key); + } + + bool device_default::secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) { + return crypto::secret_key_to_public_key(sec,pub); + } + + bool device_default::generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image){ + crypto::generate_key_image(pub, sec,image); + return true; + } + + /* ======================================================================= */ + /* TRANSACTION */ + /* ======================================================================= */ + + bool device_default::open_tx(crypto::secret_key &tx_key) { + cryptonote::keypair txkey = cryptonote::keypair::generate(); + tx_key = txkey.sec; + return true; + } + + + bool device_default::add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index, + const rct::key &amount_key, const crypto::public_key &out_eph_public_key) { + return true; + } + + bool device_default::set_signature_mode(unsigned int sig_mode) { + return true; + } + + bool device_default::encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) { + return cryptonote::encrypt_payment_id(payment_id, public_key, secret_key); + } + + bool device_default::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) { + rct::ecdhEncode(unmasked, sharedSec); + return true; + } + + bool device_default::ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) { + rct::ecdhDecode(masked, sharedSec); + return true; + } + + bool device_default::mlsag_prepare(const rct::key &H, const rct::key &xx, + rct::key &a, rct::key &aG, rct::key &aHP, rct::key &II) { + rct::skpkGen(a, aG); + rct::scalarmultKey(aHP, H, a); + rct::scalarmultKey(II, H, xx); + return true; + } + bool device_default::mlsag_prepare(rct::key &a, rct::key &aG) { + rct::skpkGen(a, aG); + return true; + } + bool device_default::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) { + prehash = rct::cn_fast_hash(hashes); + return true; + } + + + bool device_default::mlsag_hash(const rct::keyV &toHash, rct::key &c_old) { + c_old = rct::hash_to_scalar(toHash); + return true; + } + + bool device_default::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 ) { + 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"); + for (size_t j = 0; j < rows; j++) { + sc_mulsub(ss[j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes); + } + return true; + } + + bool device_default::close_tx() { + return true; + } + + + /* ---------------------------------------------------------- */ + static device_default *default_core_device = NULL; + void register_all(std::map<std::string, std::unique_ptr<device>> ®istry) { + if (!default_core_device) { + default_core_device = new device_default(); + default_core_device->set_name("default_core_device"); + + } + registry.insert(std::make_pair("default",default_core_device)); + } + + + } + +}
\ No newline at end of file diff --git a/src/device/device_default.hpp b/src/device/device_default.hpp new file mode 100644 index 000000000..f5b158a3b --- /dev/null +++ b/src/device/device_default.hpp @@ -0,0 +1,126 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// + +#pragma once + +#include "device.hpp" + +namespace hw { + + namespace core { + + void register_all(std::map<std::string, std::unique_ptr<device>> ®istry); + + class device_default : public hw::device { + public: + device_default(); + ~device_default(); + + device_default(const device_default &device) = delete; + device_default& operator=(const device_default &device) = delete; + + explicit operator bool() const override { return false; }; + + /* ======================================================================= */ + /* SETUP/TEARDOWN */ + /* ======================================================================= */ + bool set_name(const std::string &name) override; + const std::string get_name() const override; + + bool init(void) override; + bool release() override; + + bool connect(void) override; + bool disconnect() override; + + /* ======================================================================= */ + /* WALLET & ADDRESS */ + /* ======================================================================= */ + bool get_public_address(cryptonote::account_public_address &pubkey) override; + bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override; + bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) override; + + /* ======================================================================= */ + /* SUB ADDRESS */ + /* ======================================================================= */ + bool 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) override; + bool get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index, crypto::public_key &D) override; + bool 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) override; + bool get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) override; + bool get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) override; + + /* ======================================================================= */ + /* DERIVATION & KEY */ + /* ======================================================================= */ + bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) override; + bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) override; + bool scalarmultBase(rct::key &aG, const rct::key &a) override; + bool sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) override; + bool generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) override; + bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override; + bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) override; + bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override; + bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) override; + bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) override; + bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) override; + + + /* ======================================================================= */ + /* TRANSACTION */ + /* ======================================================================= */ + + bool open_tx(crypto::secret_key &tx_key) override; + + //bool get_additional_key(const bool subaddr, cryptonote::keypair &additional_txkey) override; + bool set_signature_mode(unsigned int sig_mode) override; + + bool encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) override; + + bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) override; + bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) override; + + bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index, + const rct::key &amount_key, const crypto::public_key &out_eph_public_key) override; + + + bool 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) override; + bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) override; + bool mlsag_prepare(rct::key &a, rct::key &aG) override; + bool mlsag_hash(const rct::keyV &long_message, rct::key &c) override; + bool 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) override; + + bool close_tx(void) override; + }; + + } + + + +} + diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp new file mode 100644 index 000000000..e8eb7cc8b --- /dev/null +++ b/src/device/device_ledger.cpp @@ -0,0 +1,2069 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// + +#include "device_ledger.hpp" +#include "log.hpp" +#include "ringct/rctOps.h" + + + +namespace hw { + + namespace ledger { + + #ifdef WITH_DEVICE_LEDGER + + #undef MONERO_DEFAULT_LOG_CATEGORY + #define MONERO_DEFAULT_LOG_CATEGORY "device.ledger" + + /* ===================================================================== */ + /* === Debug ==== */ + /* ===================================================================== */ + void set_apdu_verbose(bool verbose) { + apdu_verbose = verbose; + } + + #define TRACKD MTRACE("hw") + #define ASSERT_RV(rv) CHECK_AND_ASSERT_THROW_MES((rv)==SCARD_S_SUCCESS, "Fail SCard API : (" << (rv) << ") "<< pcsc_stringify_error(rv)<<" Device="<<this->id<<", hCard="<<hCard<<", hContext="<<hContext); + #define ASSERT_SW(sw,ok,msk) CHECK_AND_ASSERT_THROW_MES(((sw)&(mask))==(ok), "Wrong Device Status : SW=" << std::hex << (sw) << " (EXPECT=" << std::hex << (ok) << ", MASK=" << std::hex << (mask) << ")") ; + #define ASSERT_T0(exp) CHECK_AND_ASSERT_THROW_MES(exp, "Protocol assert failure: "#exp ) ; + + #ifdef DEBUG_HWDEVICE + #define DEVICE_CONTROLE :controle_device(hw::get_device("default")) + crypto::secret_key viewkey; + crypto::secret_key spendkey; + #else + #define DEVICE_CONTROLE + #endif + + /* ===================================================================== */ + /* === Keymap ==== */ + /* ===================================================================== */ + + ABPkeys::ABPkeys(const rct::key& A, const rct::key& B, size_t real_output_index, const rct::key& P, const rct::key& AK) { + Aout = A; + Bout = B; + index = real_output_index; + Pout = P; + AKout = AK; + } + + ABPkeys::ABPkeys(const ABPkeys& keys) { + Aout = keys.Aout; + Bout = keys.Bout; + index = keys.index; + Pout = keys.Pout; + AKout = keys.AKout; + } + + 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); + log_message (" index", std::to_string(ABP[i].index)); + log_hexbuffer(" Pout", (char*)ABP[i].Pout.bytes, 32); + } + } + #endif + + /* ===================================================================== */ + /* === Device ==== */ + /* ===================================================================== */ + + static int device_id = 0; + + #define INS_NONE 0x00 + #define INS_RESET 0x02 + + #define INS_GET_KEY 0x20 + #define INS_PUT_KEY 0x22 + #define INS_GET_CHACHA8_PREKEY 0x24 + #define INS_VERIFY_KEY 0x26 + + #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 + #define INS_BLIND 0x78 + #define INS_UNBLIND 0x7A + #define INS_VALIDATE 0x7C + #define INS_MLSAG 0x7E + #define INS_CLOSE_TX 0x80 + + + #define INS_GET_RESPONSE 0xc0 + + + void device_ledger::logCMD() { + if (apdu_verbose) { + char strbuffer[1024]; + sprintf(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] + ); + buffer_to_str(strbuffer+strlen(strbuffer), sizeof(strbuffer), (char*)(this->buffer_send+5), this->length_send-5); + MDEBUG( "CMD :" << strbuffer); + } + } + + void device_ledger::logRESP() { + if (apdu_verbose) { + char strbuffer[1024]; + sprintf(strbuffer, "%.02x%.02x ", + this->buffer_recv[this->length_recv-2], + this->buffer_recv[this->length_recv-1] + ); + buffer_to_str(strbuffer+strlen(strbuffer), sizeof(strbuffer), (char*)(this->buffer_recv), this->length_recv-2); + MDEBUG( "RESP :" << strbuffer); + + } + } + + /* -------------------------------------------------------------- */ + device_ledger::device_ledger() DEVICE_CONTROLE { + this->id = device_id++; + this->hCard = 0; + this->hContext = 0; + this->reset_buffer(); + MDEBUG( "Device "<<this->id <<" Created"); + } + + device_ledger::~device_ledger() { + this->release(); + MDEBUG( "Device "<<this->id <<" Destroyed"); + } + + + /* ======================================================================= */ + /* MISC */ + /* ======================================================================= */ + bool device_ledger::reset() { + + lock_device(); + try { + int offset; + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_RESET; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + unsigned int device_ledger::exchange(unsigned int ok, unsigned int mask) { + LONG rv; + int sw; + + ASSERT_T0(this->length_send <= BUFFER_SEND_SIZE); + logCMD(); + this->length_recv = BUFFER_RECV_SIZE; + rv = SCardTransmit(this->hCard, + SCARD_PCI_T0, this->buffer_send, this->length_send, + NULL, this->buffer_recv, &this->length_recv); + ASSERT_RV(rv); + ASSERT_T0(this->length_recv <= BUFFER_RECV_SIZE); + logRESP(); + + sw = (this->buffer_recv[this->length_recv-2]<<8) | this->buffer_recv[this->length_recv-1]; + ASSERT_SW(sw,ok,msk); + return sw; + } + + 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); + } + + void device_ledger::lock_device() { + MDEBUG( "Ask for LOCKING for device "<<this->id); + device_locker.lock(); + MDEBUG( "Device "<<this->id << " LOCKed"); + } + void device_ledger::unlock_device() { + try { + MDEBUG( "Ask for UNLOCKING for device "<<this->id); + } catch (...) { + } + device_locker.unlock(); + MDEBUG( "Device "<<this->id << " UNLOCKed"); + } + void device_ledger::lock_tx() { + MDEBUG( "Ask for LOCKING for TX "<<this->id); + //tx_locker.lock(); + MDEBUG( "TX "<<this->id << " LOCKed"); + } + void device_ledger::unlock_tx() { + MDEBUG( "Ask for UNLOCKING for TX "<<this->id); + //tx_locker.unlock(); + MDEBUG( "TX "<<this->id << " UNLOCKed"); + } + + /* ======================================================================= */ + /* SETUP/TEARDOWN */ + /* ======================================================================= */ + + bool device_ledger::set_name(const std::string & name) { + this->name = name; + return true; + } + + const std::string device_ledger::get_name() const { + if (this->full_name.empty() || (this->hCard == 0)) { + return std::string("<disconnected:").append(this->name).append(">"); + } + return this->full_name; + } + + bool device_ledger::init(void) { + LONG rv; + this->release(); + rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM,0,0, &this->hContext); + ASSERT_RV(rv); + MDEBUG( "Device "<<this->id <<" SCardContext created: hContext="<<this->hContext); + this->hCard = 0; + return true; + } + + bool device_ledger::release() { + this->disconnect(); + if (this->hContext) { + SCardReleaseContext(this->hContext); + MDEBUG( "Device "<<this->id <<" SCardContext released: hContext="<<this->hContext); + this->hContext = 0; + this->full_name.clear(); + } + return true; + } + + bool device_ledger::connect(void) { + BYTE pbAtr[MAX_ATR_SIZE]; + LPSTR mszReaders; + DWORD dwReaders; + LONG rv; + DWORD dwState, dwProtocol, dwAtrLen, dwReaderLen; + + this->disconnect(); +#ifdef SCARD_AUTOALLOCATE + dwReaders = SCARD_AUTOALLOCATE; + rv = SCardListReaders(this->hContext, NULL, (LPSTR)&mszReaders, &dwReaders); +#else + dwReaders = 0; + rv = SCardListReaders(this->hContext, NULL, NULL, &dwReaders); + if (rv != SCARD_S_SUCCESS) + return false; + mszReaders = (LPSTR)calloc(dwReaders, sizeof(char)); + rv = SCardListReaders(this->hContext, NULL, mszReaders, &dwReaders); +#endif + if (rv == SCARD_S_SUCCESS) { + char* p; + const char* prefix = this->name.c_str(); + + p = mszReaders; + MDEBUG( "Looking for " << std::string(prefix)); + while (*p) { + MDEBUG( "Device Found: " << std::string(p)); + if ((strncmp(prefix, p, strlen(prefix))==0)) { + MDEBUG( "Device Match: " << std::string(p)); + if ((rv = SCardConnect(this->hContext, + p, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0, + &this->hCard, &dwProtocol))!=SCARD_S_SUCCESS) { + break; + } + MDEBUG( "Device "<<this->id <<" Connected: hCard="<<this->hCard); + dwAtrLen = sizeof(pbAtr); + if ((rv = SCardStatus(this->hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen))!=SCARD_S_SUCCESS) { + break; + } + MDEBUG( "Device "<<this->id <<" Status OK"); + rv = SCARD_S_SUCCESS ; + this->full_name = std::string(p); + break; + } + p += strlen(p) +1; + } + } + + if (mszReaders) { + #ifdef SCARD_AUTOALLOCATE + SCardFreeMemory(this->hContext, mszReaders); + #else + free(mszReaders); + #endif + mszReaders = NULL; + } + if (rv != SCARD_S_SUCCESS) { + if ( hCard) { + SCardDisconnect(this->hCard, SCARD_UNPOWER_CARD); + MDEBUG( "Device "<<this->id <<" disconnected: hCard="<<this->hCard); + this->hCard = 0; + } + } + ASSERT_RV(rv); + + this->reset(); + #ifdef DEBUG_HWDEVICE + cryptonote::account_public_address pubkey; + this->get_public_address(pubkey); + crypto::secret_key vkey; + crypto::secret_key skey; + this->get_secret_keys(vkey,skey); + #endif + + return rv==SCARD_S_SUCCESS; + } + + bool device_ledger::disconnect() { + if (this->hCard) { + SCardDisconnect(this->hCard, SCARD_UNPOWER_CARD); + MDEBUG( "Device "<<this->id <<" disconnected: hCard="<<this->hCard); + this->hCard = 0; + } + return true; + } + + + /* ======================================================================= */ + /* WALLET & ADDRESS */ + /* ======================================================================= */ + + bool device_ledger::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) { + memset(viewkey.data, 0x00, 32); + memset(spendkey.data, 0xFF, 32); + return true; + } + + /* Application API */ + bool device_ledger::get_public_address(cryptonote::account_public_address &pubkey){ + + lock_device(); + try { + int offset; + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_KEY; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(pubkey.m_view_public_key.data, this->buffer_recv, 32); + memmove(pubkey.m_spend_public_key.data, this->buffer_recv+32, 32); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + #ifdef DEBUG_HWDEVICE + bool device_ledger::get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) { + lock_device(); + try { + //spcialkey, normal conf handled in decrypt + int offset; + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_KEY; + this->buffer_send[2] = 0x02; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //clear key + memmove(ledger::viewkey.data, this->buffer_recv+64, 32); + memmove(ledger::spendkey.data, this->buffer_recv+96, 32); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + #endif + + bool device_ledger::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) { + lock_device(); + try { + int offset; + + #ifdef DEBUG_HWDEVICE + const cryptonote::account_keys keys_x = decrypt(keys); + crypto::chacha_key key_x; + this->controle_device.generate_chacha_key(keys_x, key_x); + #endif + + reset_buffer(); + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_CHACHA8_PREKEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + char prekey[200]; + memmove(prekey, &this->buffer_recv[0], 200); + crypto::generate_chacha_key(&prekey[0], sizeof(prekey), key, true); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("generate_chacha_key", "key", (char*)key_x.data(), (char*)key.data()); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + /* ======================================================================= */ + /* 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){ + + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const crypto::public_key pub_x = pub; + const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); + const std::size_t output_index_x = output_index; + crypto::public_key derived_pub_x; + this->controle_device.derive_subaddress_public_key(pub_x, derivation_x,output_index_x,derived_pub_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_DERIVE_SUBADDRESS_PUBLIC_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //pub + memmove(this->buffer_send+offset, pub.data, 32); + offset += 32; + //derivation + memmove(this->buffer_send+offset, derivation.data, 32); + offset += 32; + //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); + + #ifdef DEBUG_HWDEVICE + hw::ledger::check32("derive_subaddress_public_key", "derived_pub", derived_pub_x.data, derived_pub.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, crypto::public_key &D) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #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; + this->controle_device.get_subaddress_spend_public_key(keys_x, index_x, D_x); + #endif + + if (index.is_zero()) { + D = keys.m_account_address.m_spend_public_key; + } else { + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool 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) { + cryptonote::subaddress_index index = {account, begin}; + crypto::public_key D; + for (uint32_t idx = begin; idx < end; ++idx) { + index.minor = idx; + this->get_subaddress_spend_public_key(keys, index, D); + pkeys.push_back(D); + } + return true; + } + + bool device_ledger::get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #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; + this->controle_device.get_subaddress(keys_x, index_x, address_x); + #endif + + if (index.is_zero()) { + address = keys.m_account_address; + } else { + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_SUBADDRESS; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #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; + this->controle_device.get_subaddress_secret_key(sec_x, index_x, sub_sec_x); + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GET_SUBADDRESS_SECRET_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //sec + memmove(this->buffer_send+offset, sec.data, 32); + offset += 32; + //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(sub_sec.data, &this->buffer_recv[0], 32); + + #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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + /* ======================================================================= */ + /* DERIVATION & KEY */ + /* ======================================================================= */ + + bool device_ledger::verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) { + lock_device(); + try { + int offset =0,sw; + unsigned char options = 0; + reset_buffer(); + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VERIFY_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //sec + memmove(this->buffer_send+offset, secret_key.data, 32); + offset += 32; + //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 ; + + unlock_device(); + return verified == 1; + }catch (...) { + unlock_device(); + throw; + } + return false; + } + + bool device_ledger::scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const rct::key pub_x = pub; + const rct::key sec_x = hw::ledger::decrypt(sec); + rct::key mulkey_x; + this->controle_device.scalarmultKey(pub_x, sec_x, mulkey_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_SECRET_SCAL_MUL_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //pub + memmove(this->buffer_send+offset, P.bytes, 32); + offset += 32; + //sec + memmove(this->buffer_send+offset, a.bytes, 32); + offset += 32; + + + 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 + hw::ledger::check32("scalarmultKey", "mulkey", (char*)mulkey_x.bytes, (char*)mulkey.bytes); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::scalarmultBase(rct::key &aG, const rct::key &a) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const rct::key sec_x = hw::ledger::decrypt(sec); + rct::key mulkey_x; + this->controle_device.scalarmultBase(sec_x, mulkey_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_SECRET_SCAL_MUL_BASE; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //sec + memmove(this->buffer_send+offset, a.bytes, 32); + offset += 32; + + 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 + hw::ledger::check32("scalarmultBase", "mulkey", (char*)mulkey_x.bytes, (char*)mulkey.bytes); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) { + + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #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; + this->controle_device.sc_secret_add(r_x, a_x, b_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_SECRET_KEY_ADD; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //sec key + memmove(this->buffer_send+offset, a.data, 32); + offset += 32; + //sec key + memmove(this->buffer_send+offset, b.data, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(r.data, &this->buffer_recv[0], 32); + + #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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) { + if (recover) { + throw std::runtime_error("device generate key does not support recover"); + } + + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + bool recover_x = recover; + const crypto::secret_key recovery_key_x = recovery_key; + crypto::public_key pub_x; + crypto::secret_key sec_x; + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GENERATE_KEYPAIR; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(pub.data, &this->buffer_recv[0], 32); + memmove(sec.data, &this->buffer_recv[32], 32); + + #ifdef DEBUG_HWDEVICE + crypto::secret_key sec_clear = hw::ledger::decrypt(sec); + sec_x = sec_clear; + crypto::secret_key_to_public_key(sec_x,pub_x); + hw::ledger::check32("generate_keys", "pub", pub_x.data, pub.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + + } + + bool device_ledger::generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const crypto::public_key pub_x = pub; + const crypto::secret_key sec_x = hw::ledger::decrypt(sec); + crypto::key_derivation derivation_x; + this->controle_device.generate_key_derivation(pub_x, sec_x, derivation_x); + hw::ledger::log_hexbuffer("generate_key_derivation: sec_x.data", sec_x.data, 32); + hw::ledger::log_hexbuffer("generate_key_derivation: pub_x.data", pub_x.data, 32); + hw::ledger::log_hexbuffer("generate_key_derivation: derivation_x.data", derivation_x.data, 32); + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GEN_KEY_DERIVATION; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //pub + memmove(this->buffer_send+offset, pub.data, 32); + offset += 32; + //sec + memmove(this->buffer_send+offset, sec.data, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //derivattion data + memmove(derivation.data, &this->buffer_recv[0], 32); + + #ifdef DEBUG_HWDEVICE + crypto::key_derivation derivation_clear = hw::ledger::decrypt(derivation); + hw::ledger::check32("generate_key_derivation", "derivation", derivation_x.data, derivation_clear.data); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) { + lock_device(); + try { + int offset; + unsigned char options; + + #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; + this->controle_device.derivation_to_scalar(derivation_x, output_index_x, res_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_DERIVATION_TO_SCALAR; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //derivattion + memmove(this->buffer_send+offset, derivation.data, 32); + offset += 32; + //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(); + + //derivattion data + memmove(res.data, &this->buffer_recv[0], 32); + + #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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + 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) { + lock_device(); + try { + int offset; + unsigned char options; + + #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; + this->controle_device.derive_secret_key(derivation_x, output_index_x, sec_x, derived_sec_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_DERIVE_SECRET_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //derivation + memmove(this->buffer_send+offset, derivation.data, 32); + offset += 32; + //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 + memmove(this->buffer_send+offset, sec.data, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + //pub key + memmove(derived_sec.data, &this->buffer_recv[0], 32); + + #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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + 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){ + lock_device(); + try { + int offset; + unsigned char options; + + #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; + this->controle_device.derive_public_key(derivation_x, output_index_x, pub_x, derived_pub_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_DERIVE_PUBLIC_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //derivation + memmove(this->buffer_send+offset, derivation.data, 32); + offset += 32; + //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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) { + lock_device(); + try { + int offset; + unsigned char options; + + #ifdef DEBUG_HWDEVICE + const crypto::secret_key sec_x = hw::ledger::decrypt(sec); + crypto::public_key pub_x; + this->controle_device.secret_key_to_public_key(sec_x, pub_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_SECRET_KEY_TO_PUBLIC_KEY; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //sec key + memmove(this->buffer_send+offset, sec.data, 32); + offset += 32; + + 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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image){ + lock_device(); + try { + int offset; + unsigned char options; + + #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; + this->controle_device.generate_key_image(pub_x, sec_x, image_x); + #endif + + reset_buffer(); + + options = 0; + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_GEN_KEY_IMAGE; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = options; + offset += 1; + //pub + memmove(this->buffer_send+offset, pub.data, 32); + offset += 32; + //sec + memmove(this->buffer_send+offset, sec.data, 32); + offset += 32; + + 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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + /* ======================================================================= */ + /* TRANSACTION */ + /* ======================================================================= */ + + bool device_ledger::open_tx(crypto::secret_key &tx_key) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + lock_tx(); + reset_buffer(); + key_map.clear(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_OPEN_TX; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //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(); + + memmove(tx_key.data, &this->buffer_recv[32], 32); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::set_signature_mode(unsigned int sig_mode) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_SET_SIGNATURE_MODE; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //account + this->buffer_send[offset] = sig_mode; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #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; + this->controle_device.encrypt_payment_id(public_key_x, secret_key_x, payment_id_x); + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_STEALTH; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //pub + memmove(&this->buffer_send[offset], public_key.data, 32); + offset += 32; + //sec + memmove(&this->buffer_send[offset], secret_key.data, 32); + offset += 32; + //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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index, + const rct::key &amount_key, const crypto::public_key &out_eph_public_key) { + lock_device(); + try { + key_map.add(ABPkeys(rct::pk2rct(Aout),rct::pk2rct(Bout), real_output_index, rct::pk2rct(out_eph_public_key), amount_key)); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & AKout) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const rct::key AKout_x = hw::ledger::decrypt(AKout); + rct::ecdhTuple unmasked_x = unmasked; + this->controle_device.ecdhEncode(AKout_x, unmasked_x); + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_BLIND; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + // AKout + memmove(this->buffer_send+offset, AKout.bytes, 32); + offset += 32; + //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 + 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); + + hw::ledger::log_hexbuffer("Blind AKV input", (char*)&this->buffer_recv[64], 3*32); + #endif + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::ecdhDecode(rct::ecdhTuple & masked, const rct::key & AKout) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + const rct::key AKout_x = hw::ledger::decrypt(AKout); + rct::ecdhTuple masked_x = masked; + this->controle_device.ecdhDecode(AKout_x, masked_x); + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_UNBLIND; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + // AKout + memmove(this->buffer_send+offset, AKout.bytes, 32); + offset += 32; + //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 + 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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + 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) { + + lock_device(); + try { + unsigned char options = 0; + 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; + this->controle_device.mlsag_prehash(blob_x, inputs_size_x, outputs_size_x, hashes_x, outPk_x, prehash_x); + 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 ====== + int offset; + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VALIDATE; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x01; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = (inputs_size == 0)?0x00:0x80; + offset += 1; + + //type + 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; + this->exchange(); + + //pseudoOuts + for ( i = 0; i < inputs_size; i++) { + reset_buffer(); + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VALIDATE; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = i+2; + this->buffer_send[4] = 0x00; + offset = 5; + //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(); + } + + // ====== Aout, Bout, AKout, C, v, k ====== + kv_offset = data_offset; + C_offset = kv_offset+ (32*2)*outputs_size; + 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"); + } + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VALIDATE; + this->buffer_send[2] = 0x02; + this->buffer_send[3] = i+1; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ; + offset += 1; + if (found) { + //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 + memmove(this->buffer_send+offset, outKeys.AKout.bytes, 32); + offset+=32; + } else { + // dummy: Aout Bout AKout + offset += 32*3; + } + //C + memmove(this->buffer_send+offset, data+C_offset,32); + offset += 32; + C_offset += 32; + //k + memmove(this->buffer_send+offset, data+kv_offset,32); + offset += 32; + //v + kv_offset += 32; + memmove(this->buffer_send+offset, data+kv_offset,32); + offset += 32; + kv_offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + #ifdef DEBUG_HWDEVICE + hw::ledger::log_hexbuffer("Prehash AKV input", (char*)&this->buffer_recv[64], 3*32); + #endif + } + + // ====== C[], message, proof====== + C_offset = kv_offset; + for (i = 0; i < outputs_size; i++) { + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VALIDATE; + this->buffer_send[2] = 0x03; + this->buffer_send[3] = i+1; + this->buffer_send[4] = 0x00; + offset = 5; + //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(); + + } + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_VALIDATE; + this->buffer_send[2] = 0x03; + this->buffer_send[3] = i+1; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + + 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) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #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 + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_MLSAG; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + //value H + memmove(this->buffer_send+offset, H.bytes, 32); + offset += 32; + //mask xin + memmove(this->buffer_send+offset, xx.bytes, 32); + offset += 32; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(a.bytes, &this->buffer_recv[32*0], 32); + memmove(aG.bytes, &this->buffer_recv[32*1], 32); + memmove(aHP.bytes, &this->buffer_recv[32*2], 32); + memmove(II.bytes, &this->buffer_recv[32*3], 32); + + #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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::mlsag_prepare(rct::key &a, rct::key &aG) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + #ifdef DEBUG_HWDEVICE + rct::key a_x; + rct::key aG_x; + #endif + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_MLSAG; + this->buffer_send[2] = 0x01; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + memmove(a.bytes, &this->buffer_recv[32*0], 32); + memmove(aG.bytes, &this->buffer_recv[32*1], 32); + + #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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::mlsag_hash(const rct::keyV &long_message, rct::key &c) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + size_t cnt; + + #ifdef DEBUG_HWDEVICE + const rct::keyV long_message_x = long_message; + rct::key c_x; + this->controle_device.mlsag_hash(long_message_x, c_x); + #endif + + cnt = long_message.size(); + for (size_t i = 0; i<cnt; i++) { + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_MLSAG; + this->buffer_send[2] = 0x02; + this->buffer_send[3] = i+1; + this->buffer_send[4] = 0x00; + offset = 5; + //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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + + } + + 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) { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + 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()); + this->controle_device.mlsag_sign(c_x, xx_x, alpha_x, rows_x, dsRows_x, ss_x); + #endif + + for (size_t j = 0; j < dsRows; j++) { + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_MLSAG; + this->buffer_send[2] = 0x03; + this->buffer_send[3] = j+1; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + if (j==(dsRows-1)) { + this->buffer_send[offset] |= 0x80; //last + } + offset += 1; + //xx + memmove(this->buffer_send+offset, xx[j].bytes, 32); + offset += 32; + //alpa + memmove(this->buffer_send+offset, alpha[j].bytes, 32); + offset += 32; + + 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 + + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + bool device_ledger::close_tx() { + lock_device(); + try { + int offset =0; + unsigned char options = 0; + + reset_buffer(); + + this->buffer_send[0] = 0x00; + this->buffer_send[1] = INS_CLOSE_TX; + this->buffer_send[2] = 0x00; + this->buffer_send[3] = 0x00; + this->buffer_send[4] = 0x00; + offset = 5; + //options + this->buffer_send[offset] = 0x00; + offset += 1; + + this->buffer_send[4] = offset-5; + this->length_send = offset; + this->exchange(); + + unlock_tx(); + unlock_device(); + }catch (...) { + unlock_device(); + throw; + } + return true; + } + + /* ---------------------------------------------------------- */ + + 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"); + } + registry.insert(std::make_pair("Ledger", legder_device)); + } + + #else //WITH_DEVICE_LEDGER + + void register_all(std::map<std::string, std::unique_ptr<device>> ®istry) { + } + + #endif //WITH_DEVICE_LEDGER + + } +} + diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp new file mode 100644 index 000000000..ab8e0c553 --- /dev/null +++ b/src/device/device_ledger.hpp @@ -0,0 +1,202 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// + + +#pragma once + +#include <cstddef> +#include <string> +#include <mutex> +#include "device.hpp" +#include <PCSC/winscard.h> +#include <PCSC/wintypes.h> + + +namespace hw { + + namespace ledger { + + void register_all(std::map<std::string, std::unique_ptr<device>> ®istry); + + #ifdef WITH_DEVICE_LEDGER + + namespace { + bool apdu_verbose =true; + } + + void set_apdu_verbose(bool verbose); + + class ABPkeys { + public: + rct::key Aout; + rct::key Bout; + size_t index; + rct::key Pout; + rct::key AKout; + ABPkeys(const rct::key& A, const rct::key& B, size_t index, const rct::key& P,const rct::key& AK); + ABPkeys(const ABPkeys& keys) ; + ABPkeys() {index=0;} + }; + + class Keymap { + public: + std::vector<ABPkeys> ABP; + + bool find(const rct::key& P, ABPkeys& keys) const; + void add(const ABPkeys& keys); + void clear(); + void log(); + }; + + #define BUFFER_SEND_SIZE 262 + #define BUFFER_RECV_SIZE 262 + + class device_ledger : public hw::device { + private: + mutable std::mutex device_locker; + mutable std::mutex tx_locker; + void lock_device() ; + void unlock_device() ; + void lock_tx() ; + void unlock_tx() ; + + std::string full_name; + SCARDCONTEXT hContext; + SCARDHANDLE hCard; + DWORD length_send; + BYTE buffer_send[BUFFER_SEND_SIZE]; + DWORD length_recv; + BYTE buffer_recv[BUFFER_RECV_SIZE]; + unsigned int id; + + Keymap key_map; + + + void logCMD(void); + void logRESP(void); + unsigned int exchange(unsigned int ok=0x9000, unsigned int mask=0xFFFF); + void reset_buffer(void); + + #ifdef DEBUGLEDGER + Device &controle_device; + #endif + + public: + device_ledger(); + ~device_ledger(); + + device_ledger(const device_ledger &device) = delete ; + device_ledger& operator=(const device_ledger &device) = delete; + + explicit operator bool() const override {return this->hContext != 0;} + + bool reset(void); + + /* ======================================================================= */ + /* SETUP/TEARDOWN */ + /* ======================================================================= */ + bool set_name(const std::string &name) override; + + const std::string get_name() const override; + bool init(void) override; + bool release() override; + bool connect(void) override; + bool disconnect() override; + + /* ======================================================================= */ + /* WALLET & ADDRESS */ + /* ======================================================================= */ + bool get_public_address(cryptonote::account_public_address &pubkey) override; + bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override; + bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) override; + + + /* ======================================================================= */ + /* SUB ADDRESS */ + /* ======================================================================= */ + bool 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) override; + bool get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index& index, crypto::public_key &D) override; + bool 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) override; + bool get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index, cryptonote::account_public_address &address) override; + bool get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index, crypto::secret_key &sub_sec) override; + + /* ======================================================================= */ + /* DERIVATION & KEY */ + /* ======================================================================= */ + bool verify_keys(const crypto::secret_key &secret_key, const crypto::public_key &public_key) override; + bool scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) override; + bool scalarmultBase(rct::key &aG, const rct::key &a) override; + bool sc_secret_add(crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) override; + bool generate_keys(crypto::public_key &pub, crypto::secret_key &sec, const crypto::secret_key& recovery_key, bool recover, crypto::secret_key &rng) override; + bool generate_key_derivation(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_derivation &derivation) override; + bool derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) override; + bool derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) override; + bool derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub) override; + bool secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) override; + bool generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image) override; + + /* ======================================================================= */ + /* TRANSACTION */ + /* ======================================================================= */ + + bool open_tx(crypto::secret_key &tx_key) override; + + bool set_signature_mode(unsigned int sig_mode) override; + + bool encrypt_payment_id(const crypto::public_key &public_key, const crypto::secret_key &secret_key, crypto::hash8 &payment_id ) override; + + bool ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & sharedSec) override; + bool ecdhDecode(rct::ecdhTuple & masked, const rct::key & sharedSec) override; + + bool add_output_key_mapping(const crypto::public_key &Aout, const crypto::public_key &Bout, size_t real_output_index, + const rct::key &amount_key, const crypto::public_key &out_eph_public_key) override; + + + bool 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) override; + bool mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &rvII) override; + bool mlsag_prepare(rct::key &a, rct::key &aG) override; + bool mlsag_hash(const rct::keyV &long_message, rct::key &c) override; + bool 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) override; + + bool close_tx(void) override; + + }; + + + + #ifdef DEBUGLEDGER + extern crypto::secret_key viewkey; + extern crypto::secret_key spendkey; + #endif + + #endif //WITH_DEVICE_LEDGER + } + +} + diff --git a/src/device/log.cpp b/src/device/log.cpp new file mode 100644 index 000000000..103b2b3ba --- /dev/null +++ b/src/device/log.cpp @@ -0,0 +1,164 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// + +#include "misc_log_ex.h" +#include "log.hpp" + +namespace hw { + + #ifdef WITH_DEVICE_LEDGER + namespace ledger { + + #undef MONERO_DEFAULT_LOG_CATEGORY + #define MONERO_DEFAULT_LOG_CATEGORY "device.ledger" + + void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) { + CHECK_AND_ASSERT_THROW_MES(to_len > (len*2), "destination buffer too short. At least" << (len*2+1) << " bytes required"); + for (size_t i=0; i<len; i++) { + sprintf(to_buff+2*i, "%.02x", (unsigned char)buff[i]); + } + } + + void log_hexbuffer(std::string msg, const char* buff, size_t len) { + char logstr[1025]; + buffer_to_str(logstr, sizeof(logstr), buff, len); + MDEBUG(msg<< ": " << logstr); + } + + void log_message(std::string msg, std::string info ) { + MDEBUG(msg << ": " << info); + } + + #ifdef DEBUGLEDGER + extern crypto::secret_key viewkey; + extern crypto::secret_key spendkey; + + + void decrypt(char* buf, size_t len) { + #ifdef IODUMMYCRYPT + int i; + if (len == 32) { + //view key? + for (i = 0; i<32; i++) { + if (buf[i] != 0) break; + } + if (i == 32) { + memmove(buf, hw::ledger::viewkey.data, 32); + return; + } + //spend key? + for (i = 0; i<32; i++) { + if (buf[i] != (char)0xff) break; + } + if (i == 32) { + memmove(buf, hw::ledger::spendkey.data, 32); + return; + } + } + //std decrypt: XOR.55h + for (i = 0; i<len;i++) { + buf[i] ^= 0x55; + } + #endif + } + + crypto::key_derivation decrypt(const crypto::key_derivation &derivation) { + crypto::key_derivation x = derivation; + decrypt(x.data, 32); + return x; + } + + cryptonote::account_keys decrypt(const cryptonote::account_keys& keys) { + cryptonote::account_keys x = keys; + decrypt(x.m_view_secret_key.data, 32); + decrypt(x.m_spend_secret_key.data, 32); + return x; + } + + + crypto::secret_key decrypt(const crypto::secret_key &sec) { + crypto::secret_key x = sec; + decrypt(x.data, 32); + return x; + } + + rct::key decrypt(const rct::key &sec) { + rct::key x = sec; + decrypt((char*)x.bytes, 32); + return x; + } + + crypto::ec_scalar decrypt(const crypto::ec_scalar &res) { + crypto::ec_scalar x = res; + decrypt((char*)x.data, 32); + return x; + } + + rct::keyV decrypt(const rct::keyV &keys) { + rct::keyV x ; + for (unsigned int j = 0; j<keys.size(); j++) { + x.push_back(decrypt(keys[j])); + } + return x; + } + + static void check(std::string msg, std::string info, const char *h, const char *d, int len, bool crypted) { + char dd[32]; + char logstr[128]; + + memmove(dd,d,len); + if (crypted) { + CHECK_AND_ASSERT_THROW_MES(len<=32, "encrypted data greater than 32"); + decrypt(dd,len); + } + + if (memcmp(h,dd,len)) { + log_message("ASSERT EQ FAIL", msg + ": "+ info ); + log_hexbuffer(" host ", h, len); + log_hexbuffer(" device", dd, len); + + } else { + buffer_to_str(logstr, dd, len); + log_message("ASSERT EQ OK", msg + ": "+ info + ": "+ std::string(logstr) ); + } + } + + void check32(std::string msg, std::string info, const char *h, const char *d, bool crypted) { + check(msg, info, h, d, 32, crypted); + } + + void check8(std::string msg, std::string info, const char *h, const char *d, bool crypted) { + check(msg, info, h, d, 8, crypted); + } + #endif + + } + #endif //WITH_DEVICE_LEDGER + +}
\ No newline at end of file diff --git a/src/device/log.hpp b/src/device/log.hpp new file mode 100644 index 000000000..1ab572c2c --- /dev/null +++ b/src/device/log.hpp @@ -0,0 +1,69 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// + +#pragma once + +#include <cstddef> +#include <string> + +#include "ringct/rctOps.h" +#include "crypto/crypto.h" +#include "cryptonote_basic/account.h" + +#include "device.hpp" + +namespace hw { + + #ifdef WITH_DEVICE_LEDGER + namespace ledger { + + void buffer_to_str(char *to_buff, size_t to_len, const char *buff, size_t len) ; + void log_hexbuffer(std::string msg, const char* buff, size_t len); + void log_message(std::string msg, std::string info ); + #ifdef DEBUG_HWDEVICE + #define TRACK printf("file %s:%d\n",__FILE__, __LINE__) + //#define TRACK MCDEBUG("ledger"," At file " << __FILE__ << ":" << __LINE__) + //#define TRACK while(0); + + void decrypt(char* buf, size_t len) ; + crypto::key_derivation decrypt(const crypto::key_derivation &derivation) ; + cryptonote::account_keys decrypt(const cryptonote::account_keys& keys) ; + crypto::secret_key decrypt(const crypto::secret_key &sec) ; + rct::key decrypt(const rct::key &sec); + crypto::ec_scalar decrypt(const crypto::ec_scalar &res); + rct::keyV decrypt(const rct::keyV &keys); + + void check32(std::string msg, std::string info, const char *h, const char *d, bool crypted=false); + void check8(std::string msg, std::string info, const char *h, const char *d, bool crypted=false); + + void set_check_verbose(bool verbose); + #endif + } + #endif +} diff --git a/src/multisig/multisig.cpp b/src/multisig/multisig.cpp index 6c05a38d9..91042d58a 100644 --- a/src/multisig/multisig.cpp +++ b/src/multisig/multisig.cpp @@ -33,6 +33,7 @@ #include "cryptonote_basic/account.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "multisig.h" +#include "device/device_default.hpp" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "multisig" @@ -116,7 +117,7 @@ namespace cryptonote bool generate_multisig_composite_key_image(const account_keys &keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key &tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, const std::vector<crypto::key_image> &pkis, crypto::key_image &ki) { cryptonote::keypair in_ephemeral; - if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki)) + if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki, keys.get_device())) return false; std::unordered_set<crypto::key_image> used; for (size_t m = 0; m < keys.m_multisig_keys.size(); ++m) diff --git a/src/ringct/CMakeLists.txt b/src/ringct/CMakeLists.txt index 3a28997dd..2d3ea5cf4 100644 --- a/src/ringct/CMakeLists.txt +++ b/src/ringct/CMakeLists.txt @@ -28,6 +28,7 @@ set(ringct_sources rctOps.cpp + rctOps_device.cpp rctSigs.cpp rctTypes.cpp rctCryptoOps.c @@ -52,6 +53,7 @@ target_link_libraries(ringct common cncrypto cryptonote_basic + device PRIVATE ${OPENSSL_LIBRARIES} ${EXTRA_LIBRARIES}) diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h index 3f8f6955c..c9f2e7a43 100644 --- a/src/ringct/rctOps.h +++ b/src/ringct/rctOps.h @@ -112,10 +112,14 @@ namespace rct { //does a * G where a is a scalar and G is the curve basepoint void scalarmultBase(key & aG, const key &a); + void scalarmultBase(key & aG, const key &a, hw::device &hwdev); key scalarmultBase(const key & a); + key scalarmultBase(const key & a, hw::device &hwdev); //does a * P where a is a scalar and P is an arbitrary point void scalarmultKey(key &aP, const key &P, const key &a); + void scalarmultKey(key &aP, const key &P, const key &a, hw::device &hwdev); key scalarmultKey(const key &P, const key &a); + key scalarmultKey(const key &P, const key &a, hw::device &hwdev); //Computes aH where H= toPoint(cn_fast_hash(G)), G the basepoint key scalarmultH(const key & a); @@ -174,6 +178,8 @@ namespace rct { //Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a // where C= aG + bH void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec); + void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec, hw::device &hwdev); void ecdhDecode(ecdhTuple & masked, const key & sharedSec); + void ecdhDecode(ecdhTuple & masked, const key & sharedSec, hw::device &hwdev); } #endif /* RCTOPS_H */ diff --git a/src/ringct/rctOps_device.cpp b/src/ringct/rctOps_device.cpp new file mode 100644 index 000000000..fbfe8e9cf --- /dev/null +++ b/src/ringct/rctOps_device.cpp @@ -0,0 +1,66 @@ +// Copyright (c) 2017-2018, The Monero Project +// +// 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. +// + +#include "misc_log_ex.h" +#include "rctOps.h" +#include "device/device.hpp" +using namespace crypto; +using namespace std; + + +namespace rct +{ + void scalarmultKey(key & aP, const key &P, const key &a, hw::device &hwdev) { + hwdev.scalarmultKey(aP, P, a); + } + + key scalarmultKey(const key & P, const key & a, hw::device &hwdev) { + key aP; + hwdev.scalarmultKey(aP, P, a); + return aP; + } + + void scalarmultBase(key &aG, const key &a, hw::device &hwdev) { + hwdev.scalarmultBase(aG, a); + } + + key scalarmultBase(const key & a, hw::device &hwdev) { + key aG; + hwdev.scalarmultBase(aG, a); + return aG; + } + + void ecdhDecode(ecdhTuple & masked, const key & sharedSec, hw::device &hwdev) { + hwdev.ecdhDecode(masked, sharedSec); + } + + void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec, hw::device &hwdev) { + hwdev.ecdhEncode(unmasked, sharedSec); + } +}
\ No newline at end of file diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index 0c2be5add..d3437eb36 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -35,6 +35,9 @@ #include "rctSigs.h" #include "bulletproofs.h" #include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/subaddress_index.h" +#include "device/device.hpp" using namespace crypto; using namespace std; @@ -153,7 +156,7 @@ namespace rct { // Gen creates a signature which proves that for some column in the keymatrix "pk" // the signer knows a secret key for each row in that column // Ver verifies that the MG sig was created correctly - mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows) { + mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev) { mgSig rv; size_t cols = pk.size(); CHECK_AND_ASSERT_THROW_MES(cols >= 2, "Error! What is c if cols = 1!"); @@ -191,11 +194,9 @@ namespace rct { } else { Hi = hashToPoint(pk[index][i]); - skpkGen(alpha[i], aG[i]); //need to save alphas for later.. - aHP[i] = scalarmultKey(Hi, alpha[i]); + hwdev.mlsag_prepare(Hi, xx[i], alpha[i] , aG[i] , aHP[i] , rv.II[i]); toHash[3 * i + 2] = aG[i]; toHash[3 * i + 3] = aHP[i]; - rv.II[i] = scalarmultKey(Hi, xx[i]); } precomp(Ip[i].k, rv.II[i]); } @@ -206,7 +207,7 @@ namespace rct { toHash[ndsRows + 2 * ii + 2] = aG[i]; } - c_old = hash_to_scalar(toHash); + hwdev.mlsag_hash(toHash, c_old); i = (index + 1) % cols; @@ -230,7 +231,7 @@ namespace rct { toHash[ndsRows + 2 * ii + 1] = pk[i][j]; toHash[ndsRows + 2 * ii + 2] = L; } - c = hash_to_scalar(toHash); + hwdev.mlsag_hash(toHash, c); copy(c_old, c); i = (i + 1) % cols; @@ -238,9 +239,7 @@ namespace rct { copy(rv.cc, c_old); } } - for (j = 0; j < rows; j++) { - sc_mulsub(rv.ss[index][j].bytes, c.bytes, xx[j].bytes, alpha[j].bytes); - } + hwdev.mlsag_sign(c, xx, alpha, rows, dsRows, rv.ss[index]); if (mscout) *mscout = c; return rv; @@ -372,7 +371,7 @@ namespace rct { catch (...) { return false; } } - key get_pre_mlsag_hash(const rctSig &rv) + key get_pre_mlsag_hash(const rctSig &rv, hw::device &hwdev) { keyV hashes; hashes.reserve(3); @@ -384,6 +383,7 @@ namespace rct { CHECK_AND_ASSERT_THROW_MES(!rv.mixRing.empty(), "Empty mixRing"); const size_t inputs = is_simple(rv.type) ? rv.mixRing.size() : rv.mixRing[0].size(); const size_t outputs = rv.ecdhInfo.size(); + key prehash; CHECK_AND_ASSERT_THROW_MES(const_cast<rctSig&>(rv).serialize_rctsig_base(ba, inputs, outputs), "Failed to serialize rctSigBase"); cryptonote::get_blob_hash(ss.str(), h); @@ -427,7 +427,8 @@ namespace rct { } } hashes.push_back(cn_fast_hash(kv)); - return cn_fast_hash(hashes); + hwdev.mlsag_prehash(ss.str(), inputs, outputs, hashes, rv.outPk, prehash); + return prehash; } //Ring-ct MG sigs @@ -438,7 +439,7 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFeeKey) { + mgSig proveRctMG(const key &message, const ctkeyM & pubs, const ctkeyV & inSk, const ctkeyV &outSk, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFeeKey, hw::device &hwdev) { mgSig mg; //setup vars size_t cols = pubs.size(); @@ -483,7 +484,7 @@ namespace rct { for (size_t j = 0; j < outPk.size(); j++) { sc_sub(sk[rows].bytes, sk[rows].bytes, outSk[j].mask.bytes); //subtract output masks in last row.. } - return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows); + return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev); } @@ -494,7 +495,7 @@ namespace rct { // inSk is x, a_in corresponding to signing index // a_out, Cout is for the output commitment // index is the signing index.. - mgSig proveRctMGSimple(const key &message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index) { + mgSig proveRctMGSimple(const key &message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index, hw::device &hwdev) { mgSig mg; //setup vars size_t rows = 1; @@ -511,7 +512,7 @@ namespace rct { sk[0] = copy(inSk.dest); sc_sub(sk[1].bytes, inSk.mask.bytes, a.bytes); } - return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows); + return MLSAG_Gen(message, M, sk, kLRki, mscout, index, rows, hwdev); } @@ -645,7 +646,7 @@ namespace rct { // must know the destination private key to find the correct amount, else will return a random number // Note: For txn fees, the last index in the amounts vector should contain that // Thus the amounts vector will be "one" longer than the destinations vectort - rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof) { + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev) { CHECK_AND_ASSERT_THROW_MES(amounts.size() == destinations.size() || amounts.size() == destinations.size() + 1, "Different number of amounts/destinations"); CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations"); CHECK_AND_ASSERT_THROW_MES(index < mixRing.size(), "Bad index into mixRing"); @@ -685,8 +686,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(amounts[i]); - ecdhEncode(rv.ecdhInfo[i], amount_keys[i]); - + ecdhEncode(rv.ecdhInfo[i], amount_keys[i], hwdev); } //set txn fee @@ -703,21 +703,21 @@ namespace rct { rv.mixRing = mixRing; if (msout) msout->c.resize(1); - rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv), rv.mixRing, inSk, outSk, rv.outPk, kLRki, msout ? &msout->c[0] : NULL, index, txnFeeKey)); + rv.p.MGs.push_back(proveRctMG(get_pre_mlsag_hash(rv, hwdev), rv.mixRing, inSk, outSk, rv.outPk, kLRki, msout ? &msout->c[0] : NULL, index, txnFeeKey,hwdev)); return rv; } - rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin) { + rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin, hw::device &hwdev) { unsigned int index; ctkeyM mixRing; ctkeyV outSk; tie(mixRing, index) = populateFromBlockchain(inPk, mixin); - return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, false); + return genRct(message, inSk, destinations, amounts, mixRing, amount_keys, kLRki, msout, index, outSk, false, hwdev); } //RCT simple //for post-rct only - rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev) { CHECK_AND_ASSERT_THROW_MES(inamounts.size() > 0, "Empty inamounts"); CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk"); CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations"); @@ -767,7 +767,7 @@ namespace rct { //mask amount and mask rv.ecdhInfo[i].mask = copy(outSk[i].mask); rv.ecdhInfo[i].amount = d2h(outamounts[i]); - ecdhEncode(rv.ecdhInfo[i], amount_keys[i]); + ecdhEncode(rv.ecdhInfo[i], amount_keys[i],hwdev); } //set txn fee @@ -790,16 +790,16 @@ namespace rct { genC(pseudoOuts[i], a[i], inamounts[i]); DP(pseudoOuts[i]); - key full_message = get_pre_mlsag_hash(rv); + key full_message = get_pre_mlsag_hash(rv,hwdev); if (msout) msout->c.resize(inamounts.size()); for (i = 0 ; i < inamounts.size(); i++) { - rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i]); + rv.p.MGs[i] = proveRctMGSimple(full_message, rv.mixRing[i], inSk[i], a[i], pseudoOuts[i], kLRki ? &(*kLRki)[i]: NULL, msout ? &msout->c[i] : NULL, index[i], hwdev); } return rv; } - rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin) { + rctSig genRctSimple(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const vector<xmr_amount> &inamounts, const vector<xmr_amount> &outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, hw::device &hwdev) { std::vector<unsigned int> index; index.resize(inPk.size()); ctkeyM mixRing; @@ -809,7 +809,7 @@ namespace rct { mixRing[i].resize(mixin+1); index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); } - return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, false); + return genRctSimple(message, inSk, destinations, inamounts, outamounts, txnFee, mixRing, amount_keys, kLRki, msout, index, outSk, false, hwdev); } //RingCT protocol @@ -868,7 +868,7 @@ namespace rct { if (!semantics) { //compute txn fee key txnFeeKey = scalarmultH(d2h(rv.txnFee)); - bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv)); + bool mgVerd = verRctMG(rv.p.MGs[0], rv.mixRing, rv.outPk, txnFeeKey, get_pre_mlsag_hash(rv, hw::get_device("default"))); DP("mg sig verified?"); DP(mgVerd); if (!mgVerd) { @@ -973,7 +973,7 @@ namespace rct { } } else { - const key message = get_pre_mlsag_hash(rv); + const key message = get_pre_mlsag_hash(rv, hw::get_device("default")); results.clear(); results.resize(rv.mixRing.size()); @@ -1017,14 +1017,14 @@ namespace rct { //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) // uses the attached ecdh info to find the amounts represented by each output commitment // must know the destination private key to find the correct amount, else will return a random number - xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask) { + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeFull || rv.type == RCTTypeFullBulletproof, false, "decodeRct called on non-full rctSig"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo"); //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - ecdhDecode(ecdh_info, sk); + ecdhDecode(ecdh_info, sk, hwdev); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -1040,19 +1040,19 @@ namespace rct { return h2d(amount); } - xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i) { + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev) { key mask; - return decodeRct(rv, sk, i, mask); + return decodeRct(rv, sk, i, mask, hwdev); } - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask) { + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) { CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeSimpleBulletproof, false, "decodeRct called on non simple rctSig"); CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index"); CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo"); //mask amount and mask ecdhTuple ecdh_info = rv.ecdhInfo[i]; - ecdhDecode(ecdh_info, sk); + ecdhDecode(ecdh_info, sk, hwdev); mask = ecdh_info.mask; key amount = ecdh_info.amount; key C = rv.outPk[i].mask; @@ -1068,9 +1068,9 @@ namespace rct { return h2d(amount); } - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i) { + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev) { key mask; - return decodeRctSimple(rv, sk, i, mask); + return decodeRctSimple(rv, sk, i, mask, hwdev); } bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key) { diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index e83083a98..17047fc0f 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -50,6 +50,8 @@ extern "C" { #include "rctTypes.h" #include "rctOps.h" +#include "cryptonote_basic/cryptonote_basic.h" +#include "device/device_declare.hpp" //Define this flag when debugging to get additional info on the console #ifdef DBG @@ -73,7 +75,7 @@ namespace rct { // the signer knows a secret key for each row in that column // Ver verifies that the MG sig was created correctly keyV keyImageV(const keyV &xx); - mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows); + mgSig MLSAG_Gen(const key &message, const keyM & pk, const keyV & xx, const multisig_kLRki *kLRki, key *mscout, const unsigned int index, size_t dsRows, hw::device &hwdev); bool MLSAG_Ver(const key &message, const keyM &pk, const mgSig &sig, size_t dsRows); //mgSig MLSAG_Gen_Old(const keyM & pk, const keyV & xx, const int index); @@ -95,8 +97,8 @@ namespace rct { // this shows that sum inputs = sum outputs //Ver: // verifies the above sig is created corretly - mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFee, const key &message); - mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index); + mgSig proveRctMG(const ctkeyM & pubs, const ctkeyV & inSk, const keyV &outMasks, const ctkeyV & outPk, const multisig_kLRki *kLRki, key *mscout, unsigned int index, key txnFee, const key &message, hw::device &hwdev); + mgSig proveRctMGSimple(const key & message, const ctkeyV & pubs, const ctkey & inSk, const key &a , const key &Cout, const multisig_kLRki *kLRki, key *mscout, unsigned int index, hw::device &hwdev); bool verRctMG(const mgSig &mg, const ctkeyM & pubs, const ctkeyV & outPk, key txnFee, const key &message); bool verRctMGSimple(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C); @@ -118,18 +120,18 @@ namespace rct { //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) // uses the attached ecdh info to find the amounts represented by each output commitment // must know the destination private key to find the correct amount, else will return a random number - rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof); - rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin); - rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin); - rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof); + rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev); + rctSig genRct(const key &message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, const int mixin, hw::device &hwdev); + rctSig genRctSimple(const key & message, const ctkeyV & inSk, const ctkeyV & inPk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, xmr_amount txnFee, unsigned int mixin, hw::device &hwdev); + rctSig genRctSimple(const key & message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & inamounts, const std::vector<xmr_amount> & outamounts, xmr_amount txnFee, const ctkeyM & mixRing, const keyV &amount_keys, const std::vector<multisig_kLRki> *kLRki, multisig_out *msout, const std::vector<unsigned int> & index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev); bool verRct(const rctSig & rv, bool semantics); static inline bool verRct(const rctSig & rv) { return verRct(rv, true) && verRct(rv, false); } bool verRctSimple(const rctSig & rv, bool semantics); static inline bool verRctSimple(const rctSig & rv) { return verRctSimple(rv, true) && verRctSimple(rv, false); } - xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask); - xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i); - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask); - xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i); + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev); + xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev); + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev); + xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev); bool signMultisig(rctSig &rv, const std::vector<unsigned int> &indices, const keyV &k, const multisig_out &msout, const key &secret_key); } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index c67a6bc6c..02deee0c7 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -62,6 +62,7 @@ #include "ringct/rctSigs.h" #include "multisig/multisig.h" #include "wallet/wallet_args.h" +#include "device/device.hpp" #include <stdexcept> #ifdef HAVE_READLINE @@ -113,6 +114,7 @@ namespace const std::array<const char* const, 5> allowed_priority_strings = {{"default", "unimportant", "normal", "elevated", "priority"}}; const auto arg_wallet_file = wallet_args::arg_wallet_file(); const command_line::arg_descriptor<std::string> arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to <arg>"), ""}; + const command_line::arg_descriptor<std::string> arg_generate_from_device = {"generate-from-device", sw::tr("Generate new wallet from device and save it to <arg>"), ""}; const command_line::arg_descriptor<std::string> arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""}; const command_line::arg_descriptor<std::string> arg_generate_from_spend_key = {"generate-from-spend-key", sw::tr("Generate deterministic wallet from spend key"), ""}; const command_line::arg_descriptor<std::string> arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""}; @@ -509,7 +511,11 @@ bool simple_wallet::viewkey(const std::vector<std::string> &args/* = std::vector { if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } // don't log - std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << std::endl; + if (m_wallet->key_on_device()) { + std::cout << "secret: On device. Not available" << std::endl; + } else { + std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << std::endl; + } std::cout << "public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_view_public_key) << std::endl; return true; @@ -524,7 +530,11 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto } if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } // don't log - std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_spend_secret_key) << std::endl; + if (m_wallet->key_on_device()) { + std::cout << "secret: On device. Not available" << std::endl; + } else { + std::cout << "secret: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_spend_secret_key) << std::endl; + } std::cout << "public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_spend_public_key) << std::endl; return true; @@ -536,6 +546,11 @@ bool simple_wallet::print_seed(bool encrypted) std::string seed; bool ready, multisig; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (m_wallet->watch_only()) { fail_msg_writer() << tr("wallet is watch-only and has no seed"); @@ -598,6 +613,11 @@ bool simple_wallet::encrypted_seed(const std::vector<std::string> &args/* = std: bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (m_wallet->multisig()) { fail_msg_writer() << tr("wallet is multisig and has no seed"); @@ -726,6 +746,11 @@ bool simple_wallet::print_fee_info(const std::vector<std::string> &args/* = std: bool simple_wallet::prepare_multisig(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (m_wallet->multisig()) { fail_msg_writer() << tr("This wallet is already multisig"); @@ -759,6 +784,11 @@ bool simple_wallet::prepare_multisig(const std::vector<std::string> &args) bool simple_wallet::make_multisig(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (m_wallet->multisig()) { fail_msg_writer() << tr("This wallet is already multisig"); @@ -833,6 +863,11 @@ bool simple_wallet::make_multisig(const std::vector<std::string> &args) bool simple_wallet::finalize_multisig(const std::vector<std::string> &args) { bool ready; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_wallet->multisig(&ready)) { fail_msg_writer() << tr("This wallet is not multisig"); @@ -877,6 +912,11 @@ bool simple_wallet::finalize_multisig(const std::vector<std::string> &args) bool simple_wallet::export_multisig(const std::vector<std::string> &args) { bool ready; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_wallet->multisig(&ready)) { fail_msg_writer() << tr("This wallet is not multisig"); @@ -924,6 +964,11 @@ bool simple_wallet::import_multisig(const std::vector<std::string> &args) { bool ready; uint32_t threshold, total; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_wallet->multisig(&ready, &threshold, &total)) { fail_msg_writer() << tr("This wallet is not multisig"); @@ -998,6 +1043,11 @@ bool simple_wallet::accept_loaded_tx(const tools::wallet2::multisig_tx_set &txs) bool simple_wallet::sign_multisig(const std::vector<std::string> &args) { bool ready; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if(!m_wallet->multisig(&ready)) { fail_msg_writer() << tr("This is not a multisig wallet"); @@ -1066,6 +1116,11 @@ bool simple_wallet::submit_multisig(const std::vector<std::string> &args) { bool ready; uint32_t threshold; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_wallet->multisig(&ready, &threshold)) { fail_msg_writer() << tr("This is not a multisig wallet"); @@ -1128,6 +1183,11 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args) { bool ready; uint32_t threshold; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_wallet->multisig(&ready, &threshold)) { fail_msg_writer() << tr("This is not a multisig wallet"); @@ -2065,12 +2125,12 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (!handle_command_line(vm)) return false; - if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_spend_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_multisig_keys.empty()) + (!m_generate_from_json.empty()) > 1) + if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_device.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_spend_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_multisig_keys.empty()) + (!m_generate_from_json.empty()) > 1) { - fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-spend-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-multisig-keys=\"wallet_name\" and --generate-from-json=\"jsonfilename\""); + fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-spend-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-multisig-keys=\"wallet_name\", --generate-from-json=\"jsonfilename\" and --generate-from-device=\"wallet_name\""); return false; } - else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty() && m_generate_from_spend_key.empty() && m_generate_from_keys.empty() && m_generate_from_multisig_keys.empty() && m_generate_from_json.empty()) + else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_device.empty() && m_generate_from_view_key.empty() && m_generate_from_spend_key.empty() && m_generate_from_keys.empty() && m_generate_from_multisig_keys.empty() && m_generate_from_json.empty()) { if(!ask_wallet_create_if_needed()) return false; } @@ -2467,6 +2527,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (!m_wallet) return false; } + else if (!m_generate_from_device.empty()) + { + m_wallet_file = m_generate_from_device; + // create wallet + bool r = new_wallet(vm, "Ledger"); + CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); + } else { if (m_generate_new.empty()) { @@ -2601,6 +2668,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ { m_wallet_file = command_line::get_arg(vm, arg_wallet_file); m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet); + m_generate_from_device = command_line::get_arg(vm, arg_generate_from_device); m_generate_from_view_key = command_line::get_arg(vm, arg_generate_from_view_key); m_generate_from_spend_key = command_line::get_arg(vm, arg_generate_from_spend_key); m_generate_from_keys = command_line::get_arg(vm, arg_generate_from_keys); @@ -2620,6 +2688,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ !m_generate_from_keys.empty() || !m_generate_from_multisig_keys.empty() || !m_generate_from_json.empty() || + !m_generate_from_device.empty() || m_restore_deterministic_wallet || m_restore_multisig_wallet; @@ -2820,6 +2889,33 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, return true; } + +//---------------------------------------------------------------------------------------------------- +bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, + const std::string &device_name) { + auto rc = tools::wallet2::make_new(vm, password_prompter); + m_wallet = std::move(rc.first); + if (!m_wallet) + { + return false; + } + if (m_restore_height) + m_wallet->set_refresh_from_block_height(m_restore_height); + + try + { + m_wallet->restore(m_wallet_file, std::move(rc.second).password(), device_name); + message_writer(console_color_white, true) << tr("Generated new on device wallet: ") + << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + } + catch (const std::exception& e) + { + fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); + return false; + } + + return true; +} //---------------------------------------------------------------------------------------------------- bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, const std::string &multisig_keys, const std::string &old_language) @@ -2893,6 +2989,9 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm) prefix = tr("Opened wallet"); message_writer(console_color_white, true) << prefix << ": " << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); + if (m_wallet->get_account().get_device()) { + message_writer(console_color_white, true) << "Wallet is on device: " << m_wallet->get_account().get_device().get_name(); + } // If the wallet file is deprecated, we should ask for mnemonic language again and store // everything in the new format. // NOTE: this is_deprecated() refers to the wallet file format before becoming JSON. It does not refer to the "old english" seed words form of "deprecated" used elsewhere. @@ -3087,6 +3186,7 @@ bool simple_wallet::stop_mining(const std::vector<std::string>& args) fail_msg_writer() << tr("wallet is null"); return true; } + COMMAND_RPC_STOP_MINING::request req; COMMAND_RPC_STOP_MINING::response res; bool r = net_utils::invoke_http_json("/stop_mining", req, res, m_http_client); @@ -4776,6 +4876,11 @@ bool simple_wallet::accept_loaded_tx(const tools::wallet2::signed_tx_set &txs) //---------------------------------------------------------------------------------------------------- bool simple_wallet::sign_transfer(const std::vector<std::string> &args_) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if(m_wallet->multisig()) { fail_msg_writer() << tr("This is a multisig wallet, it can only sign with sign_multisig"); @@ -4834,6 +4939,11 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_) //---------------------------------------------------------------------------------------------------- bool simple_wallet::submit_transfer(const std::vector<std::string> &args_) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!try_connect_to_daemon()) return true; @@ -4866,6 +4976,11 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_) { std::vector<std::string> local_args = args_; + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if(local_args.size() != 1) { fail_msg_writer() << tr("usage: get_tx_key <txid>"); return true; @@ -4901,6 +5016,11 @@ bool simple_wallet::get_tx_key(const std::vector<std::string> &args_) //---------------------------------------------------------------------------------------------------- bool simple_wallet::get_tx_proof(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (args.size() != 2 && args.size() != 3) { fail_msg_writer() << tr("usage: get_tx_proof <txid> <address> [<message>]"); @@ -5107,6 +5227,11 @@ bool simple_wallet::check_tx_proof(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::get_spend_proof(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if(args.size() != 1 && args.size() != 2) { fail_msg_writer() << tr("usage: get_spend_proof <txid> [<message>]"); return true; @@ -5192,6 +5317,11 @@ bool simple_wallet::check_spend_proof(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if(args.size() != 1 && args.size() != 2) { fail_msg_writer() << tr("usage: get_reserve_proof (all|<amount>) [<message>]"); return true; @@ -6293,6 +6423,11 @@ bool simple_wallet::wallet_info(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::sign(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (args.size() != 1) { fail_msg_writer() << tr("usage: sign <filename>"); @@ -6362,6 +6497,11 @@ bool simple_wallet::verify(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::export_key_images(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (args.size() != 1) { fail_msg_writer() << tr("usage: export_key_images <filename>"); @@ -6399,6 +6539,11 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::import_key_images(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (!m_trusted_daemon) { fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon"); @@ -6436,6 +6581,11 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::export_outputs(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (args.size() != 1) { fail_msg_writer() << tr("usage: export_outputs <filename>"); @@ -6481,6 +6631,11 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::import_outputs(const std::vector<std::string> &args) { + if (m_wallet->key_on_device()) + { + fail_msg_writer() << tr("command not supported by HW wallet"); + return true; + } if (args.size() != 1) { fail_msg_writer() << tr("usage: import_outputs <filename>"); @@ -6755,6 +6910,7 @@ int main(int argc, char* argv[]) tools::wallet2::init_options(desc_params); command_line::add_arg(desc_params, arg_wallet_file); command_line::add_arg(desc_params, arg_generate_new_wallet); + command_line::add_arg(desc_params, arg_generate_from_device); command_line::add_arg(desc_params, arg_generate_from_view_key); command_line::add_arg(desc_params, arg_generate_from_spend_key); command_line::add_arg(desc_params, arg_generate_from_keys); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index af2f940c3..4c7818bf1 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -97,6 +97,7 @@ namespace cryptonote const boost::optional<crypto::secret_key>& spendkey, const crypto::secret_key& viewkey); bool new_wallet(const boost::program_options::variables_map& vm, const std::string &multisig_keys, const std::string &old_language); + bool new_wallet(const boost::program_options::variables_map& vm, const std::string& device_name); bool open_wallet(const boost::program_options::variables_map& vm); bool close_wallet(); @@ -303,6 +304,7 @@ namespace cryptonote private: std::string m_wallet_file; std::string m_generate_new; + std::string m_generate_from_device; std::string m_generate_from_view_key; std::string m_generate_from_spend_key; std::string m_generate_from_keys; diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index bb144227e..22bc343fb 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -37,7 +37,7 @@ #include "common/updates.h" #include "version.h" #include "net/http_client.h" - +#include "deviuce/device.hpp" #include <boost/filesystem.hpp> #include <boost/regex.hpp> @@ -151,7 +151,7 @@ bool WalletManagerImpl::walletExists(const std::string &path) bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const { - return tools::wallet2::verify_password(keys_file_name, password, no_spend_key); + return tools::wallet2::verify_password(keys_file_name, password, no_spend_key, hw::get_device("default")); } std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3bad743cf..d8837eccf 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -66,6 +66,7 @@ using namespace epee; #include "memwipe.h" #include "common/base58.h" #include "ringct/rctSigs.h" +#include "device/device.hpp" extern "C" { @@ -538,7 +539,7 @@ uint8_t get_bulletproof_fork() return 8; } -crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx) +crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx, hw::device &hwdev) { crypto::hash8 payment_id8 = null_hash8; std::vector<tx_extra_field> tx_extra_fields; @@ -553,16 +554,16 @@ crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx) MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt"); return crypto::null_hash8; } - decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key); + decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key, hwdev); } } return payment_id8; } -tools::wallet2::tx_construction_data get_construction_data_with_decrypted_short_payment_id(const tools::wallet2::pending_tx &ptx) +tools::wallet2::tx_construction_data get_construction_data_with_decrypted_short_payment_id(const tools::wallet2::pending_tx &ptx, hw::device &hwdev) { tools::wallet2::tx_construction_data construction_data = ptx.construction_data; - crypto::hash8 payment_id = get_short_payment_id(ptx); + crypto::hash8 payment_id = get_short_payment_id(ptx,hwdev); if (payment_id != null_hash8) { // Remove encrypted @@ -623,7 +624,8 @@ wallet2::wallet2(bool testnet, bool restricted): m_light_wallet_blockchain_height(0), m_light_wallet_connected(false), m_light_wallet_balance(0), - m_light_wallet_unlocked_balance(0) + m_light_wallet_unlocked_balance(0), + m_key_on_device(false) { } @@ -817,40 +819,17 @@ void wallet2::set_seed_language(const std::string &language) //---------------------------------------------------------------------------------------------------- cryptonote::account_public_address wallet2::get_subaddress(const cryptonote::subaddress_index& index) const { - const cryptonote::account_keys& keys = m_account.get_keys(); - if (index.is_zero()) - return keys.m_account_address; - - crypto::public_key D = get_subaddress_spend_public_key(index); - - // C = a*D - crypto::public_key C = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(D), rct::sk2rct(keys.m_view_secret_key))); // could have defined secret_key_mult_public_key() under src/crypto - - // result: (C, D) cryptonote::account_public_address address; - address.m_view_public_key = C; - address.m_spend_public_key = D; + hw::device &hwdev = m_account.get_device(); + hwdev.get_subaddress(m_account.get_keys(), index,address); return address; } //---------------------------------------------------------------------------------------------------- crypto::public_key wallet2::get_subaddress_spend_public_key(const cryptonote::subaddress_index& index) const { - const cryptonote::account_keys& keys = m_account.get_keys(); - if (index.is_zero()) - return keys.m_account_address.m_spend_public_key; - - // m = Hs(a || index_major || index_minor) - crypto::secret_key m = cryptonote::get_subaddress_secret_key(keys.m_view_secret_key, index); - - // M = m*G - crypto::public_key M; - crypto::secret_key_to_public_key(m, M); - - // D = B + M - rct::key D_rct; - rct::addKeys(D_rct, rct::pk2rct(keys.m_account_address.m_spend_public_key), rct::pk2rct(M)); // could have defined add_public_key() under src/crypto - crypto::public_key D = rct::rct2pk(D_rct); - + crypto::public_key D ; + hw::device &hwdev = m_account.get_device(); + hwdev.get_subaddress_spend_public_key(m_account.get_keys(), index, D); return D; } //---------------------------------------------------------------------------------------------------- @@ -882,6 +861,7 @@ void wallet2::add_subaddress(uint32_t index_major, const std::string& label) //---------------------------------------------------------------------------------------------------- void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index) { + hw::device &hwdev = m_account.get_device(); if (m_subaddress_labels.size() <= index.major) { // add new accounts @@ -889,7 +869,7 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index) for (index2.major = m_subaddress_labels.size(); index2.major < index.major + m_subaddress_lookahead_major; ++index2.major) { const uint32_t end = (index2.major == index.major ? index.minor : 0) + m_subaddress_lookahead_minor; - const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, 0, end); + const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, 0, end, hwdev); for (index2.minor = 0; index2.minor < end; ++index2.minor) { const crypto::public_key &D = pkeys[index2.minor]; @@ -905,7 +885,7 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index) const uint32_t end = index.minor + m_subaddress_lookahead_minor; const uint32_t begin = m_subaddress_labels[index.major].size(); cryptonote::subaddress_index index2 = {index.major, begin}; - const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, index2.minor, end); + const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, index2.minor, end, hwdev); for (; index2.minor < end; ++index2.minor) { const crypto::public_key &D = pkeys[index2.minor - begin]; @@ -970,7 +950,7 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio LOG_ERROR("wrong type id in transaction out"); return; } - tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, boost::get<txout_to_key>(o.target).key, derivation, additional_derivations, i); + tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, boost::get<txout_to_key>(o.target).key, derivation, additional_derivations, i, m_account.get_device()); if(tx_scan_info.received) { tx_scan_info.money_transfered = o.amount; // may be 0 for ringct outputs @@ -982,20 +962,20 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio tx_scan_info.error = false; } //---------------------------------------------------------------------------------------------------- -static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &derivation, unsigned int i, rct::key & mask) +static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &derivation, unsigned int i, rct::key & mask, hw::device &hwdev) { crypto::secret_key scalar1; - crypto::derivation_to_scalar(derivation, i, scalar1); + crypto::derivation_to_scalar(derivation, i, scalar1, hwdev); try { switch (rv.type) { case rct::RCTTypeSimple: case rct::RCTTypeSimpleBulletproof: - return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask); + return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask, hwdev); case rct::RCTTypeFull: case rct::RCTTypeFullBulletproof: - return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask); + return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask, hwdev); default: LOG_ERROR("Unsupported rct type: " << rv.type); return 0; @@ -1019,7 +999,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, const crypto::publi } else { - bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki); + bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device()); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key, error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); @@ -1028,7 +1008,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, const crypto::publi outs.push_back(i); if (tx_scan_info.money_transfered == 0) { - tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_scan_info.received->derivation, i, tx_scan_info.mask); + tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_scan_info.received->derivation, i, tx_scan_info.mask, m_account.get_device()); } tx_money_got_in_outs[tx_scan_info.received->index] += tx_scan_info.money_transfered; tx_scan_info.amount = tx_scan_info.money_transfered; @@ -1076,8 +1056,9 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote tools::threadpool& tpool = tools::threadpool::getInstance(); tools::threadpool::waiter waiter; const cryptonote::account_keys& keys = m_account.get_keys(); + hw::device &hwdev = m_account.get_device(); crypto::key_derivation derivation; - if (!generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation)) + if (!generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation, hwdev)) { MWARNING("Failed to generate key derivation from tx pubkey, skipping"); static_assert(sizeof(derivation) == sizeof(rct::key), "Mismatched sizes of key_derivation and rct::key"); @@ -1090,7 +1071,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) { additional_derivations.push_back({}); - if (!generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back())) + if (!generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back(),hwdev)) { MWARNING("Failed to generate key derivation from tx pubkey, skipping"); additional_derivations.pop_back(); @@ -1382,7 +1363,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote LOG_PRINT_L2("Found encrypted payment ID: " << payment_id8); if (tx_pub_key != null_pkey) { - if (!decrypt_payment_id(payment_id8, tx_pub_key, m_account.get_keys().m_view_secret_key)) + if (!decrypt_payment_id(payment_id8, tx_pub_key, m_account.get_keys().m_view_secret_key, m_account.get_device())) { LOG_PRINT_L0("Failed to decrypt payment ID: " << payment_id8); } @@ -2385,6 +2366,10 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable } rapidjson::Value value2(rapidjson::kNumberType); + + value2.SetInt(m_key_on_device?1:0); + json.AddMember("key_on_device", value2, json.GetAllocator()); + value2.SetInt(watch_only ? 1 :0); // WTF ? JSON has different true and false types, and not boolean ?? json.AddMember("watch_only", value2, json.GetAllocator()); @@ -2482,16 +2467,6 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable return true; } //---------------------------------------------------------------------------------------------------- -namespace -{ - bool verify_keys(const crypto::secret_key& sec, const crypto::public_key& expected_pub) - { - crypto::public_key pub; - bool r = crypto::secret_key_to_public_key(sec, pub); - return r && expected_pub == pub; - } -} - /*! * \brief Load wallet information from wallet file. * \param keys_file_name Name of wallet file @@ -2539,6 +2514,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_confirm_backlog_threshold = 0; m_confirm_export_overwrite = true; m_auto_low_priority = true; + m_key_on_device = false; } else if(json.IsObject()) { @@ -2555,6 +2531,12 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ const char *field_key_data = json["key_data"].GetString(); account_data = std::string(field_key_data, field_key_data + json["key_data"].GetStringLength()); + if (json.HasMember("key_on_device")) + { + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, key_on_device, int, Int, false, false); + m_key_on_device = field_key_on_device; + } + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, seed_language, std::string, String, false, std::string()); if (field_seed_language_found) { @@ -2654,11 +2636,20 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ return false; } - const cryptonote::account_keys& keys = m_account.get_keys(); r = epee::serialization::load_t_from_binary(m_account, account_data); - r = r && verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); + if (r && m_key_on_device) { + LOG_PRINT_L0("Account on device. Initing device..."); + hw::device &hwdev = hw::get_device("Ledger"); + hwdev.init(); + hwdev.connect(); + m_account.set_device(hwdev); + LOG_PRINT_L0("Device inited..."); + } + const cryptonote::account_keys& keys = m_account.get_keys(); + hw::device &hwdev = m_account.get_device(); + r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); if(!m_watch_only && !m_multisig) - r = r && verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key); + r = r && hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key); THROW_WALLET_EXCEPTION_IF(!r, error::invalid_password); return true; } @@ -2675,7 +2666,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ */ bool wallet2::verify_password(const epee::wipeable_string& password) const { - return verify_password(m_keys_file, password, m_watch_only || m_multisig); + return verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device()); } /*! @@ -2690,7 +2681,7 @@ bool wallet2::verify_password(const epee::wipeable_string& password) const * can be used prior to rewriting wallet keys file, to ensure user has entered the correct password * */ -bool wallet2::verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key) +bool wallet2::verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev) { rapidjson::Document json; wallet2::keys_file_data keys_file_data; @@ -2725,9 +2716,9 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip r = epee::serialization::load_t_from_binary(account_data_check, account_data); const cryptonote::account_keys& keys = account_data_check.get_keys(); - r = r && verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); + r = r && hwdev.verify_keys(keys.m_view_secret_key, keys.m_account_address.m_view_public_key); if(!no_spend_key) - r = r && verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key); + r = r && hwdev.verify_keys(keys.m_spend_secret_key, keys.m_account_address.m_spend_public_key); return r; } @@ -2803,6 +2794,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& m_multisig = true; m_multisig_threshold = threshold; m_multisig_signers = multisig_signers; + m_key_on_device = false; if (!wallet_.empty()) { @@ -2851,6 +2843,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip m_multisig = false; m_multisig_threshold = 0; m_multisig_signers.clear(); + m_key_on_device = false; // -1 month for fluctuations in block time and machine date/time setup. // avg seconds per block @@ -2942,6 +2935,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& m_multisig = false; m_multisig_threshold = 0; m_multisig_signers.clear(); + m_key_on_device = false; if (!wallet_.empty()) { @@ -2988,6 +2982,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& m_multisig = false; m_multisig_threshold = 0; m_multisig_signers.clear(); + m_key_on_device = false; if (!wallet_.empty()) { @@ -3007,6 +3002,46 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& store(); } +/*! +* \brief Creates a wallet from a device +* \param wallet_ Name of wallet file +* \param password Password of wallet file +* \param device_name device string address +*/ +void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name) +{ + clear(); + prepare_file_names(wallet_); + + boost::system::error_code ignored_ec; + if (!wallet_.empty()) { + THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file); + THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file); + } + m_key_on_device = true; + m_account.create_from_device(device_name); + m_account_public_address = m_account.get_keys().m_account_address; + m_watch_only = false; + m_multisig = false; + m_multisig_threshold = 0; + m_multisig_signers.clear(); + + if (!wallet_.empty()) { + bool r = store_keys(m_keys_file, password, false); + THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); + + r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet)); + if(!r) MERROR("String with address text not saved"); + } + cryptonote::block b; + generate_genesis(b); + m_blockchain.push_back(get_block_hash(b)); + add_subaddress_account(tr("Primary account")); + if (!wallet_.empty()) { + store(); + } +} + std::string wallet2::make_multisig(const epee::wipeable_string &password, const std::vector<crypto::secret_key> &view_keys, const std::vector<crypto::public_key> &spend_keys, @@ -3070,6 +3105,8 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password, m_watch_only = false; m_multisig = true; m_multisig_threshold = threshold; + m_key_on_device = false; + if (threshold == spend_keys.size() + 1) { m_multisig_signers = spend_keys; @@ -3478,15 +3515,8 @@ bool wallet2::check_connection(uint32_t *version, uint32_t timeout) //---------------------------------------------------------------------------------------------------- bool wallet2::generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const { - const account_keys &keys = m_account.get_keys(); - const crypto::secret_key &view_key = keys.m_view_secret_key; - const crypto::secret_key &spend_key = keys.m_spend_secret_key; - tools::scrubbed_arr<char, sizeof(view_key) + sizeof(spend_key) + 1> data; - memcpy(data.data(), &view_key, sizeof(view_key)); - memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key)); - data[sizeof(data) - 1] = CHACHA8_KEY_TAIL; - crypto::generate_chacha_key(data.data(), sizeof(data), key); - return true; + hw::device &hwdev = m_account.get_device(); + return hwdev.generate_chacha_key(m_account.get_keys(), key); } //---------------------------------------------------------------------------------------------------- void wallet2::load(const std::string& wallet_, const epee::wipeable_string& password) @@ -4260,7 +4290,7 @@ crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const MWARNING("Encrypted payment id found, but no destinations public key, cannot decrypt"); return crypto::null_hash; } - if (decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key)) + if (decrypt_payment_id(payment_id8, ptx.dests[0].addr.m_view_public_key, ptx.tx_key, m_account.get_device())) { memcpy(payment_id.data, payment_id8.data, 8); } @@ -4369,7 +4399,7 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri // Short payment id is encrypted with tx_key. // Since sign_tx() generates new tx_keys and encrypts the payment id, we need to save the decrypted payment ID // Save tx construction_data to unsigned_tx_set - txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx)); + txs.txes.push_back(get_construction_data_with_decrypted_short_payment_id(tx, m_account.get_device())); } txs.transfers = m_transfers; @@ -4696,7 +4726,7 @@ std::string wallet2::save_multisig_tx(multisig_tx_set txs) for (auto &ptx: txs.m_ptx) { // Get decrypted payment id from pending_tx - ptx.construction_data = get_construction_data_with_decrypted_short_payment_id(ptx); + ptx.construction_data = get_construction_data_with_decrypted_short_payment_id(ptx, m_account.get_device()); } // save as binary @@ -6819,6 +6849,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp unsigned int original_output_index = 0; std::vector<size_t>* unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second; std::vector<size_t>* unused_dust_indices = &unused_dust_indices_per_subaddr[0].second; + hw::device &hwdev = m_account.get_device(); + hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE); while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) { TX &tx = txes.back(); @@ -7004,6 +7036,37 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp LOG_PRINT_L2("Made a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " change"); + if ((!dsts.empty()) || + (dsts.empty() && !(adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) ) + ) { + hwdev.set_signature_mode(hw::device::SIGNATURE_REAL); + if (use_rct) { + transfer_selected_rct(tx.dsts, /* NOMOD std::vector<cryptonote::tx_destination_entry> dsts,*/ + tx.selected_transfers, /* const std::list<size_t> selected_transfers */ + fake_outs_count, /* CONST size_t fake_outputs_count, */ + outs, /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */ + unlock_time, /* CONST uint64_t unlock_time, */ + needed_fee, /* CONST uint64_t fee, */ + extra, /* const std::vector<uint8_t>& extra, */ + test_tx, /* OUT cryptonote::transaction& tx, */ + test_ptx, /* OUT cryptonote::transaction& tx, */ + bulletproof); + } else { + transfer_selected(tx.dsts, + tx.selected_transfers, + fake_outs_count, + outs, + unlock_time, + needed_fee, + extra, + detail::digit_split_strategy, + tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), + test_tx, + test_ptx); + } + hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE); + } + tx.tx = test_tx; tx.ptx = test_ptx; tx.bytes = txBlob.size(); @@ -7172,6 +7235,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton needed_fee = 0; // while we have something to send + hw::device &hwdev = m_account.get_device(); + hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE); while (!unused_dust_indices.empty() || !unused_transfers_indices.empty()) { TX &tx = txes.back(); @@ -7237,6 +7302,18 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton " fee and " << print_money(test_ptx.change_dts.amount) << " change"); } while (needed_fee > test_ptx.fee); + if (!unused_transfers_indices.empty() || !unused_dust_indices.empty()) { + hwdev.set_signature_mode(hw::device::SIGNATURE_REAL); + if (use_rct) { + transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + test_tx, test_ptx, bulletproof); + } else { + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); + } + hwdev.set_signature_mode(hw::device::SIGNATURE_FAKE); + } + LOG_PRINT_L2("Made a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " change"); @@ -7526,7 +7603,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string const std::vector<crypto::public_key> in_additionakl_tx_pub_keys = get_additional_tx_pub_keys_from_extra(in_td.m_tx); keypair in_ephemeral; crypto::key_image in_img; - THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey->key, in_tx_pub_key, in_additionakl_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img), + THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey->key, in_tx_pub_key, in_additionakl_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img, m_account.get_device()), error::wallet_internal_error, "failed to generate key image"); THROW_WALLET_EXCEPTION_IF(in_key->k_image != in_img, error::wallet_internal_error, "key image mismatch"); @@ -7701,13 +7778,13 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes void wallet2::check_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, const cryptonote::account_public_address &address, uint64_t &received, bool &in_pool, uint64_t &confirmations) { crypto::key_derivation derivation; - THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation), error::wallet_internal_error, + THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, tx_key, derivation, m_account.get_device()), error::wallet_internal_error, "Failed to generate key derivation from supplied parameters"); std::vector<crypto::key_derivation> additional_derivations; additional_derivations.resize(additional_tx_keys.size()); for (size_t i = 0; i < additional_tx_keys.size(); ++i) - THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, additional_tx_keys[i], additional_derivations[i]), error::wallet_internal_error, + THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(address.m_view_public_key, additional_tx_keys[i], additional_derivations[i], m_account.get_device()), error::wallet_internal_error, "Failed to generate key derivation from supplied parameters"); check_tx_key_helper(txid, derivation, additional_derivations, address, received, in_pool, confirmations); @@ -7741,6 +7818,7 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de "The size of additional derivations is wrong"); received = 0; + hw::device &hwdev = m_account.get_device(); for (size_t n = 0; n < tx.vout.size(); ++n) { const cryptonote::txout_to_key* const out_key = boost::get<cryptonote::txout_to_key>(std::addressof(tx.vout[n].target)); @@ -7748,13 +7826,13 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de continue; crypto::public_key derived_out_key; - bool r = derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key); + bool r = derive_public_key(derivation, n, address.m_spend_public_key, derived_out_key, hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key"); bool found = out_key->key == derived_out_key; crypto::key_derivation found_derivation = derivation; if (!found && !additional_derivations.empty()) { - r = derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key); + r = derive_public_key(additional_derivations[n], n, address.m_spend_public_key, derived_out_key,hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to derive public key"); found = out_key->key == derived_out_key; found_derivation = additional_derivations[n]; @@ -7770,9 +7848,9 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de else { crypto::secret_key scalar1; - crypto::derivation_to_scalar(found_derivation, n, scalar1); + crypto::derivation_to_scalar(found_derivation, n, scalar1, hwdev); rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n]; - rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1)); + rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1), hwdev); const rct::key C = tx.rct_signatures.outPk[n].mask; rct::key Ctmp; rct::addKeys2(Ctmp, ecdh_info.mask, ecdh_info.amount, rct::H); @@ -8126,7 +8204,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t, // derive ephemeral secret key crypto::key_image ki; cryptonote::keypair ephemeral; - const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki); + const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki, m_account.get_device()); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); THROW_WALLET_EXCEPTION_IF(ephemeral.pub != td.get_public_key(), error::wallet_internal_error, "Derived public key doesn't agree with the stored one"); @@ -8500,20 +8578,21 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle // more than one, loop and search const cryptonote::account_keys& keys = m_account.get_keys(); size_t pk_index = 0; + hw::device &hwdev = m_account.get_device(); const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx); std::vector<crypto::key_derivation> additional_derivations; for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) { additional_derivations.push_back({}); - bool r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()); + bool r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back(), hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); } while (find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index++)) { const crypto::public_key tx_pub_key = pub_key_field.pub_key; crypto::key_derivation derivation; - bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation); + bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation, hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); for (size_t i = 0; i < td.m_tx.vout.size(); ++i) @@ -8584,7 +8663,7 @@ std::vector<std::pair<crypto::key_image, crypto::signature>> wallet2::export_key // generate ephemeral secret key crypto::key_image ki; cryptonote::keypair in_ephemeral; - bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki); + bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki, m_account.get_device()); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); THROW_WALLET_EXCEPTION_IF(td.m_key_image_known && !td.m_key_image_partial && ki != td.m_key_image, @@ -8784,6 +8863,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag // process each outgoing tx auto spent_txid = spent_txids.begin(); + hw::device &hwdev = m_account.get_device(); for (const COMMAND_RPC_GET_TRANSACTIONS::entry& e : gettxs_res.txs) { THROW_WALLET_EXCEPTION_IF(e.in_pool, error::wallet_internal_error, "spent tx isn't supposed to be in txpool"); @@ -8801,14 +8881,14 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag const cryptonote::account_keys& keys = m_account.get_keys(); const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(spent_tx); crypto::key_derivation derivation; - bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation); + bool r = generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation, hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(spent_tx); std::vector<crypto::key_derivation> additional_derivations; for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) { additional_derivations.push_back({}); - r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()); + r = generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back(), hwdev); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key derivation"); } size_t output_index = 0; @@ -8822,7 +8902,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag if (tx_scan_info.money_transfered == 0) { rct::key mask; - tx_scan_info.money_transfered = tools::decodeRct(spent_tx.rct_signatures, tx_scan_info.received->derivation, output_index, mask); + tx_scan_info.money_transfered = tools::decodeRct(spent_tx.rct_signatures, tx_scan_info.received->derivation, output_index, mask, hwdev); } tx_money_got_in_outs += tx_scan_info.money_transfered; } @@ -8982,7 +9062,7 @@ size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_detail const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx); const crypto::public_key& out_key = boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key; - bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image); + bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device()); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); expand_subaddresses(td.m_subaddr_index); td.m_key_image_known = true; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 28289842b..127e70a26 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -162,7 +162,7 @@ namespace tools //! Just parses variables. static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter); - static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key); + static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev); wallet2(bool testnet = false, bool restricted = false); @@ -487,6 +487,14 @@ namespace tools const cryptonote::account_public_address &account_public_address, const crypto::secret_key& viewkey = crypto::secret_key()); /*! + * \brief Restore a wallet hold by an HW. + * \param wallet_ Name of wallet file + * \param password Password of wallet file + * \param device_name name of HW to use + */ + void restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name); + + /*! * \brief Creates a multisig wallet * \return empty if done, non empty if we need to send another string * to other participants @@ -635,6 +643,7 @@ namespace tools bool multisig(bool *ready = NULL, uint32_t *threshold = NULL, uint32_t *total = NULL) const; bool has_multisig_partial_key_images() const; bool get_multisig_seed(std::string& seed, const epee::wipeable_string &passphrase = std::string(), bool raw = true) const; + bool key_on_device() const { return m_key_on_device; } // locked & unlocked balance of given or current subaddress account uint64_t balance(uint32_t subaddr_index_major) const; @@ -1105,6 +1114,7 @@ namespace tools boost::mutex m_daemon_rpc_mutex; i_wallet2_callback* m_callback; + bool m_key_on_device; bool m_testnet; bool m_restricted; std::string seed_language; /*!< Language of the mnemonics (seed). */ |