JEP 510:密钥派生函数 API

原文:JEP 510- Key Derivation Function API
作者:
日期:2025-10-26

所有者凯文·德里弗(Kevin Driver)
类型特性
范围标准版(SE)
状态已关闭 / 已交付
发布版本25
组件安全库 / javax.crypto
讨论组security - dev@openjdk.org
工作量极小
时长极短
相关内容JEP 478:密钥派生函数 API(预览版)
审核人肖恩·马伦(Sean Mullan)
批准人肖恩·马伦(Sean Mullan)
创建时间2025 年 3 月 31 日 14:08
更新时间2025 年 7 月 21 日 13:50
问题编号8353275

摘要

引入用于密钥派生函数(KDF)的 API,密钥派生函数是用于从秘密密钥和其他数据中派生额外密钥的加密算法。

历史

我们在 JEP 478 中提议将 KDF API 作为预览特性,并在 JDK 24 中发布。在此,我们提议在 JDK 25 中确定该 API,且不做更改。

目标

非目标

  • 无意通过新的 KDF API 提供基于密码的密钥派生函数 PBKDF1 和 PBKDF2 的现有实现。这些实现仍将通过现有的 SecretKeyFactory API 提供。

动机

密钥派生函数(KDF) 利用加密输入,如初始密钥材料、盐值和伪随机函数,来创建新的具有强加密性的密钥材料。KDF 通常用于创建可从中获取多个密钥的加密数据。KDF 允许以一种安全且可由共享输入信息的双方重现的方式创建密钥。

派生密钥类似于哈希密码。KDF 使用带密钥的哈希以及来自其他输入的额外熵,来提取新的密钥材料,或将值安全地扩展为更大的密钥材料流。

随着量子计算的出现,经典加密算法将越来越容易受到实际攻击。因此,Java 平台支持 后量子密码学(PQC) 至关重要,它可抵御这些攻击。我们的目标最终是通过支持混合公钥加密(HPKE)来实现这一点,HPKE 可实现向量子安全加密算法的平稳过渡。集成在 JDK 21 中的 KEM API(JEP 452)是 HPKE 的一个组成部分,是我们迈向 HPKE 和后量子准备的第一步;此处提议的 KDF API 是 HPKE 的另一个组成部分,将是第二步。

添加 KDF API 所带来的可扩展性将带来更多好处。针对加密硬件设备的 PKCS#11 标准 多年来一直描述对 KDF 的支持。通过 javax.crypto API 提供这项技术,将使与这类设备交互的应用程序和库受益。此外,第三方加密提供程序的开发者可能会提供经过测试验证并随后由 美国国家标准与技术研究院 认证的自定义 KDF 实现。

最后,Java 平台必须为比 PBKDF1 和 PBKDF2 更复杂的基于密码哈希的 KDF(如 Argon2)提供更好的 API 支持。Java 平台现有的加密 API 目前都无法以自然的方式表示 KDF(见 下文)。第三方安全提供程序的实现者已经表达了对标准 KDF API 的需求。

描述

密钥派生函数有两个基本操作:

  • 实例化与初始化,创建 KDF 并使用适当参数对其进行初始化。
  • 派生,接受密钥材料和其他可选输入,以及用于描述输出的参数,然后生成派生的密钥或数据。

我们定义一个新类 javax.crypto.KDF 来表示密钥派生函数。

实例化与初始化

KDF 类提供了常用的 getInstance 方法集,这些方法带有常见的参数组合,包括可选的 KDFParameters 和加密提供程序名称。getInstance 方法既能实例化一个 KDF,又能初始化其算法。

目前我们打算纳入的唯一 KDF 算法 HKDF,并不需要 KDFParameters 对象。然而,其他算法,如 SHAKE,可能需要。

派生

KDF 类定义了两个用于派生密钥的方法:

我们使用空接口 AlgorithmParameterSpec,因为不同的 KDF 算法采用不同的参数。一个 KDF 实现应该定义一个或多个 AlgorithmParameterSpec 的子类来描述其参数。

对于所包含的 HKDF 实现,我们提供了三个这样的子类,每个子类代表不同操作模式的输入:

包含它们的 HKDFParameterSpec 接口定义了用于创建这三个类实例的静态工厂方法。它还定义了一个构建器类 HKDFParameterSpec.Builder,用于为提取操作组装密钥材料。

示例

// 为指定算法创建一个 KDF 对象
KDF hkdf = KDF.getInstance("HKDF-SHA256");
// 创建一个提取并扩展参数规范
AlgorithmParameterSpec params =
    HKDFParameterSpec.ofExtract()
                     .addIKM(初始密钥材料)
                     .addSalt(盐).thenExpand(信息, 32);
// 派生一个 32 字节的 AES 密钥
SecretKey key = hkdf.deriveKey("AES", params);
// 可以使用同一个 KDF 对象进行更多的 deriveKey 调用
  

实现 KDF 提供程序

一个 KDF 实现必须扩展抽象类 javax.crypto.KDFSpi

一些 KDF 算法在单个派生操作中派生多个加密密钥。如果你要实现这样一种算法,我们建议你要么提供一个 SecretKey 子类,该子类带有可访问每个密钥的方法,要么在单个字节数组中返回所有密钥,并记录如何分离它们。

未来工作

  • 实现 Argon2 — 我们最终打算实现 Argon2 密码哈希 KDF。

替代方案

  • 使用现有 API — 我们考虑过使用现有的 KeyGeneratorSecretKeyFactory API 来表示 KDF。早期的密钥派生算法,如 TLS - PRF、PBKDF1 和 PBKDF2,已适配到这些 API 中,但总体而言,这些 API 对 KDF 来说并不适用。
    • KeyGenerator 是围绕通过 SecureRandom 对象引入熵来设计的,以便从一组输入中创建一个非确定性密钥。相比之下,KDF 支持两个独立方以相同方式派生相同的密钥材料。
    • SecretKeyFactory 是为创建单个密钥而设计的。尽管在某些场景中 KDF 可能以这种方式使用,但 KDF 还需要以确定性方式支持从密钥流中进行连续派生。
  • 通过新的 KDF API 提供 PBKDF2 — PBKDF2 正迅速被更强的算法(如 Argon2)所取代。已经在使用 PBKDF2 的开发者可能会继续通过 SecretKeyFactory API 使用它,而不是重构现有代码以使用 KDF API。因此,目前没有理由通过新 API 提供 PBKDF2,但如果以后出现迫切需求,我们可以这样做。

测试

如果有可用的 RFC 5869 已知答案(KAT)测试,我们将添加这些测试,同时还会添加异常处理测试和 SSL/TLS 回归测试。