[tor-commits] [tor/master] Add curve25519->ed25519 key conversion per proposal 228

nickm at torproject.org nickm at torproject.org
Thu Sep 25 19:12:41 UTC 2014


commit 4caa6fad4c71391ab41e92a32aa58b10b6febe7f
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Aug 27 00:18:26 2014 -0400

    Add curve25519->ed25519 key conversion per proposal 228
    
    For proposal 228, we need to cross-certify our identity with our
    curve25519 key, so that we can prove at descriptor-generation time
    that we own that key.  But how can we sign something with a key that
    is only for doing Diffie-Hellman?  By converting it to the
    corresponding ed25519 point.
    
    See the ALL-CAPS warning in the documentation.  According to djb
    (IIUC), it is safe to use these keys in the ways that ntor and prop228
    are using them, but it might not be safe if we start providing crazy
    oracle access.
    
    (Unit tests included.  What kind of a monster do you take me for?)
---
 src/common/crypto_ed25519.c           |   58 +++++++++++++++++++++++++++++++++
 src/common/crypto_ed25519.h           |    9 +++++
 src/ext/ed25519/ref10/ed25519_ref10.h |    5 +++
 src/ext/ed25519/ref10/keyconv.c       |   37 +++++++++++++++++++++
 src/ext/include.am                    |    3 +-
 src/test/test_crypto.c                |   40 +++++++++++++++++++++++
 6 files changed, 151 insertions(+), 1 deletion(-)

diff --git a/src/common/crypto_ed25519.c b/src/common/crypto_ed25519.c
index b465b69..4c10c5c 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 f37dd5b..82c5e6c 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 cd0244f..da8cea1 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 0000000..854b150
--- /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 69e7823..45d7dc5 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 5b2ce45..0ef5e42 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





More information about the tor-commits mailing list