Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/apdu/dispatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
* Parameter 1 for first APDU number.
*/
#define P1_START 0x00

#define P1_OUTPUTS 0x01

#define P1_INPUTS 0x02
/**
* Parameter 1 for maximum APDU number.
*/
Expand Down
7 changes: 6 additions & 1 deletion src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
/**
* Maximum transaction length (bytes).
*/
#define MAX_TRANSACTION_LEN 1410
#define MAX_TRANSACTION_LEN 128

/**
* Maximum signature length (bytes).
Expand All @@ -42,3 +42,8 @@
* Cannot be any longer than 35 in any case
*/
#define MAX_INPUT_SCRIPT_PUBLIC_KEY_LEN 35

/**
* The signing key used for sighash
*/
#define SIGNING_KEY "TransactionSigningHash"
50 changes: 15 additions & 35 deletions src/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include "globals.h"

#include "sighash.h"

int crypto_derive_private_key(cx_ecfp_private_key_t *private_key,
uint8_t chain_code[static 32],
const uint32_t *bip32_path,
Expand Down Expand Up @@ -51,15 +53,15 @@ void crypto_init_public_key(cx_ecfp_private_key_t *private_key,
int crypto_sign_message(void) {
cx_ecfp_private_key_t private_key = {0};
uint8_t chain_code[32] = {0};
// uint32_t info = 0;
uint32_t info = 0;
int sig_len = 0;

// FIXME: Forced 44'/111111'/0'/0/0
// 44'/111111'/0'/ address_type / address_index
G_context.bip32_path[0] = 0x8000002C;
G_context.bip32_path[1] = 0x8001b207;
G_context.bip32_path[2] = 0x80000000;
G_context.bip32_path[3] = 0x00000000;
G_context.bip32_path[4] = 0x00000000;
G_context.bip32_path[3] = G_context.tx_info.transaction.tx_inputs[0].derivation_path[0];
G_context.bip32_path[4] = G_context.tx_info.transaction.tx_inputs[0].derivation_path[1];

G_context.bip32_path_len = 5;

Expand All @@ -74,37 +76,15 @@ int crypto_sign_message(void) {

BEGIN_TRY {
TRY {
// FIXME: implement signing here:
// from BTC:
// https://github.com/LedgerHQ/app-bitcoin-new/blob/b2c624769c3b863b38dd133e8facabb3d7b5b76c/src/handler/sign_psbt.c
// err = cx_ecschnorr_sign_no_throw(&private_key,
// CX_ECSCHNORR_BIP0340 | CX_RND_TRNG,
// CX_SHA256,
// sighash,
// 32,
// sig,
// &sig_len);
// from doc:
// https://developers.ledger.com/docs/embedded-app/crypto-api/lcx__ecschnorr_8h/#a2aa2454ece11c17373539d7178d26a98
// static int cx_ecschnorr_sign (
// const cx_ecfp_private_key_t * pvkey,
// int mode,
// cx_md_t hashID,
// const unsigned char * msg,
// unsigned int msg_len,
// unsigned char * sig,
// size_t sig_len,
// unsigned int * info
// )

// sig_len = cx_ecschnorr_sign(&private_key,
// CX_ECSCHNORR_BIP0340 | CX_RND_TRNG,
// CX_SHA256,
// "somemessagefixme",
// sizeof("somemessagefixme"),
// G_context.tx_info.signature,
// sizeof(G_context.tx_info.signature),
// &info);
calc_sighash(&G_context.tx_info.transaction, G_context.tx_info.transaction.tx_inputs, G_context.sighash);
sig_len = cx_ecschnorr_sign(&private_key,
CX_ECSCHNORR_BIP0340 | CX_RND_TRNG,
CX_SHA256,
G_context.sighash,
32,
G_context.tx_info.signature,
sizeof(G_context.tx_info.signature),
&info);
PRINTF("Signature: %.*H\n", sig_len, G_context.tx_info.signature);
}
CATCH_OTHER(e) {
Expand Down
44 changes: 37 additions & 7 deletions src/handler/sign_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "cx.h"

#include "sign_tx.h"
#include "../apdu/dispatcher.h"
#include "../sw.h"
#include "../globals.h"
#include "../crypto.h"
Expand All @@ -15,8 +16,8 @@
#include "../transaction/types.h"
#include "../transaction/deserialize.h"

int handler_sign_tx(buffer_t *cdata, uint8_t chunk, bool more) {
if (chunk == 0) { // first APDU, parse BIP32 path
int handler_sign_tx(buffer_t *cdata, uint8_t type, bool more) {
if (type == 0) { // first APDU, parse BIP32 path
explicit_bzero(&G_context, sizeof(G_context));
G_context.req_type = CONFIRM_TRANSACTION;
G_context.state = STATE_NONE;
Expand All @@ -40,12 +41,41 @@ int handler_sign_tx(buffer_t *cdata, uint8_t chunk, bool more) {
if (G_context.tx_info.raw_tx_len + cdata->size > sizeof(G_context.tx_info.raw_tx)) {
return io_send_sw(SW_WRONG_TX_LENGTH);
}
if (!buffer_move(cdata,
G_context.tx_info.raw_tx + G_context.tx_info.raw_tx_len,
cdata->size)) {
return io_send_sw(SW_TX_PARSING_FAIL);

// Parse as we go
if (type == P1_OUTPUTS) {
// Outputs
if (G_context.tx_info.transaction.tx_output_len >= sizeof(G_context.tx_info.transaction.tx_outputs)) {
// Too many outputs!
return io_send_sw(SW_TX_PARSING_FAIL);
}

parser_status_e err = transaction_output_deserialize(cdata, &G_context.tx_info.transaction.tx_outputs[G_context.tx_info.transaction.tx_output_len]);

if (err != PARSING_OK) {
return io_send_sw(err);
} else {
G_context.tx_info.transaction.tx_output_len++;
}

} else if (type == P1_INPUTS) {
// Inputs
if (G_context.tx_info.transaction.tx_input_len >= sizeof(G_context.tx_info.transaction.tx_inputs)) {
// Too many inputs!
return io_send_sw(SW_TX_PARSING_FAIL);
}

parser_status_e err = transaction_input_deserialize(cdata, &G_context.tx_info.transaction.tx_inputs[G_context.tx_info.transaction.tx_input_len]);

if (err < 0) {
return io_send_sw(SW_TX_PARSING_FAIL);
} else {
G_context.tx_info.transaction.tx_input_len++;
}

} else {
return io_send_sw(SW_WRONG_P1P2);
}
G_context.tx_info.raw_tx_len += cdata->size;

if (more) {
// more APDUs with transaction part are expected.
Expand Down
6 changes: 3 additions & 3 deletions src/handler/sign_tx.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
*
* @param[in,out] cdata
* Command data with BIP32 path and raw transaction serialized.
* @param[in] chunk
* Index number of the APDU chunk.
* @param[in] type
* Type of data we are getting
* @param[in] more
* Whether more APDU chunk to be received or not.
*
* @return zero or positive integer if success, negative integer otherwise.
*
*/
int handler_sign_tx(buffer_t *cdata, uint8_t chunk, bool more);
int handler_sign_tx(buffer_t *cdata, uint8_t type, bool more);
158 changes: 158 additions & 0 deletions src/import/blake2-impl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
BLAKE2 reference source code package - reference C implementations

Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
your option. The terms of these licenses can be found at:

- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
- OpenSSL license : https://www.openssl.org/source/license.html
- Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0

More information about the BLAKE2 hash function can be found at
https://blake2.net.
*/
#ifndef BLAKE2_IMPL_H
#define BLAKE2_IMPL_H

#include <stdint.h>
#include <string.h>

#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
#if defined(_MSC_VER)
#define BLAKE2_INLINE __inline
#elif defined(__GNUC__)
#define BLAKE2_INLINE __inline__
#else
#define BLAKE2_INLINE
#endif
#else
#define BLAKE2_INLINE inline
#endif

static BLAKE2_INLINE uint32_t load32( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint32_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return (( uint32_t )( p[0] ) << 0) |
(( uint32_t )( p[1] ) << 8) |
(( uint32_t )( p[2] ) << 16) |
(( uint32_t )( p[3] ) << 24) ;
#endif
}

static BLAKE2_INLINE uint64_t load64( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint64_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return (( uint64_t )( p[0] ) << 0) |
(( uint64_t )( p[1] ) << 8) |
(( uint64_t )( p[2] ) << 16) |
(( uint64_t )( p[3] ) << 24) |
(( uint64_t )( p[4] ) << 32) |
(( uint64_t )( p[5] ) << 40) |
(( uint64_t )( p[6] ) << 48) |
(( uint64_t )( p[7] ) << 56) ;
#endif
}

static BLAKE2_INLINE uint16_t load16( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint16_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return ( uint16_t )((( uint32_t )( p[0] ) << 0) |
(( uint32_t )( p[1] ) << 8));
#endif
}

static BLAKE2_INLINE void store16( void *dst, uint16_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w;
#endif
}

static BLAKE2_INLINE void store32( void *dst, uint32_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
#endif
}

static BLAKE2_INLINE void store64( void *dst, uint64_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
p[4] = (uint8_t)(w >> 32);
p[5] = (uint8_t)(w >> 40);
p[6] = (uint8_t)(w >> 48);
p[7] = (uint8_t)(w >> 56);
#endif
}

static BLAKE2_INLINE uint64_t load48( const void *src )
{
const uint8_t *p = ( const uint8_t * )src;
return (( uint64_t )( p[0] ) << 0) |
(( uint64_t )( p[1] ) << 8) |
(( uint64_t )( p[2] ) << 16) |
(( uint64_t )( p[3] ) << 24) |
(( uint64_t )( p[4] ) << 32) |
(( uint64_t )( p[5] ) << 40) ;
}

static BLAKE2_INLINE void store48( void *dst, uint64_t w )
{
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
p[4] = (uint8_t)(w >> 32);
p[5] = (uint8_t)(w >> 40);
}

static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 32 - c ) );
}

static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 64 - c ) );
}

/* prevents compiler optimizing out memset() */
static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n) {
memset(v, 0, n);
}

#endif
Loading