Supposed that the 33 bytes encoded Public Key can be created like this:
Security.addProvider(provider)
val generator = KeyPairGenerator.getInstance("ECDSA")
val ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1")
generator.initialize(ecSpec)
val keyPair = generator.generateKeyPair()
val privateKey = keyPair.private as ECPrivateKey
val publicKey = keyPair.public as ECPublicKey
val publicEncoded = publicKey.q.getEncoded(true)
How can I reconstruct it again on the other side (when I am having only the 33 bytes sent from here)?
I was trying below code:
val publicKey =KeyFactory.getInstance("EC").generatePublic(X509EncodedKeySpec(publicEncoded))
But I guess this is totally wrong, as I am getting the:
java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0c000079:ASN.1 encoding routines:OPENSSL_internal:HEADER_TOO_LONG
I was trying also:
val generator = KeyPairGenerator.getInstance("ECDSA")
val ecPublicKey = generator
.generatePublic(X509EncodedKeySpec((publicEncoded))) as ECPublicKey
But the error is:
java.security.spec.InvalidKeySpecException: encoded key spec not recognised
How to achieve my goal?
This should do the job:
import org.bouncycastle.jce.ECNamedCurveTable
import org.bouncycastle.jce.spec.ECPublicKeySpec
fun publicKeyFromCompressed(compressedPublicKey: ByteArray): PublicKey {
val ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1")
val point = ecSpec.curve.decodePoint(compressedPublicKey)
val publicKeySpec = ECPublicKeySpec(point, ecSpec)
val keyFactory = KeyFactory.getInstance("ECDSA")
val publicKey = keyFactory.generatePublic(publicKeySpec)
return publicKey
}
The primary problem is that your publicEncoded
is not an encoded public key, but an encoded ECPoint
(publicKey.q
).
This means you need to first reconstruct the point and then provide the appropriate curve to reconstruct the key to obtain the correct ECPublicKeySpec
.
- First re-obtain the chosen curve spec with
ECNamedCurveTable.getParameterSpec("secp256r1")
. You can then use ecSpec.curve.decodePoint(publicEncoded)
to reconstruct the BC ECPoint
instance.
- Turn the BouncyCastle
ECNamedCurveParameterSpec
into the java.security.spec.ECParameterSpec
and the BouncyCastle ECPoint
into the java java.security.spec.ECPoint
. Then construct the appropriate ECPublicKeySpec
which can then be used by the ECDSA
key generator to recreate the complete PublicKey
.
References:
ECPoint.getEncoded()
/ ECCurve.decodePoint(byte[])
ECNamedCurveParameterSpec
/ ECPublicKeySpec
ECPublicKeySpec(ECPoint, ECParameterSpec)