Skip to content

Commit 24d37bd

Browse files
committed
lib,crypto: migrate algorithm modules to native CryptoKey
Every Web Crypto algorithm module drops `key[kKeyObject][kHandle]` symbol access in favor of `getCryptoKey*` accessors and stores the raw `KeyObjectHandle` directly (no more `SecretKeyObject`/`PublicKeyObject`/ `PrivateKeyObject` wrappers on the CryptoKey slot). Key generation moves off the promisified `generateKey`/`generateKeyPair` paths onto ones that return `KeyObjectHandle` (i.e. not wrapped in KeyObject): - `SecretKeyGenJob` for AES, ChaCha20-Poly1305, HMAC/CMAC (aes.js, chacha20_poly1305.js, mac.js). - `EcKeyPairGenJob` for ECDSA, ECDH (ec.js). - `NidKeyPairGenJob` for Ed25519/Ed448/X25519/X448, ML-DSA-{44,65,87}, ML-KEM-{512,768,1024} (cfrg.js, ml_dsa.js, ml_kem.js). - `RsaKeyPairGenJob` for RSASSA-PKCS1-v1_5, RSA-PSS, RSA-OAEP (rsa.js). `webcrypto_util.js` switches its import helpers (`importDerKey`, `importJwkKey`, `importRawKey`) to return raw `KeyObjectHandle`s and adds `importSecretKey` / `importJwkSecretKey` helpers for symmetric imports. `webcrypto.js` follows the same pattern; its `getPublicKey` builds a temporary wrapper and carries a TODO for future refactor. `hkdf.js` switches from `promisify(hkdf)` to `jobPromise(() => new HKDFJob(...))` directly. `diffiehellman.js`, `argon2.js`, and `pbkdf2.js` are accessor-only migrations (the `TODO(panva)` notes on argon2/pbkdf2 are orthogonal and left for a later cleanup). Signed-off-by: Filip Skokan <[email protected]>
1 parent 1007575 commit 24d37bd

15 files changed

Lines changed: 400 additions & 465 deletions

File tree

lib/internal/crypto/aes.js

Lines changed: 30 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ const {
77

88
const {
99
AESCipherJob,
10-
KeyObjectHandle,
1110
kCryptoJobAsync,
12-
kKeyFormatJWK,
13-
kKeyTypeSecret,
1411
kKeyVariantAES_CTR_128,
1512
kKeyVariantAES_CBC_128,
1613
kKeyVariantAES_GCM_128,
@@ -26,37 +23,32 @@ const {
2623
kKeyVariantAES_GCM_256,
2724
kKeyVariantAES_KW_256,
2825
kKeyVariantAES_OCB_256,
26+
SecretKeyGenJob,
2927
} = internalBinding('crypto');
3028

3129
const {
30+
getSortedUsages,
3231
hasAnyNotIn,
3332
jobPromise,
3433
kHandle,
35-
kKeyObject,
3634
} = require('internal/crypto/util');
3735

3836
const {
3937
lazyDOMException,
40-
promisify,
4138
} = require('internal/util');
4239

4340
const {
4441
InternalCryptoKey,
45-
SecretKeyObject,
46-
createSecretKey,
47-
kAlgorithm,
42+
getCryptoKeyAlgorithm,
43+
getCryptoKeyHandle,
4844
} = require('internal/crypto/keys');
4945

5046
const {
47+
importJwkSecretKey,
48+
importSecretKey,
5149
validateJwk,
5250
} = require('internal/crypto/webcrypto_util');
5351

54-
const {
55-
generateKey: _generateKey,
56-
} = require('internal/crypto/keygen');
57-
58-
const generateKey = promisify(_generateKey);
59-
6052
function getAlgorithmName(name, length) {
6153
switch (name) {
6254
case 'AES-CBC': return `A${length}CBC`;
@@ -116,9 +108,9 @@ function asyncAesCtrCipher(mode, key, data, algorithm) {
116108
return jobPromise(() => new AESCipherJob(
117109
kCryptoJobAsync,
118110
mode,
119-
key[kKeyObject][kHandle],
111+
getCryptoKeyHandle(key),
120112
data,
121-
getVariant('AES-CTR', key[kAlgorithm].length),
113+
getVariant('AES-CTR', getCryptoKeyAlgorithm(key).length),
122114
algorithm.counter,
123115
algorithm.length));
124116
}
@@ -127,19 +119,19 @@ function asyncAesCbcCipher(mode, key, data, algorithm) {
127119
return jobPromise(() => new AESCipherJob(
128120
kCryptoJobAsync,
129121
mode,
130-
key[kKeyObject][kHandle],
122+
getCryptoKeyHandle(key),
131123
data,
132-
getVariant('AES-CBC', key[kAlgorithm].length),
124+
getVariant('AES-CBC', getCryptoKeyAlgorithm(key).length),
133125
algorithm.iv));
134126
}
135127

136128
function asyncAesKwCipher(mode, key, data) {
137129
return jobPromise(() => new AESCipherJob(
138130
kCryptoJobAsync,
139131
mode,
140-
key[kKeyObject][kHandle],
132+
getCryptoKeyHandle(key),
141133
data,
142-
getVariant('AES-KW', key[kAlgorithm].length)));
134+
getVariant('AES-KW', getCryptoKeyAlgorithm(key).length)));
143135
}
144136

145137
function asyncAesGcmCipher(mode, key, data, algorithm) {
@@ -149,9 +141,9 @@ function asyncAesGcmCipher(mode, key, data, algorithm) {
149141
return jobPromise(() => new AESCipherJob(
150142
kCryptoJobAsync,
151143
mode,
152-
key[kKeyObject][kHandle],
144+
getCryptoKeyHandle(key),
153145
data,
154-
getVariant('AES-GCM', key[kAlgorithm].length),
146+
getVariant('AES-GCM', getCryptoKeyAlgorithm(key).length),
155147
algorithm.iv,
156148
tagByteLength,
157149
algorithm.additionalData));
@@ -164,9 +156,9 @@ function asyncAesOcbCipher(mode, key, data, algorithm) {
164156
return jobPromise(() => new AESCipherJob(
165157
kCryptoJobAsync,
166158
mode,
167-
key[kKeyObject][kHandle],
159+
getCryptoKeyHandle(key),
168160
data,
169-
getVariant('AES-OCB', key.algorithm.length),
161+
getVariant('AES-OCB', getCryptoKeyAlgorithm(key).length),
170162
algorithm.iv,
171163
tagByteLength,
172164
algorithm.additionalData));
@@ -196,20 +188,12 @@ async function aesGenerateKey(algorithm, extractable, keyUsages) {
196188
'SyntaxError');
197189
}
198190

199-
let key;
200-
try {
201-
key = await generateKey('aes', { length });
202-
} catch (err) {
203-
throw lazyDOMException(
204-
'The operation failed for an operation-specific reason' +
205-
`[${err.message}]`,
206-
{ name: 'OperationError', cause: err });
207-
}
191+
const handle = await jobPromise(() => new SecretKeyGenJob(kCryptoJobAsync, length));
208192

209193
return new InternalCryptoKey(
210-
key,
194+
handle,
211195
{ name, length },
212-
usagesSet,
196+
getSortedUsages(usagesSet),
213197
extractable);
214198
}
215199

@@ -231,60 +215,46 @@ function aesImportKey(
231215
'SyntaxError');
232216
}
233217

234-
let keyObject;
218+
let handle;
235219
let length;
236220
switch (format) {
237221
case 'KeyObject': {
238-
validateKeyLength(keyData.symmetricKeySize * 8);
239-
keyObject = keyData;
222+
length = keyData.symmetricKeySize * 8;
223+
validateKeyLength(length);
224+
handle = keyData[kHandle];
240225
break;
241226
}
242227
case 'raw-secret':
243228
case 'raw': {
244229
if (format === 'raw' && name === 'AES-OCB') {
245230
return undefined;
246231
}
247-
validateKeyLength(keyData.byteLength * 8);
248-
keyObject = createSecretKey(keyData);
232+
length = keyData.byteLength * 8;
233+
validateKeyLength(length);
234+
handle = importSecretKey(keyData);
249235
break;
250236
}
251237
case 'jwk': {
252238
validateJwk(keyData, 'oct', extractable, usagesSet, 'enc');
253-
254-
const handle = new KeyObjectHandle();
255-
try {
256-
handle.init(kKeyTypeSecret, keyData, kKeyFormatJWK, null, null);
257-
} catch (err) {
258-
throw lazyDOMException(
259-
'Invalid keyData', { name: 'DataError', cause: err });
260-
}
261-
262-
({ length } = handle.keyDetail({ }));
239+
handle = importJwkSecretKey(keyData);
240+
length = handle.getSymmetricKeySize() * 8;
263241
validateKeyLength(length);
264-
265242
if (keyData.alg !== undefined) {
266243
if (keyData.alg !== getAlgorithmName(algorithm.name, length))
267244
throw lazyDOMException(
268245
'JWK "alg" does not match the requested algorithm',
269246
'DataError');
270247
}
271-
272-
keyObject = new SecretKeyObject(handle);
273248
break;
274249
}
275250
default:
276251
return undefined;
277252
}
278253

279-
if (length === undefined) {
280-
({ length } = keyObject[kHandle].keyDetail({ }));
281-
validateKeyLength(length);
282-
}
283-
284254
return new InternalCryptoKey(
285-
keyObject,
255+
handle,
286256
{ name, length },
287-
usagesSet,
257+
getSortedUsages(usagesSet),
288258
extractable);
289259
}
290260

lib/internal/crypto/argon2.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@ const {
2424
promisify,
2525
} = require('internal/util');
2626

27+
const {
28+
getCryptoKeyHandle,
29+
} = require('internal/crypto/keys');
30+
2731
const {
2832
getArrayBufferOrView,
29-
kKeyObject,
3033
} = require('internal/crypto/util');
3134

3235
const {
@@ -216,7 +219,8 @@ async function argon2DeriveBits(algorithm, baseKey, length) {
216219
result = await argon2Promise(
217220
StringPrototypeToLowerCase(algorithm.name),
218221
{
219-
message: baseKey[kKeyObject].export(),
222+
// TODO(panva): call the job directly without needing to re-export the handle
223+
message: getCryptoKeyHandle(baseKey).export(),
220224
nonce: algorithm.nonce,
221225
parallelism: algorithm.parallelism,
222226
tagLength: length / 8,

0 commit comments

Comments
 (0)