基于EC主密钥与Bouncy Castle的私钥包装/解包问题咨询
实现CKM_ECDH1_DERIVE派生一致AES密钥(Bouncy Castle)
问题背景
需要复现HSM中的密钥派生流程:用外部EC主密钥私钥、内部EC公钥,通过CKM_ECDH1_DERIVE机制(搭配CKD_SHA256_KDF派生函数、共享数据、外部公钥数据)生成固定的AES密钥,用于验证私钥包装后的恢复结果。之前尝试UserKeyingMaterialSpec时每次生成不同密钥,不符合需求。
解决方案
Bouncy Castle提供了ECDHWithKdfParameterSpec类,可精准对应CKM_ECDH1_DERIVE的参数要求,确保每次派生的密钥一致。关键是要将共享数据、外部公钥数据等参数完整传入,且哈希算法指定为SHA-256。
代码实现
import org.bouncycastle.jce.spec.ECDHWithKdfParameterSpec; import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; import java.security.KeyPair; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Security; // 注册Bouncy Castle安全提供者 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); public class ECDHKdfDerivation { public static SecretKey deriveAESKey(PrivateKey externalEcPrivateKey, PublicKey internalEcPublicKey, byte[] sharedData, byte[] externalEcPublicKeyBytes) throws Exception { // 构建匹配CKM_ECDH1_DERIVE的参数 ECDHWithKdfParameterSpec params = new ECDHWithKdfParameterSpec( "SHA-256", // 对应CKD_SHA256_KDF派生函数 sharedData, externalEcPublicKeyBytes, null // 无额外密钥材料时传null ); KeyAgreement agreement = KeyAgreement.getInstance("ECDHwithKDF", "BC"); agreement.init(externalEcPrivateKey, params); agreement.doPhase(internalEcPublicKey, true); // 生成256位AES密钥 return agreement.generateSecret("AES"); } }
关键说明
- 参数完全匹配:
ECDHWithKdfParameterSpec的参数必须和HSM中CKM_ECDH1_DERIVE的配置完全一致:- 哈希算法固定为SHA-256,对应
CKD_SHA256_KDF; sharedData要和HSM中使用的共享数据字节完全相同;externalEcPublicKeyBytes是外部EC主密钥公钥的原始字节数组,需和HSM中传入的公钥数据一致。
- 哈希算法固定为SHA-256,对应
- 消除随机性:
UserKeyingMaterialSpec未覆盖CKM_ECDH1_DERIVE的完整参数结构,尤其是缺少外部公钥数据的传入,导致派生过程引入随机变量,所以每次生成的密钥不同。使用ECDHWithKdfParameterSpec可消除这种随机性,确保密钥一致。
内容的提问来源于stack exchange,提问作者3ric-T
相关产品推荐
相关产品推荐

