如何使用 javacardx.security.derivation 定义的 KDF (X9.63) 提取加密和 MAC 密钥

How to extract encryption and MAC keys using KDF (X9.63) defined by javacardx.security.derivation

根据Java Card v3.1 新包定义javacardx.security.derivation

https://docs.oracle.com/en/java/javacard/3.1/jc_api_srvc/api_classic/javacardx/security/derivation/package-summary.html

KDF X9.63 适用于三个输入:输入密码、计数器和共享信息。 取决于生成密钥的长度material,对哈希进行多轮计算以生成最终输出。

我正在通过 JC 使用此 KDF API 为 16 字节加密密钥、16 字节 IV 生成 64 字节输出(由 2 轮 SHA-256 执行),和一个 32 字节-MAC Key.

注意:这只是伪代码,用于提出我的问题并提供必要的详细信息。

DerivationFunction df = DerivationFunction.getInstance(DerivationFunction.ALG_KDF_ANSI_X9_63, false);
df.init(KDFAnsiX963Spec(MessageDigest.ALG_SHA_256, input, sharedInfo, (short) 64);

SecretKey encKey = KeyBuilder.buildKey(KeyBuilder.TYPE_AES, (short)16, false);
SecretKey macKey = KeyBuilder.buildKey(KeyBuilder.TYPE_HMAC, (short)32, false);

df.nextBytes(encKey); 
df.nextBytes(IVBuffer, (short)0, (short)16);
df.lastBytes(macKey);

我有以下问题:

  1. 什么时候进行KDF?这些是在 df.init() 期间执行还是在 df.nextBytes() & df.lastBytes() 期间执行?

  2. 一轮 KDF 将生成 32 字节输出(考虑 SHA-256 算法),那么 API 的 df.nextBytes()df.lastBytes() 如何处理任何输出预期长度 < 32 字节?

  3. 在此 KDF 计数器在每个下一轮递增,那么如何在 df.nextBytes()df.lastBytes() API 之间管理计数器?

  1. When rounds of KDF are performed? Are these performed during df.init() or during df.nextBytes() & df.lastBytes()?

这似乎是特定于我的实现。一次执行所有计算可能会更快,但在这种情况下,等待第一个字节请求仍然有意义。另一方面,RAM 通常也是一个问题,因此按需生成也有一定意义。不过,这需要稍微复杂一些的实现。

输出大小是预先指定的事实可能表明 API 设计者至少预见到一次生成所有密钥 material 的更简单方法(他们可能创建了一个在 JCF 对其进行同行评审之前实施。

  1. One KDF round will generate 32 bytes output (considering SHA-256 algorithm) then how API's df.nextBytes() & df.lastBytes() will work with any output expected length < 32 bytes?

它通常会 return 最左边的字节(散列输出的)并且可能将其余字节留在缓冲区中。当 lastBytes 被调用时,这个缓冲区可能会与状态的其余部分一起被销毁(所以不要忘记这样做)。

请注意,API 明确指出,如果您想再次使用它,您必须重新初始化 DerivationFunction 实例。因此,这是一个非常强烈的迹象,表明他们虽然破坏了密钥 material(FIPS 和通用标准认证要求的东西,而不仅仅是常识)。

其他 KDF 的 可能 有不同的 returning 字节方式,但是使用最左边的字节然后在右边添加轮数是很常见的,你可以称之为普遍的。对于 ANSI X9.63 KDF,情况确实如此,并且在标准中明确指定了这种方式。

  1. In this KDF counter is incremented in every next round then how counter will be managed between df.nextBytes() & df.lastBytes() API's?

这些是同一个class的方法,不能分开看,所以不是分开的API。 Class 个实例可以以任何他们想要的方式保持状态。它可能只是将计数器保存为 class 变量,但如果它决定在 init 或第一个 nextBytes / lastBytes 调用期间生成字节,那么甚至不需要计数器不再。