mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
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.
This commit is contained in:
parent
4caa6fad4c
commit
25b1a32ef8
@ -219,6 +219,41 @@ ed25519_public_key_from_curve25519_public_key(ed25519_public_key_t *pubkey,
|
||||
signbit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an ed25519 keypair in <b>inp</b>, generate a corresponding
|
||||
* ed25519 keypair in <b>out</b>, 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,
|
||||
|
@ -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
|
||||
|
||||
|
75
src/ext/ed25519/ref10/blinding.c
Normal file
75
src/ext/ed25519/ref10/blinding.c
Normal file
@ -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 <string.h>
|
||||
#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;
|
||||
}
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user