跳到主要内容

JEP 496:基于抗量子模块格的密钥封装机制

概括

通过提供抗量子的基于模块格的密钥封装机制 (ML-KEM) 的实现来增强 Java 应用程序的安全性。密钥封装机制 (KEM) 用于使用公钥加密技术通过不安全的通信通道保护对称密钥。ML-KEM 旨在抵御未来的量子计算攻击。它已由美国国家标准与技术研究所 (NIST) 在FIPS 203中进行了标准化。

目标

  • KeyPairGenerator提供、KEM和API的 ML-KEM 实现KeyFactory,并支持 FIPS 203 中标准化的参数集 ML-KEM-512、ML-KEM-768 和 ML-KEM-1024。

非目标

  • 实现ML-KEM 衍生自的Kyber 算法并不是我们的目标。这两种算法不具有互操作性。

  • 我们的目标不是为尚不存在必要标准的 Java 平台组件添加对 ML-KEM 的支持。特别是对于软件包中的传输层安全性 (TLS) 实现而言javax.net.ssl。一旦标准存在,我们就会添加此类支持。

动机

多年来,量子计算领域一直在稳步发展。未来的大型量子计算机可以使用Shor 算法(该算法能够分解整数并解决离散对数问题)来破坏广泛使用的基于公钥的算法(包括 Rivest-Shamir-Adleman (RSA) 和 Diffie-Hellman)的安全性。Java 平台使用此类算法对 JAR 文件进行数字签名并通过传输层安全性 (TLS) 协议建立安全网络连接等。传统超级计算机可能需要数千到数百万年才能完成的攻击,使用 Shor 算法的量子计算机只需几个小时即可完成。

密码学家通过发明抗量子加密算法来应对这一威胁,这种算法无法被 Shor 算法攻克。尽管大规模量子计算机尚未出现,但转向抗量子算法迫在眉睫,因为对手可以收集加密数据,存储它,并在此类计算机出现后解密它。

为了以抗量子的方式交换密钥,NIST 在FIPS 203中标准化了基于模块格的密钥封装机制 (ML-KEM) 。在美国,处理敏感信息的政府计算机系统必须在未来十年内升级以使用 ML-KEM。因此,Java 平台必须提供此算法的实现。

描述

如JEP 452中所述,KEM 由三个功能组成:

  • 密钥_对生成函数_返回包含公钥和私钥的密钥对。

  • 发送方调用密钥封装函数,接收方使用公钥和加密选项作为参数,返回一个密钥_K_和一个_密钥封装消息_。发送方将密钥封装消息发送给接收方。

  • 接收方调用的密钥解封装函数_获取接收方的私钥和接收到的密钥封装消息,并返回密钥_K。

KeyPairGenerator对于第一个函数,我们将提供生成 ML-KEM 密钥对的 API 实现。对于第二个和第三个函数,我们将提供KEM基于 ML-KEM 密钥对协商共享密钥的 API 实现。我们还将提供将KeyFactoryML-KEM 密钥与其编码相互转换的 API 实现。

Java 安全标准算法名称规范中,我们将为、和 API 定义一个新的标准"ML-KEM"算法系列KeyPairGenerator名称。KEM``KeyFactory

FIPS 203 为 ML-KEM 指定了三个参数集。按照安全强度增加和性能降低的顺序,它们被命名为"ML-KEM-512""ML-KEM-768""ML-KEM-1024"。这些参数集名称还将被定义为KeyPairGeneratorKEM和API 的标准算法名称,并且将由新常量、和KeyFactory来表示。NamedParameterSpecML_KEM_512``ML_KEM_768``ML_KEM_1024

生成 ML-KEM 密钥对

您可以通过以下三种方式之一生成 ML-KEM 密钥对:

  • 使用家族名称实例化KeyPairGenerator并使用参数集名称初始化它:

    KeyPairGenerator g = KeyPairGenerator.getInstance("ML-KEM");
    g.initialize(NamedParameterSpec.ML_KEM_512);
    KeyPair kp = g.generateKeyPair(); // an ML-KEM-512 key pair
  • 如果不使用KeyPairGenerator参数集初始化,则实现将使用 ML-KEM-768 作为默认值:

    KeyPairGenerator g = KeyPairGenerator.getInstance("ML-KEM");
    KeyPair kp = g.generateKeyPair(); // an ML-KEM-768 key pair
  • 直接KeyPairGenerator使用参数集名称实例化:

    KeyPairGenerator g = KeyPairGenerator.getInstance("ML-KEM-1024");
    KeyPair kp = g.generateKeyPair(); // an ML-KEM-1024 key pair

APIKeyPairGenerator允许在初始化期间指定整数密钥大小,但这不支持 ML-KEM 密钥对,并且会导致InvalidParameterException抛出。

keytool命令将支持生成 ML-KEM 密钥对和证书。例如,要生成 ML-KEM 密钥对并使用 EC 密钥签署证书:

$ keytool -keystore ks -storepass changeit -genkeypair -alias ec \
-keyalg ec -dname CN=ec -ext bc
$ keytool -keystore ks -storepass changeit -genkeypair -alias mlkem \
-keyalg ML-KEM -groupname ML-KEM-768 -dname CN=ML-KEM -signer ec

第一个命令创建 EC 密钥对;第二个命令创建 ML-KEM 密钥对和由 EC 密钥签名的证书。我们使用 EC 密钥来签名证书,因为 ML-KEM 本身不是签名算法,因此不能用于签名包含 ML-KEM 公钥的证书。

参数集名称(ML-KEM-768)也可以直接通过以下-keyalg选项提供:

$ keytool -keystore ks -storepass changeit -genkeypair -alias mlkem2 \
-keyalg ML-KEM-768 -dname CN=ML-KEM2 -signer ec

封装和解封装 ML-KEM 密钥

您可以使用 ML-KEMKEM实现来协商共享密钥。

例如,发送者可以调用封装函数来获取密钥和密钥封装消息:

KEM ks = KEM.getInstance("ML-KEM");
KEM.Encapsulator enc = ks.newEncapsulator(publicKey);
KEM.Encapsulated encap = enc.encapsulate();
byte[] msg = encap.encapsulation(); // send this to receiver
SecretKey sks = encap.key();

然后,接收方可以调用解封装函数从发送方发送的密钥封装消息中恢复密钥:

byte[] msg = ...;                       // received from sender
KEM kr = KEM.getInstance("ML-KEM");
KEM.Decapsulator dec = kr.newDecapsulator(privateKey);
SecretKey skr = dec.decapsulate(msg);

sks和都skr包含相同的密钥材料,只有发送者和接收者知道。

如果KEM对象使用系列名称实例化,则它会接受具有任何参数集的系列中的 ML-KEM 密钥。如果使用参数集名称实例化,则它仅接受使用该参数集的 ML-KEM 密钥;否则,newEncapsulatornewDecapsulator方法会抛出InvalidKeyException

编码和解码 ML-KEM 密钥

您可以使用 ML-KEMKeyFactory实现将 ML-KEM 私钥与其 PKCS #8 编码相互转换,或者将 ML-KEM 公钥与其 X.509 编码相互转换。

例如,将 ML-KEM 私钥转换为其 PKCS #8 编码,反之亦然:

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

类似地,将 ML-KEM 公钥转换为其 X.509 编码,反之亦然:

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

只要支持其编码格式,实现还可以使用该方法转换KeyFactory来自另一个安全提供程序的密钥。translateKey

ML-KEM或实现生成的对象getAlgorithm的方法始终返回系列名称,无论或是否使用系列名称或参数集名称之一进行实例化。ML -KEM 密钥的方法返回与密钥的参数集名称匹配的对象。Key``KeyPairGenerator``KeyFactory``"ML-KEM"``KeyPairGenerator``KeyFactory``"ML-KEM"``getParams``NamedParameterSpec

如果KeyFactory对象使用系列名称进行实例化,则它会使用任何参数集对系列中的 ML-KEM 密钥进行编码或解码。如果对象使用参数集名称进行实例化,则它仅对使用该参数集的 ML-KEM 密钥进行编码或解码;否则,该translateKey方法会抛出InvalidKeyException,而generatePrivategeneratePublicgetKeySpec方法会抛出InvalidKeySpecException

ML-KEM 使用的编码在IETF RFC 草案KeyFactory中定义。我们将跟踪此草案中的更改,直至其发布。

替代方案

  • Open Quantum Safe 项目为其C提供了一个JNI 包装器,该库实现了包括 Kyber 和 ML-KEM 在内的一系列抗量子算法。如果 Open Quantum Safe 实现了成为 OpenSSL、BoringSSL、OpenSSH 和 Mozilla 等主要项目的主要抗量子加密实现的目标,那么它将通过广泛的测试和使用获得显著的性能和稳健性。liboqs

    与本机实现相比,ML-KEM 的 Java 实现的主要优势在于可直接集成到 JDK 中。这使得它可以立即在已移植 JDK 的所有平台上使用。

测试

  • KeyGenerator单元测试将确认实现符合、KeyFactory和API的规范KEM,包括无效输入参数、边界值和不支持的操作等边缘情况。

  • 已知答案测试 (KAT) 将涵盖有效的加密操作(正面案例)和无效操作或已知漏洞(负面案例),确保全面验证。这些将包括但不限于:

  • 与其他供应商(包括但不限于liboqs)的实现进行互操作测试将确认我们的 ML-KEM 实现与其他实现能够良好地协同运行。