无需BouncyCastle:EC私钥转公钥的Kotlin实现问题
问题:从EC私钥导出公钥(Java/Kotlin实现报错)
我已在Python和Go中成功实现从EC私钥导出对应公钥,但在Java/Kotlin中遇到异常。
已成功实现的代码
Python实现
import base64 from cryptography.hazmat.primitives import serialization from cryptography.hazmat.backends import default_backend private_key_b64 = "MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAMM3sUprvk/VVF3vXhYcY0Vi9Ay1UPd4GLoBV/htAf2w==" private_key_der = base64.b64decode(private_key_b64) private_key = serialization.load_der_private_key( private_key_der, password=None, backend=default_backend() ) public_key = private_key.public_key() public_key_der = public_key.public_bytes( encoding=serialization.Encoding.DER, format=serialization.PublicFormat.SubjectPublicKeyInfo ) public_key_base64 = base64.b64encode(public_key_der).decode('utf-8') print(public_key_base64)
Go实现
package main import ( "crypto/ecdsa" "crypto/x509" "encoding/base64" "fmt" "log" ) func main() { privKeyBase64 := "MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAMM3sUprvk/VVF3vXhYcY0Vi9Ay1UPd4GLoBV/htAf2w==" privKeyDER, err := base64.StdEncoding.DecodeString(privKeyBase64) if err != nil { log.Fatalf("Error decoding base64 private key: %v", err) } privateKey, err := x509.ParsePKCS8PrivateKey(privKeyDER) if err != nil { log.Fatalf("Error parsing EC private key: %v", err) } k, ok := privateKey.(*ecdsa.PrivateKey) if !ok { panic("not ecdsa") } publicKeyDer, err := x509.MarshalPKIXPublicKey(k.Public()) if err != nil { fmt.Println("Error marshaling public key to DER:", err) return } fmt.Printf("Public Key: %s\n", base64.StdEncoding.EncodeToString(publicKeyDer)) }
出错的Kotlin实现
val privateKey64 = "MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAMM3sUprvk/VVF3vXhYcY0Vi9Ay1UPd4GLoBV/htAf2w==" val decodedKey = Base64.getDecoder().decode(privateKey64) val keySpec = PKCS8EncodedKeySpec(decodedKey) val keyFactory = KeyFactory.getInstance("EC") val privateKey: PrivateKey = keyFactory.generatePrivate(keySpec) val publicKey = keyFactory.generatePublic(keySpec) println("Private Key: ${privateKey.encoded.encodeBase64()}") println("Public Key: ${publicKey.encoded.encodeBase64()}")
运行后抛出异常:
java.security.spec.InvalidKeySpecException: Only ECPublicKeySpec and X509EncodedKeySpec supported for EC public keys
解决方案(不使用BouncyCastle)
错误原因
你错误地使用**PKCS8私钥规格(PKCS8EncodedKeySpec)**调用keyFactory.generatePublic()来生成公钥。该方法仅接受ECPublicKeySpec或X509EncodedKeySpec类型的参数,私钥规格无法用于生成公钥。
修正后的代码
import java.security.KeyFactory import java.security.spec.PKCS8EncodedKeySpec import java.util.Base64 fun main() { val privateKey64 = "MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAMM3sUprvk/VVF3vXhYcY0Vi9Ay1UPd4GLoBV/htAf2w==" val decodedKey = Base64.getDecoder().decode(privateKey64) val keySpec = PKCS8EncodedKeySpec(decodedKey) val keyFactory = KeyFactory.getInstance("EC") // 加载EC私钥并强转为ECPrivateKey类型 val privateKey = keyFactory.generatePrivate(keySpec) as java.security.interfaces.ECPrivateKey // 直接从EC私钥对象中提取公钥 val publicKey = privateKey.publicKey // 编码为Base64输出 val privateKeyBase64 = Base64.getEncoder().encodeToString(privateKey.encoded) val publicKeyBase64 = Base64.getEncoder().encodeToString(publicKey.encoded) println("Private Key: $privateKeyBase64") println("Public Key: $publicKeyBase64") }
说明
EC私钥对象(ECPrivateKey)本身包含公钥信息,无需重新通过KeyFactory生成。直接调用privateKey.publicKey即可获取对应的ECPublicKey实例,再编码为Base64即可得到与Python/Go一致的结果。
内容的提问来源于stack exchange,提问作者hoxewe7277
相关产品推荐
相关产品推荐

