Skip to content

Commit

Permalink
crypto: reconsile oneshot sign/verify sync and async implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
panva committed Mar 21, 2021
1 parent 43f599b commit c1b1f4d
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 34 deletions.
91 changes: 91 additions & 0 deletions benchmark/crypto/oneshot-sign-verify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
'use strict';

const common = require('../common.js');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const fixtures_keydir = path.resolve(__dirname, '../../test/fixtures/keys/');
const keys = {
publicKey: fs.readFileSync(`${fixtures_keydir}/ed25519_public.pem`),
privateKey: fs.readFileSync(`${fixtures_keydir}/ed25519_private.pem`),
};

const data = crypto.randomBytes(256);
const args = [null, data];

const bench = common.createBenchmark(main, {
mode: ['sync', 'async-serial', 'async-parallel'],
keyFormat: ['pem', 'keyObject'],
n: [1e3],
});

function measureSync(n, keyFormat) {
let { publicKey, privateKey } = keys;
if (keyFormat === 'keyObject') {
publicKey = crypto.createPublicKey(publicKey);
privateKey = crypto.createPrivateKey(privateKey);
}
bench.start();
for (let i = 0; i < n; ++i) {
crypto.verify(...args, publicKey,
crypto.sign(...args, privateKey));
}
bench.end(n);
}

function measureAsyncSerial(n, keyFormat) {
let { publicKey, privateKey } = keys;
if (keyFormat === 'keyObject') {
publicKey = crypto.createPublicKey(publicKey);
privateKey = crypto.createPrivateKey(privateKey);
}
let remaining = n;

function done() {
if (--remaining === 0)
bench.end(n);
else
one();
}

function one() {
crypto.sign(...args, privateKey, (err, signature) => {
crypto.verify(...args, publicKey, signature, done);
});
}
bench.start();
one();
}

function measureAsyncParallel(n, keyFormat) {
let { publicKey, privateKey } = keys;
if (keyFormat === 'keyObject') {
publicKey = crypto.createPublicKey(publicKey);
privateKey = crypto.createPrivateKey(privateKey);
}
let remaining = n;
function done() {
if (--remaining === 0)
bench.end(n);
}
bench.start();
for (let i = 0; i < n; ++i) {
crypto.sign(...args, privateKey, (err, signature) => {
crypto.verify(...args, publicKey, signature, done);
});
}
}

function main({ n, mode, keyFormat }) {
switch (mode) {
case 'sync':
measureSync(n, keyFormat);
break;
case 'async-serial':
measureAsyncSerial(n, keyFormat);
break;
case 'async-parallel':
measureAsyncParallel(n, keyFormat);
break;
}
}
48 changes: 19 additions & 29 deletions lib/internal/crypto/sig.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@ const {
Sign: _Sign,
SignJob,
Verify: _Verify,
signOneShot: _signOneShot,
verifyOneShot: _verifyOneShot,
kCryptoJobAsync,
kCryptoJobSync,
kSigEncDER,
kSigEncP1363,
kSignJobModeSign,
Expand Down Expand Up @@ -162,18 +161,6 @@ function signOneShot(algorithm, data, key, callback) {
// Options specific to (EC)DSA
const dsaSigEnc = getDSASignatureEncoding(key);

if (!callback) {
const {
data: keyData,
format: keyFormat,
type: keyType,
passphrase: keyPassphrase
} = preparePrivateKey(key);

return _signOneShot(keyData, keyFormat, keyType, keyPassphrase, data,
algorithm, rsaPadding, pssSaltLength, dsaSigEnc);
}

let keyData;
if (isKeyObject(key) || isCryptoKey(key)) {
({ data: keyData } = preparePrivateKey(key));
Expand All @@ -184,7 +171,7 @@ function signOneShot(algorithm, data, key, callback) {
}

const job = new SignJob(
kCryptoJobAsync,
callback ? kCryptoJobAsync : kCryptoJobSync,
kSignJobModeSign,
keyData,
data,
Expand All @@ -194,6 +181,14 @@ function signOneShot(algorithm, data, key, callback) {
undefined,
dsaSigEnc);

if (!callback) {
const { 0: err, 1: signature } = job.run();
if (err !== undefined)
throw err;

return Buffer.from(signature);
}

job.ondone = (error, signature) => {
if (error) return FunctionPrototypeCall(callback, job, error);
FunctionPrototypeCall(callback, job, null, Buffer.from(signature));
Expand Down Expand Up @@ -272,19 +267,6 @@ function verifyOneShot(algorithm, data, key, signature, callback) {
);
}

if (!callback) {
const {
data: keyData,
format: keyFormat,
type: keyType,
passphrase: keyPassphrase
} = preparePublicOrPrivateKey(key);

return _verifyOneShot(keyData, keyFormat, keyType, keyPassphrase,
signature, data, algorithm, rsaPadding,
pssSaltLength, dsaSigEnc);
}

let keyData;
if (isKeyObject(key) || isCryptoKey(key)) {
({ data: keyData } = preparePublicOrPrivateKey(key));
Expand All @@ -295,7 +277,7 @@ function verifyOneShot(algorithm, data, key, signature, callback) {
}

const job = new SignJob(
kCryptoJobAsync,
callback ? kCryptoJobAsync : kCryptoJobSync,
kSignJobModeVerify,
keyData,
data,
Expand All @@ -305,6 +287,14 @@ function verifyOneShot(algorithm, data, key, signature, callback) {
signature,
dsaSigEnc);

if (!callback) {
const { 0: err, 1: result } = job.run();
if (err !== undefined)
throw err;

return result;
}

job.ondone = (error, result) => {
if (error) return FunctionPrototypeCall(callback, job, error);
FunctionPrototypeCall(callback, job, null, result);
Expand Down
14 changes: 9 additions & 5 deletions test/parallel/test-crypto-sign-verify.js
Original file line number Diff line number Diff line change
Expand Up @@ -528,11 +528,15 @@ assert.throws(
// Test invalid signature lengths.
for (const i of [-2, -1, 1, 2, 4, 8]) {
sig = crypto.randomBytes(length + i);
assert.throws(() => {
crypto.verify('sha1', data, opts, sig);
}, {
message: 'Malformed signature'
});
let result;
try {
result = crypto.verify('sha1', data, opts, sig);
} catch (err) {
assert.match(err.message, /asn1 encoding/);
assert.strictEqual(err.library, 'asn1 encoding routines');
continue;
}
assert.strictEqual(result, false);
}
}

Expand Down

0 comments on commit c1b1f4d

Please sign in to comment.