0

I am using EC secp160r2 for key generation. My code looks like this:

Security.insertProviderAt(new BouncyCastleProvider(), 1);
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
keyGen.initialize(new ECGenParameterSpec("secp160r2"), new SecureRandom());
keyPair = keyGen.generateKeyPair();

Further more I get the public key (for exchange) like following:

byte [] publicKey = keyPair.getPublic().getEncoded(); // 64 bytes
ASN1Sequence sequence = DERSequence.getInstance(publicKey);
DERBitString subjectPublicKey = (DERBitString) sequence.getObjectAt(1);
byte[] ecPublicKeyBytes = subjectPublicKey.getBytes(); // 41 bytes

and I end up with a 40 byte public key when I remove the prefix.

The problem I have is when I was to do the opposite, to get the public key out of a Hex String I receive. PubKey is a hex string of length 80. I tried generating the public key like this:

KeyFactory kf = KeyFactory.getInstance("EC");
PublicKey generatedPublic = kf.generatePublic(new X509EncodedKeySpec(hexStringToByteArray(pubKey)));

However I end up getting an InvalidKeyException:

Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: null
    at jdk.crypto.ec/sun.security.ec.ECKeyFactory.engineGeneratePublic(ECKeyFactory.java:157)
    at java.base/java.security.KeyFactory.generatePublic(KeyFactory.java:352)
    at Main.main(Main.java:71)
Caused by: java.security.InvalidKeyException: IOException: null
    at java.base/sun.security.x509.X509Key.decode(X509Key.java:397)
    at java.base/sun.security.x509.X509Key.decode(X509Key.java:402)
    at jdk.crypto.ec/sun.security.ec.ECPublicKeyImpl.<init>(ECPublicKeyImpl.java:71)
    at jdk.crypto.ec/sun.security.ec.ECKeyFactory.implGeneratePublic(ECKeyFactory.java:219)
    at jdk.crypto.ec/sun.security.ec.ECKeyFactory.engineGeneratePublic(ECKeyFactory.java:153)
    ... 2 more

Additionally here is the hex conversion method which in my case results in a 40 byte array:

public static byte[] parseHexBinary(String hexString) {
        byte[] bytes = new byte[hexString.length() / 2];

        for(int i = 0; i < hexString.length(); i += 2){
            String sub = hexString.substring(i, i + 2);
            Integer intVal = Integer.parseInt(sub, 16);
            bytes[i / 2] = intVal.byteValue();
        }
        return bytes;
    }

Any help to resolve the issue is very much appreciated!

M.Mark
  • 71
  • 1
  • 6
  • What is most likely happening is that you are have a different format and/or encoding of the key when you create it vs when you retrieve it. Make sure to look up the ASN1 format to know how your string is changing. I would suggest looking at the value of the bytes of the key before you format it with DERBitString, after, and after you try to retrieve it. – Jroosterman Oct 11 '21 at 15:22
  • 3
    The import of a raw EC key (x|y, 40 bytes for secp160r2) is described e.g. [here (JCE)](https://stackoverflow.com/a/56170785/9014097) or [here (BC)](https://stackoverflow.com/a/36033552/9014097). Btw, `publicKey` is a public key in X.509/SPKI format and `ecPublicKeyBytes` is an uncompressed public key: 0x04|x|y, i.e. has a size of 41 bytes (or 40 bytes without 0x04 prefix) for secp160r2. – Topaco Oct 11 '21 at 16:46
  • 1
    @Topaco thank you very much for this solution, it fixed my issue! And thanks for pointing out the mistake I wrote in my question 40 instead of 41 bytes with prefix, I have corrected it. If you wish, post your solution as an answer instead as a comment, so that I can accept is. Thanks again! – M.Mark Oct 12 '21 at 10:57

1 Answers1

1

Thanks to the solution posted in the comments, I'd like to post the code that might help someone:

ECParameterSpec ecParameterSpec = ECNamedCurveTable.getParameterSpec("secp160r2");
ECNamedCurveSpec params = new ECNamedCurveSpec("secp160r2", ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN());
ECPoint publicPoint =  ECPointUtil.decodePoint(params.getCurve(), parseHexBinary(pubKey));
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(publicPoint, params);
KeyFactory kf = KeyFactory.getInstance("EC");
PublicKey publicKey =  kf.generatePublic(pubKeySpec);

The code above results in a 64 Byte public key. pubKey is a public key hex string, with appended prefix. Note that 02 and 03 prefixes are used for compressed, and 04 for uncompressed keys. Elliptic Curve Cryptography Subject Public Key Information

M.Mark
  • 71
  • 1
  • 6