Skip to content

Commit 971adec

Browse files
panvaaduh95
authored andcommitted
crypto: use names for asymmetric key algorithms
Provider-backed keys can have no numeric OpenSSL ID. Identify and construct asymmetric keys by algorithm name, replacing the custom PQC name-to-NID substitution with provider-aware matching in ncrypto. Centralize known algorithm names, public key-type names, capabilities, and backend compatibility in ncrypto. Use named key generation jobs and remove asymmetric EVP_PKEY constants from the internal JavaScript binding. Signed-off-by: Filip Skokan <panva.ip@gmail.com> Assisted-by: Codex PR-URL: #65966 Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 8914947 commit 971adec

33 files changed

Lines changed: 1906 additions & 1621 deletions

benchmark/crypto/kem.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ if (Object.keys(keyFixtures).length === 0) {
4545
}
4646

4747
const bench = common.createBenchmark(main, {
48-
keyType: Object.keys(keyFixtures),
48+
// Keep one size per family by default; other fixtures remain available via keyType.
49+
keyType: ['rsa', 'p-256', 'x25519', 'ml-kem-768'].filter((type) => keyFixtures[type]),
4950
mode: ['sync', 'async', 'async-parallel'],
5051
keyFormat: ['keyObject', 'keyObject.unique', 'pem', 'der', 'jwk',
5152
'raw-public', 'raw-private', 'raw-seed'],
@@ -57,6 +58,9 @@ const bench = common.createBenchmark(main, {
5758
// assess whether mutexes over the key material impact the operation
5859
if (p.keyFormat === 'keyObject.unique')
5960
return p.mode === 'async-parallel';
61+
// Compare execution modes with pre-imported keys; measure parsing synchronously.
62+
if (p.mode !== 'sync' && p.keyFormat !== 'keyObject')
63+
return false;
6064
// raw-public is only supported for encapsulate, not rsa
6165
if (p.keyFormat === 'raw-public')
6266
return p.keyType !== 'rsa' && p.op === 'encapsulate';
@@ -127,7 +131,8 @@ function main({ n, mode, keyFormat, keyType, op }) {
127131
keyFixtures[keyType].publicKey :
128132
keyFixtures[keyType].privateKey;
129133
const createKeyFn = isEncapsulate ? crypto.createPublicKey : crypto.createPrivateKey;
130-
const pems = [...Buffer.alloc(n)].map(() => pemSource);
134+
const count = keyFormat === 'keyObject.unique' ? n : 1;
135+
const pems = Array(count).fill(pemSource);
131136
const keyObjects = pems.map(createKeyFn);
132137

133138
// Warm up OpenSSL's provider operation cache for each key object
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const { hasOpenSSL, hasFIPS, isBoringSSL } = require('../../test/common/crypto.js');
5+
const fixtures = require('../../test/common/fixtures.js');
6+
const { createPrivateKey, createPublicKey } = require('crypto');
7+
8+
const keys = {
9+
'rsa': 'rsa_private_2048',
10+
'rsa-pss': 'rsa_pss_private_2048',
11+
'p-256': 'ec_p256_private',
12+
'p-384': 'ec_p384_private',
13+
'p-521': 'ec_p521_private',
14+
'ed25519': 'ed25519_private',
15+
'x25519': 'x25519_private',
16+
};
17+
if (!isBoringSSL) {
18+
keys.ed448 = 'ed448_private';
19+
keys.x448 = 'x448_private';
20+
if (!hasFIPS()) keys['rsa-multiprime'] = 'rsa_private_2048_3_primes';
21+
}
22+
if (hasOpenSSL(3, 5) || isBoringSSL) {
23+
keys['ml-dsa-44'] = 'ml_dsa_44_private_seed_only';
24+
keys['ml-dsa-87'] = 'ml_dsa_87_private_seed_only';
25+
keys['ml-kem-768'] = 'ml_kem_768_private_seed_only';
26+
keys['ml-kem-1024'] = 'ml_kem_1024_private_seed_only';
27+
}
28+
if (hasOpenSSL(3, 5)) {
29+
keys['slh-dsa-sha2-128s'] = 'slh_dsa_sha2_128s_private';
30+
keys['slh-dsa-shake-256s'] = 'slh_dsa_shake_256s_private';
31+
}
32+
33+
const bench = common.createBenchmark(main, {
34+
// Keep one size per family by default; other fixtures remain available via keyType.
35+
keyType: ['rsa', 'rsa-pss', 'p-256', 'ed25519', 'x25519',
36+
'ml-dsa-44', 'ml-kem-768', 'slh-dsa-sha2-128s'].filter((type) => keys[type]),
37+
operation: ['import', 'export'],
38+
// PEM can be selected with format=pem; DER covers ASN.1 encoding by default.
39+
format: ['jwk', 'der', 'raw-public', 'raw-private', 'raw-seed'],
40+
type: ['public', 'private'],
41+
n: [1e4],
42+
}, {
43+
combinationFilter({ keyType, format, type }) {
44+
if (format === 'jwk') return keyType !== 'rsa-pss';
45+
if (!format.startsWith('raw-')) return true;
46+
if (keyType.startsWith('rsa')) return false;
47+
if (format === 'raw-public') return type === 'public';
48+
if (format === 'raw-private') return type === 'private' && !keyType.startsWith('ml-');
49+
return type === 'private' && keyType.startsWith('ml-');
50+
},
51+
});
52+
53+
function main({ keyType, operation, format, type, n }) {
54+
const privateKey = createPrivateKey(fixtures.readKey(`${keys[keyType]}.pem`));
55+
const key = type === 'private' ? privateKey : createPublicKey(privateKey);
56+
const options = { format };
57+
if (format === 'pem' || format === 'der') {
58+
options.type = type === 'private' ? 'pkcs8' : 'spki';
59+
}
60+
let run;
61+
if (operation === 'export') {
62+
run = () => key.export(options);
63+
} else {
64+
const input = { ...options, key: key.export(options) };
65+
if (format.startsWith('raw-')) {
66+
input.asymmetricKeyType = key.asymmetricKeyType;
67+
if (input.asymmetricKeyType === 'ec') {
68+
input.namedCurve = key.asymmetricKeyDetails.namedCurve;
69+
}
70+
}
71+
const importKey = type === 'private' ? createPrivateKey : createPublicKey;
72+
run = () => importKey(input);
73+
}
74+
// Resolve provider operations and warm the JS path before timing.
75+
for (let i = 0; i < 100; i++) run();
76+
bench.start();
77+
for (let i = 0; i < n; i++) run();
78+
bench.end(n);
79+
}

benchmark/crypto/oneshot-sign.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ if (hasOpenSSL(3, 5)) {
2525

2626
const data = crypto.randomBytes(256);
2727

28-
let pems;
29-
let keyObjects;
30-
3128
const bench = common.createBenchmark(main, {
3229
keyType: Object.keys(keyFixtures),
3330
mode: ['sync', 'async', 'async-parallel'],
@@ -39,6 +36,9 @@ const bench = common.createBenchmark(main, {
3936
// assess whether mutexes over the key material impact the operation
4037
if (p.keyFormat === 'keyObject.unique')
4138
return p.mode === 'async-parallel';
39+
// Compare execution modes with pre-imported keys; measure parsing synchronously.
40+
if (p.mode !== 'sync' && p.keyFormat !== 'keyObject')
41+
return false;
4242
// raw-private is not supported for rsa and ml-dsa
4343
if (p.keyFormat === 'raw-private')
4444
return p.keyType !== 'rsa' && !p.keyType.startsWith('ml-');
@@ -97,8 +97,9 @@ function measureAsyncParallel(n, digest, privateKey, keys) {
9797
}
9898

9999
function main({ n, mode, keyFormat, keyType }) {
100-
pems ||= [...Buffer.alloc(n)].map(() => keyFixtures[keyType]);
101-
keyObjects ||= pems.map(crypto.createPrivateKey);
100+
const count = keyFormat === 'keyObject.unique' ? n : 1;
101+
const pems = Array(count).fill(keyFixtures[keyType]);
102+
const keyObjects = pems.map(crypto.createPrivateKey);
102103

103104
// Warm up OpenSSL's provider operation cache for each key object
104105
for (const keyObject of keyObjects) {

benchmark/crypto/oneshot-verify.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@ if (hasOpenSSL(3, 5)) {
3232

3333
const data = crypto.randomBytes(256);
3434

35-
let pems;
36-
let keyObjects;
37-
3835
const bench = common.createBenchmark(main, {
3936
keyType: Object.keys(keyFixtures),
4037
mode: ['sync', 'async', 'async-parallel'],
@@ -46,6 +43,9 @@ const bench = common.createBenchmark(main, {
4643
// assess whether mutexes over the key material impact the operation
4744
if (p.keyFormat === 'keyObject.unique')
4845
return p.mode === 'async-parallel';
46+
// Compare execution modes with pre-imported keys; measure parsing synchronously.
47+
if (p.mode !== 'sync' && p.keyFormat !== 'keyObject')
48+
return false;
4949
// raw-public is not supported by rsa
5050
if (p.keyFormat === 'raw-public')
5151
return p.keyType !== 'rsa';
@@ -104,8 +104,9 @@ function measureAsyncParallel(n, digest, signature, publicKey, keys) {
104104
}
105105

106106
function main({ n, mode, keyFormat, keyType }) {
107-
pems ||= [...Buffer.alloc(n)].map(() => keyFixtures[keyType].publicKey);
108-
keyObjects ||= pems.map(crypto.createPublicKey);
107+
const count = keyFormat === 'keyObject.unique' ? n : 1;
108+
const pems = Array(count).fill(keyFixtures[keyType].publicKey);
109+
const keyObjects = pems.map(crypto.createPublicKey);
109110

110111
// Warm up OpenSSL's provider operation cache for each key object
111112
const warmupDigest = keyType === 'rsa' || keyType === 'ec' ? 'sha256' : null;

0 commit comments

Comments
 (0)