读取 EC 公钥,在 python 中工作,在 java 中出错

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

我在将一些代码从 python 移动到 java 时遇到了这个问题。 以下公钥:

MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgAC2X07fCab+nIPAWBb5eRlhdOfR0Bkrhx7TgM3cGbR31g=

可以从这个python代码中成功读取:

key = bytearray.fromhex(
   "3039301306072a8648ce3d020106082a8648ce3d030107032200"
) + bytearray([0x03]) + bytearray.fromhex("d97d3b7c269bfa720f01605be5e46585d39f474064ae1c7b4e03377066d1df58")
device_public_key = load_der_public_key(
                key
            )

打印出 device_public_key 我看到:

当尝试在 Java 中执行相同操作时,我在所有可能的尝试中都失败了:

    fun loadKey() {
       
        val key  = Hex.decode("3039301306072a8648ce3d020106082a8648ce3d03010703220003d97d3b7c269bfa720f01605be5e46585d39f474064ae1c7b4e03377066d1df58")
        try {
            read(key)
        } catch (e: Exception) {
            println("Failed to load for sign $sign: $e")
        }
    }

    private fun read(publicKey: ByteArray) {
        val spec: ECNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec("prime256v1")
        val kf = KeyFactory.getInstance("ECDSA", BouncyCastleProvider())
        val params = ECNamedCurveSpec("prime256v1", spec.curve, spec.g, spec.n)
        val point: ECPoint = ECPointUtil.decodePoint(params.curve, publicKey)
        val pubKeySpec = ECPublicKeySpec(point, params)
        val t =  kf.generatePublic(pubKeySpec) as ECPublicKey
        println(t)
    }

我得到的例外是:

java.lang.IllegalArgumentException:无效点编码 0x30

我无法理解出了什么问题,因为密钥是正确的(在 python 中工作)。 我尝试进行 Byte64 编码/解码,但总是失败。

这篇文章链接到我之前的问题(下一步): 解析并加载EC私钥,曲线secp256r1

公钥不同,我尝试加载的公钥被定义为固定标头、符号字节和我收到的变量的串联:

用于带有读取器私钥的 ECDH 的压缩临时公钥,32 字节 X 坐标。注意:解压时Y坐标始终为偶数

java python key
1个回答
0
投票

该格式不是一个点,尝试将其用作点或将其解码是行不通的。另外,对于 y 坐标为偶数的点,X9 压缩点的第一个字节(即所谓的“符号字节”)是 0x02,而不是 0x03。而且您发布的语言不是 Java,尽管它显然是在调用 Java。

有两种方法:

  1. 使用您构建的格式,实际上是 ASN.1 结构SubjectPublicKeyInfo 在 X.509/PKIX 中定义由 RFC5480 补充用于 ECC:
$ xxd -r -p <<END | openssl asn1parse -inform der -i -dump
3039301306072a8648ce3d020106082a8648ce3d030107032200
02d97d3b7c269bfa720f01605be5e46585d39f474064ae1c7b4e03377066d1df58
END
    0:d=0  hl=2 l=  57 cons: SEQUENCE
    2:d=1  hl=2 l=  19 cons:  SEQUENCE
    4:d=2  hl=2 l=   7 prim:   OBJECT            :id-ecPublicKey
   13:d=2  hl=2 l=   8 prim:   OBJECT            :prime256v1
   23:d=1  hl=2 l=  34 prim:  BIT STRING
      0000 - 00 02 d9 7d 3b 7c 26 9b-fa 72 0f 01 60 5b e5 e4   ...};|&..r..`[..
      0010 - 65 85 d3 9f 47 40 64 ae-1c 7b 4e 03 37 70 66 d1   e...G@d..{N.7pf.
      0020 - df 58                                             .X
# observe that this contains an AlgorithmIdentifier for (X9-style) ECC with the desired curve
# and a BIT STRING _containing_ (after the first byte 0x00 which is actually part of 
# the ASN.1 encoding but OpenSSL displays as part of the value) the point 0x02 + 32 bytes

这是(标准)Java 加密用于公钥编码的格式,以及 OpenSSL 和使用 OpenSSL 的东西(如 python 等)使用的格式,并且(因此)可以由合适的 JCA 按原样处理

KeyFactory
:

        byte[] spki = unhex("3039301306072a8648ce3d020106082a8648ce3d030107032200"
            + "02d97d3b7c269bfa720f01605be5e46585d39f474064ae1c7b4e03377066d1df58");
        KeyFactory kf1 = KeyFactory.getInstance("EC","BC");
        PublicKey pub1 = kf1.generatePublic(new X509EncodedKeySpec(spki));
  1. 使用您发布的方法,但仅传递点而不是整个结构(即没有“固定前缀”)。您也不需要转换规格:
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint; // NOT the JCA one!
...
        byte[] raw = unhex("02d97d3b7c269bfa720f01605be5e46585d39f474064ae1c7b4e03377066d1df58");
        ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec ("prime256v1");
        ECPoint point = ecSpec.getCurve().decodePoint (raw);
        KeyFactory kf2 = KeyFactory.getInstance("EC", "BC");
        PublicKey pub2 = kf2.generatePublic(new ECPublicKeySpec(point, ecSpec));
© www.soinside.com 2019 - 2024. All rights reserved.