Open xicilion opened 4 months ago
(+ repro-exists
)
I've made a few changes to the code for better logging, and here is my output:
const crypto = require('crypto');
const data = "AABB";
// Define the private and public keys
const privateKeyPEM = `-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgbjCNHopgvyGVfLaP
PamI9E9lf6jXT+xm1Pns1t/xQTihRANCAATV+I7HUGF2gC+miVl3JfjpoZaU2hrZ
QqHwKUNtIDE/uxxWNLBbYKaiLOWrbYA8skrWQWl3RkbXW4ZI28afRw9g
-----END PRIVATE KEY-----
`;
const publicKeyPEM = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE1fiOx1BhdoAvpolZdyX46aGWlNoa
2UKh8ClDbSAxP7scVjSwW2Cmoizlq22APLJK1kFpd0ZG11uGSNvGn0cPYA==
-----END PUBLIC KEY-----
`;
// Create the private and public key objects
const privateKey = crypto.createPrivateKey(privateKeyPEM);
const publicKey = crypto.createPublicKey(publicKeyPEM);
// Log the private and public keys
console.log("Private Key:");
console.log(privateKey.export({ type: 'pkcs8', format: 'pem' }));
console.log("Public Key:");
console.log(publicKey.export({ type: 'spki', format: 'pem' }));
// Create the signature using the private key
const sign = crypto.createSign('sm3');
sign.update(data);
const signature = sign.sign(privateKey);
// Log the signature
console.log("Signature:");
console.log(signature.toString('hex'));
// Verify the signature using the public key via crypto.createVerify
const verify = crypto.createVerify('sm3');
verify.update(data);
const isVerified = verify.verify(publicKey, signature);
// Log the verification result
console.log("Signature verified (via crypto.createVerify):", isVerified);
// Verify the signature using the public key via crypto.verify
const verify2 = crypto.verify('sm3', data, publicKey, signature);
console.log("Signature verified (via crypto.verify):", verify2);
Private Key:
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgbjCNHopgvyGVfLaP
PamI9E9lf6jXT+xm1Pns1t/xQTihRANCAATV+I7HUGF2gC+miVl3JfjpoZaU2hrZ
QqHwKUNtIDE/uxxWNLBbYKaiLOWrbYA8skrWQWl3RkbXW4ZI28afRw9g
-----END PRIVATE KEY-----
Public Key:
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE1fiOx1BhdoAvpolZdyX46aGWlNoa
2UKh8ClDbSAxP7scVjSwW2Cmoizlq22APLJK1kFpd0ZG11uGSNvGn0cPYA==
-----END PUBLIC KEY-----
Signature:
3044022056cc3567aa4842c4b1c5f9de75059dbaf63efab5aa34097e5a8547419aa3175e02206deb865046f12b25f111922da6858c7e97e475b656604679bcd4a0b05d8c76f1
Signature verified (via crypto.createVerify): true
Signature verified (via crypto.verify): false
This seems to only affect crypto.verify
, CC @nodejs/crypto
That being said, I believe the issue title is misleading. crypto.createVerify
appears to be fine, it's crypto.verify
that is affected, right?
My test results are as follows:
So the results of crypto.createSign and crypto.createVerify on SM2 are both incorrect.
crypto.sign/crypto.verify and cresteSign/createVerify cannot verify each other;
Can you provide example code with createVerify
? I'm unable to reproduce that part.
const crypto = require('crypto');
const data = "AABB";
var keys = {
privateKey: crypto.createPrivateKey(`-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgbjCNHopgvyGVfLaP
PamI9E9lf6jXT+xm1Pns1t/xQTihRANCAATV+I7HUGF2gC+miVl3JfjpoZaU2hrZ
QqHwKUNtIDE/uxxWNLBbYKaiLOWrbYA8skrWQWl3RkbXW4ZI28afRw9g
-----END PRIVATE KEY-----
`),
publicKey: crypto.createPublicKey(`-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE1fiOx1BhdoAvpolZdyX46aGWlNoa
2UKh8ClDbSAxP7scVjSwW2Cmoizlq22APLJK1kFpd0ZG11uGSNvGn0cPYA==
-----END PUBLIC KEY-----`)
};
// var sig = crypto.createSign('sm3').update(data).sign(keys.privateKey);
var sig = crypto.sign('sm3', data, keys.privateKey);
var ok = crypto.createVerify('sm3').update(data).verify(keys.publicKey, sig);
console.log("verify: ", ok);
Thanks! I understand now. My reproduction used createSign
, which worked, this is weird indeed. @tniessen confirmed-bug
?
const crypto = require('crypto');
// Data to be signed and verified
const data = "AABB";
// Define the private and public keys
const privateKeyPEM = `
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgbjCNHopgvyGVfLaP
PamI9E9lf6jXT+xm1Pns1t/xQTihRANCAATV+I7HUGF2gC+miVl3JfjpoZaU2hrZ
QqHwKUNtIDE/uxxWNLBbYKaiLOWrbYA8skrWQWl3RkbXW4ZI28afRw9g
-----END PRIVATE KEY-----
`;
const publicKeyPEM = `
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE1fiOx1BhdoAvpolZdyX46aGWlNoa
2UKh8ClDbSAxP7scVjSwW2Cmoizlq22APLJK1kFpd0ZG11uGSNvGn0cPYA==
-----END PUBLIC KEY-----
`;
// Function to create private key object
function createPrivateKey(privateKeyPEM) {
return crypto.createPrivateKey(privateKeyPEM);
}
// Function to create public key object
function createPublicKey(publicKeyPEM) {
return crypto.createPublicKey(publicKeyPEM);
}
// Array of signer functions
const SIGNERS = [
// Via crypto.createSign
(data, privateKey) => {
const sign = crypto.createSign('sm3');
sign.update(data);
return sign.sign(privateKey);
},
// Via crypto.sign
(data, privateKey) => {
return crypto.sign('sm3', Buffer.from(data), { key: privateKey });
}
];
// Array of verifier functions
const VERIFIERS = [
// Via crypto.createVerify
(data, signature, publicKey) => {
const verify = crypto.createVerify('sm3');
verify.update(data);
return verify.verify(publicKey, signature);
},
// Via crypto.verify
(data, signature, publicKey) => {
return crypto.verify('sm3', Buffer.from(data), publicKey, signature);
}
];
// Function to sign data using all signers and verify using all verifiers
function signAndVerifyAll(data, privateKey, publicKey) {
const results = SIGNERS.flatMap(signer => {
const signature = signer(data, privateKey);
return VERIFIERS.map(verifier => {
return {
"Sign Method": SIGNERS.indexOf(signer) === 0 ? 'crypto.createSign' : 'crypto.sign',
"Verify Method": VERIFIERS.indexOf(verifier) === 0 ? 'crypto.createVerify' : 'crypto.verify',
"Signature": signature.toString('hex'),
"Result": verifier(data, signature, publicKey)
};
});
});
return results;
}
// Create private and public key objects
const privateKey = createPrivateKey(privateKeyPEM);
const publicKey = createPublicKey(publicKeyPEM);
// Sign and verify data using all methods
const results = signAndVerifyAll(data, privateKey, publicKey);
// Output results in a table
console.table(results);
┌─────────┬─────────────────────┬───────────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬────────┐
│ (index) │ Sign Method │ Verify Method │ Signature │ Result │
├─────────┼─────────────────────┼───────────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────┤
│ 0 │ 'crypto.createSign' │ 'crypto.createVerify' │ '3045022046fa9c7b15e1ff55aa7f5dfcc2092614e25b2b321c82e0e1c09b03d21bd48fc9022100e45cddee885a1c075691f00b577c617ff584a89c65a19896600d5569d752d9f4' │ true │
│ 1 │ 'crypto.createSign' │ 'crypto.verify' │ '3045022046fa9c7b15e1ff55aa7f5dfcc2092614e25b2b321c82e0e1c09b03d21bd48fc9022100e45cddee885a1c075691f00b577c617ff584a89c65a19896600d5569d752d9f4' │ false │
│ 2 │ 'crypto.sign' │ 'crypto.createVerify' │ '3045022100cf800e13a0ead14be0ec9d614257fb6f409187642404dccb3a4374ace9fc162602206bf6820b8902ae9ce4cd10708f188fddd5bc2a41db2c47c003ca8265a00396ae' │ false │
│ 3 │ 'crypto.sign' │ 'crypto.verify' │ '3045022100cf800e13a0ead14be0ec9d614257fb6f409187642404dccb3a4374ace9fc162602206bf6820b8902ae9ce4cd10708f188fddd5bc2a41db2c47c003ca8265a00396ae' │ true │
└─────────┴─────────────────────┴───────────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────┘
I've generated the table above to demonstrate which methods are incompatible.
openssl command line can verify with crypto.sign/crypto.verify.
So crypto.createXXX
seems to have the wrong algorithm, IIUC
crypto.sign and crypto.verify are correct.
Thanks for the excellent info! When the @nodejs/crypto team gets a chance to look at this issue, they will be able to help even more!
Version
v22.0.0
Platform
Subsystem
crypto
What steps will reproduce the bug?
When using crypto.createSign to sign SM2, I got an incorrect signature. The same issue occurs with crypto.createVerify.
How often does it reproduce? Is there a required condition?
always.
What is the expected behavior? Why is that the expected behavior?
verify: true
What do you see instead?
verify: false
Additional information
No response