[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [tor-dev] Action items wrt ed25519 onion address verification in prop224 (was Re: [tor-project] Network team meetings notes from 17 April 2017)



On Tue, Apr 25, 2017 at 03:38:37PM +0300, George Kadianakis wrote:
> > It turns out the point whose packed representation is 32 bytes of 0x00
> > is a torsion point; it is the point (-1,0).
> >
> > Indeed, these are the 7 pure torsion points in ed25519:
> >
> > 26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05
> > 0000000000000000000000000000000000000000000000000000000000000000 =(-1,0)
> > c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a
> > ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f =(0,-1)
> > c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa
> > 0000000000000000000000000000000000000000000000000000000000000080 =(1,0)
> > 26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85
> >
> > So just take any of the above points, and add it to a valid pubkey to
> > get an invalid pubkey.
> >
> > You should probably also check points not on the curve at all, such as:
> >
> > e19c65de75c68cf3b7643ea732ba9eb1a3d20d6d57ba223c2ece1df66feb5af0
> >
> > If you generate a 32-byte string at random, about 1/2 the time it won't
> > be on the curve at all (that is, if P is the unpack of those 32 bytes,
> > 8*l*P is *not* the identity), about 7/16 of the time it is on the curve,
> > but has a torsion component (8*l*P is the identity, but l*P is not), and
> > 1/16 of the time it's a valid pubkey (l*P is the identity, but P is
> > not).
> >
> 
> Good stuff Ian.
> 
> I pushed a new branch `bug22006` that:
> - Checks that the pubkey is not the identity element itself.
> - Adds tests based on the points you listed above.
> 
> Check it out here:
>          https://gitweb.torproject.org/user/asn/tor.git/log/?h=bug22006_v2

It looks to me as though you're only checking the pure torsion points
above.  You should *add* one of those points to a valid pubkey in order
to get a point to check.  For example, the points:

300ef2e64e588e1df55b48e4da0416ffb64cc85d5b00af6463d5cc6c2b1c185e
f43e3a046db8749164c6e69b193f1e942c7452e7d888736f40b98093d814d5e7
c9fff3af0471c28e33e98c2043e44f779d0427b1e37c521a6bddc011ed1869af

would be good additional tests (all should fail; they have order 8l, 4l,
2l respectively).

This one should pass:

4ba2e44760dff4c559ef3c38768c1c14a8a54740c782c8d70803e9d6e3ad8794

> Another thing:
> 
> My understanding is that this is a special-case validation and it's
> expensive,

It's a single scalar multiplication (and packing, I suppose).  I guess
"expensive" is relative; you might time it to see if the cost matters to
you.

> so I opted to not perform it everytime we generate a new
> ed25519 keypair or when we receive one from the internet. So for
> example, I'm not doing it when we extract the ed25519 signing pubkey
> that signs the HS descriptor, since we don't care if there are
> equivalent forms of that key.

You indeed don't need to do it when you generate a key yourself in a
known-good way (unless you're paranoid about fault attacks, which I
don't think you are).  I'm a little wary about ever not doing it on a
pubkey you receive from the Internet, though.  I would want to know if
someone were sending me a malformed crypto-relevant value.

> So this validation function is currently unused, and I plan to only use it
> on the prop224 client-side when a client handles received onion addresses.
> 
> Finally, how did you derive the list of points above? o.o

Attached.

   - Ian
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <openssl/sha.h>
#include "ed25519-donna.h"

static void dump_point(const char *label, const ge25519 *p)
{
    unsigned char packed[32];
    int i;

    if (label) {
	printf("%s ", label);
    }

    ge25519_pack(packed, p);
    for (i=0;i<32;++i) {
	printf("%02x", packed[i]);
    }
    printf("\n");
}

static void dump_multiples(const ge25519 *p)
{
    ge25519 kp;
    bignum256modm k = {0};
    bignum256modm zero = {0};
    char label[7] = "*  l =";
    int i;

    for (i=1;i<=8;++i) {
	k[0] = i;
	ge25519_double_scalarmult_vartime(&kp, p, k, zero);
	label[2] = '0'+i;
	dump_point(label, &kp);
    }
    printf("\n");
}

static void randpoint(char *randstate, ge25519 *p)
{
    unsigned char hash[64];
    SHA512(randstate, 32, hash);
    ge25519_unpack_negative_vartime(p, hash);
    memmove(randstate, hash+32, 32);
}

int main(int argc, char **argv)
{
    unsigned char randstate[32];
    ge25519 p, mp;
    bignum256modm zero = {0};

    int rfd = open("/dev/urandom", O_RDONLY);
    if (rfd < 0) {
	perror("open /dev/urandom");
	exit(1);
    }
    if (read(rfd, randstate, 32) < 32) {
	perror("read /dev/urandom");
	exit(1);
    }
    close(rfd);

    while(1) {
	randpoint(randstate, &p);

	dump_point("Orig =", &p);
	// Multiply by the group order
	ge25519_double_scalarmult_vartime(&mp, &p, modm_m, zero);
	dump_multiples(&mp);
    }

    return 0;
}
_______________________________________________
tor-dev mailing list
tor-dev@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-dev