5

I'm writing a program (in Java using the Bouncy Castle API) that encrypts files with AES-256/GCM with a key generated by ONE EC key pair. I have the symmetric encryption portion working perfectly but now the key generation is proving to be difficult. When trying to use the ECPublicKey object in the javax.crypto.KeyAgreement.init() method, it returns this error:

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();---

The source code for the method is as follows:

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();
}

How can I access the PrivateKey of the certificate?

**UPDATE: **updated sourcecode

** EDIT ** The following commands and instructions can be used to create some test files to demonstrate the problem.

#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
Jim
  • 587
  • 2
  • 6
  • 19

1 Answers1

3

For any given alias only one of key and cert will be non-null. In this case evidently cert was non-null and key was null. If there is an EC private key in your keystore you will need to work a little harder to find it. You can determine what kind of entry is at the alias by testing with isCertificateEntry and isKeyEntry.

EDIT 1

The error message is unfortunately confusing because it is actually coming from the bouncycastle library. The class referred to in ECDH key agreement requires ECPrivateKey is not java.security.interfaces.ECPrivateKey but rather org.bouncycastle.jce.interfaces.ECPrivateKey

The following short adaptation of the OPs sample code illustrates one way to overcome this.

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();
// ...
President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
  • it tells me it is a key entry when I run this `for (Enumeration e = ks.aliases() ; ks.aliases().hasMoreElements() ;) { if (ks.isKeyEntry(e.nextElement().toString())) System.out.println("isKeyEntry"); if (ks.isCertificateEntry(e.nextElement().toString())) System.out.println("isCertificateEntry"); }` – Jim Dec 14 '12 at 03:35
  • another thing that might be making this more difficult is that in the .pfx there is a chain certificate as well as my certificate and the private key. – Jim Dec 14 '12 at 03:36
  • 1
    A problem is that your loop keeps going, and all you get is the results of the last iteration; one of `cert` and `key` will be null. – President James K. Polk Dec 14 '12 at 12:22
  • I got the certificate using `ks.getCertificateChain(param)[0]` and subsequently its public key. The `KeyPair` is fine according to debugging however I still get the error `"ECDH key agreement requires ECPrivateKey for initialisation"` even though it is in fact not a PrivateKey but truly an ECPrivateKey. I could really use some help here because I'm giving the method what the API says to but am still getting an error. – Jim Dec 18 '12 at 06:58
  • This is an ECDH certificate? Nobody issues those! I will try to create one myself with openssl and see if I can get this to work. – President James K. Polk Dec 19 '12 at 01:04
  • Thanks, it's an EC P-521 w/ SHA512 sig cert. I can give you the openssl commands if you want. I'm trying to implement NSA Suite B encryption. After this I'm gonna try and implement the same thing but with a PKCS#11 library for this http://www.safenet-inc.com/Products/Data_Protection/Multi-Factor_Authentication/Certificate-based_(PKI)_Smart_Cards/Smart_Card_650/ – Jim Dec 19 '12 at 03:54
  • @Андрей: I have been unable to produce such a pkcs12 file, so I would appreciate it if you can show the commands you use to produce it. – President James K. Polk Dec 21 '12 at 03:05
  • `#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` – Jim Dec 21 '12 at 22:12
  • `#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` If you need any part of the openssl.cfg file (with is highly likely), I can email/message it to you – Jim Dec 21 '12 at 22:13
  • In fact, I just made a test certificate for you which is almost exactly the same as the one I'm using (except for different key bits and common name of course). It can be downloaded here https://rapidshare.com/files/4147520278/testENCRYPT.pfx and has the password 'Test' (without quotes). Note this is only the encryption certificate as there's a separate signing certificate not being used in the software yet. I hope this helps you. – Jim Dec 21 '12 at 23:04
  • Ah, the problem was actually rather simple. I am updating my answer. – President James K. Polk Dec 22 '12 at 00:07
  • Thank you so much, it works great! If you think this was a well-formed question, please rate it up as I don't have enough rep to comment on other peoples' posts. Thanks again! – Jim Dec 22 '12 at 00:31