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-256
和 secp256r1
)。顺便说一句,您发布的公钥确实是这条曲线上的一个点,因此是有效的。
【参考方案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 [关闭]