2

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.

klutt
  • 30,332
  • 17
  • 55
  • 95
Michał
  • 691
  • 1
  • 5
  • 22
  • You should be able to cast private and public key to `ECPrivateKey` and `ECPublicKey` respectively and then get the required parameters using `getD()` and `getQ()`. – Topaco Nov 05 '21 at 08:10
  • 1
    @Topaco: if you use the ones in `org.bouncycastle.jce.interfaces`; standard JCE is different. And `BigInteger` doesn't give you a fixed-size encoding, and even the X9.62 encoding from Bouncy `ECPoint` isn't _exactly_ right. However you can get the _signature_ in fixed format with Bouncy '{hash}with{PLAIN-,CVC-}ECDSA' _or_ SunEC 9+ '{hash}withECDSAinP1363format'. Michal: there are several existing Qs on getting 'raw' keys _into_ JCE, but for getting them out the closest I can find are https://stackoverflow.com/questions/52299691/ and https://stackoverflow.com/questions/51347513/ . – dave_thompson_085 Nov 05 '21 at 10:51
  • @dave_thompson_085 - I was referring to BouncyCastle (`getD()` and `getQ()` are used by BC), but thanks for the clarification. I made it clearer in my answer. – Topaco Nov 05 '21 at 11:51

1 Answers1

1

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.

Topaco
  • 40,594
  • 4
  • 35
  • 62
  • I had to rename `getD()` to `getS()`, `getQ()` to `getW()`, `getAffineXCoord()` to `getAffineX()` same for `YCoord`, but it works great now! I guess API changed between versions? Any tips how to do opposite, from raw key create a bouncy castle? – Michał Nov 05 '21 at 12:10
  • @Michał - By your change you apply the built-in Java implementation instead of BC's (s. the last part in my answer). You can do that, but x and y are not automatically padded. – Topaco Nov 05 '21 at 12:30
  • 1
    @Michał - Regarding the other way around, you can find various posts on SO, e.g. [here](https://stackoverflow.com/q/30445997/9014097) and [here](https://stackoverflow.com/q/31435160/9014097). – Topaco Nov 05 '21 at 12:44