[TOC]
The digital signature algorithm (DSA) is one of three signature schemes descripted in the digital signature standard [FIPS-186-4].
4.2 Selection of Parameter Sizes and Hash Functions for DSA The DSS specifies the following choices for the pair (L,N), where L is the size of p in bits and N is the size of q in bits:
L | N |
---|---|
1024 | 160 |
2048 | 224 |
2048 | 256 |
3072 | 256 |
The tests expect the following properties of the parameters used during key generation:
- If only the parameter L is specified by the caller then N should be one of the options proposed in [FIPS-186-4].
- If no size is specified then L should be at least 2048. This is the minimal key size recommended by NIST for the period up to the year 2030.
The DSA signature algorithm requires that each signature is computed with a new one-time secret k. This secret value should be close to uniformly distributed. If that is not the case then DSA signatures can leak the private key that was used to generate the signature. Two methods for generating the one-time secrets are described in FIPS PUB 186-4, Section B.5.1 or B.5.2 [FIPS-186-4]. There is also the possibility that the use of mismatched implementations for key generation and signature generation are leaking the private keys.
A DSA signature is a DER encoded tuple of two integers (r,s). To verify a
signature the verifier first checks
The verifier then computes:
and then verifies that
Some libraries return 0 as the modular inverse of 0 or q. This can happen if the
library computes the modular inverse of s as
TBD
The jdk8 implementation of SHA1withDSA previously checked the key size as follows:
@Override
protected void checkKey(DSAParams params)
throws InvalidKeyException {
int valueL = params.getP().bitLength();
if (valueL > 1024) {
throw new InvalidKeyException("Key is too long for this algorithm");
}
}
This check was reasonable, it partially ensures conformance with the NIST standard. In most cases would prevent the attack described above.
However, Oracle released a patch that removed the length verification in DSA in jdk9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/edd7a67585a5 https://bugs.openjdk.java.net/browse/JDK-8039921
The new code is here: http://hg.openjdk.java.net/jdk9/dev/jdk/file/edd7a67585a5/src/java.base/share/classes/sun/security/provider/DSA.java
The change was further backported to jdk8: http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/3212f1631643
Doing this was a serious mistake. It easily allowed incorrect implementations. While generating 2048 bit DSA keys in jdk7 was not yet supported, doing so in jdk8 is. To trigger this bug in jdk7 an application had to use a key generated by a third party library (e.g. OpenSSL). Now, it is possible to trigger the bug just using JCE. Moreover, the excessive use of default values in JCE makes it easy to go wrong and rather difficult to spot the errors.
The bug was for example triggered by the following code snippet:
KeyPairGenerator keygen = KeyPairGenerator.getInstance("DSA");
Keygen.initialize(2048);
KeyPair keypair = keygen.genKeyPair();
Signature s = Signature.getInstance("DSA");
s.initSign(keypair.getPrivate());
The first three lines generate a 2048 bit DSA key. 2048 bits is currently the smallest key size recommended by NIST.
KeyPairGenerator keygen = KeyPairGenerator.getInstance("DSA");
Keygen.initialize(2048);
KeyPair keypair = keygen.genKeyPair();
The key size specifies the size of p but not the size of q. The NIST standard allows either 224 or 256 bits for the size of q. The selection typically depends on the library. The Sun provider uses 224. Other libraries e.g. OpenSSL generates by default a 256 bit q for 2048 bit DSA keys.
The next line contains a default in the initialization
Signature s = Signature.getInstance("DSA");
This line is equivalent to
Signature s = Signature.getInstance("SHA1withDSA");
Hence the code above uses SHA1 but with DSA parameters generated for SHA-224 or SHA-256 hashes. Allowing this combination by itself is already a mistake, but a flawed implementation made the situation even worse.
The implementation of SHA1withDSA assumeed that the parameter q is 160 bits long and used this assumption to generate a random 160-bit k when generating a signature instead of choosing it uniformly in the range (1,q-1). Hence, k severely biased. Attacks against DSA with biased k are well known. Howgrave-Graham and Smart analyzed such a situation [HowSma99]. Their results show that about 4 signatrues leak enough information to determine the private key in a few milliseconds. Nguyen analyzed a similar flaw in GPG [Nguyen04]. I.e., Section 3.2 of Nguyens paper describes essentially the same attack as used here. More generally, attacks based on lattice reduction were developed to break a variety of cryptosystems such as the knapsack cryptosystem [Odlyzko90].
The short algorithm name “DSA” is misleading, since it hides the fact that
Signature.getInstance(“DSA”)
is equivalent to
Signature.getInstance(“SHA1withDSA”)
. To reduce the chance of a
misunderstanding short algorithm names should be deprecated. In JCE the hash
algorithm is defined by the algorithm. I.e. depending on the hash algorithm to
use one would call one of:
Signature.getInstance(“SHA1withDSA”);
Signature.getInstance(“SHA224withDSA”);
Signature.getInstance(“SHA256withDSA”);
A possible way to push such a change are code analysis tools. "DSA" is in good company with other algorithm names “RSA”, “AES”, “DES”, all of which default to weak algorithms.