Search code examples
javabouncycastleelliptic-curvefips

How to convert ECPrivateKey into ECPublicKey using FIPS BouncyCastle?


How to convert ECPrivateKey into ECPublicKey using FIPS BouncyCastle?

I use the following code (slightly simplified) to convert an ECPrivateKey into an ECPublicKey:

public static ECPublicKey getPublicKeyFromPrivateKey(ECPrivateKey privateKey) throws GeneralSecurityException {
    final KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", new BouncyCastleProvider());
    final BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) privateKey;
    final ECParameterSpec ecSpec = bcecPrivateKey.getParameters();
    final ECPoint q = ecSpec.getG().multiply(bcecPrivateKey.getD());
    final byte[] qBytes = q.getEncoded(false);
    final ECPoint point = ecSpec.getCurve().decodePoint(qBytes);
    final ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, ecSpec);
    return (ECPublicKey) keyFactory.generatePublic(pubSpec);
}

This is working fine with non-FIPS BouncyCastle. Now, we have the requirement to do the same thing in a FIPS-compliant way. And here the problem is that classes like ECParameterSpec don't appear to exist in FIPS BouncyCastle 1.0.1. How can we do the same thing with FIPS BouncyCastle?


Solution

  • I found the following solution which worked for me:

    public static PublicKey getPublicKeyForPrivateKeyEC(ECPrivateKey privateKey) throws GeneralSecurityException {
        final KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", new BouncyCastleProvider());
        final ECParameterSpec ecSpec = privateKey.getParams();
        final ECCurve ecCurve = FipsECUtil.convertCurve(ecSpec);
        final ECMultiplier multiplier = ecCurve.getMultiplier();
        final ECPoint generatorP = FipsECUtil.convertPoint(ecSpec, ecSpec.getGenerator());
        final ECPoint q = multiplier.multiply(generatorP, privateKey.getS());
        final byte[] publicDerBytes = q.getEncoded(false);
        final ECPoint point = ecCurve.decodePoint(publicDerBytes);
        final ECPublicKeySpec pubSpec = new ECPublicKeySpec(new java.security.spec.ECPoint(
            point.getAffineXCoord().toBigInteger(), 
            point.getAffineYCoord().toBigInteger()), ecSpec);
        return keyFactory.generatePublic(pubSpec);
    }