Java 我可以从openssh公钥和ECParameterSpec的Q值创建JCE ECPublicKey吗

Java 我可以从openssh公钥和ECParameterSpec的Q值创建JCE ECPublicKey吗,java,openssh,jce,elliptic-curve,ecdsa,Java,Openssh,Jce,Elliptic Curve,Ecdsa,我正在阅读openssh格式的椭圆曲线公钥()并希望使用JCE(而不是说BouncyCastle)从一个BigInteger Q值获取一个ECPublicKey实例。我想这样做是为了验证签名 e、 g: 看起来我可以使用ECPublicKeySpec。这需要两个参数。ECPoint和ECParameterSpec。我能够使用以下JCE代码(以及来自密钥数据的openssh标识符,比如“nistp256”)获取参数规范: 我已经成功地从关键数据解析了Q值。RFC 5656告诉我“Q是从椭圆曲线点编

我正在阅读openssh格式的椭圆曲线公钥()并希望使用JCE(而不是说BouncyCastle)从一个BigInteger Q值获取一个
ECPublicKey
实例。我想这样做是为了验证签名

e、 g:

看起来我可以使用
ECPublicKeySpec
。这需要两个参数。
ECPoint
ECParameterSpec
。我能够使用以下JCE代码(以及来自密钥数据的openssh标识符,比如“nistp256”)获取参数规范:

我已经成功地从关键数据解析了Q值。RFC 5656告诉我“Q是从椭圆曲线点编码为八位字节字符串的公钥”),但是JCE的
ECPoint
类的构造函数采用两个参数,X和Y

我可以从Q到X和Y吗,或者我需要采取不同的方法吗


(注意,我没有访问私钥的权限)输入的base64部分具有等效的十六进制

00 00 00 13 65 63 64 73 61 2D 73 68 61 32 2D 6E 
69 73 74 70 32 35 36 00 00 00 08 6E 69 73 74 70 
32 35 36 00 00 00 41 04 AF 21 3E D0 7B DB FB 1F 
62 03 70 D5 64 EC 91 AD 83 34 E2 45 C7 E4 21 53 
1B 95 E8 E2 C8 35 20 F6 B7 2F BA 83 17 0C F3 26 
6B BC CA 96 74 C7 8F 19 16 F6 70 68 7C 2F FD 1B 
18 E9 3E EB 82 10 FE 93 
65 63 64在我看来是“ecd”(没错,“ecdsa-sha2-nistp256”)

所以这个斑点看起来是

  • 字符串/有效负载的大端长度(19)
  • 字符串“ecdsa-sha2-nistp256”
  • 字符串/有效负载的大端长度(8)
  • 字符串“nistp256”
  • 有效负载的大端长度(0x41==65)
  • 编码的ECQ点(
    04 AF 21…10 FE 93
编码的ECPoint以
04
开头,表示它是未压缩的点(最常见的编码)。
04
编码规则(来自,2.3.5,步骤3)规定剩余的有效载荷是X和Y,每个有效载荷都用零填充到曲线字段的编码大小

所以你的ECPoint看起来像

04
Qx:
AF 21 3E D0 7B DB FB 1F 62 03 70 D5 64 EC 91 AD
83 34 E2 45 C7 E4 21 53 1B 95 E8 E2 C8 35 20 F6
Qy:
B7 2F BA 83 17 0C F3 26 6B BC CA 96 74 C7 8F 19
16 F6 70 68 7C 2F FD 1B 18 E9 3E EB 82 10 FE 93

在C#中,您需要a)反转Qx和Qy的每个字节(因为.NET BigInteger需要小的Endian,而这些是Big Endian)和b)将填充0x00字节放在比0xAF和0xB7字节更重要的位置,因为它们设置了高位(并将被解释为负数)。我不知道Java是否有这些怪癖。

不错,好吧,如果我理解正确的话,Q是一个字节字符串,以标识格式的字节开始,然后是(在04/未压缩的情况下)两组长度相等的字节,代表大整数X和Y?@DavidCarboni是的,你得到了。成功!为了谷歌的利益,我将Q的字节数组拆分为第一个字节(“04”)和两个长度相等的部分(在我的例子中,每个部分都是32字节),然后可以使用标准的JCE
java.security.spec.ECPoint point=new java.security.spec.ECPoint(x,y)
其中x和y是用这两个部分创建的
BigInteger
值。为了完成这个故事,从这里开始,
新建java.security.spec.ECPublicKeySpec(point,curveSpec)
(其中
curveSpec
是使用问题中的代码创建的)和好的
KeyFactory.getInstance(“EC”).generatePublic(spec)
让我找到了一个
公钥
。为了证明这是正确的密钥,我使用
ssh-keygen
创建了一个密钥对,用私钥签署了JWT(在Bouncycastle的
PEMParser
的帮助下),并用Bouncycastle Q方法和JCE X/Y方法对公钥进行解码。我能够使用这两个公钥实例验证签名。还值得注意的是,
ECCurve#decodePoint(byte[])
()的代码实现了不同的编码(04除外),因此可以使用
ECPoint p=new ECPoint(point.getAffineXCoord().toBigInteger(),point.getAffineYCoord().toBigInteger())以获取ta JCE ECPoint,尽管使用BC helper类。
00 00 00 13 65 63 64 73 61 2D 73 68 61 32 2D 6E 
69 73 74 70 32 35 36 00 00 00 08 6E 69 73 74 70 
32 35 36 00 00 00 41 04 AF 21 3E D0 7B DB FB 1F 
62 03 70 D5 64 EC 91 AD 83 34 E2 45 C7 E4 21 53 
1B 95 E8 E2 C8 35 20 F6 B7 2F BA 83 17 0C F3 26 
6B BC CA 96 74 C7 8F 19 16 F6 70 68 7C 2F FD 1B 
18 E9 3E EB 82 10 FE 93 
04
Qx:
AF 21 3E D0 7B DB FB 1F 62 03 70 D5 64 EC 91 AD
83 34 E2 45 C7 E4 21 53 1B 95 E8 E2 C8 35 20 F6
Qy:
B7 2F BA 83 17 0C F3 26 6B BC CA 96 74 C7 8F 19
16 F6 70 68 7C 2F FD 1B 18 E9 3E EB 82 10 FE 93