Java – recover EC private key from PEM format using bouncycastle

My application stores the private key in PEM format. The existing code is applicable to RSA key, but I tried to switch to EC key and there is a problem The key recovery appears to be valid, and the equals method on the recovery key returns true for the original key, but getalgorithm() on the original key returns "EC" and returns the recovery key "ECDSA" The difference in the algorithm later led to problems because it did not match the algorithm of the corresponding public key

What did I do wrong or was this an error in the PEM parser?

This is a test program that demonstrates the problem:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.spec.ECGenParameterSpec;

import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.PEMWriter;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.immutify.janus.keytool.KeyToolUtils;

public class TestPrivateKeyRecovery
{
    private static final String KEY_ALGORITHM           = "EC";
    private static final String SIGNATURE_ALGORITHM     = "SHA512withECDSA";
    private static final String PROVIDER                = "BC";
    private static final String CURVE_NAME              = "secp521r1";
    private static final String WRAPPING_CIPHER_SPEC    = "ECIESwithAES";

    private ECGenParameterSpec  ecGenSpec;
    private KeyPairGenerator    keyGen_;
    private SecureRandom        rand_;

    public void run()
    {
        try
        {
            rand_       = new SecureRandom();
            ecGenSpec   = new ECGenParameterSpec(CURVE_NAME);
            keyGen_     = KeyPairGenerator.getInstance(KEY_ALGORITHM,PROVIDER);

            keyGen_.initialize(ecGenSpec,rand_);


            PrivateKey privateKey = keyGen_.generateKeyPair().getPrivate();





            String der = privateKeyToDER(privateKey);

            PrivateKey recoveredKey = privateKeyFromDER(der);

            System.out.println("privateKey=" + privateKey);
            System.out.println("privateKey.getAlgorithm()=" + privateKey.getAlgorithm());
            System.out.println("der=" + der);
            System.out.println("recoveredKey=" + privateKey);
            System.out.println("recoveredKey.getAlgorithm()=" + recoveredKey.getAlgorithm());
            System.out.println();

            if(privateKey.equals(recoveredKey))
                System.out.println("Key recovery ok");
            else
                System.err.println("Private key recovery Failed");

            if(privateKey.getAlgorithm().equals(recoveredKey.getAlgorithm()))
                System.out.println("Key algorithm ok");
            else
                System.err.println("Key algorithms do not match");
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    public static   String      privateKeyToDER(PrivateKey key) throws IOException
    {
        ByteArrayOutputStream   bos = new ByteArrayOutputStream();
        PEMWriter               pemWriter = new PEMWriter(new OutputStreamWriter(bos));

        pemWriter.writeObject(key);

        pemWriter.close();

        return new String(bos.toByteArray());
    }

    public static   PrivateKey      privateKeyFromDER(String der) throws IOException
    {
        StringReader            reader = new StringReader(der);
        PEMParser               pemParser = new PEMParser(reader);

        try
        {
            Object o = pemParser.readObject();

            if (o == null || !(o instanceof PEMKeyPair))
            {
                throw new IOException("Not an OpenSSL key");
            }

            KeyPair kp = new JcaPEMKeyConverter().setProvider("BC").getKeyPair((PEMKeyPair)o);
            return kp.getPrivate();
        }
        finally
        {
            pemParser.close();
        }
    }
}

The output of the test program is:

privateKey=EC Private Key
             S: 13d19928468d14fabb9235a81fc1ec706ff5413a70a760b63e07d45a5d04a2f18425ef735500190291aacaf58c92306acd87fa01a47d907d5d3fc01531180353146

privateKey.getAlgorithm()=EC
der=-----BEGIN EC PRIVATE KEY-----
MIHcAgEBBEIBPRmShGjRT6u5I1qB/B7HBv9UE6cKdgtj4H1FpdBKLxhcxvc1UAGQ
KRqsr1jJIwas2H+gGkfZB9XT/AFTEYA1MUagBwYFK4EEACOhgYkDgYYABAFN5ZcE
zg9fV13u57ffwyN9bm9Wa9Pe0MtL2cd5CW2ku4mWzgS5m8IfNMAw2QMah5Z9fuXW
1fGJgUx1RsC09R6legFTgymlbqt+CaPhNsJkr12cjyzhT1NxR6uEzMUtBcYxqLHy
ANkhHmvAk221//YIRIWix7ZlRsRrs+iYrpWw4bMt9A==
-----END EC PRIVATE KEY-----

recoveredKey=EC Private Key
             S: 13d19928468d14fabb9235a81fc1ec706ff5413a70a760b63e07d45a5d04a2f18425ef735500190291aacaf58c92306acd87fa01a47d907d5d3fc01531180353146

recoveredKey.getAlgorithm()=ECDSA

Key recovery ok
Key algorithms do not match

Solution

The problem is not pemparser, but jcapemkeyconverter regards the EC key as the key of ECDSA:

algorithms.put(X9ObjectIdentifiers.id_ecpublicKey,"ECDSA");
...
private KeyFactory getKeyFactory(AlgorithmIdentifier algId)
throws NoSuchAlgorithmException,NoSuchProviderException
{
  ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
  String algName = (String)algorithms.get(algorithm);
...

The algorithm identifier is ID ecpublickey, which is also used for ECDSA key. Therefore, the algorithm selection is not unique here, and BC devs may choose ECDSA as the most appropriate choice You can use your own keyfactory to perform operations similar to jcapemkeyconverter, but select the correct algorithm for the EC key

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>