Skip to content

Commit

Permalink
Move dependencies to non-throwing crypto modules
Browse files Browse the repository at this point in the history
  • Loading branch information
relatko committed Oct 7, 2023
1 parent a3661c6 commit 83703bf
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 174 deletions.
153 changes: 1 addition & 152 deletions src/eos_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,155 +20,6 @@
#include "cx.h"
#include "utils.h"

#define FORWARD_CX_ERROR(call) \
{ \
cx_err_t callResult = (call); \
if (callResult != CX_OK) return callResult; \
}

/**
* EOS way to check if a signature is canonical :/
*/
unsigned char check_canonical(uint8_t *rs) {
return !(rs[0] & 0x80) && !(rs[0] == 0 && !(rs[1] & 0x80)) && !(rs[32] & 0x80) &&
!(rs[32] == 0 && !(rs[33] & 0x80));
}

int ecdsa_der_to_sig(const uint8_t *der, uint8_t *sig) {
int length;
int offset = 2;
int delta = 0;
if (der[offset + 2] == 0) {
length = der[offset + 1] - 1;
offset += 3;
} else {
length = der[offset + 1];
offset += 2;
}
if ((length < 0) || (length > 32)) {
return 0;
}
while ((length + delta) < 32) {
sig[delta++] = 0;
}
memcpy(sig + delta, der + offset, length);

delta = 0;
offset += length;
if (der[offset + 2] == 0) {
length = der[offset + 1] - 1;
offset += 3;
} else {
length = der[offset + 1];
offset += 2;
}
if ((length < 0) || (length > 32)) {
return 0;
}
while ((length + delta) < 32) {
sig[32 + delta++] = 0;
}
memcpy(sig + 32 + delta, der + offset, length);

return 1;
}

/**
* The nonce generated by internal library CX_RND_RFC6979 is not compatible
* with EOS. So this is the way to generate nonve for EOS.
* Arguments (by relatko):
* - rnd - out
* - h1 - hash, in
* - x - private key, in
* - x_len - private key length
* - q - SECP256K1_N, in
* - q_len - 32, in
* - V, out
* - K, out
*/
cx_err_t rng_rfc6979(unsigned char *rnd,
unsigned char *h1,
unsigned char *x,
unsigned int x_len,
const unsigned char *q,
unsigned int q_len,
unsigned char *V,
unsigned char *K) {
unsigned int h_len, found, i;
cx_hmac_sha256_t hmac;

h_len = 32;
// a. h1 as input

// loop for a candidate
found = 0;
while (!found) {
if (x) {
// b. Set: V = 0x01 0x01 0x01 ... 0x01
memset(V, 0x01, h_len);
// c. Set: K = 0x00 0x00 0x00 ... 0x00
memset(K, 0x00, h_len);
// d. Set: K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1))
V[h_len] = 0;
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, 0, V, h_len + 1, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, 0, x, x_len, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, h1, h_len, K, 32));
// e. Set: V = HMAC_K(V)
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, V, h_len, V, 32));
// f. Set: K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
V[h_len] = 1;
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, 0, V, h_len + 1, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, 0, x, x_len, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, h1, h_len, K, 32));
// g. Set: V = HMAC_K(V) --
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, V, h_len, V, 32));
// initial setup only once
x = NULL;
} else {
// h.3 K = HMAC_K(V || 0x00)
V[h_len] = 0;
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, V, h_len + 1, K, 32));
// h.3 V = HMAC_K(V)
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, V, h_len, V, 32));
}

// generate candidate
/* Shortcut: As only secp256k1/sha256 is supported, the step h.2 :
* While tlen < qlen, do the following:
* V = HMAC_K(V)
* T = T || V
* is replace by
* V = HMAC_K(V)
*/
x_len = q_len;
while (x_len) {
if (x_len < h_len) {
h_len = x_len;
}
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, V, h_len, V, 32));
memcpy(rnd, V, h_len);
x_len -= h_len;
}

// h.3 Check T is < n
for (i = 0; i < q_len; i++) {
if (V[i] < q[i]) {
found = 1;
break;
}
}
}

return CX_OK;
}

unsigned char const BASE58ALPHABET[58] = {
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
Expand Down Expand Up @@ -237,9 +88,7 @@ uint32_t compressed_public_key_to_wif(const uint8_t *publicKey,
uint8_t check[20];
cx_ripemd160_t riprip;
cx_ripemd160_init(&riprip);
if (cx_hash_no_throw(&riprip.header, CX_LAST, temp, 33, check, sizeof(check)) != CX_OK) {
return 0;
}
ASSERT(cx_hash_no_throw(&riprip.header, CX_LAST, temp, 33, check, sizeof(check)) == CX_OK);
memcpy(temp + 33, check, 4);

explicit_bzero(out, outLength);
Expand Down
14 changes: 0 additions & 14 deletions src/eos_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,6 @@
#include <stdint.h>
#include "cx.h"

unsigned char check_canonical(uint8_t *rs);

int ecdsa_der_to_sig(const uint8_t *der, uint8_t *sig);

cx_err_t rng_rfc6979(unsigned char *rnd,
unsigned char *h1,
unsigned char *x,
unsigned int x_len,
const unsigned char *q,
unsigned int q_len,
unsigned char *V,
unsigned char *K);

// returns 0 on error
uint32_t public_key_to_wif(const uint8_t *publicKey,
uint32_t keyLength,
char *out,
Expand Down
161 changes: 154 additions & 7 deletions src/keyDerivation.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@ static uint8_t const SECP256K1_N[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41};

__noinline_due_to_stack__ WARN_UNUSED_RESULT uint16_t derivePrivateKey(const bip44_path_t* pathSpec,
private_key_t* privateKey) {
#define FORWARD_CX_ERROR(call) \
{ \
cx_err_t callResult = (call); \
if (callResult != CX_OK) return callResult; \
}

__noinline_due_to_stack__ WARN_UNUSED_RESULT uint16_t derivePrivateKey(const bip44_path_t *pathSpec,
private_key_t *privateKey) {
// Crypto assets to be cleared
uint8_t privateKeySeed[PRIVATE_KEY_SEED_LEN];
explicit_bzero(privateKeySeed, SIZEOF(privateKeySeed));
Expand Down Expand Up @@ -58,8 +64,8 @@ __noinline_due_to_stack__ WARN_UNUSED_RESULT uint16_t derivePrivateKey(const bip
return SUCCESS;
}

__noinline_due_to_stack__ WARN_UNUSED_RESULT uint16_t derivePublicKey(const bip44_path_t* pathSpec,
public_key_t* publicKey) {
__noinline_due_to_stack__ WARN_UNUSED_RESULT uint16_t derivePublicKey(const bip44_path_t *pathSpec,
public_key_t *publicKey) {
// Crypto assets to be cleared
private_key_t privateKey;
explicit_bzero(&privateKey, SIZEOF(privateKey));
Expand Down Expand Up @@ -91,11 +97,152 @@ __noinline_due_to_stack__ WARN_UNUSED_RESULT uint16_t derivePublicKey(const bip4
return SUCCESS;
}

// EOS way to check if a signature is canonical :/
static unsigned char check_canonical(uint8_t *rs) {
return !(rs[0] & 0x80) && !(rs[0] == 0 && !(rs[1] & 0x80)) && !(rs[32] & 0x80) &&
!(rs[32] == 0 && !(rs[33] & 0x80));
}

static int ecdsa_der_to_sig(const uint8_t *der, uint8_t *sig) {
int length;
int offset = 2;
int delta = 0;
if (der[offset + 2] == 0) {
length = der[offset + 1] - 1;
offset += 3;
} else {
length = der[offset + 1];
offset += 2;
}
if ((length < 0) || (length > 32)) {
return 0;
}
while ((length + delta) < 32) {
sig[delta++] = 0;
}
memcpy(sig + delta, der + offset, length);

delta = 0;
offset += length;
if (der[offset + 2] == 0) {
length = der[offset + 1] - 1;
offset += 3;
} else {
length = der[offset + 1];
offset += 2;
}
if ((length < 0) || (length > 32)) {
return 0;
}
while ((length + delta) < 32) {
sig[32 + delta++] = 0;
}
memcpy(sig + 32 + delta, der + offset, length);

return 1;
}

/**
* The nonce generated by internal library CX_RND_RFC6979 is not compatible
* with EOS. So this is the way to generate nonve for EOS.
* Arguments (deduced by relatko):
* - rnd - out
* - h1 - hash, in
* - x - private key, in
* - x_len - private key length
* - q - SECP256K1_N, in
* - q_len - 32, in
* - V, out
* - K, out
*/
static cx_err_t rng_rfc6979(unsigned char *rnd,
unsigned char *h1,
unsigned char *x,
unsigned int x_len,
const unsigned char *q,
unsigned int q_len,
unsigned char *V,
unsigned char *K) {
unsigned int h_len, found, i;
cx_hmac_sha256_t hmac;

h_len = 32;
// a. h1 as input

// loop for a candidate
found = 0;
while (!found) {
if (x) {
// b. Set: V = 0x01 0x01 0x01 ... 0x01
memset(V, 0x01, h_len);
// c. Set: K = 0x00 0x00 0x00 ... 0x00
memset(K, 0x00, h_len);
// d. Set: K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1))
V[h_len] = 0;
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, 0, V, h_len + 1, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, 0, x, x_len, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, h1, h_len, K, 32));
// e. Set: V = HMAC_K(V)
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, V, h_len, V, 32));
// f. Set: K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
V[h_len] = 1;
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, 0, V, h_len + 1, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, 0, x, x_len, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, h1, h_len, K, 32));
// g. Set: V = HMAC_K(V) --
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, V, h_len, V, 32));
// initial setup only once
x = NULL;
} else {
// h.3 K = HMAC_K(V || 0x00)
V[h_len] = 0;
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, V, h_len + 1, K, 32));
// h.3 V = HMAC_K(V)
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, V, h_len, V, 32));
}

// generate candidate
/* Shortcut: As only secp256k1/sha256 is supported, the step h.2 :
* While tlen < qlen, do the following:
* V = HMAC_K(V)
* T = T || V
* is replace by
* V = HMAC_K(V)
*/
x_len = q_len;
while (x_len) {
if (x_len < h_len) {
h_len = x_len;
}
FORWARD_CX_ERROR(cx_hmac_sha256_init_no_throw(&hmac, K, 32));
FORWARD_CX_ERROR(cx_hmac_no_throw((cx_hmac_t *) &hmac, CX_LAST, V, h_len, V, 32));
memcpy(rnd, V, h_len);
x_len -= h_len;
}

// h.3 Check T is < n
for (i = 0; i < q_len; i++) {
if (V[i] < q[i]) {
found = 1;
break;
}
}
}

return CX_OK;
}

// This function contains code producing signatures that is taken from EOS app
// The produced signature contains both
__noinline_due_to_stack__ WARN_UNUSED_RESULT uint16_t signTransaction(bip44_path_t* wittnessPath,
// To be sure that the functionality is unchanged, constants are left as they were
__noinline_due_to_stack__ WARN_UNUSED_RESULT uint16_t signTransaction(bip44_path_t *wittnessPath,
uint8_t hashBuf[SHA_256_SIZE],
uint8_t* signature,
uint8_t *signature,
size_t signatureLen) {
// Crypto assets to be cleared
private_key_t privateKey;
Expand Down
1 change: 0 additions & 1 deletion src/signTransaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,6 @@ __noinline_due_to_stack__ void signTx_handleFinishAPDU(
}

// We add hash to the response
TRACE("ecdsa_der_to_sig_result:");
TRACE_BUFFER(G_io_apdu_buffer, PUBKEY_LENGTH);
memcpy(G_io_apdu_buffer + PUBKEY_LENGTH, hashBuf, SIZEOF(hashBuf));

Expand Down

0 comments on commit 83703bf

Please sign in to comment.