]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Implement "curve448-sha512" kex, from draft-ietf-curdle-ssh-curves-00. experimental-curve448
authorSimon Tatham <anakin@pobox.com>
Tue, 3 May 2016 14:26:36 +0000 (15:26 +0100)
committerSimon Tatham <anakin@pobox.com>
Tue, 3 May 2016 14:36:05 +0000 (15:36 +0100)
I've demonstrated by diagnostic printfs that this passes the single
Curve448 test vector given in section 6.2 of RFC 7748, but it is
otherwise NOT INTEROPERABILITY-TESTED AT ALL.

Also, its protocol identifier is not domain-suffixed despite not being
in a published RFC (yet). So this implementation is strictly
preliminary, and intended only for other SSH implementors to
interop-test against.

sshecc.c

index 3bb2082b6e4423bc2342429e8e0912912f35b5d0..5d8b08c87d411d29d556b021d0ec956a6820d5b6 100644 (file)
--- a/sshecc.c
+++ b/sshecc.c
@@ -365,6 +365,63 @@ static struct ec_curve *ec_curve25519(void)
     return &curve;
 }
 
+static struct ec_curve *ec_curve448(void)
+{
+    static struct ec_curve curve = { 0 };
+    static unsigned char initialised = 0;
+
+    if (!initialised)
+    {
+        static const unsigned char p[56] = {
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+            0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        };
+        static const unsigned char a[56] = {
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x62, 0xa6,
+        };
+        static const unsigned char b[56] = {
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+        };
+        static const unsigned char gx[56] = {
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
+        };
+
+        initialise_mcurve(&curve, 448, p, a, b, gx);
+        /* This curve doesn't need a name, because it's never used in
+         * any format that embeds the curve name */
+        curve.name = NULL;
+        curve.textname = "Curve448";
+
+        /* Now initialised, no need to do it again */
+        initialised = 1;
+    }
+
+    return &curve;
+}
+
 static struct ec_curve *ec_ed25519(void)
 {
     static struct ec_curve curve = { 0 };
@@ -2684,6 +2741,7 @@ const struct ssh_signkey ssh_ecdsa_nistp521 = {
 
 struct eckex_extra {
     struct ec_curve *(*curve)(void);
+    int low_byte_mask, high_byte_top_bit;
 };
 
 static Bignum ecdh_calculate(const Bignum private,
@@ -2750,18 +2808,21 @@ void *ssh_ecdhkex_newkey(const struct ssh_kex *kex)
     key->publicKey.curve = curve;
 
     if (curve->type == EC_MONTGOMERY) {
-        unsigned char bytes[32] = {0};
+        int nbytes = (curve->fieldBits+7) / 8;
+        unsigned char bytes[56] = {0};
         int i;
 
-        for (i = 0; i < sizeof(bytes); ++i)
+        assert(nbytes <= lenof(bytes));
+
+        for (i = 0; i < nbytes; ++i)
         {
             bytes[i] = (unsigned char)random_byte();
         }
-        bytes[0] &= 248;
-        bytes[31] &= 127;
-        bytes[31] |= 64;
-        key->privateKey = bignum_from_bytes_le(bytes, sizeof(bytes));
-        smemclr(bytes, sizeof(bytes));
+        bytes[0] &= extra->low_byte_mask;
+        bytes[nbytes-1] &= extra->high_byte_top_bit - 1;
+        bytes[nbytes-1] |= extra->high_byte_top_bit;
+        key->privateKey = bignum_from_bytes_le(bytes, nbytes);
+        smemclr(bytes, nbytes);
         if (!key->privateKey) {
             sfree(key);
             return NULL;
@@ -2866,12 +2927,22 @@ void ssh_ecdhkex_freekey(void *key)
     ecdsa_freekey(key);
 }
 
-static const struct eckex_extra kex_extra_curve25519 = { ec_curve25519 };
+static const struct eckex_extra kex_extra_curve25519 = {
+    ec_curve25519, 0xF8, 0x40,
+};
 static const struct ssh_kex ssh_ec_kex_curve25519 = {
     "curve25519-sha256@libssh.org", NULL, KEXTYPE_ECDH,
     &ssh_sha256, &kex_extra_curve25519,
 };
 
+static const struct eckex_extra kex_extra_curve448 = {
+    ec_curve448, 0xFC, 0x80,
+};
+static const struct ssh_kex ssh_ec_kex_curve448 = {
+    "curve448-sha512", NULL, KEXTYPE_ECDH,
+    &ssh_sha512, &kex_extra_curve448,
+};
+
 const struct eckex_extra kex_extra_nistp256 = { ec_p256 };
 static const struct ssh_kex ssh_ec_kex_nistp256 = {
     "ecdh-sha2-nistp256", NULL, KEXTYPE_ECDH,
@@ -2891,6 +2962,7 @@ static const struct ssh_kex ssh_ec_kex_nistp521 = {
 };
 
 static const struct ssh_kex *const ec_kex_list[] = {
+    &ssh_ec_kex_curve448,
     &ssh_ec_kex_curve25519,
     &ssh_ec_kex_nistp256,
     &ssh_ec_kex_nistp384,