5

我正在编写一个程序(在 Java 中使用 Bouncy Castle API),该程序使用 AES-256/GCM 使用由 ONE EC 密钥对生成的密钥来加密文件。我的对称加密部分工作得很好,但现在证明密钥生成很困难。当尝试在 javax.crypto.KeyAgreement.init() 方法中使用 ECPublicKey 对象时,它返回此错误:

Exception in thread "main" java.security.InvalidKeyException: ECDH key agreement requires ECPrivateKey for initialisation
    at org.bouncycastle.jcajce.provider.asymmetric.ec.KeyAgreementSpi.initFromKey(Unknown Source)
    at org.bouncycastle.jcajce.provider.asymmetric.ec.KeyAgreementSpi.engineInit(Unknown Source)
    at javax.crypto.KeyAgreement.init(KeyAgreement.java:461)
    at javax.crypto.KeyAgreement.init(KeyAgreement.java:435)
    at Encrpytion.generateKey(Encrpytion.java:188)  ---aKA.init(key);---
    at Encrpytion.main(Encrpytion.java:40) ---byte[] key = generateKey();---

该方法的源代码如下:

public static byte[] generateKey() {
    KeyStore ks = KeyStore.getInstance("PKCS12");
    FileInputStream fis = new FileInputStream("file.pfx");
    Scanner input = new Scanner(System.in);
    char[] chars = {};
    System.out.println("Enter the password for your .pfx: ");
    chars = input.nextLine().toCharArray();
    input.close();
    Enumeration aliasEnum = null;
    ks.load(fis, chars);
    aliasEnum = ks.aliases();
    Key key = null;
    Certificate cert = null;
    while (aliasEnum.hasMoreElements()){
        String param = (String)aliasEnum.nextElement();
        if (ks.isKeyEntry(param))  {
            String keyName = param;
            key = ks.getKey(keyName,chars);
        }
        cert = ks.getCertificateChain(param)[0];
    }
    KeyPair kp = new KeyPair(cert.getPublicKey(),(ECPrivateKey) key);
    KeyAgreement aKA = null;
    aKA = KeyAgreement.getInstance("ECDH", "BC");
    aKA.init(key);
    aKA.doPhase(kp.getPublic(), true);
    return aKA.generateSecret();
}

如何访问证书的 PrivateKey?

**更新:**更新源代码

** 编辑 ** 以下命令和说明可用于创建一些测试文件来演示问题。

#Make root key
openssl ecparam -name secp521r1 -genkey -out root.key
#password protect key
openssl ec -in root.key -out root.key -aes256
####change req x509_attributes to rootCA
#selfsign root
openssl req -new -x509 -key root.key -out root.crt -days 1825 -config openssl.cfg
###comment out req x509_attributes
#make new key for clientCA
openssl ecparam -name secp521r1 -genkey -out client.key
#make clientCA csr
openssl req -new -sha384 -key client.key -out client.csr -config openssl.cfg
#sign clientCA
openssl ca -out client.crt -name root -in client.csr -config openssl.cfg
#make client key
openssl ecparam -name secp521r1 -genkey -out client.key
#make server csr
openssl req -new -sha384 -key client.key -out client.csr -config openssl.cfg
#sign server cert
openssl ca -out client.crt -name client -in client.csr -config openssl.cfg
#MAKE CHAIN - copy base64 encoded root and intermidiate client ca into same "chain.cer" #export user cert 
openssl pkcs12 -export -chain -CAfile chain.crt -in client.crt -inkey client.key -out client.pfx -aes256
4

1 回答 1

3

对于任何给定的别名,只有key和之一cert是非空的。在这种情况下,显然cert是非空的,键是空的。如果您的密钥库中有 EC 私钥,您将需要更加努力地找到它。您可以通过使用和进行测试来确定别名中的条目类型isCertificateEntryisKeyEntry

编辑 1

不幸的是,错误消息令人困惑,因为它实际上来自 bouncycastle 库。中提到的ECDH key agreement requires ECPrivateKey不是 java.security.interfaces.ECPrivateKey而是org.bouncycastle.jce.interfaces.ECPrivateKey

以下对 OP 示例代码的简短改编说明了克服此问题的一种方法。

import org.bouncycastle.jce.provider.JCEECPrivateKey;
import org.bouncycastle.jce.provider.JCEECPublicKey;
// ...
// . <original example code goes here>
// .
JCEECPrivateKey ecPrivKey = new JCEECPrivateKey((ECPrivateKey) key);
JCEECPublicKey ecPubKey = new JCEECPublicKey((ECPublicKey) cert.getPublicKey());
KeyPair kp = new KeyPair(ecPubKey, ecPrivKey);
KeyAgreement aKA = null;
aKA = KeyAgreement.getInstance("ECDH", "BC");
aKA.init(ecPrivKey);
aKA.doPhase(kp.getPublic(), true);
return aKA.generateSecret();
// ...
于 2012-12-14T00:59:03.150 回答