1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Stop using short exponents for Diffie-Hellman.

I recently encountered a paper [1] which catalogues all kinds of
things that can go wrong when one party in a discrete-log system
invents a prime and the other party chooses an exponent. In
particular, some choices of prime make it reasonable to use a short
exponent to save time, but others make that strategy very bad.

That paper is about the ElGamal encryption scheme used in OpenPGP,
which is basically integer Diffie-Hellman with one side's key being
persistent: a shared-secret integer is derived exactly as in DH, and
then it's used to communicate a message integer by simply multiplying
the shared secret by the message, mod p.

I don't _know_ that any problem of this kind arises in the SSH usage
of Diffie-Hellman: the standard integer DH groups in SSH are safe
primes, and as far as I know, the usual generation of prime moduli for
DH group exchange also picks safe primes. So the short exponents PuTTY
has been using _should_ be OK.

However, the range of imaginative other possibilities shown in that
paper make me nervous, even so! So I think I'm going to retire the
short exponent strategy, on general principles of overcaution.

This slows down 4096-bit integer DH by about a factor of 3-4 (which
would be worse if it weren't for the modpow speedup in the previous
commit). I think that's OK, because, firstly, computers are a lot
faster these days than when I originally chose to use short exponents,
and secondly, more and more implementations are now switching to
elliptic-curve DH, which is unaffected by this change (and with which
we've always been using maximum-length exponents).

[1] On the (in)security of ElGamal in OpenPGP. Luca De Feo, Bertram
Poettering, Alessandro Sorniotti. https://eprint.iacr.org/2021/923
This commit is contained in:
Simon Tatham 2021-11-28 12:10:42 +00:00
parent 46fbe375bf
commit cd60a602f5
5 changed files with 6 additions and 23 deletions

View File

@ -200,19 +200,8 @@ void dh_cleanup(dh_ctx *ctx)
/*
* DH stage 1: invent a number x between 1 and q, and compute e =
* g^x mod p. Return e.
*
* If `nbits' is greater than zero, it is used as an upper limit
* for the number of bits in x. This is safe provided that (a) you
* use twice as many bits in x as the number of bits you expect to
* use in your session key, and (b) the DH group is a safe prime
* (which SSH demands that it must be).
*
* P. C. van Oorschot, M. J. Wiener
* "On Diffie-Hellman Key Agreement with Short Exponents".
* Advances in Cryptology: Proceedings of Eurocrypt '96
* Springer-Verlag, May 1996.
*/
mp_int *dh_create_e(dh_ctx *ctx, int nbits)
mp_int *dh_create_e(dh_ctx *ctx)
{
/*
* Lower limit is just 2.
@ -224,12 +213,6 @@ mp_int *dh_create_e(dh_ctx *ctx, int nbits)
*/
mp_int *hi = mp_copy(ctx->q);
mp_sub_integer_into(hi, hi, 1);
if (nbits) {
mp_int *pow2 = mp_power_2(nbits+1);
mp_min_into(pow2, pow2, hi);
mp_free(hi);
hi = pow2;
}
/*
* Make a random number in that range.

2
ssh.h
View File

@ -1223,7 +1223,7 @@ dh_ctx *dh_setup_group(const ssh_kex *kex);
dh_ctx *dh_setup_gex(mp_int *pval, mp_int *gval);
int dh_modulus_bit_size(const dh_ctx *ctx);
void dh_cleanup(dh_ctx *);
mp_int *dh_create_e(dh_ctx *, int nbits);
mp_int *dh_create_e(dh_ctx *);
const char *dh_validate_f(dh_ctx *, mp_int *f);
mp_int *dh_find_K(dh_ctx *, mp_int *f);

View File

@ -118,7 +118,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
* Now generate and send e for Diffie-Hellman.
*/
seat_set_busy_status(s->ppl.seat, BUSY_CPU);
s->e = dh_create_e(s->dh_ctx, s->nbits * 2);
s->e = dh_create_e(s->dh_ctx);
pktout = ssh_bpp_new_pktout(s->ppl.bpp, s->kex_init_value);
put_mp_ssh2(pktout, s->e);
pq_push(s->ppl.out_pq, pktout);
@ -322,7 +322,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
"exchange with hash %s", ssh_hash_alg(s->exhash)->text_name);
/* Now generate e for Diffie-Hellman. */
seat_set_busy_status(s->ppl.seat, BUSY_CPU);
s->e = dh_create_e(s->dh_ctx, s->nbits * 2);
s->e = dh_create_e(s->dh_ctx);
if (s->shgss->lib->gsslogmsg)
ppl_logevent("%s", s->shgss->lib->gsslogmsg);

View File

@ -128,7 +128,7 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted)
/*
* Generate e for Diffie-Hellman.
*/
s->e = dh_create_e(s->dh_ctx, s->nbits * 2);
s->e = dh_create_e(s->dh_ctx);
/*
* Wait to receive f.

View File

@ -339,7 +339,7 @@ FUNC_WRAPPED(val_string, ssh_cipher_decrypt_length, ARG(val_cipher, c),
FUNC(val_dh, dh_setup_group, ARG(dh_group, group))
FUNC(val_dh, dh_setup_gex, ARG(val_mpint, p), ARG(val_mpint, g))
FUNC(uint, dh_modulus_bit_size, ARG(val_dh, ctx))
FUNC(val_mpint, dh_create_e, ARG(val_dh, ctx), ARG(uint, nbits))
FUNC(val_mpint, dh_create_e, ARG(val_dh, ctx))
FUNC_WRAPPED(boolean, dh_validate_f, ARG(val_dh, ctx), ARG(val_mpint, f))
FUNC(val_mpint, dh_find_K, ARG(val_dh, ctx), ARG(val_mpint, f))