aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/crypto_ed25519.c58
-rw-r--r--src/common/crypto_ed25519.h9
-rw-r--r--src/ext/ed25519/ref10/ed25519_ref10.h5
-rw-r--r--src/ext/ed25519/ref10/keyconv.c37
-rw-r--r--src/ext/include.am3
-rw-r--r--src/test/test_crypto.c40
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