static void test_privkey_valid_enc(const char *base58_str, cstring *payload, bool compress, bool is_testnet) { assert(payload != NULL); cstring *pl = cstr_new_sz(payload->len + 1); cstr_append_buf(pl, payload->str, payload->len); if (compress) cstr_append_c(pl, 1); cstring *b58 = base58_encode_check( is_testnet ? PRIVKEY_ADDRESS_TEST : PRIVKEY_ADDRESS, true, pl->str, pl->len); assert(b58 != NULL); if (strcmp(b58->str, base58_str)) { fprintf(stderr, "base58: have %s, expected %s\n", b58->str, base58_str); assert(!strcmp(b58->str, base58_str)); } cstr_free(b58, true); cstr_free(pl, true); cstr_free(payload, true); }
void fsm_msgSignMessage(SignMessage *msg) { RESP_INIT(MessageSignature); layoutSignMessage(msg->message.bytes, msg->message.size); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled"); layoutHome(); return; } if (!protectPin(true)) { layoutHome(); return; } const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; layoutProgressSwipe("Signing", 0); if (cryptoMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->signature.bytes) == 0) { resp->has_address = true; uint8_t addr_raw[21]; ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_MessageSignature, resp); } else { fsm_sendFailure(FailureType_Failure_Other, "Error signing message"); } layoutHome(); }
void fsm_msgGetAddress(GetAddress *msg) { RESP_INIT(Address); if (!protectPin(true)) { layoutHome(); return; } const CoinType *coin = fsm_getCoin(msg->coin_name); if (!coin) return; const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; if (msg->has_multisig) { layoutProgressSwipe("Preparing", 0); if (cryptoMultisigPubkeyIndex(&(msg->multisig), node->public_key) < 0) { fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); layoutHome(); return; } uint8_t buf[32]; if (compile_script_multisig_hash(&(msg->multisig), buf) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig script"); layoutHome(); return; } ripemd160(buf, 32, buf + 1); buf[0] = coin->address_type_p2sh; // multisig cointype base58_encode_check(buf, 21, resp->address, sizeof(resp->address)); } else { ecdsa_get_address(node->public_key, coin->address_type, resp->address, sizeof(resp->address)); } if (msg->has_show_display && msg->show_display) { char desc[16]; if (msg->has_multisig) { strlcpy(desc, "Msig __ of __:", sizeof(desc)); const uint32_t m = msg->multisig.m; const uint32_t n = msg->multisig.pubkeys_count; desc[5] = (m < 10) ? ' ': ('0' + (m / 10)); desc[6] = '0' + (m % 10); desc[11] = (n < 10) ? ' ': ('0' + (n / 10)); desc[12] = '0' + (n % 10); } else { strlcpy(desc, "Address:", sizeof(desc)); } layoutAddress(resp->address, desc); if (!protectButton(ButtonRequestType_ButtonRequest_Address, true)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); layoutHome(); return; } } msg_write(MessageType_MessageType_Address, resp); layoutHome(); }
void fsm_msgDecryptMessage(DecryptMessage *msg) { if (!msg->has_nonce) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided"); return; } if (!msg->has_message) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided"); return; } if (!msg->has_hmac) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No message hmac provided"); return; } curve_point nonce_pubkey; if (msg->nonce.size != 33 || ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 0) { fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid nonce provided"); return; } if (!protectPin(true)) { layoutHome(); return; } const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if (!node) return; layoutProgressSwipe("Decrypting", 0); RESP_INIT(DecryptedMessage); bool display_only = false; bool signing = false; uint8_t address_raw[21]; if (cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error decrypting message"); layoutHome(); return; } if (signing) { base58_encode_check(address_raw, 21, resp->address, sizeof(resp->address)); } layoutDecryptMessage(resp->message.bytes, resp->message.size, signing ? resp->address : 0); protectButton(ButtonRequestType_ButtonRequest_Other, true); if (display_only) { resp->has_address = false; resp->has_message = false; memset(resp->address, 0, sizeof(resp->address)); memset(&(resp->message), 0, sizeof(resp->message)); } else { resp->has_address = signing; resp->has_message = true; } msg_write(MessageType_MessageType_DecryptedMessage, resp); layoutHome(); }
int script_output_to_address(const uint8_t *script, int scriptlen, char *addr, int addrsize) { uint8_t raw[35]; // P2PKH if (scriptlen == 25 && script[0] == 0x76 && script[1] == 0xA9 && script[2] == 0x14 && script[23] == 0x88 && script[24] == 0xAC) { raw[0] = 0x00; memcpy(raw + 1, script + 3, 20); return base58_encode_check(raw, 1 + 20, addr, addrsize); } // P2SH if (scriptlen == 23 && script[0] == 0xA9 && script[1] == 0x14 && script[22] == 0x87) { raw[0] = 0x05; memcpy(raw + 1, script + 2, 20); return base58_encode_check(raw, 1 + 20, addr, addrsize); } // P2WPKH if (scriptlen == 22 && script[0] == 0x00 && script[1] == 0x14) { raw[0] = 0x06; raw[1] = 0x00; raw[2] = 0x00; memcpy(raw + 3, script + 2, 20); return base58_encode_check(raw, 3 + 20, addr, addrsize); } // P2WSH if (scriptlen == 34 && script[0] == 0x00 && script[1] == 0x20) { raw[0] = 0x0A; raw[1] = 0x00; raw[2] = 0x00; memcpy(raw + 3, script + 2, 32); return base58_encode_check(raw, 3 + 32, addr, addrsize); } return 0; }
void fsm_msgSignMessage(SignMessage *msg) { RESP_INIT(MessageSignature); if (!storage_is_initialized()) { fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); return; } if(!confirm(ButtonRequestType_ButtonRequest_SignMessage, "Sign Message", (char *)msg->message.bytes)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled"); go_home(); return; } if(!pin_protect_cached()) { go_home(); return; } const CoinType *coin = fsm_getCoin(msg->coin_name); if(!coin) { return; } const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if(!node) { return; } if(cryptoMessageSign(coin, msg->message.bytes, msg->message.size, node->private_key, resp->signature.bytes) == 0) { resp->has_address = true; uint8_t addr_raw[21]; ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_MessageSignature, resp); } else { fsm_sendFailure(FailureType_Failure_Other, "Error signing message"); } go_home(); }
void hdnode_serialize(const HDNode *node, uint32_t version, char use_public, char *str, int strsize) { uint8_t node_data[78]; write_be(node_data, version); node_data[4] = node->depth; write_be(node_data + 5, node->fingerprint); write_be(node_data + 9, node->child_num); memcpy(node_data + 13, node->chain_code, 32); if (use_public) { memcpy(node_data + 45, node->public_key, 33); } else { node_data[45] = 0; memcpy(node_data + 46, node->private_key, 32); } base58_encode_check(node_data, 78, str, strsize); }
static void test_pubkey_valid_enc(const char *base58_str, cstring *payload, const char *addrtype_str, bool is_testnet) { assert(payload != NULL); bool addrtype_pubkey = (strcmp(addrtype_str, "pubkey") == 0); bool addrtype_script = (strcmp(addrtype_str, "script") == 0); assert(addrtype_pubkey || addrtype_script); enum bitc_address_type addrtype; if (addrtype_pubkey) { if (is_testnet) addrtype = PUBKEY_ADDRESS_TEST; else addrtype = PUBKEY_ADDRESS; } else { if (is_testnet) addrtype = SCRIPT_ADDRESS_TEST; else addrtype = SCRIPT_ADDRESS; } cstring *b58 = base58_encode_check( addrtype, true, payload->str, payload->len); if (strcmp(b58->str, base58_str)) { fprintf(stderr, "base58: have %s, expected %s\n", b58->str, base58_str); assert(!strcmp(b58->str, base58_str)); } cstr_free(b58, true); cstr_free(payload, true); }
void fsm_msgSignIdentity(SignIdentity *msg) { RESP_INIT(SignedIdentity); layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign identity cancelled"); layoutHome(); return; } if (!protectPin(true)) { layoutHome(); return; } uint8_t hash[32]; if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Invalid identity"); layoutHome(); return; } uint32_t address_n[5]; address_n[0] = 0x80000000 | 13; address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | (hash[ 3] << 24); address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | (hash[ 7] << 24); address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | (hash[11] << 24); address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | (hash[15] << 24); const HDNode *node = fsm_getDerivedNode(address_n, 5); if (!node) return; uint8_t public_key[33]; // copy public key to temporary buffer memcpy(public_key, node->public_key, sizeof(public_key)); if (msg->has_ecdsa_curve_name) { const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name); if (curve) { // correct public key (since fsm_getDerivedNode uses secp256k1 curve) ecdsa_get_public_key33(curve, node->private_key, public_key); } } bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); int result = 0; layoutProgressSwipe("Signing", 0); if (sign_ssh) { // SSH does not sign visual challenge result = sshMessageSign(msg->challenge_hidden.bytes, msg->challenge_hidden.size, node->private_key, resp->signature.bytes); } else { uint8_t digest[64]; sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); result = cryptoMessageSign(digest, 64, node->private_key, resp->signature.bytes); } if (result == 0) { if (sign_ssh) { resp->has_address = false; } else { resp->has_address = true; uint8_t addr_raw[21]; ecdsa_get_address_raw(node->public_key, 0x00, addr_raw); // hardcoded Bitcoin address type base58_encode_check(addr_raw, 21, resp->address, sizeof(resp->address)); } resp->has_public_key = true; resp->public_key.size = 33; memcpy(resp->public_key.bytes, public_key, 33); resp->has_signature = true; resp->signature.size = 65; msg_write(MessageType_MessageType_SignedIdentity, resp); } else { fsm_sendFailure(FailureType_Failure_Other, "Error signing identity"); } layoutHome(); }
void fsm_msgGetAddress(GetAddress *msg) { RESP_INIT(Address); if (!storage_is_initialized()) { fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); return; } if(!pin_protect_cached()) { go_home(); return; } const CoinType *coin = fsm_getCoin(msg->coin_name); if(!coin) { return; } const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if(!node) { return; } if(msg->has_multisig) { if(cryptoMultisigPubkeyIndex(&(msg->multisig), node->public_key) < 0) { fsm_sendFailure(FailureType_Failure_Other, "Pubkey not found in multisig script"); go_home(); return; } uint8_t buf[32]; if(compile_script_multisig_hash(&(msg->multisig), buf) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Invalid multisig script"); go_home(); return; } ripemd160(buf, 32, buf + 1); buf[0] = coin->address_type_p2sh; // multisig cointype base58_encode_check(buf, 21, resp->address, sizeof(resp->address)); } else { ecdsa_get_address(node->public_key, coin->address_type, resp->address, sizeof(resp->address)); } if(msg->has_show_display && msg->show_display) { char desc[MEDIUM_STR_BUF] = ""; if(msg->has_multisig) { const uint32_t m = msg->multisig.m; const uint32_t n = msg->multisig.pubkeys_count; /* snprintf: 22 + 10 (%lu) + 10 (%lu) + 1 (NULL) = 43 */ snprintf(desc, MEDIUM_STR_BUF, "(Multi-Signature %lu of %lu)", (unsigned long)m, (unsigned long)n); } if(!confirm_address(desc, resp->address)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); go_home(); return; } } msg_write(MessageType_MessageType_Address, resp); go_home(); }
void fsm_msgDecryptMessage(DecryptMessage *msg) { if (!storage_is_initialized()) { fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); return; } if(!msg->has_nonce) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided"); return; } if(!msg->has_message) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No message provided"); return; } if(!msg->has_hmac) { fsm_sendFailure(FailureType_Failure_SyntaxError, "No message hmac provided"); return; } curve_point nonce_pubkey; if(msg->nonce.size != 33 || ecdsa_read_pubkey(&secp256k1, msg->nonce.bytes, &nonce_pubkey) == 0) { fsm_sendFailure(FailureType_Failure_SyntaxError, "Invalid nonce provided"); return; } if(!pin_protect_cached()) { go_home(); return; } const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count); if(!node) { return; } layout_simple_message("Decrypting Message..."); RESP_INIT(DecryptedMessage); bool display_only = false; bool signing = false; uint8_t address_raw[21]; if(cryptoMessageDecrypt(&nonce_pubkey, msg->message.bytes, msg->message.size, msg->hmac.bytes, msg->hmac.size, node->private_key, resp->message.bytes, &(resp->message.size), &display_only, &signing, address_raw) != 0) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Error decrypting message"); go_home(); return; } if(signing) { base58_encode_check(address_raw, 21, resp->address, sizeof(resp->address)); } if(!confirm_decrypt_msg((char *)resp->message.bytes, signing ? resp->address : 0)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Decrypt message cancelled"); go_home(); return; } if(display_only) { resp->has_address = false; resp->has_message = false; memset(resp->address, 0, sizeof(resp->address)); memset(&(resp->message), 0, sizeof(resp->message)); } else { resp->has_address = signing; resp->has_message = true; } msg_write(MessageType_MessageType_DecryptedMessage, resp); go_home(); }