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