From 7fa0749fcb38839d7f41845e24d977744f4827cf Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sat, 23 Mar 2019 07:45:02 +0000 Subject: [PATCH] Generalise the Montgomery-curve DH support. This gets rid of the magic constants we apply to the top and bottom bytes of the random data to make the Curve25519 private DH value. Or rather, one of the magic constants is completely gone (we can infer it from curve->fieldBits), and the other is moved into the curve structure instead of being hardwired into the private-key-inventing function. With this change, it will be easy to add the similar Curve448 kex method, because it's now just a matter of adding the protocol names and curve constants. --- ssh.h | 1 + sshecc.c | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ssh.h b/ssh.h index e769e5f7..7e0b3606 100644 --- a/ssh.h +++ b/ssh.h @@ -451,6 +451,7 @@ struct ec_mcurve { MontgomeryCurve *mc; MontgomeryPoint *G; + unsigned log2_cofactor; }; /* Edwards form curve */ diff --git a/sshecc.c b/sshecc.c index 11c2ce07..2bbed6da 100644 --- a/sshecc.c +++ b/sshecc.c @@ -66,11 +66,12 @@ static void initialise_wcurve( static void initialise_mcurve( struct ec_curve *curve, mp_int *p, mp_int *a, mp_int *b, - mp_int *G_x) + mp_int *G_x, unsigned log2_cofactor) { initialise_common(curve, EC_MONTGOMERY, p); curve->m.mc = ecc_montgomery_curve(p, a, b); + curve->m.log2_cofactor = log2_cofactor; curve->m.G = ecc_montgomery_point_new(curve->m.mc, G_x); } @@ -194,7 +195,7 @@ static struct ec_curve *ec_curve25519(void) mp_int *a = MP_LITERAL(0x0000000000000000000000000000000000000000000000000000000000076d06); mp_int *b = MP_LITERAL(0x0000000000000000000000000000000000000000000000000000000000000001); mp_int *G_x = MP_LITERAL(0x0000000000000000000000000000000000000000000000000000000000000009); - initialise_mcurve(&curve, p, a, b, G_x); + initialise_mcurve(&curve, p, a, b, G_x, 3); mp_free(p); mp_free(a); mp_free(b); @@ -1283,10 +1284,17 @@ static void ssh_ecdhkex_m_setup(ecdh_key *dh) random_read(strbuf_append(bytes, dh->curve->fieldBytes), dh->curve->fieldBytes); - bytes->u[0] &= 0xF8; - bytes->u[bytes->len-1] &= 0x7F; - bytes->u[bytes->len-1] |= 0x40; dh->private = mp_from_bytes_le(ptrlen_from_strbuf(bytes)); + + /* Ensure the private key has the highest valid bit set, and no + * bits _above_ the highest valid one */ + mp_reduce_mod_2to(dh->private, dh->curve->fieldBits); + mp_set_bit(dh->private, dh->curve->fieldBits - 1, 1); + + /* Clear a curve-specific number of low bits */ + for (unsigned bit = 0; bit < dh->curve->m.log2_cofactor; bit++) + mp_set_bit(dh->private, bit, 0); + strbuf_free(bytes); dh->m_public = ecc_montgomery_multiply(dh->curve->m.G, dh->private);