Skip to content

Commit dfdf742

Browse files
committed
crypto: reconcile oneshot sign/verify sync and async implementations
1 parent 43f599b commit dfdf742

File tree

8 files changed

+230
-258
lines changed

8 files changed

+230
-258
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const crypto = require('crypto');
5+
6+
const data = crypto.randomBytes(256);
7+
8+
let pems;
9+
let keyObjects;
10+
11+
function generateKeyPair() {
12+
return crypto.generateKeyPairSync('ed25519', {
13+
privateKeyEncoding: { format: 'pem', type: 'pkcs8' },
14+
publicKeyEncoding: { format: 'pem', type: 'spki' }
15+
});
16+
}
17+
18+
function getKeyObject({ privateKey, publicKey }) {
19+
return {
20+
privateKey: crypto.createPrivateKey(privateKey),
21+
publicKey: crypto.createPublicKey(publicKey)
22+
};
23+
}
24+
25+
const bench = common.createBenchmark(main, {
26+
mode: ['sync', 'async-serial', 'async-parallel'],
27+
keyFormat: ['pem', 'keyObject', 'pem.unique', 'keyObject.unique'],
28+
n: [1e3],
29+
});
30+
31+
function measureSync(n, privateKey, publicKey, keys) {
32+
bench.start();
33+
for (let i = 0; i < n; ++i) {
34+
crypto.verify(
35+
null,
36+
data,
37+
publicKey || keys[i].publicKey,
38+
crypto.sign(
39+
null,
40+
data,
41+
privateKey || keys[i].privateKey));
42+
}
43+
bench.end(n);
44+
}
45+
46+
function measureAsyncSerial(n, privateKey, publicKey, keys) {
47+
let remaining = n;
48+
function done() {
49+
if (--remaining === 0)
50+
bench.end(n);
51+
else
52+
one();
53+
}
54+
55+
function one() {
56+
crypto.sign(
57+
null,
58+
data,
59+
privateKey || keys[n - remaining].privateKey,
60+
(err, signature) => {
61+
crypto.verify(
62+
null,
63+
data,
64+
publicKey || keys[n - remaining].publicKey,
65+
signature,
66+
done);
67+
});
68+
}
69+
bench.start();
70+
one();
71+
}
72+
73+
function measureAsyncParallel(n, privateKey, publicKey, keys) {
74+
let remaining = n;
75+
function done() {
76+
if (--remaining === 0)
77+
bench.end(n);
78+
}
79+
bench.start();
80+
for (let i = 0; i < n; ++i) {
81+
crypto.sign(
82+
null,
83+
data,
84+
privateKey || keys[i].privateKey,
85+
(err, signature) => {
86+
crypto.verify(
87+
null,
88+
data,
89+
publicKey || keys[i].publicKey,
90+
signature,
91+
done);
92+
});
93+
}
94+
}
95+
96+
function main({ n, mode, keyFormat }) {
97+
pems ||= [...Buffer.alloc(n)].map(generateKeyPair);
98+
keyObjects ||= pems.map(getKeyObject);
99+
100+
let privateKey, publicKey, keys;
101+
102+
switch (keyFormat) {
103+
case 'keyObject':
104+
publicKey = keyObjects[0].publicKey;
105+
privateKey = keyObjects[0].privateKey;
106+
break;
107+
case 'pem':
108+
publicKey = pems[0].publicKey;
109+
privateKey = pems[0].privateKey;
110+
break;
111+
case 'pem.unique':
112+
keys = pems;
113+
break;
114+
case 'keyObject.unique':
115+
keys = keyObjects;
116+
break;
117+
default:
118+
throw new Error('not implemented');
119+
}
120+
121+
switch (mode) {
122+
case 'sync':
123+
measureSync(n, privateKey, publicKey, keys);
124+
break;
125+
case 'async-serial':
126+
measureAsyncSerial(n, privateKey, publicKey, keys);
127+
break;
128+
case 'async-parallel':
129+
measureAsyncParallel(n, privateKey, publicKey, keys);
130+
break;
131+
}
132+
}

lib/internal/crypto/dsa.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,12 +251,15 @@ function dsaSignVerify(key, data, algorithm, signature) {
251251
kCryptoJobAsync,
252252
signature === undefined ? kSignJobModeSign : kSignJobModeVerify,
253253
key[kKeyObject][kHandle],
254+
undefined,
255+
undefined,
256+
undefined,
254257
data,
255258
normalizeHashName(key.algorithm.hash.name),
256259
undefined, // Salt-length is not used in DSA
257260
undefined, // Padding is not used in DSA
258-
signature,
259-
kSigEncDER));
261+
kSigEncDER,
262+
signature));
260263
}
261264

262265
module.exports = {

lib/internal/crypto/ec.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,12 +467,15 @@ function ecdsaSignVerify(key, data, { name, hash }, signature) {
467467
kCryptoJobAsync,
468468
mode,
469469
key[kKeyObject][kHandle],
470+
undefined,
471+
undefined,
472+
undefined,
470473
data,
471474
hashname,
472475
undefined, // Salt length, not used with ECDSA
473476
undefined, // PSS Padding, not used with ECDSA
474-
signature,
475-
kSigEncP1363));
477+
kSigEncP1363,
478+
signature));
476479
}
477480

478481
module.exports = {

lib/internal/crypto/rsa.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,14 @@ function rsaSignVerify(key, data, { saltLength }, signature) {
356356
kCryptoJobAsync,
357357
signature === undefined ? kSignJobModeSign : kSignJobModeVerify,
358358
key[kKeyObject][kHandle],
359+
undefined,
360+
undefined,
361+
undefined,
359362
data,
360363
normalizeHashName(key.algorithm.hash.name),
361364
saltLength,
362365
padding,
366+
undefined,
363367
signature));
364368
}
365369

lib/internal/crypto/sig.js

Lines changed: 39 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@ const {
2424
Sign: _Sign,
2525
SignJob,
2626
Verify: _Verify,
27-
signOneShot: _signOneShot,
28-
verifyOneShot: _verifyOneShot,
2927
kCryptoJobAsync,
28+
kCryptoJobSync,
3029
kSigEncDER,
3130
kSigEncP1363,
3231
kSignJobModeSign,
@@ -40,10 +39,6 @@ const {
4039
} = require('internal/crypto/util');
4140

4241
const {
43-
createPrivateKey,
44-
createPublicKey,
45-
isCryptoKey,
46-
isKeyObject,
4742
preparePrivateKey,
4843
preparePublicOrPrivateKey,
4944
} = require('internal/crypto/keys');
@@ -162,38 +157,34 @@ function signOneShot(algorithm, data, key, callback) {
162157
// Options specific to (EC)DSA
163158
const dsaSigEnc = getDSASignatureEncoding(key);
164159

165-
if (!callback) {
166-
const {
167-
data: keyData,
168-
format: keyFormat,
169-
type: keyType,
170-
passphrase: keyPassphrase
171-
} = preparePrivateKey(key);
172-
173-
return _signOneShot(keyData, keyFormat, keyType, keyPassphrase, data,
174-
algorithm, rsaPadding, pssSaltLength, dsaSigEnc);
175-
}
176-
177-
let keyData;
178-
if (isKeyObject(key) || isCryptoKey(key)) {
179-
({ data: keyData } = preparePrivateKey(key));
180-
} else if (key != null && (isKeyObject(key.key) || isCryptoKey(key.key))) {
181-
({ data: keyData } = preparePrivateKey(key.key));
182-
} else {
183-
keyData = createPrivateKey(key)[kHandle];
184-
}
160+
const {
161+
data: keyData,
162+
format: keyFormat,
163+
type: keyType,
164+
passphrase: keyPassphrase
165+
} = preparePrivateKey(key);
185166

186167
const job = new SignJob(
187-
kCryptoJobAsync,
168+
callback ? kCryptoJobAsync : kCryptoJobSync,
188169
kSignJobModeSign,
189170
keyData,
171+
keyFormat,
172+
keyType,
173+
keyPassphrase,
190174
data,
191175
algorithm,
192176
pssSaltLength,
193177
rsaPadding,
194-
undefined,
195178
dsaSigEnc);
196179

180+
if (!callback) {
181+
const { 0: err, 1: signature } = job.run();
182+
if (err !== undefined)
183+
throw err;
184+
185+
return Buffer.from(signature);
186+
}
187+
197188
job.ondone = (error, signature) => {
198189
if (error) return FunctionPrototypeCall(callback, job, error);
199190
FunctionPrototypeCall(callback, job, null, Buffer.from(signature));
@@ -272,38 +263,34 @@ function verifyOneShot(algorithm, data, key, signature, callback) {
272263
);
273264
}
274265

275-
if (!callback) {
276-
const {
277-
data: keyData,
278-
format: keyFormat,
279-
type: keyType,
280-
passphrase: keyPassphrase
281-
} = preparePublicOrPrivateKey(key);
282-
283-
return _verifyOneShot(keyData, keyFormat, keyType, keyPassphrase,
284-
signature, data, algorithm, rsaPadding,
285-
pssSaltLength, dsaSigEnc);
286-
}
287-
288-
let keyData;
289-
if (isKeyObject(key) || isCryptoKey(key)) {
290-
({ data: keyData } = preparePublicOrPrivateKey(key));
291-
} else if (key != null && (isKeyObject(key.key) || isCryptoKey(key.key))) {
292-
({ data: keyData } = preparePublicOrPrivateKey(key.key));
293-
} else {
294-
keyData = createPublicKey(key)[kHandle];
295-
}
266+
const {
267+
data: keyData,
268+
format: keyFormat,
269+
type: keyType,
270+
passphrase: keyPassphrase
271+
} = preparePublicOrPrivateKey(key);
296272

297273
const job = new SignJob(
298-
kCryptoJobAsync,
274+
callback ? kCryptoJobAsync : kCryptoJobSync,
299275
kSignJobModeVerify,
300276
keyData,
277+
keyFormat,
278+
keyType,
279+
keyPassphrase,
301280
data,
302281
algorithm,
303282
pssSaltLength,
304283
rsaPadding,
305-
signature,
306-
dsaSigEnc);
284+
dsaSigEnc,
285+
signature);
286+
287+
if (!callback) {
288+
const { 0: err, 1: result } = job.run();
289+
if (err !== undefined)
290+
throw err;
291+
292+
return result;
293+
}
307294

308295
job.ondone = (error, result) => {
309296
if (error) return FunctionPrototypeCall(callback, job, error);

0 commit comments

Comments
 (0)