Ohhnews

分类导航

$ cd ..
Baeldung原文

Java 24原生支持抗量子密码:ML-KEM与ML-DSA实践

#抗量子计算#ml-kem#ml-dsa#java 24#密钥封装

1. 概述

ML-KEM(基于模格的关键封装机制)是一种后量子密码学密钥交换算法,允许双方安全地建立共享密钥,即使面对未来量子计算机的攻击也能保持安全。而 ML-DSA(基于模格的数字签名算法)是一种后量子数字签名算法,能够提供安全的身份验证和消息完整性保护,抵抗量子计算机的攻击。

在 Java 24 之前,ML-KEM 和 ML-DSA 并不属于标准 JDK(Java 开发工具包)的一部分。我们需要使用 Bounty Castle 等外部库来执行密码学操作。

从 Java 24 开始,这两种算法都已纳入原生 Java API。原生 Java API 中的 ML-KEM 和 ML-DSA 实现分别由 JEP 496JEP 497 提出。

在本教程中,我们将讨论如何在 Java 中使用抗量子的 ML-KEM 和 ML-DSA。

2. 抗量子 ML-KEM

关键封装机制 允许两方(即发送方和接收方)在不安全的网络上安全地交换共享密钥。该机制包括以下步骤:

  • 接收方创建公钥/私钥对
  • 发送方使用公钥创建加密的共享密钥
  • 接收方使用私钥解密加密的共享密钥

因此,双方获得相同的密钥。该共享密钥可用于对称密钥算法,如 AES(高级加密标准)和 Blowfish。

ML-KEM 基于 M-LWE(模学习带误差)问题,该问题在计算上非常困难。M-LWE 问题的困难性进一步依赖于模格中某些计算问题的困难性。因此,ML-KEM 能够抵抗经典和量子攻击。

2.1. 生成密钥对

让我们首先在接收方生成一个 ML-KEM 密钥对:

$ java
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-KEM");
kpg.initialize(NamedParameterSpec.ML_KEM_768);
KeyPair receiverKeyPair = kpg.generateKeyPair();
PrivateKey privateKey = receiverKeyPair.getPrivate();
PublicKey publicKey = receiverKeyPair.getPublic();

首先,我们获取一个用于 ML-KEM 算法的 KeyPairGenerator 对象。然后,我们选择 ML_KEM_768 来设置即将生成的密钥的安全强度。JEP 496 增加了对 ML-KEM-512、ML-KEM-768 和 ML-KEM-1024 的支持。实际上,ML_KEM_768 是默认选项,即如果我们不通过 initialize() 方法初始化 KeyPairGenerator 对象,安全级别仍然是 ML_KEM_768

也可以直接将安全强度传递给 getInstance(),这种情况下也无需调用 initialize() 方法:

$ java
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-KEM-768");
KeyPair receiverKeyPair = kpg.generateKeyPair();

receiverKeyPairKeyPair 类型,包含一个公钥和一个私钥。我们可以分别使用 getPublic()getPrivate() 成员方法访问这些密钥。接收方可以安全地将公钥分享给发送方,但私钥必须保密。

2.2. 生成并封装共享密钥

一旦发送方收到接收方的公钥,它就会生成并封装一个共享密钥,该密钥将被发送方和接收方共同使用:

$ java
KEM senderKem = KEM.getInstance("ML-KEM");
KEM.Encapsulator encapsulator = senderKem.newEncapsulator(publicKey);
KEM.Encapsulated encapsulated = encapsulator.encapsulate();
SecretKey senderSharedSecret = encapsulated.key();
byte[] ciphertext = encapsulated.encapsulation();

senderSharedSecret 是实际用于通信的密钥。但发送方并不直接将其发送给接收方,而是通过使用接收方的公钥封装(加密)它来发送。ciphertext 对应于 senderSharedSecret 的加密版本

2.3. 解封装共享密钥

接收方收到加密密钥后,使用私钥解封装该密钥:

$ java
KEM receiverKem = KEM.getInstance("ML-KEM");
KEM.Decapsulator decapsulator = receiverKem.newDecapsulator(privateKey);
SecretKey receiverSharedSecret = decapsulator.decapsulate(ciphertext);

实际的密钥 receiverSharedSecret 通过解封装接收到的 ciphertext 提取得到。因此,双方获得相同的共享密钥,用于对称加密和解密。我们可以通过以下方式检查双方使用的是相同密钥:

$ java
boolean match = Arrays.equals(senderSharedSecret.getEncoded(), receiverSharedSecret.getEncoded());

比较结果为 true。因此,我们实现了在不安全网络上的安全通信。此外,该方法能够抵抗量子攻击,而 RSA 或 Diffie-Hellman 则无法做到这一点。

3. 抗量子 ML-DSA

数字签名算法 是一种用于验证数字消息或文档真实性和完整性的密码学方法。该算法包括以下步骤:

  • 签名者(发送方)创建公钥/私钥对
  • 签名者使用消息和私钥创建签名
  • 验证者(接收方)使用收到的消息和公钥验证签名

与 ML-KEM 类似,ML-DSA 也基于 M-LWE 问题和另一个计算上困难的问题——M-SIS(模短整数解问题)。因此,ML-DSA 能够抵抗经典和量子攻击。

3.1. 生成密钥对

让我们首先在签名方生成一个 ML-DSA 密钥对:

$ java
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA");
kpg.initialize(NamedParameterSpec.ML_DSA_65);
KeyPair kp = kpg.generateKeyPair();
PrivateKey privateKey = kp.getPrivate();
PublicKey publicKey = kp.getPublic();

首先,我们获取一个用于 ML-DSA 算法的 KeyPairGenerator 对象。然后,我们选择 ML_DSA_65 来设置即将生成的密钥的安全强度。实际上,ML_DSA_65 是默认选项。JEP 497 增加了对 ML-DSA-44、ML-DSA-65 和 ML-DSA-87 的支持

与 ML-KEM 类似,也可以直接将安全强度传递给 getInstance()

3.2. 签名

然后,作为签名者,我们使用私钥对待发送的消息进行签名:

$ java
Signature signature = Signature.getInstance("ML-DSA");
String message = "This is a test message signed";
byte[] messageBytes = message.getBytes();
signature.initSign(privateKey);
signature.update(messageBytes);
byte[] sigBytes = signature.sign();

首先,我们获取一个实现 ML-DSA 算法的 Signature 对象。然后,我们使用 initSign() 方法将该对象初始化为签名模式,并将私钥传递给该方法。接着,我们使用 update() 方法将消息馈送到 Signature 对象。最后,我们使用 Signature 对象的 sign() 方法创建数字签名

3.3. 验证

然后,作为验证者,收到消息和签名后,我们使用公钥验证签名:

$ java
signature.initVerify(publicKey);
signature.update(messageBytes);
boolean isValid = signature.verify(sigBytes);

这次,我们使用 initVerify() 方法将 Signature 对象初始化为验证模式。然后,我们使用 update() 方法将签名方发来的消息馈送到 Signature 对象。最后,我们使用 Signature 对象的 verify() 方法验证签名。如果返回 true,则表示验证成功,签名是用对应的私钥创建的。

4. 总结

在本文中,我们讨论了如何在 Java 中使用抗量子的 ML-KEM 和 ML-DSA。首先,我们了解到这些算法在 Java 24 之前并不存在于标准 JDK 中。

然后,我们看到了这些算法在 Java 中的用法。我们使用 ML-KEM 模拟了接收方和发送方之间的密钥交换。类似地,我们使用 ML-DSA 模拟了双方之间的消息签名和签名验证。从示例中可以看出,Java 24 为 KeyPairGeneratorKEM 类提供了 ML-KEM 实现,并为 KeyPairGeneratorSignature 类提供了 ML-DSA 实现。

与往常一样,示例的完整源代码可在 GitHub 上获取。