ECPrivateKey 到 ECPublicKey(无需 BouncyCastle)

问题描述 投票:0回答:1

我正在尝试从私钥获取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 怎么办?

java kotlin security cryptography elliptic-curve
1个回答
0
投票

我最终使用了 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
}

注意它可能包括安全漏洞和性能问题

© www.soinside.com 2019 - 2024. All rights reserved.