I am using the prime256v1 curves for generating key pairs and sign using nodejs with the default crypto module.
Using 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');
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
which returns
'04f36e41189420db05dd8a73e3cb310b0c55809190bdedd89bf19769ac8df3cd06c1380f646e9e65e31c24affff79e43516b37e0186c3753cfdfd29894c2becc84'
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;
}
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;
}
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);
}
returns
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: DerInputStream.getLength(): lengthTag=26, too big.
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
How do I format the publicKey generated by nodejs in an X.509 format to be used on the java's side?
Edit:
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.