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 20, 2021
1 parent 43f599b commit b2f8ba7
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 258 deletions.
51 changes: 51 additions & 0 deletions benchmark/crypto/oneshot-sign-verify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
'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: crypto.createPublicKey(
fs.readFileSync(`${fixtures_keydir}/ed25519_public.pem`)),
privateKey: crypto.createPrivateKey(
fs.readFileSync(`${fixtures_keydir}/ed25519_private.pem`)),
};

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

const bench = common.createBenchmark(main, {
sync: [0, 1],
n: [1e4],
});

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

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

function main({ n, sync }) {
if (sync)
measureSync(n);
else
measureAsync(n);
}
7 changes: 5 additions & 2 deletions lib/internal/crypto/dsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,15 @@ function dsaSignVerify(key, data, algorithm, signature) {
kCryptoJobAsync,
signature === undefined ? kSignJobModeSign : kSignJobModeVerify,
key[kKeyObject][kHandle],
undefined,
undefined,
undefined,
data,
normalizeHashName(key.algorithm.hash.name),
undefined, // Salt-length is not used in DSA
undefined, // Padding is not used in DSA
signature,
kSigEncDER));
kSigEncDER,
signature));
}

module.exports = {
Expand Down
7 changes: 5 additions & 2 deletions lib/internal/crypto/ec.js
Original file line number Diff line number Diff line change
Expand Up @@ -467,12 +467,15 @@ function ecdsaSignVerify(key, data, { name, hash }, signature) {
kCryptoJobAsync,
mode,
key[kKeyObject][kHandle],
undefined,
undefined,
undefined,
data,
hashname,
undefined, // Salt length, not used with ECDSA
undefined, // PSS Padding, not used with ECDSA
signature,
kSigEncP1363));
kSigEncP1363,
signature));
}

module.exports = {
Expand Down
4 changes: 4 additions & 0 deletions lib/internal/crypto/rsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,14 @@ function rsaSignVerify(key, data, { saltLength }, signature) {
kCryptoJobAsync,
signature === undefined ? kSignJobModeSign : kSignJobModeVerify,
key[kKeyObject][kHandle],
undefined,
undefined,
undefined,
data,
normalizeHashName(key.algorithm.hash.name),
saltLength,
padding,
undefined,
signature));
}

Expand Down
91 changes: 39 additions & 52 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 All @@ -40,10 +39,6 @@ const {
} = require('internal/crypto/util');

const {
createPrivateKey,
createPublicKey,
isCryptoKey,
isKeyObject,
preparePrivateKey,
preparePublicOrPrivateKey,
} = require('internal/crypto/keys');
Expand Down Expand Up @@ -162,38 +157,34 @@ 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));
} else if (key != null && (isKeyObject(key.key) || isCryptoKey(key.key))) {
({ data: keyData } = preparePrivateKey(key.key));
} else {
keyData = createPrivateKey(key)[kHandle];
}
const {
data: keyData,
format: keyFormat,
type: keyType,
passphrase: keyPassphrase
} = preparePrivateKey(key);

const job = new SignJob(
kCryptoJobAsync,
callback ? kCryptoJobAsync : kCryptoJobSync,
kSignJobModeSign,
keyData,
keyFormat,
keyType,
keyPassphrase,
data,
algorithm,
pssSaltLength,
rsaPadding,
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,38 +263,34 @@ 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));
} else if (key != null && (isKeyObject(key.key) || isCryptoKey(key.key))) {
({ data: keyData } = preparePublicOrPrivateKey(key.key));
} else {
keyData = createPublicKey(key)[kHandle];
}
const {
data: keyData,
format: keyFormat,
type: keyType,
passphrase: keyPassphrase
} = preparePublicOrPrivateKey(key);

const job = new SignJob(
kCryptoJobAsync,
callback ? kCryptoJobAsync : kCryptoJobSync,
kSignJobModeVerify,
keyData,
keyFormat,
keyType,
keyPassphrase,
data,
algorithm,
pssSaltLength,
rsaPadding,
signature,
dsaSigEnc);
dsaSigEnc,
signature);

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);
Expand Down
Loading

0 comments on commit b2f8ba7

Please sign in to comment.