Michał
Michał

Reputation: 711

Get raw keys from Bouncy Castle Java

I am working with both C and Java implementations for ECDSA. C implementation is using raw formats - 32-byte private key, 64-byte public key, 64-byte signature.

I am creating keys in Java using Bouncy Castle:

    public static KeyPair GenerateKeys() throws NoSuchAlgorithmException,
        NoSuchProviderException, InvalidAlgorithmParameterException {
        ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1");
        KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC");

        g.initialize(ecSpec, new SecureRandom());

        return g.generateKeyPair();
    }

and want to store them as byte arrays, as I need to export them to my C application later on. I noticed that:

        KeyPair vendorKeys = GenerateKeys();
        for (byte byt : vendorKeys.getPublic().getEncoded()) {
            System.out.println("byt: " +  byt);
        }

will return bytes of Public key, but length is wrong. I guess it is related to format which is X.509 for PublicKey and PKCS#8 for private. Looking for help I found out that there are some classes in Java like PKCS8EncodedKeySpec which should help me get raw key, but wasn't able to figure out how to do it.

Upvotes: 2

Views: 2089

Answers (1)

Topaco
Topaco

Reputation: 49141

The private key or the x and y coordinates of the public key can be determined with BouncyCastle via its implementations ECPrivateKey and ECPublicKey. With getD() the private and with getQ() the public key can be determined, e.g.:

import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.encoders.Hex;
...
ECPublicKey publickKey = (ECPublicKey)vendorKeys.getPublic();
ECPrivateKey privateKey = (ECPrivateKey)vendorKeys.getPrivate();
byte[] rawPrivate = BigIntegers.asUnsignedByteArray(privateKey.getD());
byte[] x = publickKey.getQ().getAffineXCoord().getEncoded();
byte[] y = publickKey.getQ().getAffineYCoord().getEncoded();        
byte[] rawPublic = ByteBuffer.allocate(x.length + y.length).put(x).put(y).array();

System.out.println(Hex.toHexString(rawPrivate));
System.out.println(Hex.toHexString(rawPublic));

The public key here for secp256r1 always has a length of 64 bytes. The private key is 32 bytes in size, but can also be smaller.


dave_thompson_085 has pointed out the built-in Java implementations for ECPublicKey and ECPrivateKey in his comment (java.security.interfaces). Here the corresponding methods for the private and public key are getS() and getW(), respectively.
This implementation does not automatically pad with leading 0x00 values in the case of an x or y smaller than 32 bytes, so this must be done manually. Therefore, the BouncyCastle approach is probably more convenient for you, also because you already use BouncyCastle.

Upvotes: 1

Related Questions