mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Implement "curve448-sha512" kex, from RFC 8731.
With all the preparation now in place, this is more or less trivial. We add a new curve setup function in sshecc.c, and an ssh_kex linking to it; we add the curve parameters to the reference / test code eccref.py, and use them to generate the list of low-order input values that should be rejected by the sanity check on the kex output; we add the standard test vectors from RFC 7748 in cryptsuite.py, and the low-order values we just generated.
This commit is contained in:
parent
75e7ddea02
commit
31e5b621b5
1
ssh.h
1
ssh.h
@ -981,6 +981,7 @@ extern const ssh_kexes ssh_diffiehellman_gex;
|
||||
extern const ssh_kexes ssh_gssk5_sha1_kex;
|
||||
extern const ssh_kexes ssh_rsa_kex;
|
||||
extern const ssh_kex ssh_ec_kex_curve25519;
|
||||
extern const ssh_kex ssh_ec_kex_curve448;
|
||||
extern const ssh_kex ssh_ec_kex_nistp256;
|
||||
extern const ssh_kex ssh_ec_kex_nistp384;
|
||||
extern const ssh_kex ssh_ec_kex_nistp521;
|
||||
|
42
sshecc.c
42
sshecc.c
@ -213,6 +213,35 @@ static struct ec_curve *ec_curve25519(void)
|
||||
return &curve;
|
||||
}
|
||||
|
||||
static struct ec_curve *ec_curve448(void)
|
||||
{
|
||||
static struct ec_curve curve = { 0 };
|
||||
static bool initialised = false;
|
||||
|
||||
if (!initialised)
|
||||
{
|
||||
mp_int *p = MP_LITERAL(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
|
||||
mp_int *a = MP_LITERAL(0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000262a6);
|
||||
mp_int *b = MP_LITERAL(0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001);
|
||||
mp_int *G_x = MP_LITERAL(0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005);
|
||||
initialise_mcurve(&curve, p, a, b, G_x, 2);
|
||||
mp_free(p);
|
||||
mp_free(a);
|
||||
mp_free(b);
|
||||
mp_free(G_x);
|
||||
|
||||
/* 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 = true;
|
||||
}
|
||||
|
||||
return &curve;
|
||||
}
|
||||
|
||||
static struct ec_curve *ec_ed25519(void)
|
||||
{
|
||||
static struct ec_curve curve = { 0 };
|
||||
@ -1492,6 +1521,18 @@ const ssh_kex ssh_ec_kex_curve25519_libssh = {
|
||||
&ssh_sha256, &kex_extra_curve25519,
|
||||
};
|
||||
|
||||
static const struct eckex_extra kex_extra_curve448 = {
|
||||
ec_curve448,
|
||||
ssh_ecdhkex_m_setup,
|
||||
ssh_ecdhkex_m_cleanup,
|
||||
ssh_ecdhkex_m_getpublic,
|
||||
ssh_ecdhkex_m_getkey,
|
||||
};
|
||||
const ssh_kex ssh_ec_kex_curve448 = {
|
||||
"curve448-sha512", NULL, KEXTYPE_ECDH,
|
||||
&ssh_sha512, &kex_extra_curve448,
|
||||
};
|
||||
|
||||
static const struct eckex_extra kex_extra_nistp256 = {
|
||||
ec_p256,
|
||||
ssh_ecdhkex_w_setup,
|
||||
@ -1529,6 +1570,7 @@ const ssh_kex ssh_ec_kex_nistp521 = {
|
||||
};
|
||||
|
||||
static const ssh_kex *const ec_kex_list[] = {
|
||||
&ssh_ec_kex_curve448,
|
||||
&ssh_ec_kex_curve25519,
|
||||
&ssh_ec_kex_curve25519_libssh,
|
||||
&ssh_ec_kex_nistp256,
|
||||
|
@ -1565,11 +1565,35 @@ class crypt(MyTestBase):
|
||||
"eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
]
|
||||
|
||||
# Same for Curve448, found by the analogous eccref function call
|
||||
# find_montgomery_power2_order_x_values(curve448.p, curve448.a)
|
||||
bad_keys_448 = [
|
||||
# The first three are the bad values in canonical
|
||||
# representationm. In Curve448 these are just 0, 1 and -1.
|
||||
'0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||
'0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
|
||||
'fefffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||
|
||||
# As with Curve25519, we must also include values in
|
||||
# non-canonical representation that reduce to one of the
|
||||
# above mod p.
|
||||
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff',
|
||||
'00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
|
||||
|
||||
# But that's all, because Curve448 fits neatly into a
|
||||
# whole number of bytes, so there's no secondary reduction
|
||||
# mod a power of 2.
|
||||
]
|
||||
|
||||
with random_prng("doesn't matter"):
|
||||
ecdh25519 = ssh_ecdhkex_newkey('curve25519')
|
||||
ecdh448 = ssh_ecdhkex_newkey('curve448')
|
||||
for pub in bad_keys_25519:
|
||||
key = ssh_ecdhkex_getkey(ecdh25519, unhex(pub))
|
||||
self.assertEqual(key, None)
|
||||
for pub in bad_keys_448:
|
||||
key = ssh_ecdhkex_getkey(ecdh448, unhex(pub))
|
||||
self.assertEqual(key, None)
|
||||
|
||||
def testPRNG(self):
|
||||
hashalg = 'sha256'
|
||||
@ -2423,36 +2447,53 @@ class standard_test_vectors(MyTestBase):
|
||||
# string and peer public value, giving the expected output
|
||||
# shared key. Source: RFC 7748 section 5.2.
|
||||
rfc7748s5_2 = [
|
||||
('a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4',
|
||||
('curve25519',
|
||||
'a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4',
|
||||
'e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c',
|
||||
0xc3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552),
|
||||
('4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d',
|
||||
('curve25519',
|
||||
'4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d',
|
||||
'e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493',
|
||||
0x95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957),
|
||||
('curve448',
|
||||
'3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3',
|
||||
'06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086',
|
||||
0xce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f),
|
||||
('curve448',
|
||||
'203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f',
|
||||
'0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db',
|
||||
0x884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d),
|
||||
]
|
||||
|
||||
for priv, pub, expected in rfc7748s5_2:
|
||||
for method, priv, pub, expected in rfc7748s5_2:
|
||||
with queued_specific_random_data(unhex(priv)):
|
||||
ecdh = ssh_ecdhkex_newkey('curve25519')
|
||||
ecdh = ssh_ecdhkex_newkey(method)
|
||||
key = ssh_ecdhkex_getkey(ecdh, unhex(pub))
|
||||
self.assertEqual(int(key), expected)
|
||||
|
||||
# Bidirectional tests, consisting of the input random number
|
||||
# strings for both parties, and the expected public values and
|
||||
# shared key. Source: RFC 7748 section 6.1.
|
||||
rfc7748s6_1 = [
|
||||
('77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a',
|
||||
# shared key. Source: RFC 7748 section 6.
|
||||
rfc7748s6 = [
|
||||
('curve25519', # section 6.1
|
||||
'77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a',
|
||||
'8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a',
|
||||
'5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb',
|
||||
'de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f',
|
||||
0x4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742),
|
||||
('curve448', # section 6.2
|
||||
'9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b',
|
||||
'9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0',
|
||||
'1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d',
|
||||
'3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609',
|
||||
0x07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d),
|
||||
]
|
||||
|
||||
for apriv, apub, bpriv, bpub, expected in rfc7748s6_1:
|
||||
for method, apriv, apub, bpriv, bpub, expected in rfc7748s6:
|
||||
with queued_specific_random_data(unhex(apriv)):
|
||||
alice = ssh_ecdhkex_newkey('curve25519')
|
||||
alice = ssh_ecdhkex_newkey(method)
|
||||
with queued_specific_random_data(unhex(bpriv)):
|
||||
bob = ssh_ecdhkex_newkey('curve25519')
|
||||
bob = ssh_ecdhkex_newkey(method)
|
||||
self.assertEqualBin(ssh_ecdhkex_getpublic(alice), unhex(apub))
|
||||
self.assertEqualBin(ssh_ecdhkex_getpublic(bob), unhex(bpub))
|
||||
akey = ssh_ecdhkex_getkey(alice, unhex(bpub))
|
||||
|
@ -316,6 +316,9 @@ p521.G_order = 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
curve25519 = MontgomeryCurve(2**255-19, 0x76d06, 1)
|
||||
curve25519.G = curve25519.cpoint(9)
|
||||
|
||||
curve448 = MontgomeryCurve(2**448-2**224-1, 0x262a6, 1)
|
||||
curve448.G = curve448.cpoint(5)
|
||||
|
||||
ed25519 = TwistedEdwardsCurve(2**255-19, 0x52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3, -1)
|
||||
ed25519.G = ed25519.point(0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a,0x6666666666666666666666666666666666666666666666666666666666666658)
|
||||
ed25519.G_order = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
|
||||
|
@ -340,6 +340,7 @@ static const ssh_kex *get_ecdh_alg(BinarySource *in)
|
||||
const ssh_kex *value;
|
||||
} algs[] = {
|
||||
{"curve25519", &ssh_ec_kex_curve25519},
|
||||
{"curve448", &ssh_ec_kex_curve448},
|
||||
{"nistp256", &ssh_ec_kex_nistp256},
|
||||
{"nistp384", &ssh_ec_kex_nistp384},
|
||||
{"nistp521", &ssh_ec_kex_nistp521},
|
||||
|
Loading…
Reference in New Issue
Block a user