Deriving ECDSA Public Key from Private Key

前端 未结 3 1664
既然无缘
既然无缘 2021-01-03 01:41

I was attempting to generate a public ECDSA key from a private key, and I haven\'t managed to find much help on the internet as to how to do this. Pretty much everything is

相关标签:
3条回答
  • 2021-01-03 01:53

    So after a while, I figured out a solution and decided to post it in case anyone else has the same issue as me:

    KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC");
        ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("secp256k1");
    
        ECPoint Q = ecSpec.getG().multiply(((org.bouncycastle.jce.interfaces.ECPrivateKey) this.privateKey).getD());
    
        ECPublicKeySpec pubSpec = new ECPublicKeySpec(Q, ecSpec);
        PublicKey publicKeyGenerated = keyFactory.generatePublic(pubSpec);
        this.publicKey = publicKeyGenerated;
    

    EDIT: Removed the code decoding the ECPoint as per @MaartenBodewes comment.

    0 讨论(0)
  • 2021-01-03 02:02

    Building on the previous answer one can extend this to the case that all one is given is a private key satisfying BCECPrivateKey interface:

    DerivePubKeyFromPrivKey(BCECPrivateKey definingKey, Provider provider) {
    
        KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
    
        BigInteger d = definingKey.getD();
        org.bouncycastle.jce.spec.ECParameterSpec ecSpec = 
        definingKey.getParameters();
        ECPoint Q = definingKey.getParameters().getG().multiply(d);
    
        org.bouncycastle.jce.spec.ECPublicKeySpec pubSpec = new 
        org.bouncycastle.jce.spec.ECPublicKeySpec(Q, ecSpec);
        PublicKey publicKeyGenerated = keyFactory.generatePublic(pubSpec);
        return publicKeyGenerated;
    }
    
    0 讨论(0)
  • 2021-01-03 02:09

    I came here with the same problem in Kotlin, so, in case it helps anyone, here's how I derived the PublicKey from an ECDSA PrivateKey in Kotlin. This code is based on Lev Knoblock's Java answer and then trial-and-errored until it worked.

    In my case I knew that my key used the secp256k1 curve, so I could hard-code that part. I didn't bother to learn how to generalize it to other curves.

    import java.security.KeyFactory
    import java.security.KeyPair
    import java.security.PrivateKey
    import java.security.PublicKey
    import org.bouncycastle.asn1.pkcs.PrivateKeyInfo
    import org.bouncycastle.jce.ECNamedCurveTable
    import org.bouncycastle.jce.interfaces.ECPrivateKey
    import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec
    import org.bouncycastle.jce.spec.ECPublicKeySpec
    import org.bouncycastle.math.ec.ECPoint
    import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter
    import org.bouncycastle.openssl.PEMParser
    
    fun getECPrivateKeyFromPEM(privatePem: String): ECPrivateKey {
        val pemParser = PEMParser(privatePem.reader())
        val privateKeyInfo = pemParser.readObject() as PrivateKeyInfo
        return JcaPEMKeyConverter().getPrivateKey(privateKeyInfo) as ECPrivateKey
    }
    
    fun getKeyPairFromECPrivateKey(privateKey: ECPrivateKey): KeyPair {
        val keyFactory: KeyFactory = KeyFactory.getInstance("ECDSA", "BC")
        val spec: ECNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec("secp256k1")
        val Q: ECPoint = spec.getG().multiply(privateKey.getD())
        val publicKey: PublicKey = keyFactory.generatePublic(ECPublicKeySpec(Q, spec))
        return KeyPair(publicKey, privateKey)
    }
    

    And here's my test harness:

    import java.io.StringWriter
    import org.bouncycastle.openssl.jcajce.JcaPEMWriter
    
    fun main() {
        val privatePem = """
           |-----BEGIN PRIVATE KEY-----
           |MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg55EMdhNJX+YN/bjN
           |Eof91oKqEqD0QidEsRMhHBwSRjShRANCAARnSFpE0LDugORBWlSJz0Zf9e0mR9s6
           |tlxSeo1Nbd2vv9LDedm+l/CfZpbyYvPm49DAKDhkUHFIVDd2SsiPrRa7
           |-----END PRIVATE KEY-----
        """.trimMargin()
        val privateKey: ECPrivateKey = getECPrivateKeyFromPEM(privatePem)
        val pair: KeyPair = getKeyPairFromECPrivateKey(privateKey)
        val pems: String = StringWriter().use {
            val pemWriter = JcaPEMWriter(it)
            pemWriter.writeObject(pair.getPublic())
            pemWriter.writeObject(pair.getPrivate())
            pemWriter.flush()
            it.toString()
        }
        println(pems)
    }
    

    This prints out:

    -----BEGIN PUBLIC KEY-----
    MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcE4HMAHLDvPr6xHKsjhPXJzTdxLlRRR8
    BfYnI2TGb0QLTFyyXm13CeYiLnxbkGhSvz9ZRo0zGQygKPVpgiThSw==
    -----END PUBLIC KEY-----
    -----BEGIN EC PRIVATE KEY-----
    MHcCAQEEIOeRDHYTSV/mDf24zRKH/daCqhKg9EInRLETIRwcEkY0oAoGCCqGSM49
    AwEHoUQDQgAEZ0haRNCw7oDkQVpUic9GX/XtJkfbOrZcUnqNTW3dr7/Sw3nZvpfw
    n2aW8mLz5uPQwCg4ZFBxSFQ3dkrIj60Wuw==
    -----END EC PRIVATE KEY-----
    
    0 讨论(0)
提交回复
热议问题