diff options
-rw-r--r-- | src/common/crypto_ed25519.c | 58 | ||||
-rw-r--r-- | src/common/crypto_ed25519.h | 9 | ||||
-rw-r--r-- | src/ext/ed25519/ref10/ed25519_ref10.h | 5 | ||||
-rw-r--r-- | src/ext/ed25519/ref10/keyconv.c | 37 | ||||
-rw-r--r-- | src/ext/include.am | 3 | ||||
-rw-r--r-- | src/test/test_crypto.c | 40 |
6 files changed, 151 insertions, 1 deletions
diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c index b465b69d03..4c10c5ca01 100644 --- a/src/common/crypto_ed25519.c +++ b/src/common/crypto_ed25519.c @@ -17,6 +17,8 @@ #include "ed25519/ref10/ed25519_ref10.h" +#include <openssl/sha.h> + int ed25519_secret_key_generate(ed25519_secret_key_t *seckey_out, int extra_strong) @@ -161,6 +163,62 @@ ed25519_checksig_batch(int *okay_out, return res; } +/** + * Given a curve25519 keypair in <b>inp</b>, generate a corresponding + * ed25519 keypair in <b>out</b>, and set <b>signbit_out</b> to the + * sign bit of the X coordinate of the ed25519 key. + * + * NOTE THAT IT IS PROBABLY NOT SAFE TO USE THE GENERATED KEY FOR ANYTHING + * OUTSIDE OF WHAT'S PRESENTED IN PROPOSAL 228. In particular, it's probably + * not a great idea to use it to sign attacker-supplied anything. + */ +int +ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out, + int *signbit_out, + const curve25519_keypair_t *inp) +{ + const char string[] = "Derive high part of ed25519 key from curve25519 key"; + ed25519_public_key_t pubkey_check; + SHA512_CTX ctx; + uint8_t sha512_output[64]; + + memcpy(out->seckey.seckey, inp->seckey.secret_key, 32); + SHA512_Init(&ctx); + SHA512_Update(&ctx, out->seckey.seckey, 32); + SHA512_Update(&ctx, string, sizeof(string)); + SHA512_Final(sha512_output, &ctx); + memcpy(out->seckey.seckey + 32, sha512_output, 32); + + ed25519_public_key_generate(&out->pubkey, &out->seckey); + + *signbit_out = out->pubkey.pubkey[31] >> 7; + + ed25519_public_key_from_curve25519_public_key(&pubkey_check, &inp->pubkey, + *signbit_out); + + tor_assert(fast_memeq(pubkey_check.pubkey, out->pubkey.pubkey, 32)); + + memwipe(&pubkey_check, 0, sizeof(pubkey_check)); + memwipe(&ctx, 0, sizeof(ctx)); + memwipe(sha512_output, 0, sizeof(sha512_output)); + + return 0; +} + +/** + * Given a curve25519 public key and sign bit of X coordinate of the ed25519 + * public key, generate the corresponding ed25519 public key. + */ +int +ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey, + const curve25519_public_key_t *pubkey_in, + int signbit) +{ + return ed25519_ref10_pubkey_from_curve25519_pubkey(pubkey->pubkey, + pubkey_in->public_key, + signbit); +} + /** 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 f37dd5b770..82c5e6c6e3 100644 --- a/src/common/crypto_ed25519.h +++ b/src/common/crypto_ed25519.h @@ -67,6 +67,15 @@ typedef struct { int ed25519_checksig_batch(int *okay_out, const ed25519_checkable_t *checkable, int n_checkable); + +int ed25519_keypair_from_curve25519_keypair(ed25519_keypair_t *out, + int *signbit_out, + const curve25519_keypair_t *inp); + +int ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey, + const curve25519_public_key_t *pubkey_in, + int signbit); + #endif #define ED25519_BASE64_LEN 43 diff --git a/src/ext/ed25519/ref10/ed25519_ref10.h b/src/ext/ed25519/ref10/ed25519_ref10.h index cd0244f306..da8cea19f0 100644 --- a/src/ext/ed25519/ref10/ed25519_ref10.h +++ b/src/ext/ed25519/ref10/ed25519_ref10.h @@ -16,4 +16,9 @@ int ed25519_ref10_sign( const unsigned char *m,uint64_t mlen, const unsigned char *sk, const unsigned char *pk); +/* Added in Tor */ +int ed25519_ref10_pubkey_from_curve25519_pubkey(unsigned char *out, + const unsigned char *inp, + int signbit); + #endif diff --git a/src/ext/ed25519/ref10/keyconv.c b/src/ext/ed25519/ref10/keyconv.c new file mode 100644 index 0000000000..854b150d69 --- /dev/null +++ b/src/ext/ed25519/ref10/keyconv.c @@ -0,0 +1,37 @@ +/* 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 "ed25519_ref10.h" + +int ed25519_ref10_pubkey_from_curve25519_pubkey(unsigned char *out, + const unsigned char *inp, + int signbit) +{ + fe u; + fe one; + fe y; + fe uplus1; + fe uminus1; + fe inv_uplus1; + + /* From prop228: + + Given a curve25519 x-coordinate (u), we can get the y coordinate + of the ed25519 key using + + y = (u-1)/(u+1) + */ + fe_frombytes(u, inp); + fe_1(one); + fe_sub(uminus1, u, one); + fe_add(uplus1, u, one); + fe_invert(inv_uplus1, uplus1); + fe_mul(y, uminus1, inv_uplus1); + + fe_tobytes(out, y); + + /* propagate sign. */ + out[31] |= (!!signbit) << 7; + + return 0; +} diff --git a/src/ext/include.am b/src/ext/include.am index 69e7823583..45d7dc565a 100644 --- a/src/ext/include.am +++ b/src/ext/include.am @@ -56,7 +56,8 @@ src_ext_ed25519_ref10_libed25519_ref10_a_SOURCES= \ src/ext/ed25519/ref10/open.c \ src/ext/ed25519/ref10/sc_muladd.c \ src/ext/ed25519/ref10/sc_reduce.c \ - src/ext/ed25519/ref10/sign.c + src/ext/ed25519/ref10/sign.c \ + src/ext/ed25519/ref10/keyconv.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 5b2ce4508d..0ef5e42a15 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -1370,6 +1370,45 @@ test_crypto_ed25519_encode(void *arg) } static void +test_crypto_ed25519_convert(void *arg) +{ + const uint8_t msg[] = + "The eyes are not here / There are no eyes here."; + const int N = 30; + int i; + (void)arg; + + for (i = 0; i < N; ++i) { + curve25519_keypair_t curve25519_keypair; + ed25519_keypair_t ed25519_keypair; + ed25519_public_key_t ed25519_pubkey; + + int bit=0; + ed25519_signature_t sig; + + tt_int_op(0,==,curve25519_keypair_generate(&curve25519_keypair, i&1)); + tt_int_op(0,==,ed25519_keypair_from_curve25519_keypair( + &ed25519_keypair, &bit, &curve25519_keypair)); + tt_int_op(0,==,ed25519_public_key_from_curve25519_public_key( + &ed25519_pubkey, &curve25519_keypair.pubkey, bit)); + tt_mem_op(ed25519_pubkey.pubkey, ==, ed25519_keypair.pubkey.pubkey, 32); + + tt_int_op(0,==,ed25519_sign(&sig, msg, sizeof(msg), &ed25519_keypair)); + tt_int_op(0,==,ed25519_checksig(&sig, msg, sizeof(msg), + &ed25519_pubkey)); + + tt_int_op(-1,==,ed25519_checksig(&sig, msg, sizeof(msg)-1, + &ed25519_pubkey)); + sig.sig[0] ^= 15; + tt_int_op(-1,==,ed25519_checksig(&sig, msg, sizeof(msg), + &ed25519_pubkey)); + } + + done: + ; +} + +static void test_crypto_siphash(void *arg) { /* From the reference implementation, taking @@ -1509,6 +1548,7 @@ struct testcase_t crypto_tests[] = { { "ed25519_simple", test_crypto_ed25519_simple, 0, NULL, NULL }, { "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 }, #endif { "siphash", test_crypto_siphash, 0, NULL, NULL }, END_OF_TESTCASES |