How to generate 33-byte compressed NIST P-256 publ

2019-08-26 03:35发布

问题:

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:

● Curve:

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
                .getParameterSpec("prime256v1")
        generator.initialize(ecSpec)
        val keyPair = generator.generateKeyPair()

        val privKey = keyPair.private
        val encodedPrivKey = privKey.encoded
        System.out.println(toHex(encodedPrivKey))

        val pubKey = keyPair.public
        val encodedPubKey = pubKey.encoded
        System.out.println(toHex(encodedPubKey))

        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

回答1:

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

Security.addProvider(BouncyCastleProvider())  

generator = KeyPairGenerator.getInstance("ECDSA")
val ecSpec = ECNamedCurveTable.getParameterSpec("prime256v1")        
generator.initialize(ecSpec)
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")
signer.initSign(otherPrivateKey)
signer.update(compressedPublicKey)
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).