如何从先前生成的 ECDSA 两个编码密钥对构造私钥?

Posted

技术标签:

【中文标题】如何从先前生成的 ECDSA 两个编码密钥对构造私钥?【英文标题】:How to construct private key from generated previously ECDSA both encoded key pair? 【发布时间】:2018-12-13 15:12:39 【问题描述】:

生成了这样的私钥:

    fun getKeyPair(): Pair<ByteArray, ByteArray> 
        Security.addProvider(provider)
        val generator = KeyPairGenerator.getInstance("ECDSA")
        val ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1")
        generator.initialize(ecSpec)
        val keyPair = generator.generateKeyPair()
        val publicKey = keyPair.public as ECPublicKey
        val privateKey = keyPair.private
        return Pair(publicKey.q.getEncoded(true), privateKey.getEncoded())
    

可以像这样再次重构公钥:

    Security.addProvider(...spongy castle provider)
    val ecSpecs = ECNamedCurveTable.getParameterSpec("secp256r1")
    val q = ecSpecs.curve.decodePoint(publicKeyEncoded)
    val pubSpec = ECPublicKeySpec(q, ecSpecs)
    val keyFactory = KeyFactory.getInstance("ECDSA")
    val generatedPublic = keyFactory.generatePublic(pubSpec)

如何同时从字节重建私钥?

更新:

此代码在实际应用中运行良好,但在 JUnit 测试中却不行:

val keyFactory = KeyFactory.getInstance("ECDSA")
val privSpec = PKCS8EncodedKeySpec(privateEncoded)
val generatedPrivate = keyFactory.generatePrivate(privSpec)

在 JUnit 测试中我收到此错误:

java.security.spec.InvalidKeySpecException: encoded key spec not recognised

我作为编码字节的私钥有 150 字节大小。

【问题讨论】:

要找出编码密钥的格式,从而提示重新生成它所需的 KeySpec 类型,请检查密钥的 .format 属性,例如val privFormat = privateKey.format 确保您的应用和 Junit 都使用您已安装的提供程序。 Security.addProvider (provider) 会在最后安装提供程序,因此如果系统有另一个能够处理 EC 密钥的提供程序,它将被使用,并且您会得到意想不到的结果。您可以使用Security.insertProviderAt (sc, 1); 或在调用KeyFactory.getInstance ("ECDSA", "SC") 时指定它 @pedrofb 不幸的是,我当然尝试过 - 它没有用 我有一种感觉,我之前已经向您提过这个,但是android Studio Junit测试环境是在主机上,而不是在Android上。因此,单元测试中使用的安全提供者可能需要是官方的 bouncycastle 提供者而不是 spongycastle。 publicKey.q.getEncoded(true) 在我的环境中似乎无法编译。 ECPublicKey 没有 q 属性。当然,除了在 IDE 中瞎摸索之外,我真的不了解 Kotlin。 【参考方案1】:

由于密钥是使用标准Key.getEncoded() 编码的,因此以下标准解决方案应该有效:

val keyFactory = KeyFactory.getInstance("EC")
val privSpec = PKCS8EncodedKeySpec(privateEncoded)
val generatedPrivate = keyFactory.generatePrivate(privSpec)

编码后的密钥应包含重建私钥所需的所有信息,而无需像为简化的公钥那样指定额外的参数。

【讨论】:

不幸的是,当我使用它然后想在我的 JUnit 测试中测试这一代时,我收到了这个错误:“java.security.spec.InvalidKeySpecException:编码的密钥规范无法识别”我正在使用 AndroidStudio - 当我在实际应用程序中运行此代码时,它正在工作。你能帮帮我吗? 它在某些平台上运行但在其他平台上运行的事实表明代码本身很好。您是否为最后一段代码注册了安全提供程序? 不知道你到底是什么意思,但我在上面的问题中注册了安全提供程序(见代码)

以上是关于如何从先前生成的 ECDSA 两个编码密钥对构造私钥?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中加载私有 ecdsa 密钥 es256?

如何使用椭圆曲线私钥和 ECDSA 算法签署证书?

ECDSA密钥

Linux秘钥登录

node.js 中的十六进制编码 ECDSA 密钥

java - 如何在java中生成与openssl生成的相同类型的ecdsa密钥对?