PKCS11 derivedKey 每次返回不同的值

Posted

技术标签:

【中文标题】PKCS11 derivedKey 每次返回不同的值【英文标题】:PKCS11 deriveKey returning different values every time 【发布时间】:2019-09-17 21:29:54 【问题描述】:

我有一个主密钥,并希望将其多样化/派生为其他密钥(在 HSM 内)。在关注this answer 之后,我有这个代码:

final java.security.Key key = token.getKeyStore().getKey(baseKeyAlias, null);
iaik.pkcs.pkcs11.objects.Key baseKey = ((iaik.pkcs.pkcs11.provider.keys.IAIKPKCS11SecretKey) key).getKeyObject();

DESSecretKey derived3DESKeyTemplate = new DESSecretKey();
SecretKey derivedKeyTemplate = derived3DESKeyTemplate;
derivedKeyTemplate.getLabel().setCharArrayValue(derivedKeyAlias.toCharArray());
derivedKeyTemplate.getId().setByteArrayValue(derivedKeyAlias.getBytes());
derivedKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
derivedKeyTemplate.getKeyType().setLongValue(PKCS11Constants.CKK_DES2);
derivedKeyTemplate.getEncrypt().setBooleanValue(Boolean.TRUE);
derivedKeyTemplate.getDecrypt().setBooleanValue(Boolean.TRUE);
derivedKeyTemplate.getWrap().setBooleanValue(Boolean.TRUE);
derivedKeyTemplate.getUnwrap().setBooleanValue(Boolean.TRUE);
derivedKeyTemplate.getDerive().setBooleanValue(Boolean.TRUE);
derivedKeyTemplate.getExtractable().setBooleanValue(Boolean.TRUE);
derivedKeyTemplate.getPrivate().setBooleanValue(Boolean.FALSE);
derivedKeyTemplate.getSign().setBooleanValue(Boolean.TRUE);

byte[] derivationData = DatatypeConverter.parseHexBinary("45525448555200749916");
KeyDerivationStringDataParameters param = new KeyDerivationStringDataParameters(derivationData);
Mechanism mechanism = new Mechanism(PKCS11Constants.CKM_DES3_ECB);
mechanism.setParameters(param);
final Key deriveKey = session.deriveKey(mechanism, baseKey, derivedKeyTemplate);
System.out.println("deriveKey successful!");        

如您所见,我使用的是 PKCS#11 包装器 (IAIK)。问题是生成具有相同推导数据的不同密钥的推导。这是预期的行为吗?

我认为每次派生的密钥都不一样,因为我用这个密钥加密一个已知值,每次结果都不一样:

byte[] data = DatatypeConverter.parseHexBinary("01020304050607080C7D8B973D588B478000000000000000");
Mechanism m = new Mechanism(PKCS11Constants.CKM_DES3_ECB);
session.encryptInit(m, deriveKey);
byte[] bytes;
bytes = session.encrypt(data);
System.out.println(DatatypeConverter.printHexBinary(bytes));

第一次运行密钥推导和值加密

deriveKey successful!
encrypt using deriveKey: 7C4BB979F26FC78831CC83AB378E7B1D8E2F2D73B140D25D

第二轮密钥推导和值加密

deriveKey successful!
encrypt using deriveKey: F1CE8649333EA10E63B13DB3733CD55FFB010A63C6CEC7F2

第三轮密钥推导和值加密

deriveKey successful!
encrypt using deriveKey: A8D801BC1C0142B9E77576AEA0FBE677915E47144B6DCF3C

据我所知,派生是使用基本密钥对数据(派生数据)进行加密。然后将此加密值转换为另一个密钥(派生密钥),因此如果派生数据和基本密钥相同,则该值应该相同,this answer 解释此步骤。

【问题讨论】:

【参考方案1】:

您应该使用CKM_DES3_ECB_ENCRYPT_DATA 而不是CKM_DES3_ECB

奇怪的是,您没有收到错误,因为不应允许 CKM_DES3_ECB 进行密钥派生(请参阅 PKCS#11 v2.40 中的表 68)。

您的假设是正确的——该密钥派生算法必须为相同的派生数据(和主密钥)提供相同的密钥。

祝你的项目好运!


请注意:您的示例派生数据似乎具有固定结构。这样(在 ECB 模式下使用 DES)生成的 DES 密钥的第三部分将始终相同(即 8000000000000000 的加密)。您可能希望在派生数据用于密钥派生之前对其进行哈希处理(例如,使用 SHA-256)。或者完全重新考虑这个算法。

免责声明:我不是加密专家,所以请验证我的想法。

【讨论】:

以上是关于PKCS11 derivedKey 每次返回不同的值的主要内容,如果未能解决你的问题,请参考以下文章

如何通过模板获取PKCS11 PublicKey

PKCS11证书

sun.security.pkcs11.SunPKCS11的访问限制

sun.security.pkcs11.wrapper.PKCS11Exception:CKR_ATTRIBUTE_TYPE_INVALID

用于 openSSL 的 PKCS#11 引擎

PHP中的PKCS#7签名使用PKCS#11而没有CLI调用