如何从33个字节重构33个字节的压缩NIST P-256公钥?

时间:2018-12-10 13:32:34

标签: android kotlin cryptography bouncycastle ecdsa

假设可以像这样创建33字节编码的公钥:

Security.addProvider(provider)
val generator = KeyPairGenerator.getInstance("ECDSA")
val ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1")
generator.initialize(ecSpec)
val keyPair = generator.generateKeyPair()
val privateKey = keyPair.private as ECPrivateKey
val publicKey = keyPair.public as ECPublicKey
val publicEncoded = publicKey.q.getEncoded(true)

如何在另一侧重新构建它(当我仅从此处发送33个字节时)?

我正在尝试下面的代码:

val publicKey =KeyFactory.getInstance("EC").generatePublic(X509EncodedKeySpec(publicEncoded))

但是我想这是完全错误的,因为我得到了:

  

java.security.spec.InvalidKeySpecException:java.lang.RuntimeException:错误:0c000079:ASN.1编码例程:OPENSSL_internal:HEADER_TOO_LONG

我也在尝试:

val generator = KeyPairGenerator.getInstance("ECDSA")
val ecPublicKey = generator
        .generatePublic(X509EncodedKeySpec((publicEncoded))) as ECPublicKey

但是错误是:

  

java.security.spec.InvalidKeySpecException:无法识别编码的密钥规范

如何实现我的目标?

2 个答案:

答案 0 :(得分:2)

主要问题是您的 publicEncoded 不是已编码的公共密钥,而是已编码的 ECPoint publicKey.q )。 这意味着您需要首先重建该点,然后提供适当的曲线以重建关键点以获得正确的 ECPublicKeySpec

  1. 首先使用 ECNamedCurveTable.getParameterSpec(“ secp256r1”)重新获得所选曲线规格。然后,您可以使用 ecSpec.curve.decodePoint(publicEncoded)重建BC ECPoint 实例。
  2. 将BouncyCastle ECNamedCurveParameterSpec 转换为 java.security.spec.ECParameterSpec ,将BouncyCastle ECPoint 转换为java java.security .spec.ECPoint 。然后构造适当的 ECPublicKeySpec ,然后供 ECDSA 密钥生成器使用,以重新创建完整的 PublicKey

参考文献:

答案 1 :(得分:1)

这应该可以完成工作:

import org.bouncycastle.jce.ECNamedCurveTable
import org.bouncycastle.jce.spec.ECPublicKeySpec

fun publicKeyFromCompressed(compressedPublicKey: ByteArray): PublicKey {
    val ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1")
    val point = ecSpec.curve.decodePoint(compressedPublicKey)
    val publicKeySpec = ECPublicKeySpec(point, ecSpec)
    val keyFactory = KeyFactory.getInstance("ECDSA")
    val publicKey = keyFactory.generatePublic(publicKeySpec)
    return publicKey
}