android kotlin cryptography bouncycastle ecdsa
Updated Thu, 18 Aug 2022 19:38:23 GMT

How to generate 33-byte compressed NIST P-256 public key?

I need to generate such public key and do the additional signing of the bytes (which will include this generated previously key)

I need to construct bytes of: ASN.1 prefix + signature of (33-byte compressed NIST P-256 public key)

The signature should be delivered from other defined private key

The ECDSA specifications:


NIST P-256 Otherwise known as secp256r1 and prime256v1 (openssl)

Signature format ASN.1. The r and s values of the ECDSA signature must be positive integers, and DER-encoded as such.

Is there API in Android to do such process? How can I use it then?

WHAT I've tried:

 try {
        val generator = KeyPairGenerator.getInstance("ECDSA")
        val ecSpec = ECNamedCurveTable
        val keyPair = generator.generateKeyPair()
        val privKey = keyPair.private
        val encodedPrivKey = privKey.encoded
        val pubKey = keyPair.public
        val encodedPubKey = pubKey.encoded
        val keyFactory = KeyFactory.getInstance("ECDSA")
        val pubKey2 = keyFactory.generatePublic(X509EncodedKeySpec(encodedPubKey))
        if (Arrays.equals(pubKey2.getEncoded(), encodedPubKey)) {
            println("That worked for the public key")
        val privKey2 = keyFactory.generatePrivate(PKCS8EncodedKeySpec(encodedPrivKey))
        if (Arrays.equals(privKey2.getEncoded(), encodedPrivKey)) {
            println("That worked for the private key")
    } catch (e: GeneralSecurityException) {
        throw IllegalStateException(e)

Here - the encoded public key has the lenght of 90 bytes which i guess i want it to be 33 bytes


To encode a Bouncy Castle elliptic curve public key in compressed format:

generator = KeyPairGenerator.getInstance("ECDSA")
val ecSpec = ECNamedCurveTable.getParameterSpec("prime256v1")        
val keyPair = generator.generateKeyPair()
val publicKey = keyPair.public as org.bouncycastle.jce.interfaces.ECPublicKey
val compressedPublicKey = publicKey.q.getEncoded(true)

You are not including all the necessary details about how to sign the key and encode the signature, but my best guess would be a standard ECDSA signature on the public key with a standard encoding:

val signer = Signature.getInstance("SHA256withECDSA")
val signature = signer.sign()

This hashes the public key using SHA256, signs it using ECDSA and formats and serializes it as the DER encoding of the ASN.1 structure ECDSASignature.

ECDSASignature ::= SEQUENCE {
    r   INTEGER,
    s   INTEGER

r and s will be positive integers and encoded with DER. There are other ways of doing so, but this is by far the most common way (the only other common ECDSA signature format is just padding r and s with zeroes and concatenating them).

Comments (5)

  • +0 – Thanks, can you explain more if it covers the part that i described in my question: Signature format ASN.1. The r and s values of the ECDSA signature must be positive integers, and DER-encoded as such. — Dec 05, 2018 at 13:30  
  • +0 – Regarding the signature I will be using "SHA256withECDSA" — Dec 05, 2018 at 13:31  
  • +0 – @K.Os Perhaps this helps. — Dec 05, 2018 at 13:50  
  • +0 – The ASN.1 / DER signature format is X9.62 compatible and is the default for Java. The other format is sometimes called a "flat" signature as the r and s value are not embedded in a hierarchical structure. DER encoded ASN.1 INTEGER values are signed, but the numbers will be padded with zero bytes if the most significant bit is set, so the result is always positive. — Dec 05, 2018 at 14:17  
  • +1 – @K.Os I think linehrr already have answered this correctly. Ping me again if his solution doesn't work. — Dec 06, 2018 at 08:31