From 25b1a32ef85c0b1d57a326991df002c86097a142 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 27 Aug 2014 17:59:15 -0400 Subject: [PATCH] Draft implementation for ed25519 key blinding, as in prop224 This implementation allows somebody to add a blinding factor to a secret key, and a corresponding blinding factor to the public key. Robert Ransom came up with this idea, I believe. Nick Hopper proved a scheme like this secure. The bugs are my own. --- src/common/crypto_ed25519.c | 35 +++++++++++++ src/common/crypto_ed25519.h | 7 ++- src/ext/ed25519/ref10/blinding.c | 75 +++++++++++++++++++++++++++ src/ext/ed25519/ref10/ed25519_ref10.h | 6 +++ src/ext/include.am | 3 +- src/test/test_crypto.c | 48 +++++++++++++++++ 6 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 src/ext/ed25519/ref10/blinding.c diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c index 4c10c5ca01..15fc626fa2 100644 --- a/src/common/crypto_ed25519.c +++ b/src/common/crypto_ed25519.c @@ -219,6 +219,41 @@ ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey, signbit); } +/** + * Given an ed25519 keypair in inp, generate a corresponding + * ed25519 keypair in out, blinded by the corresponding 32-byte input + * in 'param'. + * + */ +int +ed25519_keypair_blind(ed25519_keypair_t *out, + const ed25519_keypair_t *inp, + const uint8_t *param) +{ + ed25519_public_key_t pubkey_check; + + ed25519_ref10_derive_secret_key(out->seckey.seckey, + inp->seckey.seckey, param); + + ed25519_public_blind(&pubkey_check, &inp->pubkey, param); + ed25519_public_key_generate(&out->pubkey, &out->seckey); + + tor_assert(fast_memeq(pubkey_check.pubkey, out->pubkey.pubkey, 32)); + + memwipe(&pubkey_check, 0, sizeof(pubkey_check)); + + return 0; +} + +int +ed25519_public_blind(ed25519_public_key_t *out, + const ed25519_public_key_t *inp, + const uint8_t *param) +{ + ed25519_ref10_derive_public_key(out->pubkey, inp->pubkey, param); + return 0; +} + /** DOCDOC */ int ed25519_seckey_write_to_file(const ed25519_secret_key_t *seckey, diff --git a/src/common/crypto_ed25519.h b/src/common/crypto_ed25519.h index 82c5e6c6e3..1271312dfe 100644 --- a/src/common/crypto_ed25519.h +++ b/src/common/crypto_ed25519.h @@ -75,6 +75,12 @@ int ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out, int ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey, const curve25519_public_key_t *pubkey_in, int signbit); +int ed25519_keypair_blind(ed25519_keypair_t *out, + const ed25519_keypair_t *inp, + const uint8_t *param); +int ed25519_public_blind(ed25519_public_key_t *out, + const ed25519_public_key_t *inp, + const uint8_t *param); #endif @@ -100,6 +106,5 @@ int ed25519_pubkey_read_from_file(ed25519_public_key_t *pubkey_out, char **tag_out, const char *filename); - #endif diff --git a/src/ext/ed25519/ref10/blinding.c b/src/ext/ed25519/ref10/blinding.c new file mode 100644 index 0000000000..a17dbcd3e3 --- /dev/null +++ b/src/ext/ed25519/ref10/blinding.c @@ -0,0 +1,75 @@ +/* Added to ref10 for Tor. We place this in the public domain. Alternatively, + * you may have it under the Creative Commons 0 "CC0" license. */ +//#include "fe.h" +#include "ge.h" +#include "sc.h" +#include "crypto_hash_sha512.h" +#include "ed25519_ref10.h" + +#include +#include "crypto.h" + +static void +gettweak(unsigned char *out, const unsigned char *param) +{ + const char str[] = "Derive temporary signing key"; + crypto_hash_sha512_2(out, (const unsigned char*)str, strlen(str), param, 32); + out[0] &= 248; /* Necessary ? */ + out[31] &= 63; + out[31] |= 64; +} + +int ed25519_ref10_derive_secret_key(unsigned char *out, + const unsigned char *inp, + const unsigned char *param) +{ + const char str[] = "Derive temporary signing key hash input"; + unsigned char tweak[64]; + unsigned char zero[32]; + gettweak(tweak, param); + + memset(zero, 0, 32); + sc_muladd(out, inp, tweak, zero); + + crypto_hash_sha512_2(tweak, (const unsigned char *)str, strlen(str), + inp+32, 32); + memcpy(out+32, tweak, 32); + + memwipe(tweak, 0, sizeof(tweak)); + + return 0; +} + +int ed25519_ref10_derive_public_key(unsigned char *out, + const unsigned char *inp, + const unsigned char *param) +{ + unsigned char tweak[64]; + unsigned char zero[32]; + unsigned char pkcopy[32]; + ge_p3 A; + ge_p2 Aprime; + + gettweak(tweak, param); + + memset(zero, 0, sizeof(zero)); + /* Not the greatest implementation of all of this. I wish I had + * better-suited primitives to work with here... (but I don't wish that so + * strongly that I'm about to code my own ge_scalarmult_vartime). */ + + /* We negate the public key first, so that we can pass it to + * frombytes_negate_vartime, which negates it again. */ + memcpy(pkcopy, inp, 32); + pkcopy[31] ^= (1<<7); + ge_frombytes_negate_vartime(&A, pkcopy); + /* There isn't a regular ge_scalarmult -- we have to do tweak*A + zero*B. */ + ge_double_scalarmult_vartime(&Aprime, tweak, &A, zero); + ge_tobytes(out, &Aprime); + + memwipe(tweak, 0, sizeof(tweak)); + memwipe(&A, 0, sizeof(A)); + memwipe(&Aprime, 0, sizeof(Aprime)); + memwipe(&pkcopy, 0, sizeof(pkcopy)); + + return 0; +} diff --git a/src/ext/ed25519/ref10/ed25519_ref10.h b/src/ext/ed25519/ref10/ed25519_ref10.h index da8cea19f0..f4a76e621c 100644 --- a/src/ext/ed25519/ref10/ed25519_ref10.h +++ b/src/ext/ed25519/ref10/ed25519_ref10.h @@ -20,5 +20,11 @@ int ed25519_ref10_sign( int ed25519_ref10_pubkey_from_curve25519_pubkey(unsigned char *out, const unsigned char *inp, int signbit); +int ed25519_ref10_derive_secret_key(unsigned char *out, + const unsigned char *inp, + const unsigned char *param); +int ed25519_ref10_derive_public_key(unsigned char *out, + const unsigned char *inp, + const unsigned char *param); #endif diff --git a/src/ext/include.am b/src/ext/include.am index 45d7dc565a..69c136b184 100644 --- a/src/ext/include.am +++ b/src/ext/include.am @@ -57,7 +57,8 @@ src_ext_ed25519_ref10_libed25519_ref10_a_SOURCES= \ src/ext/ed25519/ref10/sc_muladd.c \ src/ext/ed25519/ref10/sc_reduce.c \ src/ext/ed25519/ref10/sign.c \ - src/ext/ed25519/ref10/keyconv.c + src/ext/ed25519/ref10/keyconv.c \ + src/ext/ed25519/ref10/blinding.c ED25519_REF10_HDRS = \ src/ext/ed25519/ref10/api.h \ diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index 0ef5e42a15..d4478d59dd 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -1408,6 +1408,53 @@ test_crypto_ed25519_convert(void *arg) ; } +static void +test_crypto_ed25519_blinding(void *arg) +{ + const uint8_t msg[] = + "Eyes I dare not meet in dreams / In death's dream kingdom"; + + const int N = 30; + int i; + (void)arg; + + for (i = 0; i < N; ++i) { + uint8_t blinding[32]; + ed25519_keypair_t ed25519_keypair; + ed25519_keypair_t ed25519_keypair_blinded; + ed25519_public_key_t ed25519_pubkey_blinded; + + ed25519_signature_t sig; + + crypto_rand((char*) blinding, sizeof(blinding)); + + tt_int_op(0,==,ed25519_keypair_generate(&ed25519_keypair, 0)); + tt_int_op(0,==,ed25519_keypair_blind(&ed25519_keypair_blinded, + &ed25519_keypair, blinding)); + + tt_int_op(0,==,ed25519_public_blind(&ed25519_pubkey_blinded, + &ed25519_keypair.pubkey, blinding)); + + tt_mem_op(ed25519_pubkey_blinded.pubkey, ==, + ed25519_keypair_blinded.pubkey.pubkey, 32); + + tt_int_op(0,==,ed25519_sign(&sig, msg, sizeof(msg), + &ed25519_keypair_blinded)); + + tt_int_op(0,==,ed25519_checksig(&sig, msg, sizeof(msg), + &ed25519_pubkey_blinded)); + + tt_int_op(-1,==,ed25519_checksig(&sig, msg, sizeof(msg)-1, + &ed25519_pubkey_blinded)); + sig.sig[0] ^= 15; + tt_int_op(-1,==,ed25519_checksig(&sig, msg, sizeof(msg), + &ed25519_pubkey_blinded)); + } + + done: + ; +} + static void test_crypto_siphash(void *arg) { @@ -1549,6 +1596,7 @@ struct testcase_t crypto_tests[] = { { "ed25519_test_vectors", test_crypto_ed25519_test_vectors, 0, NULL, NULL }, { "ed25519_encode", test_crypto_ed25519_encode, 0, NULL, NULL }, { "ed25519_convert", test_crypto_ed25519_convert, 0, NULL, NULL }, + { "ed25519_blinding", test_crypto_ed25519_blinding, 0, NULL, NULL }, #endif { "siphash", test_crypto_siphash, 0, NULL, NULL }, END_OF_TESTCASES