跳到主要内容

JEP 329:ChaCha20 和 Poly1305 加密算法

QWen Max 中英对照 JEP 329 ChaCha20 and Poly1305 Cryptographic Algorithms

概述

根据 RFC 7539 的规范实现 ChaCha20 和 ChaCha20-Poly1305 加密算法。ChaCha20 是一种相对较新的流加密算法,可以替代较旧且不安全的 RC4 流加密算法。

目标

  • 提供 ChaCha20 和 ChaCha20-Poly1305 的 Cipher 实现。这些算法将在 SunJCE 提供者中实现。
  • 提供一个 KeyGenerator 实现,用于创建适用于 ChaCha20 和 ChaCha20-Poly1305 算法的密钥。
  • 提供一个用于 ChaCha20-Poly1305 算法的 AlgorithmParameters 实现。

非目标

TLS 密码套件支持将不会是此 JEP 的一部分。这些密码的 TLS 支持将会是后续增强的一部分。

动机

唯一其他被广泛采用的流加密算法 RC4,长期以来被认为不安全。行业共识是,ChaCha20-Poly1305 在当前时间点上是安全的,并且它在 TLS 实现以及其他加密协议中已经得到了相当广泛的采用。JDK 需要与其他加密工具包和 TLS 实现保持一致。

此外,TLS 1.3 仅允许使用基于 AEAD 的加密套件。实现 ChaCha20-Poly1305 算法是在 AEAD 模式下运行的不同加密套件实现的第一步,以防将来在 AES 或 GCM 中发现弱点。

描述

ChaCha20 和 ChaCha20-Poly1305 算法将在 SunJCE 提供程序中实现 javax.crypto.CipherSpi API。这些加密算法将与其他加密算法相同,使用 Cipher.getInstance() 方法进行实例化。对于这两种加密算法,允许使用两种可接受的转换形式。单名称转换是首选方法,即 "ChaCha20" 表示不带身份验证的简单流加密算法 ChaCha20,而 "ChaCha20-Poly1305" 表示使用 Poly1305 作为身份验证器的 AEAD 加密算法 ChaCha20。还可以接受的转换字符串包括 "ChaCha20/None/NoPadding""ChaCha20-Poly1305/None/NoPadding",不过除了 "None""NoPadding" 之外,不会接受其他模式或填充值。使用其他模式或填充值将会导致抛出异常。

初始化 ChaCha20 加密算法时,将接受一个新的 AlgorithmParameterSpec 实现,即 javax.crypto.spec.ChaCha20ParameterSpec

ChaCha20ParameterSpec(byte[] nonce, int counter);     // Constructor
public byte[] getNonce(); // Obtains a copy of the nonce value
public int getCounter(); // Obtains the initial counter value

随机数(nonce)值的长度必须为 96 位(12 字节)。任何其他长度都会导致抛出异常。整数计数器值可以是任何整数值,甚至是负数,以便允许完整的无符号 32 位值范围。

在没有 ChaCha20ParameterSpec 的情况下初始化该算法时,密码器将在内部生成自己的 12 字节随机数,并将计数器值设置为 1。可以通过调用 Cipher.getIV() 方法获取计数器字节。

通过提供一个包含 12 字节随机数的当前 javax.crypto.spec.IvParameterSpec 类实例,可以完成对 ChaCha20-Poly1305 的初始化。选择使用 IvParameterSpec 而非 ChaCha20ParameterSpec 可以在不进行任何 API 更改的情况下,将 ChaCha20-Poly1305 回溯移植到早期版本。由于 IvParameterSpec 不对其所包含的字节设置长度要求,因此加密对象本身将在初始化期间强制执行 12 字节的长度要求。

与 ChaCha20 类似,ChaCha20-Poly1305 也可以在没有 IvParameterSpec 的情况下进行初始化,在这种情况下,随机数将被随机生成,并且可以通过 Cipher.getIV() 获取。

通过任何 init 方法提供的关键对象必须具有 “ChaCha20” 的算法类型。将创建一个新的 KeyGenerator 实现来支持这一点。与现有的针对其他算法(如 AES、RC2、ARCFOUR 和 HmacSHA2 系列)的 KeyGenerator 实现一样,该 KeyGenerator 可能不会使用 AlgorithmParameterSpec 进行初始化。如果调用允许调整密钥长度的 init 方法形式,则该参数必须设置为 256,否则将抛出 InvalidParameterException

使用 ChaCha20 算法遵循用于其他流密码的现有 Cipher API。一个简单的单部分加密可以编写如下:

// Get a Cipher instance and set up the parameters
// Assume SecretKey "key", 12-byte nonce "nonceBytes" and plaintext "pText"
// are coming from outside this code snippet
Cipher mambo = Cipher.getInstance("ChaCha20");
ChaCha20ParameterSpec mamboSpec
= new ChaCha20ParameterSpec(nonceBytes, 7); // Use a starting counter value of "7"
// Encrypt our input
mambo.init(Cipher.ENCRYPT_MODE, key, mamboSpec);
byte[] encryptedResult = mambo.doFinal(pText);

对于以 AEAD 模式运行并使用 Poly1305 认证器的 ChaCha20,由于 RFC 7539 定义了数据初始计数器值从 1 开始,因此只需要提供随机数(nonce)。为了使此加密算法实现能够向后兼容,并促进其在我们的 JSSE 提供程序中的使用,将使用 javax.crypto.spec.IvParameterSpec 来提供随机数(nonce)。

在 AEAD 模式下运行时,由于添加了认证标签(用于加密)或消耗和验证标签(用于解密),输出大小可能与输入不同。如果希望在加密/解密之前分配输出缓冲区,则应使用 getOutputSize() 方法。以下是一个单部分加密的示例:

// Get a Cipher instance and set up the parameters
// Assume SecretKey "key", 12-byte nonce "nonceBytes" and plaintext "pText"
// are coming from outside this code snippet
Cipher mambo = Cipher.getInstance("ChaCha20-Poly1305");
AlgorithmParameterSpec mamboSpec = new IvParameterSpec(nonceBytes);

// Encrypt our input
mambo.init(Cipher.ENCRYPT_MODE, key, mamboSpec);
byte[] encryptedResult = new byte[mambo.getOutputSize(pText.length)];
mambo.doFinal(pText, 0, pText.length, encryptedResult);

对于 ChaCha20 和 ChaCha20-Poly1305 这两种加密算法,一个重要的要求是:在调用 doFinal() 之后,必须重新调用 init(),并提供一个与当前配置不同的随机数(nonce)。这与 AES-GCM 加密算法的要求类似,但在上述两种加密算法中,初始化的要求必须在加密和解密操作之后都执行。如果在前一次调用 doFinal() 后没有调用 init(),后续再调用 Cipher.update()Cipher.updateAAD()Cipher.doFinal() 将导致抛出 IllegalStateException 异常。

测试

测试将涵盖以下领域:

  • 验证 ChaCha20 和 ChaCha20-Poly1305 加密算法通过所有已知答案测试
  • 验证 ChaCha20 密钥生成器接受正确的初始化形式,并生成适当大小的密钥
  • 验证加密算法在初始化时遵循限制(不允许重复使用随机数等)
  • 验证加密算法在完整的加密/解密操作之间执行正确的重新初始化要求
  • 验证我们的实现至少与另一个实现互操作
  • 验证 ChaCha20-Poly1305 的 AlgorithmParameters 实现以正确的格式接受随机数数据。

依赖

唯一的重大依赖是恒定时间数学 API。这些将作为 JEP 324 的一部分提供。