Skip to content

Commit 96c63ed

Browse files
committed
crypto: reconsile oneshot sign/verify sync and async implementations
1 parent 43f599b commit 96c63ed

File tree

8 files changed

+235
-258
lines changed

8 files changed

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

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)