Skip to content

Commit 7bcee80

Browse files
committed
src,lib: switch usages internal slot to a bitmask
Signed-off-by: Filip Skokan <[email protected]>
1 parent 1a8a0f0 commit 7bcee80

14 files changed

Lines changed: 185 additions & 146 deletions

File tree

lib/internal/crypto/aes.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const {
2727
} = internalBinding('crypto');
2828

2929
const {
30-
getSortedUsages,
30+
getUsagesMask,
3131
hasAnyNotIn,
3232
jobPromise,
3333
kHandle,
@@ -193,7 +193,7 @@ async function aesGenerateKey(algorithm, extractable, keyUsages) {
193193
return new InternalCryptoKey(
194194
handle,
195195
{ name, length },
196-
getSortedUsages(usagesSet),
196+
getUsagesMask(usagesSet),
197197
extractable);
198198
}
199199

@@ -254,7 +254,7 @@ function aesImportKey(
254254
return new InternalCryptoKey(
255255
handle,
256256
{ name, length },
257-
getSortedUsages(usagesSet),
257+
getUsagesMask(usagesSet),
258258
extractable);
259259
}
260260

lib/internal/crypto/cfrg.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const {
2424
} = internalBinding('crypto');
2525

2626
const {
27-
getSortedUsages,
27+
getUsagesMask,
2828
getUsagesUnion,
2929
hasAnyNotIn,
3030
jobPromise,
@@ -137,14 +137,14 @@ async function cfrgGenerateKey(algorithm, extractable, keyUsages) {
137137
new InternalCryptoKey(
138138
handles[0],
139139
keyAlgorithm,
140-
getSortedUsages(publicUsages),
140+
getUsagesMask(publicUsages),
141141
true);
142142

143143
const privateKey =
144144
new InternalCryptoKey(
145145
handles[1],
146146
keyAlgorithm,
147-
getSortedUsages(privateUsages),
147+
getUsagesMask(privateUsages),
148148
extractable);
149149

150150
return { __proto__: null, privateKey, publicKey };
@@ -237,7 +237,7 @@ function cfrgImportKey(
237237
return new InternalCryptoKey(
238238
handle,
239239
{ name },
240-
getSortedUsages(usagesSet),
240+
getUsagesMask(usagesSet),
241241
extractable);
242242
}
243243

lib/internal/crypto/chacha20_poly1305.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const {
1111
} = internalBinding('crypto');
1212

1313
const {
14-
getSortedUsages,
14+
getUsagesMask,
1515
hasAnyNotIn,
1616
jobPromise,
1717
kHandle,
@@ -64,7 +64,7 @@ async function c20pGenerateKey(algorithm, extractable, keyUsages) {
6464
return new InternalCryptoKey(
6565
handle,
6666
{ name },
67-
getSortedUsages(usagesSet),
67+
getUsagesMask(usagesSet),
6868
extractable);
6969
}
7070

@@ -116,7 +116,7 @@ function c20pImportKey(
116116
return new InternalCryptoKey(
117117
handle,
118118
{ name },
119-
getSortedUsages(usagesSet),
119+
getUsagesMask(usagesSet),
120120
extractable);
121121
}
122122

lib/internal/crypto/ec.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const {
2929
} = internalBinding('constants');
3030

3131
const {
32-
getSortedUsages,
32+
getUsagesMask,
3333
getUsagesUnion,
3434
hasAnyNotIn,
3535
jobPromise,
@@ -119,14 +119,14 @@ async function ecGenerateKey(algorithm, extractable, keyUsages) {
119119
new InternalCryptoKey(
120120
handles[0],
121121
keyAlgorithm,
122-
getSortedUsages(publicUsages),
122+
getUsagesMask(publicUsages),
123123
true);
124124

125125
const privateKey =
126126
new InternalCryptoKey(
127127
handles[1],
128128
keyAlgorithm,
129-
getSortedUsages(privateUsages),
129+
getUsagesMask(privateUsages),
130130
extractable);
131131

132132
return { __proto__: null, publicKey, privateKey };
@@ -258,7 +258,7 @@ function ecImportKey(
258258
return new InternalCryptoKey(
259259
handle,
260260
{ name, namedCurve },
261-
getSortedUsages(usagesSet),
261+
getUsagesMask(usagesSet),
262262
extractable);
263263
}
264264

lib/internal/crypto/keys.js

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
'use strict';
22

33
const {
4-
ArrayFrom,
54
ArrayPrototypeSlice,
65
ObjectDefineProperties,
76
ObjectDefineProperty,
@@ -63,7 +62,9 @@ const {
6362
bigIntArrayToUnsignedBigInt,
6463
normalizeAlgorithm,
6564
hasAnyNotIn,
66-
getSortedUsages,
65+
getUsagesMask,
66+
getUsagesFromMask,
67+
hasUsage,
6768
} = require('internal/crypto/util');
6869

6970
const {
@@ -255,7 +256,7 @@ const {
255256
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
256257
}
257258

258-
if (getCryptoKeyUsages(result).length === 0) {
259+
if (getCryptoKeyUsagesMask(result) === 0) {
259260
throw lazyDOMException(
260261
`Usages cannot be empty when importing a ${getCryptoKeyType(result)} key.`,
261262
'SyntaxError');
@@ -351,7 +352,7 @@ const {
351352
}
352353

353354
const resultType = getCryptoKeyType(result);
354-
if (resultType === 'private' && getCryptoKeyUsages(result).length === 0) {
355+
if (resultType === 'private' && getCryptoKeyUsagesMask(result) === 0) {
355356
throw lazyDOMException(
356357
`Usages cannot be empty when importing a ${resultType} key.`,
357358
'SyntaxError');
@@ -770,9 +771,9 @@ function isKeyObject(obj) {
770771
}
771772

772773
// CryptoKey is a plain JS class whose prototype's [[Prototype]] is
773-
// Object.prototype, as Web Crypto requires. Instance storage (type,
774-
// extractable, algorithm, usages, and the KeyObject handle) lives on
775-
// a C++ class, NativeCryptoKey, created by createCryptoKeyClass.
774+
// Object.prototype, as Web Crypto requires. Instance storage (type enum,
775+
// extractable, algorithm, usages mask, and the KeyObject handle) lives
776+
// on a C++ class, NativeCryptoKey, created by createCryptoKeyClass.
776777
// InternalCryptoKey is the only constructor we expose to internal
777778
// code; it extends NativeCryptoKey to get that storage and then has
778779
// its prototype spliced so the chain visible to user code is:
@@ -786,18 +787,21 @@ function isKeyObject(obj) {
786787
// reflection (`Object.getOwnPropertySymbols` etc.) and leaves each
787788
// CryptoKey's hidden class pristine. The `getCryptoKey{Type,
788789
// Extractable,Algorithm,Usages,Handle}` helpers index into that
789-
// array; the public `algorithm` / `usages` getters further cache a
790-
// cloned copy (as Web Crypto requires repeat reads to return the
791-
// same object so a consumer's mutation is visible next time).
790+
// array and convert native enums/masks back to Web Crypto strings.
791+
// The public `algorithm` getter caches a cloned dictionary and the
792+
// public `usages` getter caches a synthesized array (as Web Crypto
793+
// requires repeat reads to return the same object so a consumer's
794+
// mutation is visible next time).
792795
let getSlots; // Populated by the createCryptoKeyClass callback below.
793796

794797
const kSlotType = 0;
795798
const kSlotExtractable = 1;
796799
const kSlotAlgorithm = 2;
797-
const kSlotUsages = 3;
800+
const kSlotUsagesMask = 3;
798801
const kSlotHandle = 4;
799802
const kSlotClonedAlgorithm = 5;
800803
const kSlotClonedUsages = 6;
804+
const kSlotUsages = 7;
801805

802806
function cloneAlgorithm(raw) {
803807
const cloned = { ...raw };
@@ -855,7 +859,7 @@ const {
855859
const slots = getSlots(this);
856860
let cached = slots[kSlotClonedUsages];
857861
if (cached === undefined) {
858-
cached = ArrayFrom(slots[kSlotUsages]);
862+
cached = ArrayPrototypeSlice(getCryptoKeyUsagesFromSlots(slots), 0);
859863
slots[kSlotClonedUsages] = cached;
860864
}
861865
return cached;
@@ -900,8 +904,9 @@ const {
900904
// The helpers below return a CryptoKey's internal slot value,
901905
// populating the per-instance cache on first access via a single
902906
// native call. The public `type` getter converts the native enum to
903-
// the Web Crypto string. The public `algorithm` / `usages` getters on
904-
// `CryptoKey.prototype` further clone their slot before returning.
907+
// the Web Crypto string. The `usages` helper converts the native usage
908+
// mask to Web Crypto strings. The public `algorithm` / `usages` getters
909+
// on `CryptoKey.prototype` cache their returned objects.
905910

906911
/**
907912
* Returns the value of a CryptoKey's `[[type]]` internal slot.
@@ -914,7 +919,6 @@ function getCryptoKeyType(key) {
914919
case kKeyTypePublic: return 'public';
915920
case kKeyTypePrivate: return 'private';
916921
default: {
917-
// It is not possible to get here because all possible cases are handled above.
918922
const assert = require('internal/assert');
919923
assert.fail('Unreachable code');
920924
}
@@ -940,14 +944,31 @@ function getCryptoKeyAlgorithm(key) {
940944
return getSlots(key)[kSlotAlgorithm];
941945
}
942946

947+
function getCryptoKeyUsagesMask(key) {
948+
return getSlots(key)[kSlotUsagesMask];
949+
}
950+
951+
function hasCryptoKeyUsage(key, usage) {
952+
return hasUsage(getCryptoKeyUsagesMask(key), usage);
953+
}
954+
955+
function getCryptoKeyUsagesFromSlots(slots) {
956+
let usages = slots[kSlotUsages];
957+
if (usages === undefined) {
958+
usages = getUsagesFromMask(slots[kSlotUsagesMask]);
959+
slots[kSlotUsages] = usages;
960+
}
961+
return usages;
962+
}
963+
943964
/**
944965
* Returns the CryptoKey's `[[usages]]` internal slot, bypassing the
945966
* public `usages` getter (which returns a cloned array).
946967
* @param {CryptoKey} key
947968
* @returns {string[]}
948969
*/
949970
function getCryptoKeyUsages(key) {
950-
return getSlots(key)[kSlotUsages];
971+
return getCryptoKeyUsagesFromSlots(getSlots(key));
951972
}
952973

953974
/**
@@ -1009,7 +1030,7 @@ function importGenericSecretKey(
10091030
return new InternalCryptoKey(
10101031
handle,
10111032
{ name },
1012-
getSortedUsages(usagesSet),
1033+
getUsagesMask(usagesSet),
10131034
false);
10141035
}
10151036

@@ -1038,6 +1059,8 @@ module.exports = {
10381059
getCryptoKeyExtractable,
10391060
getCryptoKeyAlgorithm,
10401061
getCryptoKeyUsages,
1062+
getCryptoKeyUsagesMask,
1063+
hasCryptoKeyUsage,
10411064
getCryptoKeyHandle,
10421065
importGenericSecretKey,
10431066
};

lib/internal/crypto/mac.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const {
1616

1717
const {
1818
getBlockSize,
19-
getSortedUsages,
19+
getUsagesMask,
2020
hasAnyNotIn,
2121
jobPromise,
2222
normalizeHashName,
@@ -58,7 +58,7 @@ async function hmacGenerateKey(algorithm, extractable, keyUsages) {
5858
return new InternalCryptoKey(
5959
handle,
6060
{ name, length, hash },
61-
getSortedUsages(usageSet),
61+
getUsagesMask(usageSet),
6262
extractable);
6363
}
6464

@@ -84,7 +84,7 @@ async function kmacGenerateKey(algorithm, extractable, keyUsages) {
8484
return new InternalCryptoKey(
8585
handle,
8686
{ name, length },
87-
getSortedUsages(usageSet),
87+
getUsagesMask(usageSet),
8888
extractable);
8989
}
9090

@@ -160,7 +160,7 @@ function macImportKey(
160160
return new InternalCryptoKey(
161161
handle,
162162
algorithmObject,
163-
getSortedUsages(usagesSet),
163+
getUsagesMask(usagesSet),
164164
extractable);
165165
}
166166

lib/internal/crypto/ml_dsa.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const {
2525
} = internalBinding('crypto');
2626

2727
const {
28-
getSortedUsages,
28+
getUsagesMask,
2929
getUsagesUnion,
3030
hasAnyNotIn,
3131
jobPromise,
@@ -82,23 +82,23 @@ async function mlDsaGenerateKey(algorithm, extractable, keyUsages) {
8282
}
8383

8484
const handles = await jobPromise(() => new NidKeyPairGenJob(kCryptoJobAsync, nid));
85-
const publicUsages = getSortedUsages(getUsagesUnion(usageSet, 'verify'));
86-
const privateUsages = getSortedUsages(getUsagesUnion(usageSet, 'sign'));
85+
const publicUsagesMask = getUsagesMask(getUsagesUnion(usageSet, 'verify'));
86+
const privateUsagesMask = getUsagesMask(getUsagesUnion(usageSet, 'sign'));
8787

8888
const keyAlgorithm = { name };
8989

9090
const publicKey =
9191
new InternalCryptoKey(
9292
handles[0],
9393
keyAlgorithm,
94-
publicUsages,
94+
publicUsagesMask,
9595
true);
9696

9797
const privateKey =
9898
new InternalCryptoKey(
9999
handles[1],
100100
keyAlgorithm,
101-
privateUsages,
101+
privateUsagesMask,
102102
extractable);
103103

104104
return { __proto__: null, privateKey, publicKey };
@@ -208,7 +208,7 @@ function mlDsaImportKey(
208208
return new InternalCryptoKey(
209209
handle,
210210
{ name },
211-
getSortedUsages(usagesSet),
211+
getUsagesMask(usagesSet),
212212
extractable);
213213
}
214214

0 commit comments

Comments
 (0)