blue-app-btc/src/btchip_helpers.c

316 lines
11 KiB
C

/*******************************************************************************
* Ledger Blue - Bitcoin Wallet
* (c) 2016 Ledger
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
********************************************************************************/
#include "btchip_internal.h"
#include "btchip_apdu_constants.h"
const unsigned char TRANSACTION_OUTPUT_SCRIPT_PRE[] = {
0x19, 0x76, 0xA9,
0x14}; // script length, OP_DUP, OP_HASH160, address length
const unsigned char TRANSACTION_OUTPUT_SCRIPT_POST[] = {
0x88, 0xAC}; // OP_EQUALVERIFY, OP_CHECKSIG
const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE[] = {
0x17, 0xA9, 0x14}; // script length, OP_HASH160, address length
const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2SH_POST[] = {0x87}; // OP_EQUAL
#ifdef NATIVE_SEGWIT_PREFIX
const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE[] = {0x16, 0x00, 0x14};
const unsigned char TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE[] = {0x22, 0x00, 0x20};
#endif
unsigned char btchip_output_script_is_regular(unsigned char *buffer) {
#ifdef NATIVE_SEGWIT_PREFIX
if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE,
sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) ||
(os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE,
sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) {
return 1;
}
#endif
if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_PRE,
sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE)) == 0) &&
(os_memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE) + 20,
TRANSACTION_OUTPUT_SCRIPT_POST,
sizeof(TRANSACTION_OUTPUT_SCRIPT_POST)) == 0)) {
return 1;
}
return 0;
}
unsigned char btchip_output_script_is_p2sh(unsigned char *buffer) {
if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE,
sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)) == 0) &&
(os_memcmp(buffer + sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE) + 20,
TRANSACTION_OUTPUT_SCRIPT_P2SH_POST,
sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)) == 0)) {
return 1;
}
return 0;
}
unsigned char btchip_output_script_is_native_witness(unsigned char *buffer) {
#ifdef NATIVE_SEGWIT_PREFIX
if ((os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE,
sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WPKH_PRE)) == 0) ||
(os_memcmp(buffer, TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE,
sizeof(TRANSACTION_OUTPUT_SCRIPT_P2WSH_PRE)) == 0)) {
return 1;
}
#endif
return 0;
}
unsigned char btchip_output_script_is_op_return(unsigned char *buffer) {
return (buffer[1] == 0x6A);
}
#ifdef HAVE_QTUM_SUPPORT
unsigned char btchip_output_script_is_op_create(unsigned char *buffer) {
return (!btchip_output_script_is_regular(buffer) &&
!btchip_output_script_is_p2sh(buffer) &&
!btchip_output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) &&
(buffer[buffer[0]] == 0xC1));
}
unsigned char btchip_output_script_is_op_call(unsigned char *buffer) {
return (!btchip_output_script_is_regular(buffer) &&
!btchip_output_script_is_p2sh(buffer) &&
!btchip_output_script_is_op_return(buffer) && (buffer[0] <= 0xEA) &&
(buffer[buffer[0]] == 0xC2));
}
#endif
unsigned char btchip_rng_u8_modulo(unsigned char modulo) {
unsigned int rng_max = 256 % modulo;
unsigned int rng_limit = 256 - rng_max;
unsigned char candidate;
while ((candidate = cx_rng_u8()) > rng_limit)
;
return (candidate % modulo);
}
unsigned char btchip_secure_memcmp(const void WIDE *buf1, const void WIDE *buf2,
unsigned short length) {
unsigned char error = 0;
while (length--) {
error |= ((unsigned char WIDE *)buf1)[length] ^
((unsigned char WIDE *)buf2)[length];
}
if (length != 0xffff) {
return 1;
}
return error;
}
unsigned long int btchip_read_u32(unsigned char WIDE *buffer, unsigned char be,
unsigned char skipSign) {
unsigned char i;
unsigned long int result = 0;
unsigned char shiftValue = (be ? 24 : 0);
for (i = 0; i < 4; i++) {
unsigned char x = (unsigned char)buffer[i];
if ((i == 0) && skipSign) {
x &= 0x7f;
}
result += ((unsigned long int)x) << shiftValue;
if (be) {
shiftValue -= 8;
} else {
shiftValue += 8;
}
}
return result;
}
void btchip_write_u32_be(unsigned char *buffer, unsigned long int value) {
buffer[0] = ((value >> 24) & 0xff);
buffer[1] = ((value >> 16) & 0xff);
buffer[2] = ((value >> 8) & 0xff);
buffer[3] = (value & 0xff);
}
void btchip_write_u32_le(unsigned char *buffer, unsigned long int value) {
buffer[0] = (value & 0xff);
buffer[1] = ((value >> 8) & 0xff);
buffer[2] = ((value >> 16) & 0xff);
buffer[3] = ((value >> 24) & 0xff);
}
void btchip_retrieve_keypair_discard(unsigned char WIDE *privateComponent,
unsigned char derivePublic) {
BEGIN_TRY {
TRY {
cx_ecdsa_init_private_key(BTCHIP_CURVE, privateComponent, 32,
&btchip_private_key_D);
L_DEBUG_BUF(("Using private component\n", privateComponent, 32));
if (derivePublic) {
cx_ecfp_generate_pair(BTCHIP_CURVE, &btchip_public_key_D,
&btchip_private_key_D, 1);
}
}
FINALLY {
}
}
END_TRY;
}
void btchip_public_key_hash160(unsigned char WIDE *in, unsigned short inlen,
unsigned char *out) {
union {
cx_sha256_t shasha;
cx_ripemd160_t riprip;
} u;
unsigned char buffer[32];
cx_sha256_init(&u.shasha);
cx_hash(&u.shasha.header, CX_LAST, in, inlen, buffer);
cx_ripemd160_init(&u.riprip);
cx_hash(&u.riprip.header, CX_LAST, buffer, 32, out);
}
unsigned short btchip_public_key_to_encoded_base58(
unsigned char WIDE *in, unsigned short inlen, unsigned char *out,
unsigned short outlen, unsigned short version,
unsigned char alreadyHashed) {
unsigned char tmpBuffer[26];
unsigned char checksumBuffer[32];
cx_sha256_t hash;
unsigned char versionSize = (version > 255 ? 2 : 1);
if (!alreadyHashed) {
L_DEBUG_BUF(("To hash\n", in, inlen));
btchip_public_key_hash160(in, inlen, tmpBuffer + versionSize);
L_DEBUG_BUF(("Hash160\n", (tmpBuffer + versionSize), 20));
if (version > 255) {
tmpBuffer[0] = (version >> 8);
tmpBuffer[1] = version;
} else {
tmpBuffer[0] = version;
}
} else {
os_memmove(tmpBuffer, in, 20 + versionSize);
}
cx_sha256_init(&hash);
cx_hash(&hash.header, CX_LAST, tmpBuffer, 20 + versionSize, checksumBuffer);
cx_sha256_init(&hash);
cx_hash(&hash.header, CX_LAST, checksumBuffer, 32, checksumBuffer);
L_DEBUG_BUF(("Checksum\n", checksumBuffer, 4));
os_memmove(tmpBuffer + 20 + versionSize, checksumBuffer, 4);
return btchip_encode_base58(tmpBuffer, 24 + versionSize, out, outlen);
}
void btchip_swap_bytes(unsigned char *target, unsigned char *source,
unsigned char size) {
unsigned char i;
for (i = 0; i < size; i++) {
target[i] = source[size - 1 - i];
}
}
unsigned short btchip_decode_base58_address(unsigned char WIDE *in,
unsigned short inlen,
unsigned char *out,
unsigned short outlen) {
unsigned char hashBuffer[32];
cx_sha256_t hash;
outlen = btchip_decode_base58(in, inlen, out, outlen);
// Compute hash to verify address
cx_sha256_init(&hash);
cx_hash(&hash.header, CX_LAST, out, outlen - 4, hashBuffer);
cx_sha256_init(&hash);
cx_hash(&hash.header, CX_LAST, hashBuffer, 32, hashBuffer);
if (os_memcmp(out + outlen - 4, hashBuffer, 4)) {
L_DEBUG_BUF(
("Hash checksum mismatch\n", hashBuffer, sizeof(hashBuffer)));
THROW(INVALID_CHECKSUM);
}
return outlen;
}
void btchip_private_derive_keypair(unsigned char WIDE *bip32Path,
unsigned char derivePublic,
unsigned char *out_chainCode) {
unsigned char bip32PathLength;
unsigned char i;
unsigned int bip32PathInt[MAX_BIP32_PATH];
unsigned char privateComponent[32];
bip32PathLength = bip32Path[0];
if (bip32PathLength > MAX_BIP32_PATH) {
THROW(INVALID_PARAMETER);
}
bip32Path++;
for (i = 0; i < bip32PathLength; i++) {
bip32PathInt[i] = btchip_read_u32(bip32Path, 1, 0);
bip32Path += 4;
}
os_perso_derive_node_bip32(CX_CURVE_256K1, bip32PathInt, bip32PathLength,
privateComponent, out_chainCode);
btchip_retrieve_keypair_discard(privateComponent, derivePublic);
os_memset(privateComponent, 0, sizeof(privateComponent));
}
void btchip_transaction_add_output(unsigned char *hash160Address,
unsigned char *amount, unsigned char p2sh) {
const unsigned char *pre = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE
: TRANSACTION_OUTPUT_SCRIPT_PRE);
const unsigned char *post = (p2sh ? TRANSACTION_OUTPUT_SCRIPT_P2SH_POST
: TRANSACTION_OUTPUT_SCRIPT_POST);
unsigned char sizePre = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_PRE)
: sizeof(TRANSACTION_OUTPUT_SCRIPT_PRE));
unsigned char sizePost = (p2sh ? sizeof(TRANSACTION_OUTPUT_SCRIPT_P2SH_POST)
: sizeof(TRANSACTION_OUTPUT_SCRIPT_POST));
if (amount != NULL) {
btchip_swap_bytes(btchip_context_D.tmp, amount, 8);
btchip_context_D.tmp += 8;
}
os_memmove(btchip_context_D.tmp, (void *)pre, sizePre);
btchip_context_D.tmp += sizePre;
os_memmove(btchip_context_D.tmp, hash160Address, 20);
btchip_context_D.tmp += 20;
os_memmove(btchip_context_D.tmp, (void *)post, sizePost);
btchip_context_D.tmp += sizePost;
}
void btchip_signverify_finalhash(void WIDE *keyContext, unsigned char sign,
unsigned char WIDE *in, unsigned short inlen,
unsigned char *out, unsigned short outlen,
unsigned char rfc6979) {
if (sign) {
cx_ecdsa_sign((cx_ecfp_private_key_t WIDE *)keyContext,
CX_LAST | (rfc6979 ? CX_RND_RFC6979 : CX_RND_TRNG),
CX_SHA256, in, inlen, out
#if CX_APILEVEL >= 8
,
NULL
#endif
);
} else {
cx_ecdsa_verify((cx_ecfp_public_key_t WIDE *)keyContext, CX_LAST,
CX_SHA256, in, inlen, out, outlen);
}
}