Reputation: 711
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
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