EC 将字符串转换为 PublicKey / PrivateKey

Posted

技术标签:

【中文标题】EC 将字符串转换为 PublicKey / PrivateKey【英文标题】:EC Converting String to PublicKey / PrivateKey 【发布时间】:2020-12-01 09:07:53 【问题描述】:

我一直在尝试将下面粘贴的代码转换为公钥。我正在尝试创建一个共享秘密。我有密钥的未压缩十六进制表示。我想从中创建一个公钥。同样,我希望创建一个私钥并在之后加入它们。

String plainPublicKey = "042E3E5CCF6B9AB04BE7A22F3FACCFDE73C87E87155394A34815408A896CA18A374DAC669AF3BF6220FC863767F4AF47507C5BC221FC4A19874DAF39B4074E3EB8";
        EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Hex.decodeHex(plainPublicKey.toCharArray()));
        KeyFactory kf = KeyFactory.getInstance("EC");
        PublicKey pub = kf.generatePublic(publicKeySpec);
        return pub;
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
    at jdk.crypto.ec/sun.security.ec.ECKeyFactory.engineGeneratePublic(ECKeyFactory.java:157)
    at java.base/java.security.KeyFactory.generatePublic(KeyFactory.java:352)
    at AESExample.getPublicKey(AESExample.java:66)
    at AESExample.main(AESExample.java:74)
Caused by: java.security.InvalidKeyException: invalid key format
    at java.base/sun.security.x509.X509Key.decode(X509Key.java:386)
    at java.base/sun.security.x509.X509Key.decode(X509Key.java:401)
    at jdk.crypto.ec/sun.security.ec.ECPublicKeyImpl.<init>(ECPublicKeyImpl.java:71)
    at jdk.crypto.ec/sun.security.ec.ECKeyFactory.implGeneratePublic(ECKeyFactory.java:219)
    at jdk.crypto.ec/sun.security.ec.ECKeyFactory.engineGeneratePublic(ECKeyFactory.java:153)
    ... 3 more

【问题讨论】:

要从未压缩的公共 EC 密钥中派生 java.security.PublicKey,请参见例如here。此外还需要曲线名称。您还必须删除密钥的前导 04 字节(标记未压缩的密钥)。 私钥见here。此代码使用 BouncyCastle 派生 ECParameterSpec。或者,可以从第一个链接使用ecParameterSpecForCurve(...)。为此,当然需要原始的私有 EC 密钥。 非常感谢!在删除前导 04 字节后,我根据提到的链接尝试使用公钥。仍然收到 InvalidKey 异常。我怎么知道要使用哪条曲线?随机尝试了secp256r1和secp256k1。两者都不起作用。 An InvalidKeyException 可以由于各种原因被抛出,通常会显示附加信息,例如密钥必须是 PrivateKey 的实例。因此,请编辑您的问题并在末尾添加 complete 堆栈跟踪、使用的 Java 版本和您的 最新 代码。曲线名称(或domain parameters)必须是已知的,因为它们是键的参考系统。因此,双方必须就共同的曲线名称达成一致。 根据组织的不同,相同的曲线使用不同的名称,例如NIST P-256 (NIST) 也称为 secp256r1 (SECG) 或 prime256v1 (ANSI X9.62),请参阅 Rfc4492。链接代码接受前两个名称(NIST P-256secp256r1)。顺便说一句,您发布的公钥确实是这条曲线上的一个点,因此是有效的。 【参考方案1】:

我知道这是一个老问题,但无论如何我都会发布一个解决方案,以便它可以帮助其他人。

首先,您必须指定用于生成公钥的曲线,如下所示:

ECParameterSpec ecParameterSpec = ECNamedCurveTable.getParameterSpec("secp256r1");
ECNamedCurveSpec params = new ECNamedCurveSpec("secp256r1", ecParameterSpec.getCurve(), ecParameterSpec.getG(), ecParameterSpec.getN());

看看这个问题,看看如何找出您正在使用的提供商支持的曲线:Supported EC curves。

然后你像下面这样解码你的公钥:

ECPoint publicPoint =  ECPointUtil.decodePoint(params.getCurve(), parseHexBinary(pubKey));

并用它来生成公钥:

ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(publicPoint, params);
KeyFactory kf = KeyFactory.getInstance("EC");
PublicKey publicKey =  kf.generatePublic(pubKeySpec);

另外,这里是我关于同一主题的问题和解决方案的链接:Hex to public key in java。

【讨论】:

以上是关于EC 将字符串转换为 PublicKey / PrivateKey的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Byte 数组转换为 PrivateKey 或 PublicKey 类型?

将 JSON 公钥/私钥对转换为 rsa.PrivateKey 和 rsa.PublicKey

即使使用新的 EC2 实例,AWS SSH 登录仍会继续失败 [权限被拒绝 (PublicKey)]

如何从 base64 编码的字符串构造 java.security.PublicKey 对象?

如何将“24cd2ec2-6674-4aa2-a761-1b0a953124ba”(字符串对象)转换为 BigDecimal [关闭]

如何在聚合期间将mongodb子集合的objectid转换为字符串