Nodejs加密ECDH公钥十六进制为X.509 [英] Nodejs Crypto ECDH PublicKey Hex as X.509

查看:168
本文介绍了Nodejs加密ECDH公钥十六进制为X.509的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 prime256v1 曲线来生成密钥对,并使用 nodejs 和默认的 crypto 模块进行签名.

I am using the prime256v1 curves for generating key pairs and sign using nodejs with the default crypto module.

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');

我获得了一个公共密钥,看起来像下面的十六进制字符串:

I obtain a publickey which looks like the hex string below:

'049a6b0ac242afe41128cf59736412686ca83c9e902ee3fa0f13810b9d59ebfe5e49204427c23b630be12ae33815b0bda6ed8d0603386c6ea5f1906cdb0e731286'

Usign jsrsasign

let jsrsa = require('jsrsasign');
let KEYUTIL = jsrsa.KEYUTIL;
let kp = KEYUTIL.generateKeypair("EC", "prime256v1");
let pkHex = kp.pubKeyObj.pubKeyHex

返回

'04f36e41189420db05dd8a73e3cb310b0c55809190bdedd89bf19769ac8df3cd06c1380f646e9e65e31c24affff79e43516b37e0186c3753cfdfd29894c2becc84'

将Java中的PublicKey十六进制转换为PublicKey对象

我想使用这些publicKeys并将其转换为 java 中的 PublicKey 对象.使用 EC KeyFactory,我将十六进制转换为 byte [] ,并尝试在Java中构造需要X.509的 PublicKey 对象.格式编码.

Converting the PublicKey Hex to PublicKey object in Java

I want to use these publicKeys and convert it into a PublicKey object in java. Using the EC KeyFactory, I convert the hex to a byte[] and try to construct the PublicKey object in java which expects a X.509 format encoding.

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 [] ,我使用以下命令:

To convert the hex string to a byte[] I use the following:

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 :

Trying to do the same using the test case as follows results in an InvalidKeySpecException:

@Test
public void pkConversionTest() throws NoSuchAlgorithmException, InvalidKeySpecException {
    ECDSA.setDebug(true);
    byte[] pk = hexStringToByteArray("049a6b0ac242afe41128cf59736412686ca83c9e902ee3fa0f13810b9d59ebfe5e49204427c23b630be12ae33815b0bda6ed8d0603386c6ea5f1906cdb0e731286");
    PublicKey pub = ECDSA.getPublicKey(pk);
    System.out.println(pub);
}

返回

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: DerInputStream.getLength(): lengthTag=26, too big.

但是我可以使用 java 生成 KeyPair ,并使用通过 nodejs 获得的publicKey十六进制执行签名 verify .从Java生成的示例十六进制公钥如下:

I am however able to generate a KeyPair using java and use the publicKey hex obtained with nodejs to perform signature verify. A sample publickey hex generated from java looks as follows:

3059301306072a8648ce3d020106082a8648ce3d0301070342000425a321d5a1a74e6c04a6e3cab030401f3dbc04d5242f9bc629175c3d3988799175eb80cd96d7e76ea924630a8d86b93c54dec7cb965b58de31705eb3343846a1

如何将Nodejs生成的publicKey格式化为X.509格式,以便在Java端使用?

How do I format the publicKey generated by nodejs in an X.509 format to be used on the java's side?

3059301306072a8648ce3d020106082a8648ce3d030107034200 似乎是使用 java 生成的publicKey十六进制的通用前缀.通过将

3059301306072a8648ce3d020106082a8648ce3d030107034200 seems to be a common prefix for the publicKey hexes generated using java. By Prefixing this to the hex values of the PublicKey obtained using nodejs since the length is smaller seems to solve the problem. But can someone explain why?

Thank you.

谢谢.

推荐答案

但是有人可以解释为什么吗?

Java encodes public keys in "X.509" format or more exactly the SubjectPublicKeyInfo structure (SPKI) defined by X.509/PKIX; see rfc5280, rfc3279, and for ECC specifically rfc5480. That's why the data you pass to the key factory is in a class named X509EncodedKeySpec. This ASN.1 structure contains an AlgorithmIdentifier which identifies the algorithm used and its parameters (which for ECC is the curve/group used, in your case an OID identifying prime256 aka P-256 aka secp256r1) plus a BIT STRING type containing the actual encoded publickey value (which for ECC is the point in X9.62 format, which has several variants; here you are using uncompressed; according to the doc nodejs.crypto also supports compressed).

Java以"X.509"格式编码公钥,或更确切地说,是X.509/PKIX定义的 SubjectPublicKeyInfo 结构(SPKI);请参阅rfc5280,rfc3279,对于ECC,请参见rfc5480.这就是为什么您传递给密钥工厂的数据位于名为 X509EncodedKeySpec 的类中的原因.这个ASN.1结构包含一个 AlgorithmIdentifier ,用于标识所使用的算法及其参数(对于ECC,它是所使用的曲线/组,在您的情况下,其OID标识prime256 aka P-256 aka secp256r1)加上一个BIT STRING类型,包含实际的编码公共密钥值(对于ECC,它是X9.62格式的点,具有多种变体;在这里您使用的是未压缩的;根据

Your "prefix" is the DER encoding of the ASN.1 outer SEQUENCE, AlgorithmIdentifier, and tag length and padcount which begin the BIT STRING to contain the publickey point.

您的前缀"是ASN.1外部SEQUENCE的DER编码,AlgorithmIdentifier以及标签长度和填充数,它们开始BIT STRING包含公钥点.

Basically dupe:
* How can I get a PublicKey object from EC public key bytes?
* Loading raw 64-byte long ECDSA public key in Java (Maarten's answer is effectively what you did)
* How can I generate a valid ECDSA EC key pair? (disclosure: mine)

基本欺骗:
*
我如何从EC公钥字节中获取PublicKey对象?
* 在Java中加载原始的64字节长的ECDSA公钥(Maarten的回答实际上是您所做的事情)
* 如何生成有效的ECDSA EC密钥对?(公开:我的)

FYI: Effectively the same issue also occurs for RSA and there are more Qs on that. And there are also similar issues with privatekeys in generic PKCS8 format compared to algorithm-specific formats, but since publickeys are usually exchanged with other systems and/or programs while privatekeys usually aren't interoperability of privatekey encoding is less often a concern.

这篇关于Nodejs加密ECDH公钥十六进制为X.509的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆