Search code examples
androidkotlincryptographybouncycastleecdsa

How to reconstruct 33-byte compressed NIST P-256 public key from 33 bytes?


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?


Solution

  • 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
    }