IAIK PKCS#11 包装器:ECDH KeyAgreement 示例
IAIK PKCS#11 Wrapper: ECDH KeyAgreement Example
我尝试执行一些 ECDH 密钥协议,使用 IAIK PKCS#11 包装器 (https://jce.iaik.tugraz.at/sic/Products/Core_Crypto_Toolkits/PKCS_11_Wrapper),明确地不使用 JCE 提供程序。到目前为止,我没有找到任何示例如何执行此操作,尤其是设置密钥模板和机制(以及机制参数)。
你有一些例子,如何执行此操作并验证结果,最佳地使用 BouncyCastle?
谢谢!
最后,我自己搞定了。
首先请注意,IAIK PKCS#11 包装器不支持 PKCS#11 的所有密钥派生函数。
DHKeyDerivationParameters.KeyDerivationFunctionType 指定它支持什么,遗憾的是,尽管您
提供一个 long,它检查该值是否已知,因此您不能简单地提供为其他 KDF 定义的值
职能。不过,如果您的 PKCS#11 模块支持它,您可以使用 DHKeyDerivationParameters.KeyDerivationFunctionType.NULL
并自己进行推导。
对于下面的片段,让会话是一些 iaik.pkcs.pkcs11.Session,这是正确的
已通过身份验证以使用所选的 ECDH 密钥。
执行以下操作导出密钥,在本例中为 AES(2Des 和 3DES 或其他 AES 长度基本相同):
final long CKA_VALUE_LEN = 0x00000161;
byte[] deriveKey(byte[] publicKey, byte[] salt, long keyDerivationFunction) throws Exception {
// setting up mechanism:
EcDH1KeyDerivationParameters params = new EcDH1KeyDerivationParameters(keyDerivationFunction, salt, publicKey);
Mechanism mechanism = Mechanism.get(PKCS11Constants.CKM_ECDH1_DERIVE );
mechanism.setParameters(params);
// setting up keyTemplate, specifying how the derived key looks like:
Key keyTemplate = new AESSecretKey();
keyTemplate.putAttribute(CKA_VALUE_LEN, new Long(32));
AESSecretKey derivedKey = ((AESSecretKey)session.deriveKey(mechanism, key, keyTemplate));
return derivedKey.getValue().getByteArrayValue();
}
要检索纯 ECDH 共享密钥,请按以下步骤操作:
byte[] getSharedSecret(byte[] publicKey) throws Exception{
// setting up mechanism:
EcDH1KeyDerivationParameters params = new EcDH1KeyDerivationParameters(DHKeyDerivationParameters.KeyDerivationFunctionType.NULL, null, publicKey);
Mechanism mechanism = Mechanism.get(PKCS11Constants.CKM_ECDH1_DERIVE );
mechanism.setParameters(params);
// four our PKCS#11 module, using a GenericSecretKey without length returns
// the complete derived secret:
Key keyTemplate = new GenericSecretKey();
GenericSecretKey derivedKey = ((GenericSecretKey)session.deriveKey(mechanism, key, keyTemplate));
return derivedKey.getValue().getByteArrayValue();
}
要执行 'other' 端并验证派生值是否符合预期,您可以使用 BouncyCastle 和以下代码:
void testKeyDerivation(ECPublicKey otherPublic, byte[] salt) throws Exception{
// create some keypair, which fits to the EC key, IAIK is using:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDH", BouncyCastleProvider.PROVIDER_NAME);
keyGen.initialize(otherPublic.getParams());
KeyPair testKeyPair = keyGen.generateKeyPair();
ECPublicKey publicTestKey = (ECPublicKey) testKeyPair.getPublic();
// convert the JCE Publickey to the required format, using BouncyCastle:
byte[] encodedPublicTestKey = EC5Util.convertPoint(publicTestKey.getParams(), publicTestKey.getW(),false).getEncoded(false);
// format is 0x04 X Y where X and Y are byte[], containing the (padded) coordinates of the point,
// specifying the public key
// in fact, you need to do only one of these, but I want to show, how both works:
byte[] iaikDerivedKey = deriveKey(encodedPublicTestKey, salt, DHKeyDerivationParameters.KeyDerivationFunctionType.SHA1_KDF);
byte[] iaikDerivedSecret = getSharedSecret(encodedPublicTestKey);
// verify that both sides indeed agree:
KeyAgreement ka = KeyAgreement.getInstance("ECDH", BouncyCastleProvider.PROVIDER_NAME);
ka.init(testKeyPair.getPrivate());
ka.doPhase(otherPublic, true);
byte [] secret = ka.generateSecret();
Assert.assertTrue(Arrays.equals(iaikDerivedSecret, secret));
Digest digest = new SHA1Digest();
KDF2BytesGenerator kdf = new KDF2BytesGenerator(digest);
DerivationParameters derivationParameters = new KDFParameters(secret,salt);
kdf.init(derivationParameters);
byte[] derivedKey = new byte[iaikDerivedKey.length];
kdf.generateBytes(derivedKey, 0, iaikDerivedKey.length);
Assert.assertTrue(Arrays.equals(iaikDerivedKey, derivedKey));
}
这确实适用于 IAIK PKCS#11 包装器版本 1.5 和 BouncyCastle 版本 1.59,使用我公司的 PKCS#11 中间件和一些智能卡。我希望它也能帮助其他人,尝试做同样的事情。
我尝试执行一些 ECDH 密钥协议,使用 IAIK PKCS#11 包装器 (https://jce.iaik.tugraz.at/sic/Products/Core_Crypto_Toolkits/PKCS_11_Wrapper),明确地不使用 JCE 提供程序。到目前为止,我没有找到任何示例如何执行此操作,尤其是设置密钥模板和机制(以及机制参数)。
你有一些例子,如何执行此操作并验证结果,最佳地使用 BouncyCastle?
谢谢!
最后,我自己搞定了。
首先请注意,IAIK PKCS#11 包装器不支持 PKCS#11 的所有密钥派生函数。 DHKeyDerivationParameters.KeyDerivationFunctionType 指定它支持什么,遗憾的是,尽管您 提供一个 long,它检查该值是否已知,因此您不能简单地提供为其他 KDF 定义的值 职能。不过,如果您的 PKCS#11 模块支持它,您可以使用 DHKeyDerivationParameters.KeyDerivationFunctionType.NULL 并自己进行推导。
对于下面的片段,让会话是一些 iaik.pkcs.pkcs11.Session,这是正确的 已通过身份验证以使用所选的 ECDH 密钥。
执行以下操作导出密钥,在本例中为 AES(2Des 和 3DES 或其他 AES 长度基本相同):
final long CKA_VALUE_LEN = 0x00000161;
byte[] deriveKey(byte[] publicKey, byte[] salt, long keyDerivationFunction) throws Exception {
// setting up mechanism:
EcDH1KeyDerivationParameters params = new EcDH1KeyDerivationParameters(keyDerivationFunction, salt, publicKey);
Mechanism mechanism = Mechanism.get(PKCS11Constants.CKM_ECDH1_DERIVE );
mechanism.setParameters(params);
// setting up keyTemplate, specifying how the derived key looks like:
Key keyTemplate = new AESSecretKey();
keyTemplate.putAttribute(CKA_VALUE_LEN, new Long(32));
AESSecretKey derivedKey = ((AESSecretKey)session.deriveKey(mechanism, key, keyTemplate));
return derivedKey.getValue().getByteArrayValue();
}
要检索纯 ECDH 共享密钥,请按以下步骤操作:
byte[] getSharedSecret(byte[] publicKey) throws Exception{
// setting up mechanism:
EcDH1KeyDerivationParameters params = new EcDH1KeyDerivationParameters(DHKeyDerivationParameters.KeyDerivationFunctionType.NULL, null, publicKey);
Mechanism mechanism = Mechanism.get(PKCS11Constants.CKM_ECDH1_DERIVE );
mechanism.setParameters(params);
// four our PKCS#11 module, using a GenericSecretKey without length returns
// the complete derived secret:
Key keyTemplate = new GenericSecretKey();
GenericSecretKey derivedKey = ((GenericSecretKey)session.deriveKey(mechanism, key, keyTemplate));
return derivedKey.getValue().getByteArrayValue();
}
要执行 'other' 端并验证派生值是否符合预期,您可以使用 BouncyCastle 和以下代码:
void testKeyDerivation(ECPublicKey otherPublic, byte[] salt) throws Exception{
// create some keypair, which fits to the EC key, IAIK is using:
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECDH", BouncyCastleProvider.PROVIDER_NAME);
keyGen.initialize(otherPublic.getParams());
KeyPair testKeyPair = keyGen.generateKeyPair();
ECPublicKey publicTestKey = (ECPublicKey) testKeyPair.getPublic();
// convert the JCE Publickey to the required format, using BouncyCastle:
byte[] encodedPublicTestKey = EC5Util.convertPoint(publicTestKey.getParams(), publicTestKey.getW(),false).getEncoded(false);
// format is 0x04 X Y where X and Y are byte[], containing the (padded) coordinates of the point,
// specifying the public key
// in fact, you need to do only one of these, but I want to show, how both works:
byte[] iaikDerivedKey = deriveKey(encodedPublicTestKey, salt, DHKeyDerivationParameters.KeyDerivationFunctionType.SHA1_KDF);
byte[] iaikDerivedSecret = getSharedSecret(encodedPublicTestKey);
// verify that both sides indeed agree:
KeyAgreement ka = KeyAgreement.getInstance("ECDH", BouncyCastleProvider.PROVIDER_NAME);
ka.init(testKeyPair.getPrivate());
ka.doPhase(otherPublic, true);
byte [] secret = ka.generateSecret();
Assert.assertTrue(Arrays.equals(iaikDerivedSecret, secret));
Digest digest = new SHA1Digest();
KDF2BytesGenerator kdf = new KDF2BytesGenerator(digest);
DerivationParameters derivationParameters = new KDFParameters(secret,salt);
kdf.init(derivationParameters);
byte[] derivedKey = new byte[iaikDerivedKey.length];
kdf.generateBytes(derivedKey, 0, iaikDerivedKey.length);
Assert.assertTrue(Arrays.equals(iaikDerivedKey, derivedKey));
}
这确实适用于 IAIK PKCS#11 包装器版本 1.5 和 BouncyCastle 版本 1.59,使用我公司的 PKCS#11 中间件和一些智能卡。我希望它也能帮助其他人,尝试做同样的事情。