0

To generate an ECDH keypair I have written below code which is the same as server's one which is using open-ssl. But my public key to Hex is like this (176):

3056301006072a8648ce3d020106052b8104000a0342000462bf4308171cffa3a3ed74a9e72cd3d5fde26d760322a5e39cd67166240f75f87edaffa52bef5e0895a37751f5b90b7b8fc077a90d76893e7cb857c1a49e4818

And the server public key is shorter, like this (130):

041f13436e59b8a4e61952b1f184052b330977732f7f8a0505c46028da82bdafd34ded7444a19acdbbf5de91cd914437c3ac9b827dac2f899a4bba961fd72a7ea3

Code:

        KeyPairGenerator kpgen = KeyPairGenerator.getInstance("ECDH", "SC");
        ECGenParameterSpec genspec = new ECGenParameterSpec("secp256k1");
        kpgen.initialize(genspec);

What's the cause of this discrepancy? Iuse this line to turn public key into byte array:

kpgen.generateKeyPair().getPublic().getEncoded()).getBytes();

I tried to convert Android-generated public key by:

PublicKey pub = kpgen.generateKeyPair().getPublic();    
byte[] pubBytes = pub.getEncoded();
SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(pubBytes);
ASN1Primitive primitive = spkInfo.parsePublicKey();
byte[] publicKeyPKCS1 = primitive.getEncoded();

But I get this error:

java.io.EOFException: DEF length 126 object truncated by 63 2021-04-01 17:52:56.113 20381-24882/ at org.spongycastle.asn1.DefiniteLengthInputStream.toByteArray(DefiniteLengthInputStream.java:103) 2021-04-01 17:52:56.113 20381-24882/... W/System.err: at org.spongycastle.asn1.ASN1InputStream.createPrimitiveDERObject(ASN1InputStream.java:455) 2021-04-01 17:52:56.113 20381-24882/... W/System.err: at org.spongycastle.asn1.ASN1InputStream.buildObject(ASN1InputStream.java:190) 2021-04-01 17:52:56.113 20381-24882/... W/System.err: at org.spongycastle.asn1.ASN1InputStream.readObject(ASN1InputStream.java:278) 2021-04-01 17:52:56.113 20381-24882/... W/System.err: at org.spongycastle.asn1.x509.SubjectPublicKeyInfo.parsePublicKey(SubjectPublicKeyInfo.java:112)

Ali Has
  • 598
  • 1
  • 8
  • 24
  • 1
    These are simply two different key formats. The upper public key _305630..._ is in X.509/SPKI format (s. https://lapo.it/asn1js), the lower _041f13..._ is an uncompressed public key (04 + x + y). – Topaco Apr 01 '21 at 12:59
  • How can I convert the first one into the other? – Ali Has Apr 01 '21 at 13:02
  • Please see the edit. – Ali Has Apr 01 '21 at 13:18
  • 1
    You can cast the public key `kpgen.generateKeyPair().getPublic()` to `ECPublicKey` and then you can get the x and y coordinates. Since you also use SpongyCastle, you can apply `java.security.interfaces.ECPublicKey` or `org.spongycastle.jce.interfaces.ECPublicKey` (with different names regarding x and y coordinate). The uncompressed key results as 0x04 | x | y. Note that the compressed public key is not the same as the X.509/SPKI key ([here](https://security.stackexchange.com/a/185552)). – Topaco Apr 01 '21 at 13:52
  • But with having X, Y ow do I get to X.509 format to send to server? Sorry I think I didn't understand you. – Ali Has Apr 01 '21 at 14:02
  • 1
    Your first posted key is in X.509/SPKI format. You asked how to convert the first format (X.509/SPKI) to the second (uncompressed). Now you seem to need the opposite direction. This is described e.g. [here](https://stackoverflow.com/a/56170785). – Topaco Apr 01 '21 at 14:06
  • Sorry, I got it mixed up. Now I casted my X.509/SPKI key to uncomressed format by: `ECPublicKey pub = (ECPublicKey) kpgen.generateKeyPair().getPublic();` But I still have the same length for new Public Key. – Ali Has Apr 01 '21 at 14:18
  • Which `ECPublicKey` did you use, from `java.security.interfaces` or from `org.spongycastle.jce.interfaces`? Anyway, with `getW()` or `getQ()` you can get the `ECPoint` that represents the public key, and thus the x and y coordinates. – Topaco Apr 01 '21 at 14:24
  • I used both and had the same results. Can you explain more on converting from getW , getQ to ECPoint? Is there a better solution? – Ali Has Apr 01 '21 at 14:46
  • 1
    `getW()` and `getQ()` already return an `ECPoint` (`java.security.spec` and `org.spongycastle.math.ec` respectively), so nothing to convert here. Both types have methods (e.g. `getAffineX()` or `getAffineXCoord()`) that return types (`BigInteger` or `ECFieldElement`) that encapsulate the x or y coordinate and methods that return these coordinates as hex string (e.g. `toString(16)`) or as `byte[]` (`getEncoded()`). You then only need to concatenate the parts (0x04 | x | y). A quick and dirty solution is: The last 65 bytes of the X.509/SPKI key are the uncompressed key. – Topaco Apr 01 '21 at 15:36
  • So how come the uncompressed has 130 members an not 65? exactly twice? – Ali Has Apr 01 '21 at 15:51
  • 1
    The uncompressed key (for secp256k1) consists of 65 bytes. If it is encoded as a hex string it has 130 bytes, since each byte is represented by two characters and thus two bytes (i.e. in the hex encoded X509/SPKI key the last 130 characters represent the uncompressed hex encoded key). – Topaco Apr 01 '21 at 15:54
  • Thank you! I got it. Really appreciate it! – Ali Has Apr 02 '21 at 05:05

0 Answers0