'Convert ECDSA secp521r1 private key into PEM format using bouncy castle

We are programatically generating ECDSA private/public key in java as follows:

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(new ECGenParameterSpec("secp521r1"));
KeyPair keyPair = keyPairGenerator.generateKeyPair();

The private key is used by JGit to connect to a git provider where the public key is published. So we need to convert the private key to PEM format. This was working fine when using RSA based private/public key. However now that we are using ECDSA to generate the keys are running into issues while JGit connects to github. The following code is used to convert private key in PEM format that worked fine with RSA based keys.

private String getPrivateKeyInPEM(KeyPair keyPair) throws IOException {

   StringWriter writer = new StringWriter();
   JcaPEMWriter privatePemWriter = new JcaPEMWriter(writer);
   privatePemWriter.writeObject(keyPair.getPrivate());
   privatePemWriter.close();
   String privateKey = writer.toString();
   writer.close();

   return privateKey;
}

Now we are getting the following error from Jsch when generating keys using ECDSA.

Caused by: com.jcraft.jsch.JSchException: invalid privatekey: 
        at com.jcraft.jsch.KeyPair.load(KeyPair.java:664)
        at com.jcraft.jsch.IdentityFile.newInstance(IdentityFile.java:46)
        at com.jcraft.jsch.JSch.addIdentity(JSch.java:441)

Do we need to generate the PEM format of private key for ECDSA based keys in a different way? We are using bouncy castle version 1.70 and Jsch verison 0.1.55



Solution 1:[1]

The relevant format is ECPrivateKey from the standards document "SEC 1: Elliptic Curve Cryptography", section "C.4 Syntax for Elliptic Curve Private Keys":

ECPrivateKey ::= SEQUENCE {
  version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
  privateKey OCTET STRING,
  parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
  publicKey [1] BIT STRING OPTIONAL
}

We see that the last two elements of the SEQUENCE are optional. Unfortunately Jsch implicitly requires them to be present (see com.jcraft.jsch.KeyPairECDSA.parse in the 0.1.55 source code). When running your example code with the default provider configuration I see the failure coming from the absence of those optional elements.

Happily your example works if you use the BouncyCastle provider to actually generate the KeyPair, since BC adds those components to the ECPrivateKey structure when it encodes the private key.

e.g.

Security.addProvider(new BouncyCastleProvider());
...
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Peter Dettman