Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f0b4412

Browse filesBrowse files
panvaaduh95
authored andcommitted
crypto: add KeyObject.prototype.toCryptoKey
PR-URL: #55262 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
1 parent c126543 commit f0b4412
Copy full SHA for f0b4412

File tree

Expand file treeCollapse file tree

10 files changed

+415
-59
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

10 files changed

+415
-59
lines changed
Open diff view settings
Collapse file

‎doc/api/crypto.md‎

Copy file name to clipboardExpand all lines: doc/api/crypto.md
+19Lines changed: 19 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -2134,6 +2134,24 @@ added: v11.6.0
21342134
For secret keys, this property represents the size of the key in bytes. This
21352135
property is `undefined` for asymmetric keys.
21362136

2137+
### `keyObject.toCryptoKey(algorithm, extractable, keyUsages)`
2138+
2139+
<!-- YAML
2140+
added: REPLACEME
2141+
-->
2142+
2143+
<!--lint disable maximum-line-length remark-lint-->
2144+
2145+
* `algorithm`: {AlgorithmIdentifier|RsaHashedImportParams|EcKeyImportParams|HmacImportParams}
2146+
2147+
<!--lint enable maximum-line-length remark-lint-->
2148+
2149+
* `extractable`: {boolean}
2150+
* `keyUsages`: {string\[]} See [Key usages][].
2151+
* Returns: {CryptoKey}
2152+
2153+
Converts a `KeyObject` instance to a `CryptoKey`.
2154+
21372155
### `keyObject.type`
21382156

21392157
<!-- YAML
@@ -6084,6 +6102,7 @@ See the [list of SSL OP Flags][] for details.
60846102
[FIPS provider from OpenSSL 3]: https://www.openssl.org/docs/man3.0/man7/crypto.html#FIPS-provider
60856103
[HTML 5.2]: https://www.w3.org/TR/html52/changes.html#features-removed
60866104
[JWK]: https://tools.ietf.org/html/rfc7517
6105+
[Key usages]: webcrypto.md#cryptokeyusages
60876106
[NIST SP 800-131A]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar2.pdf
60886107
[NIST SP 800-132]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf
60896108
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
Collapse file

‎lib/internal/crypto/aes.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/aes.js
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ async function aesGenerateKey(algorithm, extractable, keyUsages) {
245245
extractable);
246246
}
247247

248-
async function aesImportKey(
248+
function aesImportKey(
249249
algorithm,
250250
format,
251251
keyData,
@@ -266,6 +266,11 @@ async function aesImportKey(
266266
let keyObject;
267267
let length;
268268
switch (format) {
269+
case 'KeyObject': {
270+
validateKeyLength(keyData.symmetricKeySize * 8);
271+
keyObject = keyData;
272+
break;
273+
}
269274
case 'raw': {
270275
validateKeyLength(keyData.byteLength * 8);
271276
keyObject = createSecretKey(keyData);
Collapse file

‎lib/internal/crypto/cfrg.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/cfrg.js
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ function cfrgExportKey(key, format) {
197197
key[kKeyObject][kHandle]));
198198
}
199199

200-
async function cfrgImportKey(
200+
function cfrgImportKey(
201201
format,
202202
keyData,
203203
algorithm,
@@ -208,6 +208,11 @@ async function cfrgImportKey(
208208
let keyObject;
209209
const usagesSet = new SafeSet(keyUsages);
210210
switch (format) {
211+
case 'KeyObject': {
212+
verifyAcceptableCfrgKeyUse(name, keyData.type === 'public', usagesSet);
213+
keyObject = keyData;
214+
break;
215+
}
211216
case 'spki': {
212217
verifyAcceptableCfrgKeyUse(name, true, usagesSet);
213218
try {
Collapse file

‎lib/internal/crypto/ec.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/ec.js
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ function ecExportKey(key, format) {
149149
key[kKeyObject][kHandle]));
150150
}
151151

152-
async function ecImportKey(
152+
function ecImportKey(
153153
format,
154154
keyData,
155155
algorithm,
@@ -167,6 +167,11 @@ async function ecImportKey(
167167
let keyObject;
168168
const usagesSet = new SafeSet(keyUsages);
169169
switch (format) {
170+
case 'KeyObject': {
171+
verifyAcceptableEcKeyUse(name, keyData.type === 'public', usagesSet);
172+
keyObject = keyData;
173+
break;
174+
}
170175
case 'spki': {
171176
verifyAcceptableEcKeyUse(name, true, usagesSet);
172177
try {
Collapse file

‎lib/internal/crypto/keys.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/keys.js
+159Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const {
66
ObjectDefineProperties,
77
ObjectDefineProperty,
88
ObjectSetPrototypeOf,
9+
SafeSet,
910
Symbol,
1011
SymbolToStringTag,
1112
Uint8Array,
@@ -49,6 +50,8 @@ const {
4950
kKeyObject,
5051
getArrayBufferOrView,
5152
bigIntArrayToUnsignedBigInt,
53+
normalizeAlgorithm,
54+
hasAnyNotIn,
5255
} = require('internal/crypto/util');
5356

5457
const {
@@ -65,6 +68,7 @@ const {
6568
const {
6669
customInspectSymbol: kInspect,
6770
kEnumerableProperty,
71+
lazyDOMException,
6872
} = require('internal/util');
6973

7074
const { inspect } = require('internal/util/inspect');
@@ -148,6 +152,8 @@ const {
148152
},
149153
});
150154

155+
let webidl;
156+
151157
class SecretKeyObject extends KeyObject {
152158
constructor(handle) {
153159
super('secret', handle);
@@ -168,6 +174,51 @@ const {
168174
}
169175
return this[kHandle].export();
170176
}
177+
178+
toCryptoKey(algorithm, extractable, keyUsages) {
179+
webidl ??= require('internal/crypto/webidl');
180+
algorithm = normalizeAlgorithm(webidl.converters.AlgorithmIdentifier(algorithm), 'importKey');
181+
extractable = webidl.converters.boolean(extractable);
182+
keyUsages = webidl.converters['sequence<KeyUsage>'](keyUsages);
183+
184+
let result;
185+
switch (algorithm.name) {
186+
case 'HMAC':
187+
result = require('internal/crypto/mac')
188+
.hmacImportKey('KeyObject', this, algorithm, extractable, keyUsages);
189+
break;
190+
case 'AES-CTR':
191+
// Fall through
192+
case 'AES-CBC':
193+
// Fall through
194+
case 'AES-GCM':
195+
// Fall through
196+
case 'AES-KW':
197+
result = require('internal/crypto/aes')
198+
.aesImportKey(algorithm, 'KeyObject', this, extractable, keyUsages);
199+
break;
200+
case 'HKDF':
201+
// Fall through
202+
case 'PBKDF2':
203+
result = importGenericSecretKey(
204+
algorithm,
205+
'KeyObject',
206+
this,
207+
extractable,
208+
keyUsages);
209+
break;
210+
default:
211+
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
212+
}
213+
214+
if (result.usages.length === 0) {
215+
throw lazyDOMException(
216+
`Usages cannot be empty when importing a ${result.type} key.`,
217+
'SyntaxError');
218+
}
219+
220+
return result;
221+
}
171222
}
172223

173224
const kAsymmetricKeyType = Symbol('kAsymmetricKeyType');
@@ -209,6 +260,51 @@ const {
209260
return {};
210261
}
211262
}
263+
264+
toCryptoKey(algorithm, extractable, keyUsages) {
265+
webidl ??= require('internal/crypto/webidl');
266+
algorithm = normalizeAlgorithm(webidl.converters.AlgorithmIdentifier(algorithm), 'importKey');
267+
extractable = webidl.converters.boolean(extractable);
268+
keyUsages = webidl.converters['sequence<KeyUsage>'](keyUsages);
269+
270+
let result;
271+
switch (algorithm.name) {
272+
case 'RSASSA-PKCS1-v1_5':
273+
// Fall through
274+
case 'RSA-PSS':
275+
// Fall through
276+
case 'RSA-OAEP':
277+
result = require('internal/crypto/rsa')
278+
.rsaImportKey('KeyObject', this, algorithm, extractable, keyUsages);
279+
break;
280+
case 'ECDSA':
281+
// Fall through
282+
case 'ECDH':
283+
result = require('internal/crypto/ec')
284+
.ecImportKey('KeyObject', this, algorithm, extractable, keyUsages);
285+
break;
286+
case 'Ed25519':
287+
// Fall through
288+
case 'Ed448':
289+
// Fall through
290+
case 'X25519':
291+
// Fall through
292+
case 'X448':
293+
result = require('internal/crypto/cfrg')
294+
.cfrgImportKey('KeyObject', this, algorithm, extractable, keyUsages);
295+
break;
296+
default:
297+
throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
298+
}
299+
300+
if (result.type === 'private' && result.usages.length === 0) {
301+
throw lazyDOMException(
302+
`Usages cannot be empty when importing a ${result.type} key.`,
303+
'SyntaxError');
304+
}
305+
306+
return result;
307+
}
212308
}
213309

214310
class PublicKeyObject extends AsymmetricKeyObject {
@@ -801,6 +897,68 @@ function isCryptoKey(obj) {
801897
return obj != null && obj[kKeyObject] !== undefined;
802898
}
803899

900+
function importGenericSecretKey(
901+
{ name, length },
902+
format,
903+
keyData,
904+
extractable,
905+
keyUsages) {
906+
const usagesSet = new SafeSet(keyUsages);
907+
if (extractable)
908+
throw lazyDOMException(`${name} keys are not extractable`, 'SyntaxError');
909+
910+
if (hasAnyNotIn(usagesSet, ['deriveKey', 'deriveBits'])) {
911+
throw lazyDOMException(
912+
`Unsupported key usage for a ${name} key`,
913+
'SyntaxError');
914+
}
915+
916+
switch (format) {
917+
case 'KeyObject': {
918+
if (hasAnyNotIn(usagesSet, ['deriveKey', 'deriveBits'])) {
919+
throw lazyDOMException(
920+
`Unsupported key usage for a ${name} key`,
921+
'SyntaxError');
922+
}
923+
924+
const checkLength = keyData.symmetricKeySize * 8;
925+
926+
// The Web Crypto spec allows for key lengths that are not multiples of
927+
// 8. We don't. Our check here is stricter than that defined by the spec
928+
// in that we require that algorithm.length match keyData.length * 8 if
929+
// algorithm.length is specified.
930+
if (length !== undefined && length !== checkLength) {
931+
throw lazyDOMException('Invalid key length', 'DataError');
932+
}
933+
return new InternalCryptoKey(keyData, { name }, keyUsages, false);
934+
}
935+
case 'raw': {
936+
if (hasAnyNotIn(usagesSet, ['deriveKey', 'deriveBits'])) {
937+
throw lazyDOMException(
938+
`Unsupported key usage for a ${name} key`,
939+
'SyntaxError');
940+
}
941+
942+
const checkLength = keyData.byteLength * 8;
943+
944+
// The Web Crypto spec allows for key lengths that are not multiples of
945+
// 8. We don't. Our check here is stricter than that defined by the spec
946+
// in that we require that algorithm.length match keyData.length * 8 if
947+
// algorithm.length is specified.
948+
if (length !== undefined && length !== checkLength) {
949+
throw lazyDOMException('Invalid key length', 'DataError');
950+
}
951+
952+
const keyObject = createSecretKey(keyData);
953+
return new InternalCryptoKey(keyObject, { name }, keyUsages, false);
954+
}
955+
}
956+
957+
throw lazyDOMException(
958+
`Unable to import ${name} key with format ${format}`,
959+
'NotSupportedError');
960+
}
961+
804962
module.exports = {
805963
// Public API.
806964
createSecretKey,
@@ -822,4 +980,5 @@ module.exports = {
822980
PrivateKeyObject,
823981
isKeyObject,
824982
isCryptoKey,
983+
importGenericSecretKey,
825984
};
Collapse file

‎lib/internal/crypto/mac.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/mac.js
+19-1Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ function getAlgorithmName(hash) {
8282
}
8383
}
8484

85-
async function hmacImportKey(
85+
function hmacImportKey(
8686
format,
8787
keyData,
8888
algorithm,
@@ -96,6 +96,24 @@ async function hmacImportKey(
9696
}
9797
let keyObject;
9898
switch (format) {
99+
case 'KeyObject': {
100+
const checkLength = keyData.symmetricKeySize * 8;
101+
102+
if (checkLength === 0 || algorithm.length === 0)
103+
throw lazyDOMException('Zero-length key is not supported', 'DataError');
104+
105+
// The Web Crypto spec allows for key lengths that are not multiples of
106+
// 8. We don't. Our check here is stricter than that defined by the spec
107+
// in that we require that algorithm.length match keyData.length * 8 if
108+
// algorithm.length is specified.
109+
if (algorithm.length !== undefined &&
110+
algorithm.length !== checkLength) {
111+
throw lazyDOMException('Invalid key length', 'DataError');
112+
}
113+
114+
keyObject = keyData;
115+
break;
116+
}
99117
case 'raw': {
100118
const checkLength = keyData.byteLength * 8;
101119

Collapse file

‎lib/internal/crypto/rsa.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/rsa.js
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ function rsaExportKey(key, format) {
200200
kRsaVariants[key.algorithm.name]));
201201
}
202202

203-
async function rsaImportKey(
203+
function rsaImportKey(
204204
format,
205205
keyData,
206206
algorithm,
@@ -209,6 +209,11 @@ async function rsaImportKey(
209209
const usagesSet = new SafeSet(keyUsages);
210210
let keyObject;
211211
switch (format) {
212+
case 'KeyObject': {
213+
verifyAcceptableRsaKeyUse(algorithm.name, keyData.type === 'public', usagesSet);
214+
keyObject = keyData;
215+
break;
216+
}
212217
case 'spki': {
213218
verifyAcceptableRsaKeyUse(algorithm.name, true, usagesSet);
214219
try {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.