当前位置: 首页 > 知识库问答 >
问题:

从私钥导出ECDSA公钥

於宏大
2023-03-14

我试图从私钥中生成一个公共ECDSA密钥,但我还没有在互联网上找到多少关于如何实现这一点的帮助。几乎所有的事情都是为了从公钥规范生成公钥,我不知道如何得到它。到目前为止,我总结了以下内容:

public void setPublic() throws GeneralSecurityException {
    ECNamedCurveParameterSpec params = ECNamedCurveTable.getParameterSpec("secp256k1");
    KeyFactory fact = KeyFactory.getInstance("ECDSA", "BC");
    ECCurve curve = params.getCurve();
    java.security.spec.EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, params.getSeed());
    java.security.spec.ECPoint point = ECPointUtil.decodePoint(ellipticCurve, this.privateKey.getEncoded());
    java.security.spec.ECParameterSpec params2=EC5Util.convertSpec(ellipticCurve, params);
    java.security.spec.ECPublicKeySpec keySpec = new java.security.spec.ECPublicKeySpec(point,params2);
    this.publicKey = fact.generatePublic(keySpec);
}

但是,在运行时,我会出现以下错误:

Exception in thread "main" java.lang.IllegalArgumentException: Invalid point encoding 0x30
at org.bouncycastle.math.ec.ECCurve.decodePoint(Unknown Source)
at org.bouncycastle.jce.ECPointUtil.decodePoint(Unknown Source)
at Wallet.Wallet.setPublic(Wallet.java:125)

我做错了什么?有更好/更简单的方法吗?

编辑:我已经设法编译了一些代码,但它不能正常工作:

public void setPublic() throws GeneralSecurityException {
    BigInteger privKey = new BigInteger(getHex(privateKey.getEncoded()),16);
    X9ECParameters ecp = SECNamedCurves.getByName("secp256k1");
    ECPoint curvePt = ecp.getG().multiply(privKey);
    BigInteger x = curvePt.getX().toBigInteger();
    BigInteger y = curvePt.getY().toBigInteger();
    byte[] xBytes = removeSignByte(x.toByteArray());
    byte[] yBytes = removeSignByte(y.toByteArray());
    byte[] pubKeyBytes = new byte[65];
    pubKeyBytes[0] = new Byte("04");
    System.arraycopy(xBytes, 0, pubKeyBytes, 1, xBytes.length);
    System.arraycopy(yBytes, 0, pubKeyBytes, 33, xBytes.length);




    ECNamedCurveParameterSpec params = ECNamedCurveTable.getParameterSpec("secp256k1");
    KeyFactory fact = KeyFactory.getInstance("ECDSA", "BC");
    ECCurve curve = params.getCurve();
    java.security.spec.EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, params.getSeed());
    java.security.spec.ECPoint point = ECPointUtil.decodePoint(ellipticCurve, pubKeyBytes);
    java.security.spec.ECParameterSpec params2 = EC5Util.convertSpec(ellipticCurve, params);
    java.security.spec.ECPublicKeySpec keySpec = new java.security.spec.ECPublicKeySpec(point,params2);
    this.publicKey = fact.generatePublic(keySpec);
}

private byte[] removeSignByte(byte[] arr)
{
    if(arr.length==33)
    {
        byte[] newArr = new byte[32];
        System.arraycopy(arr, 1, newArr, 0, newArr.length);
        return newArr;
    }
    return arr;
}

当我运行它时,它会生成一个公钥,但它不是私钥对应的公钥。

共有3个答案

陈誉
2023-03-14

我在静态编程语言中遇到了同样的问题,所以,如果它对任何人有帮助,下面是我如何从静态编程语言中的ECDSA私人密钥中导出PublicKey。这段代码基于列夫·诺布洛克的Java答案,然后反复试验直到成功。

在我的例子中,我知道我的密钥使用了secp256k1曲线,所以我可以对这部分进行硬编码。我没有费心学习如何将其推广到其他曲线。

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

这是我的测试背带:

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

这个打印出来:

-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcE4HMAHLDvPr6xHKsjhPXJzTdxLlRRR8
BfYnI2TGb0QLTFyyXm13CeYiLnxbkGhSvz9ZRo0zGQygKPVpgiThSw==
-----END PUBLIC KEY-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIOeRDHYTSV/mDf24zRKH/daCqhKg9EInRLETIRwcEkY0oAoGCCqGSM49
AwEHoUQDQgAEZ0haRNCw7oDkQVpUic9GX/XtJkfbOrZcUnqNTW3dr7/Sw3nZvpfw
n2aW8mLz5uPQwCg4ZFBxSFQ3dkrIj60Wuw==
-----END EC PRIVATE KEY-----
江佐
2023-03-14

在前面的答案的基础上,我们可以将其扩展到以下情况,即所有给定的都是满足BCECPrivateKey接口的私钥:

DerivePubKeyFromPrivKey(BCECPrivateKey definingKey, Provider provider) {

    KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);

    BigInteger d = definingKey.getD();
    org.bouncycastle.jce.spec.ECParameterSpec ecSpec = 
    definingKey.getParameters();
    ECPoint Q = definingKey.getParameters().getG().multiply(d);

    org.bouncycastle.jce.spec.ECPublicKeySpec pubSpec = new 
    org.bouncycastle.jce.spec.ECPublicKeySpec(Q, ecSpec);
    PublicKey publicKeyGenerated = keyFactory.generatePublic(pubSpec);
    return publicKeyGenerated;
}
湛安宁
2023-03-14

因此,过了一段时间,我想出了一个解决方案,并决定发布它,以防其他人与我有相同的问题:

KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC");
    ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("secp256k1");

    ECPoint Q = ecSpec.getG().multiply(((org.bouncycastle.jce.interfaces.ECPrivateKey) this.privateKey).getD());

    ECPublicKeySpec pubSpec = new ECPublicKeySpec(Q, ecSpec);
    PublicKey publicKeyGenerated = keyFactory.generatePublic(pubSpec);
    this.publicKey = publicKeyGenerated;

编辑:根据@MaartenBodewes注释删除了解码ECPoint的代码。

 类似资料:
  • 问题内容: 我试图从私钥生成公共ECDSA密钥,但是在Internet上如何进行此操作方面,我还没有找到太多帮助。几乎所有内容都是根据公共密钥规范生成公共密钥的,我不知道该如何获得。到目前为止,这是我汇总的内容: 但是,在运行时,出现以下错误: 我究竟做错了什么?有没有更好/更简便的方法可以做到这一点? 编辑:我设法获得一些代码进行编译,但不能正常工作: 当我运行它时,它会生成一个publicKe

  • 我正在尝试用c#签署比特币交易。我有两段代码要完成。我可以使用Bouncy castle创建一组私钥和公钥。我可以将其转换为钱包导入格式ok。 我还可以从ECDSA公钥生成比特币地址。 然而,我想签署一项交易,我所拥有的只是我的私钥。我不想把东西放进钱包里签名。那么,在只提供私钥的情况下,如何生成公钥呢? 我发现了一个javascript方法可以做到这一点: 我在充气城堡看到的唯一方法是生成随机一

  • 以下网站经常被引用,而且我认为是准确的: https://gobittest.appspot.com/Address 我试图在Golang中重现这些步骤,但第一步就失败了:-( 有人能给我提供一个Golang片段,给定ECDSA私钥,返回公钥吗?我想我可能具体指的是上述站点示例中的私钥指数和公钥指数。 i、 例如,给定随机生成的(十六进制编码的)私钥(指数?)<代码>E83385AF76B2B19

  • 从这里我指出了自己如何获得公钥,并使用EC_POINT_bn2point,而不是hex2point,根据OpenSSL源代码,它在内部执行BN_hex2bn。 那么,为什么EC_POINT_bn2point返回null呢?我正在认真考虑重新编译OpenSSL,并放一些调试例程来找出它失败的原因。

  • 我已经阅读了如何在OpenSSL中从ECDSA私钥获取公钥? 并想做同样的事情,但在Java中与充气城堡。 我也见过Bouncy Castle ESCDA从私钥创建公钥,但这并没有帮助。

  • 我想通过RSACryptServiceProvider签名和验证数据 为此,我需要公钥和私钥。 在我的项目中,我将公钥和私钥存储在XML文件中。 有一次,我生成了我的公钥和私钥 在上面,我展示了“通过公钥验证数据” 我的SignData方法类似。 在那里, 我的问题是:举个例子,我认识到;通过crt/pem/cert等导入公钥和私钥。证书文件。在那里我存储了XML文件。 我的解决方案错了吗? 第二