mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-04-15 23:05:45 +00:00
feat(crypto): add wrappers for anti-exfil functions
This commit is contained in:
parent
55031fb30b
commit
d202a6bf49
@ -70,7 +70,8 @@ ZKP_CFLAGS = \
|
||||
-DENABLE_MODULE_RECOVERY \
|
||||
-DENABLE_MODULE_SCHNORRSIG \
|
||||
-DENABLE_MODULE_EXTRAKEYS \
|
||||
-DENABLE_MODULE_ECDH
|
||||
-DENABLE_MODULE_ECDH \
|
||||
-DENABLE_MODULE_ECDSA_S2C
|
||||
ZKP_PATH = ../vendor/secp256k1-zkp
|
||||
# this is specific for 64-bit builds
|
||||
CFLAGS += -DSECP256K1_CONTEXT_SIZE=208
|
||||
|
@ -4172,6 +4172,78 @@ START_TEST(test_zkp_ecdsa_sign_digest_recoverable_deterministic) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_zkp_ecdsa_anti_exfil_commit_nonce) {
|
||||
static const struct {
|
||||
const char *priv_key;
|
||||
const char *digest;
|
||||
const char *entropy;
|
||||
const char *expected_nonce_commitment;
|
||||
} tests[] = {
|
||||
{"8521fa4b1f08d39b91e2fcc6a342b2395fbada5146c494be485b6d5ff8002da0",
|
||||
"0d841da7d1d6c5edb90864118f52c865f2ac56deb13a41229ef7cbd2951593fd",
|
||||
"88e381faa8f2297cd6295b19e8a3563291e4c86a873f9a758b0cd6629a102eac",
|
||||
"032b756f0b1937eef6d269b35781c7a1a5435e00e3c06245ef2162d51c15b2992c"}};
|
||||
|
||||
const ecdsa_curve *curve = &secp256k1;
|
||||
uint8_t priv_key[32] = {0};
|
||||
uint8_t digest[32] = {0};
|
||||
uint8_t entropy[32] = {0};
|
||||
uint8_t nonce_commitment[64] = {0};
|
||||
uint8_t expected_nonce_commitment[64] = {0};
|
||||
int res = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
|
||||
memcpy(priv_key, fromhex(tests[i].priv_key), 32);
|
||||
memcpy(digest, fromhex(tests[i].digest), 32);
|
||||
memcpy(entropy, fromhex(tests[i].entropy), 32);
|
||||
memcpy(expected_nonce_commitment,
|
||||
fromhex(tests[i].expected_nonce_commitment), 33);
|
||||
|
||||
res = zkp_ecdsa_anti_exfil_commit_nonce(curve, priv_key, digest, entropy,
|
||||
nonce_commitment);
|
||||
ck_assert_int_eq(res, 0);
|
||||
ck_assert_mem_eq(expected_nonce_commitment, nonce_commitment, 33);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_zkp_ecdsa_anti_exfil_sign_digest) {
|
||||
static const struct {
|
||||
const char *priv_key;
|
||||
const char *digest;
|
||||
const char *entropy_commitment;
|
||||
const char *expected_sig;
|
||||
} tests[] = {
|
||||
{"8521fa4b1f08d39b91e2fcc6a342b2395fbada5146c494be485b6d5ff8002da0",
|
||||
"0d841da7d1d6c5edb90864118f52c865f2ac56deb13a41229ef7cbd2951593fd",
|
||||
// entropy:
|
||||
// 88e381faa8f2297cd6295b19e8a3563291e4c86a873f9a758b0cd6629a102eac
|
||||
"bc07f96c351484fecb4c1b1820070c446f4f5398530e85ed2955041bdef54abf",
|
||||
"e4450fb09d21528a3b75e34e1a7d0872f8f02f243087f69a472029c6622ed9790b1855b"
|
||||
"91149ea55d5336b0967d25c73890b126220dd4ad885b69b65028178da"}};
|
||||
|
||||
const ecdsa_curve *curve = &secp256k1;
|
||||
uint8_t priv_key[32] = {0};
|
||||
uint8_t digest[32] = {0};
|
||||
uint8_t entropy_commitment[32] = {0};
|
||||
uint8_t expected_sig[64] = {0};
|
||||
uint8_t computed_sig[64] = {0};
|
||||
int res = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
|
||||
memcpy(priv_key, fromhex(tests[i].priv_key), 32);
|
||||
memcpy(digest, fromhex(tests[i].digest), 32);
|
||||
memcpy(entropy_commitment, fromhex(tests[i].entropy_commitment), 32);
|
||||
memcpy(expected_sig, fromhex(tests[i].expected_sig), 64);
|
||||
|
||||
res = zkp_ecdsa_anti_exfil_sign_digest(curve, priv_key, digest,
|
||||
entropy_commitment, computed_sig);
|
||||
ck_assert_int_eq(res, 0);
|
||||
ck_assert_mem_eq(expected_sig, computed_sig, 64);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
// test vectors from
|
||||
// http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors
|
||||
START_TEST(test_aes) {
|
||||
@ -11524,6 +11596,8 @@ Suite *test_suite(void) {
|
||||
tcase_add_test(tc, test_tc_ecdsa_sign_digest_recoverable_deterministic);
|
||||
tcase_add_test(tc, test_zkp_ecdsa_sign_digest_recoverable_deterministic);
|
||||
#endif
|
||||
tcase_add_test(tc, test_zkp_ecdsa_anti_exfil_commit_nonce);
|
||||
tcase_add_test(tc, test_zkp_ecdsa_anti_exfil_sign_digest);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("rfc6979");
|
||||
|
@ -28,9 +28,11 @@
|
||||
#include "memzero.h"
|
||||
#include "secp256k1.h"
|
||||
#include "zkp_context.h"
|
||||
#include "zkp_ecdsa.h"
|
||||
|
||||
#include "vendor/secp256k1-zkp/include/secp256k1.h"
|
||||
#include "vendor/secp256k1-zkp/include/secp256k1_ecdh.h"
|
||||
#include "vendor/secp256k1-zkp/include/secp256k1_ecdsa_s2c.h"
|
||||
#include "vendor/secp256k1-zkp/include/secp256k1_recovery.h"
|
||||
|
||||
#include "zkp_ecdsa.h"
|
||||
@ -260,6 +262,125 @@ int zkp_ecdsa_sign_digest_recoverable(
|
||||
return result;
|
||||
}
|
||||
|
||||
// anti-exfil ECDSA signing
|
||||
// curve has to be &secp256k1
|
||||
// private_key_bytes has 32 bytes
|
||||
// digest has 32 bytes
|
||||
// entropy_commitment has 32 bytes
|
||||
// signature_bytes has 64 bytes
|
||||
// returns 0 on success
|
||||
int zkp_ecdsa_anti_exfil_sign_digest(const ecdsa_curve *curve,
|
||||
const uint8_t *private_key_bytes,
|
||||
const uint8_t *digest,
|
||||
const uint8_t *entropy,
|
||||
uint8_t *signature_bytes) {
|
||||
int result = 0;
|
||||
secp256k1_context *context_writable = NULL;
|
||||
|
||||
if (curve != &secp256k1) {
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (is_zero_digest(digest)) {
|
||||
// The probability of the digest being all-zero by chance is
|
||||
// infinitesimal, so this is most likely an indication of a bug.
|
||||
// Furthermore, the signature has no value, because in this case it can be
|
||||
// easily forged for any public key, see zkp_ecdsa_verify_digest().
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
context_writable = zkp_context_acquire_writable();
|
||||
if (context_writable == NULL) {
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (secp256k1_context_writable_randomize(context_writable) != 0) {
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
secp256k1_ecdsa_signature signature = {0};
|
||||
if (secp256k1_anti_exfil_sign(context_writable, &signature, digest,
|
||||
private_key_bytes, entropy) != 1) {
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
const secp256k1_context *context_read_only = zkp_context_get_read_only();
|
||||
if (secp256k1_ecdsa_signature_serialize_compact(
|
||||
context_read_only, signature_bytes, &signature) != 1) {
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (context_writable) {
|
||||
zkp_context_release_writable();
|
||||
context_writable = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// anti-exfil ECDSA commit
|
||||
// curve has to be &secp256k1
|
||||
// private_key_bytes has 32 bytes
|
||||
// digest has 32 bytes
|
||||
// entropy_commitment has 32 bytes
|
||||
// public_nonce_bytes has 33 bytes
|
||||
// returns 0 on success
|
||||
int zkp_ecdsa_anti_exfil_commit_nonce(const ecdsa_curve *curve,
|
||||
const uint8_t *private_key_bytes,
|
||||
const uint8_t *digest,
|
||||
const uint8_t *entropy_commitment,
|
||||
uint8_t *nonce_commitment) {
|
||||
int result = 0;
|
||||
secp256k1_context *context_writable = NULL;
|
||||
|
||||
assert(curve == &secp256k1);
|
||||
if (curve != &secp256k1) {
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
context_writable = zkp_context_acquire_writable();
|
||||
if (context_writable == NULL) {
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (secp256k1_context_writable_randomize(context_writable) != 0) {
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
secp256k1_ecdsa_s2c_opening s2c_opening = {0};
|
||||
if (secp256k1_ecdsa_anti_exfil_signer_commit(context_writable, &s2c_opening,
|
||||
digest, private_key_bytes,
|
||||
entropy_commitment) != 1) {
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
const secp256k1_context *context_read_only = zkp_context_get_read_only();
|
||||
if (secp256k1_ecdsa_s2c_opening_serialize(context_read_only, nonce_commitment,
|
||||
&s2c_opening) != 1) {
|
||||
result = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (context_writable) {
|
||||
zkp_context_release_writable();
|
||||
context_writable = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ECDSA public key recovery
|
||||
// public_key_bytes has 65 bytes
|
||||
// signature_bytes has 64 bytes
|
||||
@ -338,12 +459,12 @@ int zkp_ecdsa_verify_digest(const ecdsa_curve *curve,
|
||||
|
||||
if (result == 0) {
|
||||
if (is_zero_digest(digest)) {
|
||||
// The digest was all-zero. The probability of this happening by chance is
|
||||
// infinitesimal, but it could be induced by a fault injection. In this
|
||||
// case the signature (r,s) can be forged by taking r := (t * Q).x mod n
|
||||
// and s := r * t^-1 mod n for any t in [1, n-1]. We fail verification,
|
||||
// because there is no guarantee that the signature was created by the
|
||||
// owner of the private key.
|
||||
// The digest was all-zero. The probability of this happening by
|
||||
// chance is infinitesimal, but it could be induced by a fault
|
||||
// injection. In this case the signature (r,s) can be forged by taking
|
||||
// r := (t * Q).x mod n and s := r * t^-1 mod n for any t in [1, n-1].
|
||||
// We fail verification, because there is no guarantee that the
|
||||
// signature was created by the owner of the private key.
|
||||
result = 3;
|
||||
}
|
||||
}
|
||||
@ -370,8 +491,8 @@ int zkp_ecdsa_verify_digest(const ecdsa_curve *curve,
|
||||
if (result == 0) {
|
||||
(void)secp256k1_ecdsa_signature_normalize(
|
||||
context_read_only, &signature,
|
||||
&signature); // The return value inidicates whether the signature was
|
||||
// already normalized
|
||||
&signature); // The return value inidicates whether the signature
|
||||
// was already normalized
|
||||
|
||||
if (secp256k1_ecdsa_verify(context_read_only, &signature, digest,
|
||||
&public_key) != 1) {
|
||||
@ -515,8 +636,8 @@ ecdsa_tweak_pubkey_result zkp_ecdsa_tweak_pubkey(
|
||||
|
||||
if (secp256k1_ec_pubkey_tweak_add(context_writable, &public_key,
|
||||
tweak_bytes) != 1) {
|
||||
// The tweak is not less than the group order, or the resulting public key
|
||||
// is the point at infinity.
|
||||
// The tweak is not less than the group order, or the resulting public
|
||||
// key is the point at infinity.
|
||||
result = ECDSA_TWEAK_PUBKEY_INVALID_TWEAK_OR_RESULT_ERR;
|
||||
goto end;
|
||||
}
|
||||
|
@ -32,4 +32,14 @@ int zkp_ecdh_multiply(const ecdsa_curve *curve, const uint8_t *priv_key,
|
||||
ecdsa_tweak_pubkey_result zkp_ecdsa_tweak_pubkey(
|
||||
const ecdsa_curve *curve, const uint8_t *public_key_bytes,
|
||||
const uint8_t *tweak_bytes, uint8_t *tweaked_public_key_bytes);
|
||||
int zkp_ecdsa_anti_exfil_sign_digest(const ecdsa_curve *curve,
|
||||
const uint8_t *private_key_bytes,
|
||||
const uint8_t *digest,
|
||||
const uint8_t *entropy,
|
||||
uint8_t *signature_bytes);
|
||||
int zkp_ecdsa_anti_exfil_commit_nonce(const ecdsa_curve *curve,
|
||||
const uint8_t *private_key_bytes,
|
||||
const uint8_t *digest,
|
||||
const uint8_t *entropy_commitment,
|
||||
uint8_t *nonce_commitment);
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user