我可以从 openssh public 密钥和 ECParameterSpec 的 Q 值创建 JCE ECPublicKey

Can I create a JCE ECPublicKey from a Q value from an openssh public key and ECParameterSpec

我正在阅读 openssh 格式的椭圆曲线 public 密钥(RFC 5656, section 3.1) and would like to get from a BigInteger Q value to an ECPublicKey instance using JCE (rather than say BouncyCastle). I want to do this to verify JWT 签名。

例如https://api.github.com/users/davidcarboni/keys:

ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK8hPtB72/sfYgNw1WTska2DNOJFx+QhUxuV6OLINSD2ty+6gxcM8yZrvMqWdMePGRb2cGh8L/0bGOk+64IQ/pM=

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

ECParameterSpec getECParameterSpec(String identifier) {
    try {
        AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
        String name = identifier.replace("nist", "sec") + "r1";
        parameters.init(new ECGenParameterSpec(name));
        return parameters.getParameterSpec(ECParameterSpec.class);
    } catch (InvalidParameterSpecException | NoSuchAlgorithmException e) {
        throw new IllegalArgumentException("Unable to get parameter spec for identifier " + identifier, e);
    }
}

我已经从关键数据中成功解析出Q值。 RFC 5656 告诉我“Q 是从椭圆曲线点编码为八位字节字符串的 public 密钥”)但是 JCE 的 ECPoint class 的构造函数采用两个参数,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")。

所以这个斑点看起来是

  • string/payload (19)
  • 的大端长度
  • 字符串"ecdsa-sha2-nistp256"
  • string/payload (8)
  • 的大端长度
  • 字符串"nistp256"
  • 有效负载的大字节序长度 (0x41 == 65)
  • 编码的ECPoint Q (04 AF 21 ... 10 FE 93)

编码的 ECPoint 以 04 开头,表示它是一个未压缩的点(最常见的编码)。 04 编码规则(来自 http://www.secg.org/sec1-v2.pdf,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 需要 Little Endian,而这些是 Big Endian)和 b) 将填充 0x00 字节作为更重要的字节而不是 0xAF 和 0xB7 字节,因为它们设置了高位(并且会被解释为负数)。不知道 Java 是否有这些怪癖。