我正在尝试从私钥获取EC的公钥。
我已经使用 Python、Go 完成了它,效果很好,但我还无法在 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 版本:
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 怎么办?
我最终使用了 https://github.com/Archerxy/ecdsa_java 代码的版本。
val curve = Ecdsa(Curve.SECP_256_R1)
val keystore = buildKeyStore {
certificate("key") {
hash = HashAlgorithm.SHA256
sign = SignatureAlgorithm.ECDSA
keySizeInBits = 256
password = "changeit"
}
}
val privateKey = keystore.getKey("key", "changeit".toCharArray()) as ECPrivateKey
val publicKeyReal = keystore.getCertificate("key").publicKey as ECPublicKey
// create public key from private
val publicKey = curve.privateKeyToPublicKey(privateKey)
println("Public Key Match: ${publicKey == publicKeyReal}")
并将
privateKeyToPublicKey
修改为:
fun privateKeyToPublicKey(privateKey: ECPrivateKey): ECPublicKey {
val priv = privateKey.s
if (priv > N) throw RuntimeException("Invalid private key.")
val p: Array<BigInteger> = fastMultiply(Gx, Gy, NUM[1], priv)
val z: BigInteger = inv(p[2], P)
val x = z.pow(2).multiply(p[0]).mod(P)
val y = z.pow(3).multiply(p[1]).mod(P)
val w = ECPoint(x, y)
return KeyFactory.getInstance("EC")
.generatePublic(ECPublicKeySpec(w, privateKey.params)) as ECPublicKey
}
注意它可能包括安全漏洞和性能问题