Java IAIK PKCS#11包装器:ECDH密钥协商示例

Java IAIK PKCS#11包装器:ECDH密钥协商示例,java,pkcs#11,iaik-jce,ecdh,Java,Pkcs#11,Iaik Jce,Ecdh,我尝试使用IAIK PKCS#11包装器()执行一些ECDH密钥协议,显然不使用JCE提供程序。到目前为止,我还没有找到任何这样做的例子,特别是设置关键模板和机制(以及机制参数) 您是否有一些示例,如何使用BouncyCastle执行此操作并验证结果 谢谢大家! 最后,我自己完成了 首先要注意,IAIK PKCS#11包装器并不支持PKCS#11的所有键派生函数。 DHKeyDerivationParameters.KeyDerivationFunctionType指定它支持的内容,遗憾的是 提

我尝试使用IAIK PKCS#11包装器()执行一些ECDH密钥协议,显然不使用JCE提供程序。到目前为止,我还没有找到任何这样做的例子,特别是设置关键模板和机制(以及机制参数)

您是否有一些示例,如何使用BouncyCastle执行此操作并验证结果


谢谢大家!

最后,我自己完成了

首先要注意,IAIK PKCS#11包装器并不支持PKCS#11的所有键派生函数。 DHKeyDerivationParameters.KeyDerivationFunctionType指定它支持的内容,遗憾的是 提供一个long,它检查值是否已知,因此不能简单地提供为其他KDF定义的值 功能。但是,如果您的PKCS#11模块支持它,您可以使用DHKeyDerivationParameters.KeyDerivationFunctionType.NULL 然后自己推导

对于下面的代码段,让session为一些iaik.pkcs.pkcs11.session,这是正确的 已通过身份验证以使用选定的ECDH密钥

在这种情况下,请执行以下操作以导出AES密钥(2DE和3DES或其他AES长度基本相同):

要检索普通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();
}
要执行“其他”端并验证派生值是否符合预期,可以使用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中间件和一些智能卡。我希望它也能帮助其他人,尝试着做同样的事情。

Hi@Daniel,获得一个共享的秘密似乎和获得一把钥匙是一样的?我注意到您正在派生公钥而不是私钥?如何从公钥获取私钥:ka.init(publicTestKey.getPrivate());?这是不可能的。谢谢。我们如何使用Bouncy Castle在HSM中存储的私钥(EC)执行密钥协议?@AhmedMANSOUR:session能够使用私钥,因此如果我交上公钥,则需要一个私钥和一个公钥来计算共享密钥。此共享密钥用于派生AES密钥。在bouncycastle中,您无法使用HSM中的私钥签署密钥协议。私钥在HSM中,并且(希望)永远不会离开它,因此bouncycastle无法使用它。感谢您的回答,代码中的ka.init(publictKey.getPrivate())不起作用,ECPublicKey中没有getPrivate方法。
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));
}