Hello all,
OpenSSL’s DH implementation uses an unnecessarily long exponent, leading to
significant performance loss
OpenSSL handles the Diffie Hellman (DH) protocol in a very conservative way. By
default, the length of the private key equals to the bit-length of the prime
modulus. For example, DH2048 will use a 2048-bit exponent (and two such
exponentiations are executed for a key exchange).
This is an overkill: NIST suggests that 224 bit exponent is sufficient for 112
bit security (which is what DH2048 offers).
There is no API to specify the exponent’ length when generating the key.
However, there is a parameter in the DH struct, which that defines the size of
the exponent:
struct dh_st
{
/* This first argument is used to pick up errors when
* a DH is passed instead of a EVP_PKEY */
int pad;
int version;
BIGNUM *p;
BIGNUM *g;
<****> long length; /* optional */
BIGNUM *pub_key; /* g^x */
BIGNUM *priv_key; /* x */
int flags;
BN_MONT_CTX *method_mont_p;
/* Place holders if we want to do X9.42 DH */
BIGNUM *q;
BIGNUM *j;
unsigned char *seed;
int seedlen;
BIGNUM *counter;
int references;
CRYPTO_EX_DATA ex_data;
const DH_METHOD *meth;
ENGINE *engine;
};
So, by *manually* changing the ‘length’ field, a user can control the exponent
length and reduce it to a more desirable size.
Unfortunately, users of the OpenSSL library, such as Apache (and it seems that
nginx also), are either unaware of the implementation’s default, or are not
aware of the performance impact of choosing such a long exponent (this leads to
~9X performance loss, compared to DH2048 with a 224 bits exponent).
This performance overhead is significant when moving to Perfect Forward
Security (PFS) protocols (e.g., RSA & DHE).
We should point out that the NSS library defaults to the NIST recommended
values --- here is a snippet.
/* Lengths are in bytes. */
static unsigned int
dh_GetSecretKeyLen(unsigned int primeLen)
{
/* Based on Table 2 in NIST SP 800-57. */
if (primeLen >= 1920) { /* 15360 bits */
return 64; /* 512 bits */
}
if (primeLen >= 960) { /* 7680 bits */
return 48; /* 384 bits */
}
if (primeLen >= 384) { /* 3072 bits */
return 32; /* 256 bits */
}
if (primeLen >= 256) { /* 2048 bits */
return 28; /* 224 bits */
}
return 20; /* 160 bits */
}
We would like to propose a way to alleviate what seems to be an unnecessary
overhead.
For OpenSSL, we recommend to *consider* the following:
Change the implementation to default the private key (exponent) to the NIST
recommended values. The change is very easy to carry out.
This way, the longer exponent would be the choice that is actively & explicitly
required by the user. Specify in the documentation what the default exponent
length is. Then, automatically have servers that use OpenSSL enjoy a much
faster DH speed on TLS sessions that use DH (for PFS).
For the server applications (e.g., Apache) that use OpenSSL library, we
recommend to *consider* the following:
Change the implementation so that it invokes the DH functions with the NIST
recommended key size. Especially, as browsers (e.g., using NSS) use 224 bit on
their side of the key exchange, anyway.
***************************************************************
Shay Gueron (1, 2), and Vlad Krasnov (1)
(1) Intel Corporation, Israel Development Center, Haifa, Israel
(2) University of Haifa, Israel
***************************************************************
Copyright(c) 2013, Intel Corp.
---------------------------------------------------------------------
Intel Israel (74) Limited
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List [email protected]
Automated List Manager [email protected]