You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 14:37:33