[keycard] Account generation & tx signing on simulated card

This commit is contained in:
Roman Volosovskyi 2020-05-07 13:57:10 +03:00
parent 6cf242a036
commit ee5d53eba9
No known key found for this signature in database
GPG Key ID: 0238A4B5ECEE70DE
15 changed files with 152 additions and 58 deletions

View File

@ -276,6 +276,16 @@ RCT_EXPORT_METHOD(multiAccountImportPrivateKey:(NSString *)json
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// hashTransaction
RCT_EXPORT_METHOD(hashTransaction:(NSString *)txArgsJSON
callback:(RCTResponseSenderBlock)callback) {
#if DEBUG
NSLog(@"HashTransaction() method called");
#endif
NSString *result = StatusgoHashTransaction(txArgsJSON);
callback(@[result]);
}
//////////////////////////////////////////////////////////////////// multiAccountImportMnemonic
RCT_EXPORT_METHOD(multiAccountImportMnemonic:(NSString *)json
callback:(RCTResponseSenderBlock)callback) {

View File

@ -412,3 +412,6 @@
(defn login [args]
(keycard/login card args))
(defn send-transaction-with-signature [args]
(keycard/send-transaction-with-signature card args))

View File

@ -1,6 +1,8 @@
(ns status-im.hardwallet.core
(:require [status-im.hardwallet.change-pin :as change-pin]
[status-im.hardwallet.common :as common]
status-im.hardwallet.delete-key
status-im.hardwallet.export-key
[status-im.hardwallet.login :as login]
[status-im.hardwallet.mnemonic :as mnemonic]
[status-im.hardwallet.onboarding :as onboarding]

View File

@ -100,8 +100,7 @@
(re-frame/reg-fx
:send-transaction-with-signature
(fn [{:keys [transaction signature on-completed]}]
(status/send-transaction-with-signature transaction signature on-completed)))
card/send-transaction-with-signature)
(re-frame/reg-fx
:hardwallet/persist-pairings

View File

@ -29,4 +29,5 @@
(get-keys [this args])
(sign [this args])
(save-multiaccount-and-login [this args])
(login [this args]))
(login [this args])
(send-transaction-with-signature [this args]))

View File

@ -29,4 +29,5 @@
(sign [this args])
(sign-typed-data [this args])
(save-multiaccount-and-login [this args])
(login [this args]))
(login [this args])
(send-transaction-with-signature [this args]))

View File

@ -211,6 +211,10 @@
(defn login [args]
(status/login-with-keycard args))
(defn send-transaction-with-signature
[{:keys [transaction signature on-completed]}]
(status/send-transaction-with-signature transaction signature on-completed))
(defrecord RealKeycard []
keycard/Keycard
(keycard/check-nfc-support [this args]

View File

@ -1,11 +1,15 @@
(ns status-im.hardwallet.simulated-keycard
(:require [re-frame.db :as re-frame.db]
(:require [re-frame.core :as re-frame]
[re-frame.db :as re-frame.db]
[status-im.constants :as constants]
[status-im.ethereum.core :as ethereum]
[status-im.hardwallet.keycard :as keycard]
[status-im.native-module.core :as status]
[status-im.utils.types :as types]
[status-im.utils.utils :as utils]))
[status-im.utils.utils :as utils]
[status-im.i18n :as i18n]
[clojure.string :as string]
[taoensso.timbre :as log]))
(def initial-state
{:card-connected? false
@ -23,7 +27,7 @@
{:free-pairing-slots 5
:app-version "2.2"
:secure-channel-pub-key "04c3071768912a515c00aeab7ceb8a5bfda91d036f4a4e60b7944cee3ca7fb67b6d118e8df1e2480b87fd636c6615253245bbbc93a6a407f155f2c58f76c96ef0e",
:instance-uid "9c3f27ee5dfc39c2b14f4d6d3379cd68"
:instance-uid "1b360b10a9a68b7d494e8f059059f118"
:paired? true
:has-master-key? true
:initialized? true
@ -79,20 +83,22 @@
(defn install-applet [_])
(defn install-cash-applet [_])
(def kk1-password "6d9ZHjn94kFP4bPm")
(def kk1-password "000000")
(defn init-card [{:keys [pin on-success]}]
(swap! state assoc :application-info
{:free-pairing-slots 5
:app-version "2.2"
:secure-channel-pub-key "04c3071768912a515c00aeab7ceb8a5bfda91d036f4a4e60b7944cee3ca7fb67b6d118e8df1e2480b87fd636c6615253245bbbc93a6a407f155f2c58f76c96ef0e", :key-uid "", :instance-uid "9c3f27ee5dfc39c2b14f4d6d3379cd68"
:secure-channel-pub-key "04c3071768912a515c00aeab7ceb8a5bfda91d036f4a4e60b7944cee3ca7fb67b6d118e8df1e2480b87fd636c6615253245bbbc93a6a407f155f2c58f76c96ef0e",
:key-uid "",
:instance-uid "1b360b10a9a68b7d494e8f059059f118"
:paired? false
:has-master-key? false
:initialized? true})
(swap! state assoc :pin pin)
(later
#(on-success {:password kk1-password
:puk "320612366918"
:puk "000000000000"
:pin pin})))
(defn install-applet-and-init-card [_])
@ -111,7 +117,21 @@
multiaccount
whisper (get derived constants/path-whisper-keyword)
wallet (get derived constants/path-default-wallet-keyword)
password (ethereum/sha3 pin)]
wallet-root (get derived constants/path-wallet-root-keyword)
password (ethereum/sha3 pin)
response {:key-uid key-uid
:encryption-public-key (ethereum/sha3 pin)
:address address
:whisper-public-key (:public-key whisper)
:instance-uid "1b360b10a9a68b7d494e8f059059f118"
:wallet-root-public-key (:public-key wallet-root)
:wallet-root-address (:address wallet-root)
:whisper-address (:address whisper)
:public-key public-key
:whisper-private-key "34bc7d0c258c4f2ac1dac4fd6c55c9478bac1f4a9d8b9f1152c8551ab7187b43"
:wallet-address (:address wallet)
:wallet-public-key (:public-key wallet)}]
(log/debug "[simulated kk] generate-and-load-key response" response)
(status/multiaccount-store-derived
id
[constants/path-wallet-root
@ -119,19 +139,7 @@
constants/path-whisper
constants/path-default-wallet]
password
#(on-success
{:key-uid key-uid
:encryption-public-key (ethereum/sha3 pin)
:address address
:whisper-public-key (:public-key whisper)
:instance-uid "1b360b10a9a68b7d494e8f059059f118"
:wallet-root-public-key "0463187f5c917eef481e04af704c14e57a9e8596516f0ec10a4556561ad49b5aa249976ec545d37d04f4d4c7d1c0d9a2141dc61e458b09631d25fa7858c6323ea3"
:wallet-root-address "e034a084d2282e265f83e3fdfa48b42c3d53312a"
:whisper-address (:address whisper)
:public-key public-key
:whisper-private-key "34bc7d0c258c4f2ac1dac4fd6c55c9478bac1f4a9d8b9f1152c8551ab7187b43"
:wallet-address (:address wallet)
:wallet-public-key (:public-key wallet)})))))
#(on-success response)))))
(defn unblock-pin [_])
@ -140,22 +148,70 @@
(= pin (get @state :pin)))
(later #(on-success 3))))
(defn change-pin [_])
(defn unpair [_])
(defn delete [_])
(defn remove-key [_])
(defn remove-key-with-unpair [_])
(defn export-key [_])
(defn change-pin [args]
(log/warn "change-pin not implemented" args))
(defn unpair [args]
(log/warn "unpair not implemented" args))
(defn delete [args]
(log/warn "delete not implemented" args))
(defn remove-key [args]
(log/warn "remove-key not implemented" args))
(defn remove-key-with-unpair [args]
(log/warn "remove-key-with-unpair not implemented" args))
(defn normalize-path [path]
(if (string/starts-with? path "m/")
(str constants/path-wallet-root
"/" (last (string/split path "/")))
path))
(defn export-key [{:keys [pin on-success on-failure]}]
(let [wallet-root-address (get-in
@re-frame.db/app-db
[:multiaccount :wallet-root-address])
accounts (get @re-frame.db/app-db :multiaccount/accounts)
hashed-password (ethereum/sha3 pin)
path-num (inc (get-in @re-frame.db/app-db [:multiaccount :latest-derived-path]))
path (str "m/" path-num)]
(status/multiaccount-load-account
wallet-root-address
hashed-password
(fn [value]
(let [{:keys [id error]} (types/json->clj value)]
(if error
(re-frame/dispatch [::new-account-error :password-error error])
(status/multiaccount-derive-addresses
id
[path]
(fn [derived]
(let [derived-address (get-in (types/json->clj derived) [(keyword path) :address])]
(if (some #(= derived-address (get % :address)) accounts)
(re-frame/dispatch [::new-account-error :account-error (i18n/label :t/account-exists-title)])
(status/multiaccount-store-derived
id
[path]
hashed-password
(fn [result]
(let [{:keys [error] :as result} (types/json->clj result)
{:keys [publicKey]} (get result (keyword path))]
(if error
(on-failure error)
(on-success publicKey)))))))))))))))
(defn unpair-and-delete [_])
(defn get-keys [{:keys [on-success pin]}]
(swap! state assoc :pin pin)
;;TODO(rasom): verify password before callback
(later
#(on-success
{:key-uid (get-in @state [:application-info :key-uid])
:encryption-public-key (ethereum/sha3 pin)})))
(defn sign [_])
(defn sign-typed-data [_])
(defn sign [{:keys [on-success]}]
(on-success "123"))
(defn sign-typed-data [args]
(log/warn "sign-typed-data not implemented" args))
(defn save-multiaccount-and-login
[{:keys [multiaccount-data password settings node-config accounts-data]}]
@ -169,6 +225,10 @@
(defn login [{:keys [multiaccount-data password]}]
(status/login multiaccount-data password))
(defn send-transaction-with-signature
[{:keys [transaction on-completed]}]
(status/send-transaction transaction (ethereum/sha3 (:pin @state)) on-completed))
(defrecord SimulatedKeycard []
keycard/Keycard
(keycard/check-nfc-support [this args]
@ -224,4 +284,6 @@
(keycard/save-multiaccount-and-login [this args]
(save-multiaccount-and-login args))
(keycard/login [this args]
(login args)))
(login args))
(keycard/send-transaction-with-signature [this args]
(send-transaction-with-signature args)))

View File

@ -5,7 +5,8 @@
[status-im.hardwallet.common :as common]
[status-im.constants :as constants]
[status-im.ethereum.eip55 :as eip55]
[status-im.ui.components.bottom-sheet.core :as bottom-sheet]))
[status-im.ui.components.bottom-sheet.core :as bottom-sheet]
[status-im.utils.hex :as utils.hex]))
(fx/defn show-pin-sheet
{:events [:hardwallet/new-account-pin-sheet]}
@ -41,10 +42,14 @@
(assoc-in
db [:hardwallet :on-export-success]
#(vector :wallet.accounts/account-stored
(let [public-key (utils.hex/normalize-hex %)]
{;; Strip leading 04 prefix denoting uncompressed key format
:address (eip55/address->checksum (str "0x" (ethereum/public-key->address (subs % 2))))
:public-key (str "0x" %)
:path path}))
:address (eip55/address->checksum
(str "0x"
(ethereum/public-key->address
(subs public-key 2))))
:public-key (str "0x" public-key)
:path path})))
:hardwallet/export-key {:pin pin :pairing pairing :path path}}))

View File

@ -13,6 +13,7 @@
[status-im.ui.components.bottom-sheet.core :as bottom-sheet]
[status-im.ui.components.colors :as colors]
[status-im.navigation :as navigation]
[status-im.utils.config :as config]
[status-im.utils.fx :as fx]
[status-im.utils.platform :as platform]
[status-im.utils.security :as security]
@ -39,7 +40,8 @@
(defn inc-step [step]
(let [inverted (map-invert step-kw-to-num)]
(if (and (= step :choose-key)
(or (not platform/android?)
(or (not (or platform/android?
config/keycard-test-menu-enabled?))
(not (nfc/nfc-supported?))))
:create-code
(inverted (inc (step-kw-to-num step))))))
@ -320,7 +322,9 @@
(status/multiaccount-generate-and-derive-addresses
5
12
[constants/path-whisper constants/path-default-wallet]
[constants/path-whisper
constants/path-wallet-root
constants/path-default-wallet]
#(re-frame/dispatch [:intro-wizard/on-keys-generated
(mapv normalize-multiaccount-data-keys
(types/json->clj %))]))))

View File

@ -16,7 +16,8 @@
[status-im.utils.platform :as platform]
[status-im.utils.utils :as utils]
[status-im.ui.components.bottom-sheet.core :as bottom-sheet]
[taoensso.timbre :as log]))
[taoensso.timbre :as log]
[status-im.utils.config :as config]))
(defn existing-account?
[multiaccounts key-uid]
@ -250,7 +251,8 @@
assoc :step :select-key-storage
:forward-action :multiaccounts.recover/select-storage-next-pressed
:selected-storage-type :default)}
(if (and platform/android?
(if (and (or platform/android?
config/keycard-test-menu-enabled?)
(nfc/nfc-supported?))
(navigation/navigate-to-cofx :recover-multiaccount-select-storage nil)
(select-storage-next-pressed))))

View File

@ -176,8 +176,13 @@
(i18n/label type)]]
[react/touchable-highlight
{:accessibility-label (keyword (str "select-storage-" type))
:on-press #(re-frame/dispatch [:intro-wizard/on-key-storage-selected (if (and config/hardwallet-enabled?
platform/android?) type :default)])}
:on-press #(re-frame/dispatch
[:intro-wizard/on-key-storage-selected
(if (and config/hardwallet-enabled?
(or platform/android?
config/keycard-test-menu-enabled?))
type
:default)])}
[react/view (assoc (styles/list-item selected?)
:align-items :flex-start
:padding-top 16

View File

@ -50,7 +50,8 @@
:icon :main-icons/text
:on-press #(re-frame/dispatch [::multiaccounts.recover/enter-phrase-pressed])}]
(when (and config/hardwallet-enabled?
platform/android?
(or platform/android?
config/keycard-test-menu-enabled?)
(nfc/nfc-supported?))
[list-item/list-item
{:theme :action

View File

@ -138,7 +138,8 @@
:accessibility-label :sync-settings-button
:accessories [:chevron]
:on-press #(re-frame/dispatch [:navigate-to :sync-settings])}
(when (and platform/android?
(when (and (or platform/android?
config/keycard-test-menu-enabled?)
config/hardwallet-enabled?
keycard-account?)
{:icon :main-icons/keycard

View File

@ -136,14 +136,8 @@
path-num (inc (get-in db [:multiaccount :latest-derived-path]))
accounts (:multiaccount/accounts db)]
{:db (assoc-in db [:add-account :step] :generating)
::generate-account {:derivation-info (if wallet-root-address
;; Use the walllet-root-address for stored on disk keys
;; This needs to be the RELATIVE path to the key used to derive
{:path (str "m/" path-num)
::generate-account {:derivation-info {:path (str "m/" path-num)
:address wallet-root-address}
;; Fallback on the master account for keycards, use the absolute path
{:path (str constants/path-wallet-root "/" path-num)
:address (get-in db [:multiaccount :address])})
:hashed-password hashed-password
:accounts accounts}}))