nodejs / help

:sparkles: Need help with Node.js? File an Issue here. :rocket:
1.46k stars 279 forks source link

How to verify the signed message against the signature with raw ec public key only #4447

Open chlin501 opened 1 month ago

chlin501 commented 1 month ago

Node.js Version

v20.14.0

NPM Version

v9.2.0

Operating System

Linux debian 6.6.15-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.6.15-2 (2024-02-04) x86_64 GNU/Linux

Subsystem

crypto

Description

I have a process which receives a signed message, its corresponded signature, as well as a raw ec public key from a client. The raw ec public key is a 88 chars length base64 string. An example is BEAgXhzprs3lhokv0ESvgXnsMn3FlOLdkyqCJ56UyzJWhQvaVvcQXQR/TuaW85aJKi5uUQnweCr+zTLDLZMB6Ds=. And this raw ec public key is generated by

const gen = createECDH('prime256v1');
gen.generateKeys();
return {  publicKey: gen.getPublicKey('base64'),
    privateKey: gen.getPrivateKey('base64')
};

And the way to sign is done by

const privatekey = createPrivateKey({ key: pem }); // pem is a string created from the method like this link https://gist.github.com/canterberry/bf190ae6402265751e51725be535a4e4
const signer = createSign('SHA256')
signer.update(message); // the message is a string
signer.end();
signer.sign(privatekey, 'base64'); 

Now the problem is the process that needs to verify the signed message and the corresponded signature is at another machine. So that machine do not have private key, thus I can't recreate pem file from the private and the public key.

I attempted to create a public key only pem string as below

function convert_raw_ec_key(raw_key) {
    return Buffer.concat([Buffer.from('MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgA', 'base64'), Buffer.from(raw_key, 'base64')]);
}

const pemstr = `-----BEGIN PUBLIC KEY-----
${conver_raw_ec_key(client_raw_ec_key).toString('base64')}
-----END PUBLIC KEY-----`;
const myv = createVerify('SHA256');
myv.update(message);// the message is a string
myv.end();
const result = myv.verify(pemstr, Buffer.from(signature, 'base64'));
assert(true === result); // but this fails because result is false

Unfortunately, the result value is false. How can I reconstruct the public key so that it can be passed as the parameter to the verify() method for verifying the signed message?

Many thanks.

Minimal Reproduction

  1. Sign
    1. Create the pem string from the private key and public key
    2. Pass the pem string to createPrivateKey({key: pem})
    3. sign the message with createSign(), update(), end(), then sign() for generating signature
  2. Verify
    1. Create the pem string from the public key
    2. Verify the message createVerify(), update(), end(), then verify() with the signed message and the signature provided at the sign stage

Output

const result = verify.verify(pem, Buffer.from(signature, 'base64')); console.log(result ); assert(true === result); console show the result is false, and assert also fail as the result is false.

Before You Submit

RedYetiDev commented 1 month ago

CC @nodejs/crypto