Nodejs 加密 ECDH PublicKey Hex 作为 X.509
Nodejs Crypto ECDH PublicKey Hex as X.509
我正在使用 prime256v1
曲线生成密钥对并使用 nodejs
和默认 crypto
模块进行签名。
使用crypto
let crypto = require('crypto');
let e = crypto.createECDH('prime256v1');
e.generateKeys();
privateKey = e.getPrivateKey();
privateKeyHex = privateKey.toString('hex');
publicKey = e.getPublicKey();
publicKeyHex = publicKey.toString('hex');
我获得了一个公钥,它看起来像下面的十六进制字符串:
'049a6b0ac242afe41128cf59736412686ca83c9e902ee3fa0f13810b9d59ebfe5e49204427c23b630be12ae33815b0bda6ed8d0603386c6ea5f1906cdb0e731286'
Usign jsrsasign
let jsrsa = require('jsrsasign');
let KEYUTIL = jsrsa.KEYUTIL;
let kp = KEYUTIL.generateKeypair("EC", "prime256v1");
let pkHex = kp.pubKeyObj.pubKeyHex
其中 returns
'04f36e41189420db05dd8a73e3cb310b0c55809190bdedd89bf19769ac8df3cd06c1380f646e9e65e31c24affff79e43516b37e0186c3753cfdfd29894c2becc84'
将 PublicKey Hex 转换为 Java
中的 PublicKey 对象
我想使用这些 publicKeys 并将其转换为 java
中的 PublicKey
对象。使用 EC
KeyFactory,我将十六进制转换为 byte[]
并尝试在 java 中构造 PublicKey
对象,该对象需要 X.509 格式编码。
public PublicKey getPublicKey(byte[] pk) throws NoSuchAlgorithmException, InvalidKeySpecException {
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pk);
KeyFactory kf = KeyFactory.getInstance("EC");
PublicKey pub = kf.generatePublic(publicKeySpec);
return pub;
}
要将十六进制字符串转换为 byte[]
,我使用以下内容:
public byte[] hexStringToByteArray(String hexString) {
byte[] bytes = new byte[hexString.length() / 2];
for(int i = 0; i < hexString.length(); i += 2) {
String sub = hexString.substring(i, i + 2);
Integer intVal = Integer.parseInt(sub, 16);
bytes[i / 2] = intVal.byteValue();
String hex = "".format("0x%x", bytes[i / 2]);
}
return bytes;
}
尝试使用测试用例执行相同操作会导致 InvalidKeySpecException
:
@Test
public void pkConversionTest() throws NoSuchAlgorithmException, InvalidKeySpecException {
ECDSA.setDebug(true);
byte[] pk = hexStringToByteArray("049a6b0ac242afe41128cf59736412686ca83c9e902ee3fa0f13810b9d59ebfe5e49204427c23b630be12ae33815b0bda6ed8d0603386c6ea5f1906cdb0e731286");
PublicKey pub = ECDSA.getPublicKey(pk);
System.out.println(pub);
}
returns
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: DerInputStream.getLength(): lengthTag=26, too big.
然而,我能够使用 java
生成 KeyPair
并使用通过 nodejs
获得的公钥十六进制来执行签名 verify
。从 java 生成的示例公钥十六进制如下所示:
3059301306072a8648ce3d020106082a8648ce3d0301070342000425a321d5a1a74e6c04a6e3cab030401f3dbc04d5242f9bc629175c3d3988799175eb80cd96d7e76ea924630a8d86b93c54dec7cb965b58de31705eb3343846a1
如何将 nodejs 生成的 publicKey 格式化为 X.509 格式以便在 java 端使用?
编辑:
3059301306072a8648ce3d020106082a8648ce3d030107034200
似乎是使用 java
生成的公钥十六进制的通用前缀。通过 Prefix
将其转换为使用 nodejs
获得的 PublicKey 的十六进制值,因为长度较小似乎可以解决问题。但是有人可以解释为什么吗?
谢谢。
But can someone explain why?
Java 将 public 键编码为 "X.509" 格式 或更确切地说是 X 定义的 SubjectPublicKeyInfo
结构 (SPKI) .509/PKIX;参见 rfc5280、rfc3279,对于 ECC,特别是 rfc5480。这就是为什么您传递给密钥工厂的数据位于名为 X509EncodedKeySpec
的 class 中。此 ASN.1 结构包含一个 AlgorithmIdentifier
,它标识所使用的算法及其参数(对于 ECC,它是使用的 curve/group,在您的情况下,一个 OID 标识 prime256 aka P-256 aka secp256r1)加上一个 BIT包含实际编码的 public 密钥值的字符串类型(ECC 是 X9.62 格式中的点,它有多种变体;这里您使用的是未压缩的;根据 the doc nodejs.crypto 也支持压缩)。
您的 "prefix" 是 ASN.1 外部序列的 DER 编码、AlgorithmIdentifier、标签长度和 padcount,它们开始包含 public 关键点的 BIT STRING。
基本上是骗人的:
* How can I get a PublicKey object from EC public key bytes?
* (Maarten 的回答实际上就是您所做的)
* How can I generate a valid ECDSA EC key pair?(披露:我的)
仅供参考:同样的问题实际上也发生在 RSA 上,并且有更多关于它的问题。
与特定算法格式相比,通用 PKCS8 格式的私钥也存在类似问题,但由于 public 密钥通常与其他系统 and/or 程序交换,而私钥通常不是私钥编码的互操作性不太常见。
我正在使用 prime256v1
曲线生成密钥对并使用 nodejs
和默认 crypto
模块进行签名。
使用crypto
let crypto = require('crypto');
let e = crypto.createECDH('prime256v1');
e.generateKeys();
privateKey = e.getPrivateKey();
privateKeyHex = privateKey.toString('hex');
publicKey = e.getPublicKey();
publicKeyHex = publicKey.toString('hex');
我获得了一个公钥,它看起来像下面的十六进制字符串:
'049a6b0ac242afe41128cf59736412686ca83c9e902ee3fa0f13810b9d59ebfe5e49204427c23b630be12ae33815b0bda6ed8d0603386c6ea5f1906cdb0e731286'
Usign jsrsasign
let jsrsa = require('jsrsasign');
let KEYUTIL = jsrsa.KEYUTIL;
let kp = KEYUTIL.generateKeypair("EC", "prime256v1");
let pkHex = kp.pubKeyObj.pubKeyHex
其中 returns
'04f36e41189420db05dd8a73e3cb310b0c55809190bdedd89bf19769ac8df3cd06c1380f646e9e65e31c24affff79e43516b37e0186c3753cfdfd29894c2becc84'
将 PublicKey Hex 转换为 Java
中的 PublicKey 对象我想使用这些 publicKeys 并将其转换为 java
中的 PublicKey
对象。使用 EC
KeyFactory,我将十六进制转换为 byte[]
并尝试在 java 中构造 PublicKey
对象,该对象需要 X.509 格式编码。
public PublicKey getPublicKey(byte[] pk) throws NoSuchAlgorithmException, InvalidKeySpecException {
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pk);
KeyFactory kf = KeyFactory.getInstance("EC");
PublicKey pub = kf.generatePublic(publicKeySpec);
return pub;
}
要将十六进制字符串转换为 byte[]
,我使用以下内容:
public byte[] hexStringToByteArray(String hexString) {
byte[] bytes = new byte[hexString.length() / 2];
for(int i = 0; i < hexString.length(); i += 2) {
String sub = hexString.substring(i, i + 2);
Integer intVal = Integer.parseInt(sub, 16);
bytes[i / 2] = intVal.byteValue();
String hex = "".format("0x%x", bytes[i / 2]);
}
return bytes;
}
尝试使用测试用例执行相同操作会导致 InvalidKeySpecException
:
@Test
public void pkConversionTest() throws NoSuchAlgorithmException, InvalidKeySpecException {
ECDSA.setDebug(true);
byte[] pk = hexStringToByteArray("049a6b0ac242afe41128cf59736412686ca83c9e902ee3fa0f13810b9d59ebfe5e49204427c23b630be12ae33815b0bda6ed8d0603386c6ea5f1906cdb0e731286");
PublicKey pub = ECDSA.getPublicKey(pk);
System.out.println(pub);
}
returns
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: DerInputStream.getLength(): lengthTag=26, too big.
然而,我能够使用 java
生成 KeyPair
并使用通过 nodejs
获得的公钥十六进制来执行签名 verify
。从 java 生成的示例公钥十六进制如下所示:
3059301306072a8648ce3d020106082a8648ce3d0301070342000425a321d5a1a74e6c04a6e3cab030401f3dbc04d5242f9bc629175c3d3988799175eb80cd96d7e76ea924630a8d86b93c54dec7cb965b58de31705eb3343846a1
如何将 nodejs 生成的 publicKey 格式化为 X.509 格式以便在 java 端使用?
编辑:
3059301306072a8648ce3d020106082a8648ce3d030107034200
似乎是使用 java
生成的公钥十六进制的通用前缀。通过 Prefix
将其转换为使用 nodejs
获得的 PublicKey 的十六进制值,因为长度较小似乎可以解决问题。但是有人可以解释为什么吗?
谢谢。
But can someone explain why?
Java 将 public 键编码为 "X.509" 格式 或更确切地说是 X 定义的 SubjectPublicKeyInfo
结构 (SPKI) .509/PKIX;参见 rfc5280、rfc3279,对于 ECC,特别是 rfc5480。这就是为什么您传递给密钥工厂的数据位于名为 X509EncodedKeySpec
的 class 中。此 ASN.1 结构包含一个 AlgorithmIdentifier
,它标识所使用的算法及其参数(对于 ECC,它是使用的 curve/group,在您的情况下,一个 OID 标识 prime256 aka P-256 aka secp256r1)加上一个 BIT包含实际编码的 public 密钥值的字符串类型(ECC 是 X9.62 格式中的点,它有多种变体;这里您使用的是未压缩的;根据 the doc nodejs.crypto 也支持压缩)。
您的 "prefix" 是 ASN.1 外部序列的 DER 编码、AlgorithmIdentifier、标签长度和 padcount,它们开始包含 public 关键点的 BIT STRING。
基本上是骗人的:
* How can I get a PublicKey object from EC public key bytes?
*
* How can I generate a valid ECDSA EC key pair?(披露:我的)
仅供参考:同样的问题实际上也发生在 RSA 上,并且有更多关于它的问题。 与特定算法格式相比,通用 PKCS8 格式的私钥也存在类似问题,但由于 public 密钥通常与其他系统 and/or 程序交换,而私钥通常不是私钥编码的互操作性不太常见。