Search code examples
javacryptographybouncycastleencryption-asymmetricecdsa

Can't cast ECPublicKeyImpl to BCECPublicKey


I would like to get a compressed EC public key representation, and I did this by following this answer. But when I try to cast a java.security.PublicKey to a org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey I get an exception:

jdk.crypto.ec/sun.security.ec.ECPublicKeyImpl cannot be cast to org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey

Imports:

import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.math.ec.ECPoint;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.spec.ECGenParameterSpec;

Code:

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256k1");
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
keyGen.initialize(ecSpec, random);
KeyPair pair = keyGen.generateKeyPair();

ECPoint ecPoint = ((BCECPublicKey) pair.getPublic()).getQ(); - Exception

System.out.println(new String(ecPoint.getEncoded(true)));

Solution

  • KeyPairGenerator.getInstance(String) gets you the first security provider that implements the given algorithm. Without further configuration it is "SunEC".

    Since you clearly want to rely on BouncyCastle to generate your key, use the 2 parameter factory method:

    final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
    

    However, if you were to receive the KeyPair object as parameter, you can not assume it comes from BouncyCastle and you should convert it manually to a BCECPublicKey as in Topaco's comment:

    final BCECPublicKey pubKey = pair.getPublic() instanceof BCECPublicKey
      ? (BCECPublicKey) pair.getPublic()
      : new BCECPublicKey((ECPublicKey) pair.getPublic(), BouncyCastleProvider.CONFIGURATION);