30static const char *
card_fault(Pn532NfcTransport &transport)
34 uint8_t n =
static_cast<uint8_t
>(
sizeof(r));
35 if (!transport.sendAPDU(SELECT,
static_cast<uint8_t
>(
sizeof(SELECT)), r, n)) {
40 ESP_LOGW(
TAG,
"card refused: state %d",
static_cast<int>(st));
52const char *
pin_fail_text(Pn532NfcTransport &transport,
const char *wrong)
56 uint8_t n =
static_cast<uint8_t
>(
sizeof(r));
57 if (!transport.sendAPDU(SELECT,
static_cast<uint8_t
>(
sizeof(SELECT)), r, n)) {
58 ESP_LOGW(
TAG,
"verifyPin failed and the card is gone - not a PIN error");
59 return "Card moved - tap it again";
79bool card_connect(CryptnoxWallet &wallet, Pn532NfcTransport &transport,
80 CW_SecureSession &session,
bool setup)
91 transport.resetReader();
94 const int64_t card_wait_us = 60LL * 1000000LL;
95 const int64_t start_us = esp_timer_get_time();
101 if ((esp_timer_get_time() - start_us) > card_wait_us) {
104 if (transport.inListPassiveTarget()) {
109 vTaskDelay(pdMS_TO_TICKS(200));
114 transport.resetReader();
117 if (wallet.establishSecureChannel(session)) {
122 transport.resetReader();
128 vTaskDelay(pdMS_TO_TICKS(200));
160bool card_sign(CryptnoxWallet &wallet, CW_SecureSession &session,
161 const uint8_t *hash, uint8_t hash_len,
162 const uint8_t *path, uint8_t path_len,
163 const char *pin,
size_t pin_chars,
164 uint8_t rs_out[64],
char *err_out,
size_t err_max)
166 CW_SignRequest req(session,
168 CW_SIGN_SIG_ECDSA_LOW_S,
171 req.hashLength = hash_len;
172 req.derivePath = path;
173 req.derivePathLength = path_len;
177 const size_t copy_len = (pin_chars < CW_MAX_PIN_LENGTH) ? pin_chars
179 (void)CW_Utils::safe_memcpy(req.pin,
sizeof(req.pin),
180 reinterpret_cast<const uint8_t *
>(pin),
183 CW_SignResult result = wallet.sign(req);
184 WipeGuard g_sig(result.signature,
sizeof(result.signature));
185 wallet.disconnect(session);
189 CW_Utils::secure_wipe(req.pin,
sizeof(req.pin));
191 if (result.errorCode != CW_OK) {
194 if (result.errorCode == CW_SIGN_PIN_INCORRECT) {
195 (void)snprintf(err_out, err_max,
"Wrong PIN");
197 (void)snprintf(err_out, err_max,
"Sign error 0x%02X",
198 static_cast<unsigned int>(result.errorCode));
203 (void)CW_Utils::safe_memcpy(rs_out, 32U,
204 result.signature + CW_SIG_R_OFFSET, 32U);
205 (void)CW_Utils::safe_memcpy(rs_out + 32U, 32U,
206 result.signature + CW_SIG_S_OFFSET, 32U);
234 Pn532NfcTransport &transport,
235 CW_CryptoProvider &crypto,
236 const char *pin,
size_t pin_chars,
237 char *eth_out,
size_t eth_n,
238 char *tron_out,
size_t tron_n,
239 char *err,
size_t err_n)
244 CW_SecureSession session;
248 (void)snprintf(err, err_n,
"%s",
255 if (!wallet.verifyPin(session,
reinterpret_cast<const uint8_t *
>(pin),
256 static_cast<uint8_t
>(pin_chars))) {
257 (void)snprintf(err, err_n,
"%s",
pin_fail_text(transport,
"Wrong card PIN"));
258 wallet.disconnect(session);
273 CW_Utils::secure_wipe(h,
sizeof(h));
275 ESP_LOGW(
TAG,
"card would not export its Ethereum key");
278 uint8_t addr21[CW_TRON_ADDRESS_BYTES];
279 if (wallet.getPublicKey(session, CW_TRON_DERIVE_PATH,
280 CW_TRON_PATH_LENGTH, pubkey) &&
281 CW_Tron::addressBytesFromPublicKey(pubkey, addr21)) {
282 (void)CW_Tron::encodeAddress(addr21, crypto, tron_out, tron_n);
284 ESP_LOGW(
TAG,
"card would not export its Tron key");
287 wallet.disconnect(session);
289 if ((eth_out[0] ==
'\0') && (tron_out[0] ==
'\0')) {
290 (void)snprintf(err, err_n,
"Card gave no usable address");
293 ESP_LOGI(
TAG,
"card addresses: eth=%s tron=%s", eth_out, tron_out);
bool card_sign(CryptnoxWallet &wallet, CW_SecureSession &session, const uint8_t *hash, uint8_t hash_len, const uint8_t *path, uint8_t path_len, const char *pin, size_t pin_chars, uint8_t rs_out[64], char *err_out, size_t err_max)
Have the card sign hash, then close the session.
const char * s_card_fault
bool card_read_payouts(CryptnoxWallet &wallet, Pn532NfcTransport &transport, CW_CryptoProvider &crypto, const char *pin, size_t pin_chars, char *eth_out, size_t eth_n, char *tron_out, size_t tron_n, char *err, size_t err_n)
Read the card's payout addresses and put them through the panel.
bool card_connect(CryptnoxWallet &wallet, Pn532NfcTransport &transport, CW_SecureSession &session, bool setup)
Wait for a card and open a secure channel, cancellable from the UI.
static const char * card_fault(Pn532NfcTransport &transport)
Whether the card now on the reader is set up at all.
const char * pin_fail_text(Pn532NfcTransport &transport, const char *wrong)
Why verifyPin said no: the PIN, or the card leaving the field.
card_state_t
What a tapped card is missing.
static const char * card_state_text(card_state_t s)
The line to put in front of the operator, or NULL if there is none.
#define CARD_SELECT_APDU
SELECT for the Cryptnox applet: CLA INS P1 P2 Lc || AID.
static card_state_t card_state(const uint8_t *r, size_t n)
Judge a card from its SELECT response.
bool eth_addr_format(const uint8_t addr[ETH_ADDR_LEN], char *out, size_t n)
Render a 20-byte address as an EIP-55 mixed-case "0x..." string.
static const char *const TAG
void keccak256(const uint8_t *input, size_t length, uint8_t digest[32])
Compute the Keccak-256 digest of a buffer.
std::atomic< bool > s_user_cancelled
const uint8_t ETH_DERIVE_PATH[20]
Private to the application files (main, boot, card_io, pay, pay_evm, pay_tron): the state they share ...
Scrubs a buffer with CW_Utils::secure_wipe when it leaves scope.
void ui_show_tx_status(ui_tx_state_t state, const char *info)
Switch to the transaction-status screen.
void ui_show_card_wait(const char *note)
"Hold your card to the reader" while the address is read.
static void wdt_feed(void)
Feed the task watchdog if, and only if, the calling task is subscribed.