JEP 497: Quantum-Resistant Module-Lattice-Based Digital Signature Algorithm | 量子抗性基于模块格的数字签名算法
概述
通过提供抗量子的基于模块格的数字签名算法(ML-DSA)的实现来增强 Java 应用程序的安全性。数字签名用于检测对数据的未授权修改,并验证签署者的身份。ML-DSA 旨在抵御未来量子计算攻击。它已被美国国家标准与技术研究院(NIST)在 FIPS 204 中标准化。
目标
- 提供
KeyPairGenerator
、Signature
和KeyFactory
API 的 ML-DSA 实现,支持 FIPS 204 中标准化的参数集 ML-DSA-44、ML-DSA-65 和 ML-DSA-87。
非目标
不打算实现从 ML-DSA 衍生出的 Dilithium 算法。这两种算法不互通。
对于尚未存在必要标准的 Java 平台组件,不打算添加 ML-DSA 支持,尤其是 JAR 文件签名以及
javax.net.ssl
包中传输层安全(TLS)协议的实现。一旦这些标准存在,我们将添加相应的支持。不打算支持预哈希 ML-DSA(FIPS 204 §5.4)或允许用户设置应用特定上下文字符串(FIPS 204 §5.2)。我们可能在未来版本中实现这些功能。
动机
多年来,量子计算 领域一直在稳步发展。未来的大型量子计算机可以使用能够分解整数和解决离散对数问题的 Shor 算法,从而威胁到广泛部署的基于公钥的算法的安全性,包括 Rivest-Shamir-Adleman(RSA)和 Diffie-Hellman。Java 平台利用这些算法进行数字签名 JAR 文件和通过传输层安全(TLS)协议建立安全网络连接等操作。传统超级计算机需要成千上万到百万年才能完成的攻击,量子计算机只需几小时就能通过 Shor 算法实现。作为回应,密码学家发明了 抗量子 加密算法,这些算法不能被 Shor 算法破解。
为了以抗量子的方式进行数据签名和身份验证,NIST 在 FIPS 204 中标准化了基于模块格的数字签名算法(ML-DSA)。在美国,处理敏感信息的 政府计算机系统 必须在未来十年升级使用 ML-DSA。因此,为 Java 平台提供该算法的实现至关重要。
描述
我们将为生成 ML-DSA 密钥对的 KeyPairGenerator
API、签署和验证 ML-DSA 签名的 Signature
API 以及将 ML-DSA 密钥转换为其编码形式的 KeyFactory
API 提供 ML-DSA 实现。
在 Java 安全标准算法名称规范 中,我们将定义一个新的标准算法族名 "ML-DSA"
,用于 KeyPairGenerator
、Signature
和 KeyFactory
API。
FIPS 204 指定了三个 ML-DSA 的参数集。按安全强度递增和性能递减排序,它们分别名为 "ML-DSA-44"
、"ML-DSA-65"
和 "ML-DSA-87"
。这些参数集名称也将被定义为 KeyPairGenerator
、Signature
和 KeyFactory
API 的标准算法名称,并进一步由新的 NamedParameterSpec
常量 ML_DSA_44
、ML_DSA_65
和 ML_DSA_87
表示。
生成 ML-DSA 密钥对
您可以通过以下三种方式之一生成 ML-DSA 密钥对:
使用家族名实例化一个
KeyPairGenerator
并用参数集名称初始化它:javaKeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA"); g.initialize(NamedParameterSpec.ML_DSA_44); KeyPair kp = g.generateKeyPair(); // ML-DSA-44 密钥对
如果您没有使用参数集初始化
KeyPairGenerator
,则实现将默认使用 ML-DSA-65:javaKeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA"); KeyPair kp = g.generateKeyPair(); // ML-DSA-65 密钥对
直接使用参数集名称实例化一个
KeyPairGenerator
:javaKeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA-87"); KeyPair kp = g.generateKeyPair(); // ML-DSA-87 密钥对
KeyPairGenerator
API 允许在初始化期间指定一个整数密钥大小,但这对于 ML-DSA 密钥对不支持,并且会抛出 InvalidParameterException
。
keytool
命令将支持生成 ML-DSA 密钥对和证书。例如:
$ keytool -keystore ks -storepass changeit -genkeypair -alias mldsa \
-keyalg ML-DSA -groupname ML-DSA-65 -dname CN=ML-DSA
您也可以直接通过 -keyalg
选项提供参数集名称 ML-DSA-65
:
$ keytool -keystore ks -storepass changeit -genkeypair -alias mldsa \
-keyalg ML-DSA-65 -dname CN=ML-DSA2
使用 ML-DSA 密钥进行签名
您可以使用 ML-DSA Signature
实现来签署和验证 ML-DSA 签名。
例如,使用私钥签署消息:
byte[] msg = ...;
Signature ss = Signature.getInstance("ML-DSA");
ss.initSign(privateKey);
ss.update(msg);
byte[] sig = ss.sign();
使用公钥验证签名:
byte[] msg = ...;
byte[] sig = ...;
Signature sv = Signature.getInstance("ML-DSA");
sv.initVerify(publicKey);
sv.update(msg);
boolean verified = sv.verify(sig);
如果使用家族名实例化了一个 Signature
对象,则它接受该家族中使用任何参数集的 ML-DSA 密钥。如果使用参数集名称实例化,则它只接受使用该参数集的 ML-DSA 密钥;否则,initSign
和 initVerify
方法将抛出 InvalidKeyException
。
编码和解码 ML-DSA 密钥
您可以使用 ML-DSA KeyFactory
实现将 ML-DSA 私钥转换为其 PKCS #8 编码或反之,或将 ML-DSA 公钥转换为其 X.509 编码或反之。
例如,将 ML-DSA 私钥转换为其 PKCS #8 编码,反之亦然:
KeyFactory f = KeyFactory.getInstance("ML-DSA");
PKCS8EncodedKeySpec p8spec = f.getKeySpec(kp.getPrivate(), PKCS8EncodedKeySpec.class);
PrivateKey sk2 = f.generatePrivate(p8spec);
同样,将 ML-DSA 公钥转换为其 X.509 编码,反之亦然:
X509EncodedKeySpec x509spec = f.getKeySpec(kp.getPublic(), X509EncodedKeySpec.class);
PublicKey pk2 = f.generatePublic(x509spec);
只要支持其编码格式,KeyFactory
实现还可以使用 translateKey
方法从另一个安全提供者那里翻译密钥。
由 ML-DSA KeyPairGenerator
或 KeyFactory
实现生成的 Key
对象的 getAlgorithm
方法总是返回家族名 "ML-DSA"
,无论 KeyPairGenerator
或 KeyFactory
是用 "ML-DSA"
家族名还是其中一个参数集名称实例化的。ML-DSA 密钥的 getParams
方法返回一个与密钥参数集名称匹配的 NamedParameterSpec
对象。
如果使用家族名实例化了一个 KeyFactory
对象,则它编码或解码该家族中使用任何参数集的 ML-DSA 密钥。如果使用参数集名称实例化,则它仅编码或解码使用该参数集的 ML-DSA 密钥;否则,translateKey
方法将抛出 InvalidKeyException
,而 generatePrivate
、generatePublic
和 getKeySpec
方法将抛出 InvalidKeySpecException
。
ML-DSA KeyFactory
使用的编码在 IETF RFC 草案 中定义。我们将跟踪此草案中的更改直至其发布。
替代方案
Open Quantum Safe 项目 为他们的
liboqs
C 库 提供了 JNI 封装,该库实现了包括 Dilithium 和 ML-DSA 在内的量子抗性算法集合。如果 Open Quantum Safe 能够实现成为 OpenSSL、BoringSSL、OpenSSH 和 Mozilla 等主要项目的首要量子抗性加密实现的目标,那么通过广泛的测试和使用,它将在性能和鲁棒性方面获得显著提升。与原生实现相比,ML-DSA 的 Java 实现的主要优势在于直接集成到 JDK 中。这使得它在 JDK 已移植的所有平台上都立即可用。
测试
单元测试将确认实现是否符合
KeyGenerator
、Signature
和KeyFactory
API 的规范,包括无效输入参数、边界值和支持的操作等边缘情况。已知答案测试(KATs)将涵盖有效的加密操作(正面案例)和无效操作或已知漏洞(负面案例),确保全面验证。这些测试包括但不限于:
NIST 的 密码算法验证程序服务 生成的 KATs(这里,这里,以及 这里)
正在开发中的来自 Wycheproof 项目 的 ML-DSA 测试,详情见此处.
与其他供应商实现的互操作性测试,包括但不限于
liboqs
,将确认我们的 ML-DSA 实现能很好地与其他实现协作。