]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Add curve25519->ed25519 key conversion per proposal 228
authorNick Mathewson <nickm@torproject.org>
Wed, 27 Aug 2014 04:18:26 +0000 (00:18 -0400)
committerNick Mathewson <nickm@torproject.org>
Thu, 25 Sep 2014 19:08:31 +0000 (15:08 -0400)
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
src/common/crypto_ed25519.h
src/ext/ed25519/ref10/ed25519_ref10.h
src/ext/ed25519/ref10/keyconv.c [new file with mode: 0644]
src/ext/include.am
src/test/test_crypto.c

index b465b69d03279a762f007c1b70344277bd00db23..4c10c5ca0123a04e162b8702756e76f47609db88 100644 (file)
@@ -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,
index f37dd5b770576b80e9a30d1bd918523a1f4d51e5..82c5e6c6e377e4e4eb1174dd6c718b3206cdd8e7 100644 (file)
@@ -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
index cd0244f306ad1f4b89fd9700d20ff3c9eb5b4752..da8cea19f0f29367bda09e873aabcf1d6f5399af 100644 (file)
@@ -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 (file)
index 0000000..854b150
--- /dev/null
@@ -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;
+}
index 69e7823583eee4f671cbce0ad1a3bfb45d3df006..45d7dc565ae3ec866cd2d3ab6d3d64b30f957889 100644 (file)
@@ -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 \
index 5b2ce4508d06da36992acc7bf6f9e636a5837b7a..0ef5e42a15be55b31136f48e243e637d3dfc2afa 100644 (file)
@@ -1369,6 +1369,45 @@ test_crypto_ed25519_encode(void *arg)
   tor_free(mem_op_hex_tmp);
 }
 
+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)
 {
@@ -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