JEP 497: Quantum-Resistant Module-Lattice-Based Digital Signature Algorithm

OwnerWeijun Wang
TypeFeature
ScopeSE
StatusProposed to Target
Release24
Componentsecurity-libs / java.security
Discussionsecurity dash dev at openjdk dot org
EffortM
DurationM
Reviewed bySean Mullan
Endorsed byAlan Bateman, Sean Mullan
Created2024/08/26 18:34
Updated2024/11/14 14:11
Issue8339010

Summary

Enhance the security of Java applications by providing an implementation of the quantum-resistant Module-Lattice-Based Digital Signature Algorithm (ML-DSA). Digital signatures are used to detect unauthorized modifications to data and to authenticate the identity of signatories. ML-DSA is designed to be secure against future quantum computing attacks. It has been standardized by the United States National Institute of Standards and Technology (NIST) in FIPS 204.

Goals

Non Goals

Motivation

The field of quantum computing has been advancing steadily for years. A future large-scale quantum computer could use Shor’s algorithm, which is capable of factoring integers and solving the discrete logarithm problem, to compromise the security of widely-deployed public-key based algorithms including Rivest-Shamir-Adleman (RSA) and Diffie-Hellman. Such algorithms are used by the Java Platform to, among other things, digitally sign JAR files and establish secure network connections via the Transport Layer Security (TLS) protocol. An attack that a conventional supercomputer might need thousands to millions of years to complete could be accomplished by a quantum computer using Shor's algorithm in mere hours. Cryptographers have responded to this threat by inventing quantum-resistant cryptographic algorithms, which cannot be defeated by Shor's algorithm.

For the purposes of signing data and authenticating identities in a quantum-resistant fashion, NIST standardized the Module-Lattice-Based Digital Signature Algorithm (ML-DSA) in FIPS 204. In the United States, government computer systems that handle sensitive information must be upgraded over the next decade to use ML-DSA. It is thus essential for the Java Platform to provide an implementation of this algorithm.

Description

We will provide ML-DSA implementations of the KeyPairGenerator API to generate ML-DSA key pairs, of the Signature API to sign and verify ML-DSA signatures, and of the KeyFactory API to convert ML-DSA keys to and from their encodings.

In the Java Security Standard Algorithm Names Specification, we will define a new standard algorithm family name, "ML-DSA", for the KeyPairGenerator, Signature, and KeyFactory APIs.

FIPS 204 specifies three parameter sets for ML-DSA. In order of increasing security strength and decreasing performance, they are named "ML-DSA-44", "ML-DSA-65", and "ML-DSA-87". These parameter-set names will also be defined as standard algorithm names for the KeyPairGenerator, Signature, and KeyFactory APIs, and, further, will be represented by the new NamedParameterSpec constants ML_DSA_44, ML_DSA_65, and ML_DSA_87.

Generating ML-DSA key pairs

You can generate an ML-DSA key pair in one of three ways:

The KeyPairGenerator API allows an integer key size to be specified during initialization, but this is not supported for ML-DSA key pairs and will cause an InvalidParameterException to be thrown.

The keytool command will support generating ML-DSA key pairs and certificates. For example:

$ keytool -keystore ks -storepass changeit -genkeypair -alias mldsa \
          -keyalg ML-DSA -groupname ML-DSA-65 -dname CN=ML-DSA

You can also provide the parameter-set name, ML-DSA-65, directly via the -keyalg option:

$ keytool -keystore ks -storepass changeit -genkeypair -alias mldsa \
          -keyalg ML-DSA-65 -dname CN=ML-DSA2

Signing with ML-DSA keys

You can use the ML-DSA Signature implementation to sign and verify ML-DSA signatures.

For example, to sign a message using a private key:

byte[] msg = ...;
Signature ss = Signature.getInstance("ML-DSA");
ss.initSign(privateKey);
ss.update(msg);
byte[] sig = ss.sign();

To verify a signature with a public key:

byte[] msg = ...;
byte[] sig = ...;
Signature sv = Signature.getInstance("ML-DSA");
sv.initVerify(publicKey);
sv.update(msg);
boolean verified = sv.verify(sig);

If a Signature object is instantiated with a family name, it accepts ML-DSA keys in the family with any parameter set. If it is instantiated with a parameter-set name, it only accepts ML-DSA keys that use that parameter set; otherwise, the initSign and initVerify methods throw an InvalidKeyException.

Encoding and decoding ML-DSA keys

You can use the ML-DSA KeyFactory implementation to convert an ML-DSA private key to or from its PKCS #8 encoding, or an ML-DSA public key to or from its X.509 encoding.

For example, to convert a ML-DSA private key to its PKCS #8 encoding, and vice-versa:

KeyFactory f = KeyFactory.getInstance("ML-DSA");
PKCS8EncodedKeySpec p8spec = f.getKeySpec(kp.getPrivate(),
                                          PKCS8EncodedKeySpec.class);
PrivateKey sk2 = f.generatePrivate(p8spec);

Similarly, to convert a ML-DSA public key to its X.509 encoding, and vice-versa:

X509EncodedKeySpec x509spec = f.getKeySpec(kp.getPublic(),
                                           X509EncodedKeySpec.class);
PublicKey pk2 = f.generatePublic(x509spec);

The KeyFactory implementation can also translate a key from another security provider using the translateKey method, as long as its encoding format is supported.

The getAlgorithm method of a Key object generated by an ML-DSA KeyPairGenerator or KeyFactory implementation always returns the family name "ML-DSA", regardless of whether the KeyPairGenerator or KeyFactory was instantiated with the "ML-DSA" family name or one of the parameter-set names. The getParams method of an ML-DSA key returns a NamedParameterSpec object that matches the key's parameter-set name.

If a KeyFactory object is instantiated with a family name, it encodes or decodes ML-DSA keys in the family with any parameter set. If it is instantiated with a parameter-set name, it only encodes or decodes ML-DSA keys that use that parameter set; otherwise, the translateKey method throws an InvalidKeyException, and the generatePrivate, generatePublic, and getKeySpec methods throw an InvalidKeySpecException.

The encoding used by the ML-DSA KeyFactory is defined in a draft IETF RFC. We will track changes in this draft until it is published.

Alternatives

Testing