react-native-quick-crypto 0.7.0-rc.8 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/cpp/Cipher/MGLGenerateKeyPairInstaller.cpp +51 -14
  2. package/cpp/Cipher/MGLGenerateKeyPairSyncInstaller.cpp +25 -9
  3. package/cpp/Cipher/MGLRsa.cpp +13 -12
  4. package/cpp/Cipher/MGLRsa.h +2 -8
  5. package/cpp/JSIUtils/MGLJSIUtils.h +9 -0
  6. package/cpp/MGLKeys.cpp +174 -149
  7. package/cpp/MGLKeys.h +18 -13
  8. package/cpp/Sig/MGLSignHostObjects.cpp +284 -421
  9. package/cpp/Sig/MGLSignHostObjects.h +40 -0
  10. package/cpp/Utils/MGLUtils.cpp +0 -41
  11. package/cpp/Utils/MGLUtils.h +27 -6
  12. package/cpp/webcrypto/MGLWebCrypto.cpp +14 -4
  13. package/cpp/webcrypto/crypto_ec.cpp +106 -0
  14. package/cpp/webcrypto/crypto_ec.h +18 -0
  15. package/lib/commonjs/Cipher.js +138 -95
  16. package/lib/commonjs/Cipher.js.map +1 -1
  17. package/lib/commonjs/NativeQuickCrypto/Cipher.js +11 -8
  18. package/lib/commonjs/NativeQuickCrypto/Cipher.js.map +1 -1
  19. package/lib/commonjs/NativeQuickCrypto/sig.js +17 -0
  20. package/lib/commonjs/NativeQuickCrypto/sig.js.map +1 -1
  21. package/lib/commonjs/Utils.js +15 -1
  22. package/lib/commonjs/Utils.js.map +1 -1
  23. package/lib/commonjs/ec.js +79 -91
  24. package/lib/commonjs/ec.js.map +1 -1
  25. package/lib/commonjs/keys.js +28 -39
  26. package/lib/commonjs/keys.js.map +1 -1
  27. package/lib/commonjs/random.js +0 -1
  28. package/lib/commonjs/random.js.map +1 -1
  29. package/lib/commonjs/subtle.js +114 -0
  30. package/lib/commonjs/subtle.js.map +1 -1
  31. package/lib/module/Cipher.js +136 -93
  32. package/lib/module/Cipher.js.map +1 -1
  33. package/lib/module/NativeQuickCrypto/Cipher.js +10 -7
  34. package/lib/module/NativeQuickCrypto/Cipher.js.map +1 -1
  35. package/lib/module/NativeQuickCrypto/sig.js +13 -0
  36. package/lib/module/NativeQuickCrypto/sig.js.map +1 -1
  37. package/lib/module/Utils.js +12 -0
  38. package/lib/module/Utils.js.map +1 -1
  39. package/lib/module/ec.js +76 -93
  40. package/lib/module/ec.js.map +1 -1
  41. package/lib/module/keys.js +26 -39
  42. package/lib/module/keys.js.map +1 -1
  43. package/lib/module/random.js +0 -1
  44. package/lib/module/random.js.map +1 -1
  45. package/lib/module/subtle.js +115 -1
  46. package/lib/module/subtle.js.map +1 -1
  47. package/lib/typescript/Cipher.d.ts +23 -13
  48. package/lib/typescript/Cipher.d.ts.map +1 -1
  49. package/lib/typescript/NativeQuickCrypto/Cipher.d.ts +11 -6
  50. package/lib/typescript/NativeQuickCrypto/Cipher.d.ts.map +1 -1
  51. package/lib/typescript/NativeQuickCrypto/sig.d.ts +10 -0
  52. package/lib/typescript/NativeQuickCrypto/sig.d.ts.map +1 -1
  53. package/lib/typescript/NativeQuickCrypto/webcrypto.d.ts +2 -0
  54. package/lib/typescript/NativeQuickCrypto/webcrypto.d.ts.map +1 -1
  55. package/lib/typescript/Utils.d.ts +3 -1
  56. package/lib/typescript/Utils.d.ts.map +1 -1
  57. package/lib/typescript/ec.d.ts +3 -1
  58. package/lib/typescript/ec.d.ts.map +1 -1
  59. package/lib/typescript/index.d.ts +10 -7
  60. package/lib/typescript/index.d.ts.map +1 -1
  61. package/lib/typescript/keys.d.ts +12 -1
  62. package/lib/typescript/keys.d.ts.map +1 -1
  63. package/lib/typescript/random.d.ts +1 -1
  64. package/lib/typescript/random.d.ts.map +1 -1
  65. package/lib/typescript/subtle.d.ts +4 -1
  66. package/lib/typescript/subtle.d.ts.map +1 -1
  67. package/package.json +1 -1
  68. package/src/Cipher.ts +139 -75
  69. package/src/NativeQuickCrypto/Cipher.ts +14 -14
  70. package/src/NativeQuickCrypto/sig.ts +27 -0
  71. package/src/NativeQuickCrypto/webcrypto.ts +2 -0
  72. package/src/Utils.ts +24 -1
  73. package/src/ec.ts +114 -90
  74. package/src/keys.ts +53 -57
  75. package/src/random.ts +1 -11
  76. package/src/subtle.ts +157 -1
package/src/ec.ts CHANGED
@@ -1,4 +1,6 @@
1
+ import { generateKeyPairPromise, type GenerateKeyPairOptions } from './Cipher';
1
2
  import { NativeQuickCrypto } from './NativeQuickCrypto/NativeQuickCrypto';
3
+ import { DSASigEnc, SignMode } from './NativeQuickCrypto/sig';
2
4
  import {
3
5
  bufferLikeToArrayBuffer,
4
6
  type BufferLike,
@@ -8,6 +10,8 @@ import {
8
10
  validateKeyOps,
9
11
  hasAnyNotIn,
10
12
  ab2str,
13
+ getUsagesUnion,
14
+ normalizeHashName,
11
15
  } from './Utils';
12
16
  import {
13
17
  type ImportFormat,
@@ -22,7 +26,9 @@ import {
22
26
  type AnyAlgorithm,
23
27
  PrivateKeyObject,
24
28
  KeyType,
29
+ type CryptoKeyPair,
25
30
  } from './keys';
31
+ import type { KeyObjectHandle } from './NativeQuickCrypto/webcrypto';
26
32
 
27
33
  // const {
28
34
  // ArrayPrototypeIncludes,
@@ -114,71 +120,6 @@ function createECPublicKeyRaw(
114
120
  return new PublicKeyObject(handle);
115
121
  }
116
122
 
117
- // async function ecGenerateKey(algorithm, extractable, keyUsages) {
118
- // const { name, namedCurve } = algorithm;
119
-
120
- // if (!ArrayPrototypeIncludes(ObjectKeys(kNamedCurveAliases), namedCurve)) {
121
- // throw lazyDOMException(
122
- // 'Unrecognized namedCurve',
123
- // 'NotSupportedError');
124
- // }
125
-
126
- // const usageSet = new SafeSet(keyUsages);
127
- // switch (name) {
128
- // case 'ECDSA':
129
- // if (hasAnyNotIn(usageSet, ['sign', 'verify'])) {
130
- // throw lazyDOMException(
131
- // 'Unsupported key usage for an ECDSA key',
132
- // 'SyntaxError');
133
- // }
134
- // break;
135
- // case 'ECDH':
136
- // if (hasAnyNotIn(usageSet, ['deriveKey', 'deriveBits'])) {
137
- // throw lazyDOMException(
138
- // 'Unsupported key usage for an ECDH key',
139
- // 'SyntaxError');
140
- // }
141
- // // Fall through
142
- // }
143
-
144
- // const keypair = await generateKeyPair('ec', { namedCurve }).catch((err) => {
145
- // throw lazyDOMException(
146
- // 'The operation failed for an operation-specific reason',
147
- // { name: 'OperationError', cause: err });
148
- // });
149
-
150
- // let publicUsages;
151
- // let privateUsages;
152
- // switch (name) {
153
- // case 'ECDSA':
154
- // publicUsages = getUsagesUnion(usageSet, 'verify');
155
- // privateUsages = getUsagesUnion(usageSet, 'sign');
156
- // break;
157
- // case 'ECDH':
158
- // publicUsages = [];
159
- // privateUsages = getUsagesUnion(usageSet, 'deriveKey', 'deriveBits');
160
- // break;
161
- // }
162
-
163
- // const keyAlgorithm = { name, namedCurve };
164
-
165
- // const publicKey =
166
- // new InternalCryptoKey(
167
- // keypair.publicKey,
168
- // keyAlgorithm,
169
- // publicUsages,
170
- // true);
171
-
172
- // const privateKey =
173
- // new InternalCryptoKey(
174
- // keypair.privateKey,
175
- // keyAlgorithm,
176
- // privateUsages,
177
- // extractable);
178
-
179
- // return { __proto__: null, publicKey, privateKey };
180
- // }
181
-
182
123
  export function ecExportKey(
183
124
  key: CryptoKey,
184
125
  format: KWebCryptoKeyFormat
@@ -310,8 +251,8 @@ export function ecImportKey(
310
251
  case 'ECDSA':
311
252
  // Fall through
312
253
  case 'ECDH':
313
- // if (keyObject.asymmetricKeyType !== 'ec')
314
- // throw new Error('Invalid key type');
254
+ if (keyObject.asymmetricKeyType !== 'ec')
255
+ throw new Error('Invalid key type');
315
256
  break;
316
257
  }
317
258
 
@@ -326,26 +267,109 @@ export function ecImportKey(
326
267
  return new CryptoKey(keyObject, { name, namedCurve }, keyUsages, extractable);
327
268
  }
328
269
 
329
- // function ecdsaSignVerify(key, data, { name, hash }, signature) {
330
- // const mode = signature === undefined ? kSignJobModeSign : kSignJobModeVerify;
331
- // const type = mode === kSignJobModeSign ? 'private' : 'public';
332
-
333
- // if (key.type !== type)
334
- // throw lazyDOMException(`Key must be a ${type} key`, 'InvalidAccessError');
335
-
336
- // const hashname = normalizeHashName(hash.name);
337
-
338
- // return jobPromise(() => new SignJob(
339
- // kCryptoJobAsync,
340
- // mode,
341
- // key[kKeyObject][kHandle],
342
- // undefined,
343
- // undefined,
344
- // undefined,
345
- // data,
346
- // hashname,
347
- // undefined, // Salt length, not used with ECDSA
348
- // undefined, // PSS Padding, not used with ECDSA
349
- // kSigEncP1363,
350
- // signature));
351
- // }
270
+ export const ecdsaSignVerify = (
271
+ key: CryptoKey,
272
+ data: BufferLike,
273
+ { hash }: SubtleAlgorithm,
274
+ signature?: BufferLike
275
+ ) => {
276
+ const mode: SignMode =
277
+ signature === undefined
278
+ ? SignMode.kSignJobModeSign
279
+ : SignMode.kSignJobModeVerify;
280
+ const type = mode === SignMode.kSignJobModeSign ? 'private' : 'public';
281
+
282
+ if (key.type !== type)
283
+ throw lazyDOMException(`Key must be a ${type} key`, 'InvalidAccessError');
284
+
285
+ const hashname = normalizeHashName(hash);
286
+
287
+ return NativeQuickCrypto.webcrypto.signVerify(
288
+ mode,
289
+ key.keyObject.handle,
290
+ // three undefined args because C++ uses `GetPublicOrPrivateKeyFromJs` & friends
291
+ undefined,
292
+ undefined,
293
+ undefined,
294
+ bufferLikeToArrayBuffer(data),
295
+ hashname,
296
+ undefined, // salt length, not used with ECDSA
297
+ undefined, // pss padding, not used with ECDSA
298
+ DSASigEnc.kSigEncP1363,
299
+ bufferLikeToArrayBuffer(signature || new ArrayBuffer(0))
300
+ );
301
+ };
302
+
303
+ export const ecGenerateKey = async (
304
+ algorithm: SubtleAlgorithm,
305
+ extractable: boolean,
306
+ keyUsages: KeyUsage[]
307
+ ): Promise<CryptoKeyPair> => {
308
+ const { name, namedCurve } = algorithm;
309
+
310
+ if (!Object.keys(kNamedCurveAliases).includes(namedCurve || '')) {
311
+ throw lazyDOMException(
312
+ `Unrecognized namedCurve '${namedCurve}'`,
313
+ 'NotSupportedError'
314
+ );
315
+ }
316
+
317
+ // const usageSet = new SafeSet(keyUsages);
318
+ switch (name) {
319
+ case 'ECDSA':
320
+ const checkUsages = ['sign', 'verify'];
321
+ if (hasAnyNotIn(keyUsages, checkUsages)) {
322
+ throw lazyDOMException(
323
+ 'Unsupported key usage for an ECDSA key',
324
+ 'SyntaxError'
325
+ );
326
+ }
327
+ break;
328
+ case 'ECDH':
329
+ if (hasAnyNotIn(keyUsages, ['deriveKey', 'deriveBits'])) {
330
+ throw lazyDOMException(
331
+ 'Unsupported key usage for an ECDH key',
332
+ 'SyntaxError'
333
+ );
334
+ }
335
+ // Fall through
336
+ }
337
+
338
+ const options: GenerateKeyPairOptions = { namedCurve };
339
+ const [err, keypair] = await generateKeyPairPromise('ec', options);
340
+
341
+ if (err) {
342
+ throw lazyDOMException('ecGenerateKey (generateKeyPairPromise) failed', {
343
+ name: 'OperationError',
344
+ cause: err,
345
+ });
346
+ }
347
+
348
+ let publicUsages: KeyUsage[] = [];
349
+ let privateUsages: KeyUsage[] = [];
350
+ switch (name) {
351
+ case 'ECDSA':
352
+ publicUsages = getUsagesUnion(keyUsages, 'verify');
353
+ privateUsages = getUsagesUnion(keyUsages, 'sign');
354
+ break;
355
+ case 'ECDH':
356
+ publicUsages = [];
357
+ privateUsages = getUsagesUnion(keyUsages, 'deriveKey', 'deriveBits');
358
+ break;
359
+ }
360
+
361
+ const keyAlgorithm = { name, namedCurve };
362
+
363
+ const pub = new PublicKeyObject(keypair?.publicKey as KeyObjectHandle);
364
+ const publicKey = new CryptoKey(pub, keyAlgorithm, publicUsages, true);
365
+
366
+ const priv = new PrivateKeyObject(keypair?.privateKey as KeyObjectHandle);
367
+ const privateKey = new CryptoKey(
368
+ priv,
369
+ keyAlgorithm,
370
+ privateUsages,
371
+ extractable
372
+ );
373
+
374
+ return { publicKey, privateKey };
375
+ };
package/src/keys.ts CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  } from './Utils';
6
6
  import type { KeyObjectHandle } from './NativeQuickCrypto/webcrypto';
7
7
  import { NativeQuickCrypto } from './NativeQuickCrypto/NativeQuickCrypto';
8
+ import type { KeyPairKey } from './Cipher';
8
9
 
9
10
  export const kNamedCurveAliases = {
10
11
  'P-256': 'prime256v1',
@@ -28,16 +29,16 @@ export type AnyAlgorithm =
28
29
 
29
30
  export type HashAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
30
31
 
32
+ export type KeyPairType = 'rsa' | 'rsa-pss' | 'ec';
33
+
34
+ export type RSAKeyPairAlgorithm = 'RSASSA-PKCS1-v1_5' | 'RSA-PSS' | 'RSA-OAEP';
35
+ export type ECKeyPairAlgorithm = 'ECDSA' | 'ECDH';
36
+ export type CFRGKeyPairAlgorithm = 'Ed25519' | 'Ed448' | 'X25519' | 'X448';
37
+
31
38
  export type KeyPairAlgorithm =
32
- | 'ECDSA'
33
- | 'ECDH'
34
- | 'Ed25519'
35
- | 'Ed448'
36
- | 'RSASSA-PKCS1-v1_5'
37
- | 'RSA-PSS'
38
- | 'RSA-OAEP'
39
- | 'X25519'
40
- | 'X448';
39
+ | RSAKeyPairAlgorithm
40
+ | ECKeyPairAlgorithm
41
+ | CFRGKeyPairAlgorithm;
41
42
 
42
43
  export type SecretKeyAlgorithm =
43
44
  | 'HMAC'
@@ -175,6 +176,11 @@ const encodingNames = {
175
176
  [KeyEncoding.kKeyEncodingSEC1]: 'sec1',
176
177
  };
177
178
 
179
+ export type CryptoKeyPair = {
180
+ publicKey: KeyPairKey;
181
+ privateKey: KeyPairKey;
182
+ };
183
+
178
184
  function option(name: string, objName: string | undefined) {
179
185
  return objName === undefined
180
186
  ? `options.${name}`
@@ -417,40 +423,41 @@ export function parsePrivateKeyEncoding(
417
423
  }
418
424
 
419
425
  function prepareSecretKey(
420
- key: ArrayBuffer | KeyObject | CryptoKey | string,
426
+ key: BinaryLike,
421
427
  encoding?: string,
422
428
  bufferOnly = false
423
429
  ): any {
424
- if (!bufferOnly) {
425
- // TODO: maybe use `key.constructor.name === 'KeyObject'` ?
426
- if (key instanceof KeyObject) {
427
- if (key.type !== 'secret')
428
- throw new Error(
429
- `invalid KeyObject type: ${key.type}, expected 'secret'`
430
- );
431
- return key.handle;
432
- }
433
- // TODO: maybe use `key.constructor.name === 'CryptoKey'` ?
434
- else if (key instanceof CryptoKey) {
435
- if (key.type !== 'secret')
436
- throw new Error(
437
- `invalid CryptoKey type: ${key.type}, expected 'secret'`
438
- );
439
- return key.keyObject.handle;
430
+ try {
431
+ if (!bufferOnly) {
432
+ // TODO: maybe use `key.constructor.name === 'KeyObject'` ?
433
+ if (key instanceof KeyObject) {
434
+ if (key.type !== 'secret')
435
+ throw new Error(
436
+ `invalid KeyObject type: ${key.type}, expected 'secret'`
437
+ );
438
+ return key.handle;
439
+ }
440
+ // TODO: maybe use `key.constructor.name === 'CryptoKey'` ?
441
+ else if (key instanceof CryptoKey) {
442
+ if (key.type !== 'secret')
443
+ throw new Error(
444
+ `invalid CryptoKey type: ${key.type}, expected 'secret'`
445
+ );
446
+ return key.keyObject.handle;
447
+ }
440
448
  }
441
- }
442
449
 
443
- if (key instanceof ArrayBuffer) {
444
- return key;
445
- }
450
+ if (key instanceof ArrayBuffer) {
451
+ return key;
452
+ }
446
453
 
447
- if (typeof key === 'string') {
448
454
  return binaryLikeToArrayBuffer(key, encoding);
455
+ } catch (error) {
456
+ throw new Error(
457
+ 'Invalid argument type for "key". Need ArrayBuffer, TypedArray, KeyObject, CryptoKey, string',
458
+ { cause: error }
459
+ );
449
460
  }
450
-
451
- throw new Error(
452
- 'Invalid argument type for "key". Need ArrayBuffer, KeyObject, CryptoKey, string'
453
- );
454
461
  }
455
462
 
456
463
  export function createSecretKey(key: any, encoding?: string) {
@@ -516,18 +523,6 @@ export class CryptoKey {
516
523
  }
517
524
  }
518
525
 
519
- // ObjectDefineProperties(CryptoKey.prototype, {
520
- // type: kEnumerableProperty,
521
- // extractable: kEnumerableProperty,
522
- // algorithm: kEnumerableProperty,
523
- // usages: kEnumerableProperty,
524
- // [SymbolToStringTag]: {
525
- // __proto__: null,
526
- // configurable: true,
527
- // value: 'CryptoKey',
528
- // },
529
- // });
530
-
531
526
  class KeyObject {
532
527
  handle: KeyObjectHandle;
533
528
  type: 'public' | 'secret' | 'private' | 'unknown' = 'unknown';
@@ -568,14 +563,6 @@ class KeyObject {
568
563
  // }
569
564
  }
570
565
 
571
- // ObjectDefineProperties(KeyObject.prototype, {
572
- // [SymbolToStringTag]: {
573
- // __proto__: null,
574
- // configurable: true,
575
- // value: 'KeyObject',
576
- // },
577
- // });
578
-
579
566
  export class SecretKeyObject extends KeyObject {
580
567
  constructor(handle: KeyObjectHandle) {
581
568
  super('secret', handle);
@@ -616,12 +603,17 @@ class AsymmetricKeyObject extends KeyObject {
616
603
  super(type, handle);
617
604
  }
618
605
 
606
+ private _asymmetricKeyType?: AsymmetricKeyType;
607
+
619
608
  get asymmetricKeyType(): AsymmetricKeyType {
620
- return this.asymmetricKeyType || this.handle.getAsymmetricKeyType();
609
+ if (!this._asymmetricKeyType) {
610
+ this._asymmetricKeyType = this.handle.getAsymmetricKeyType();
611
+ }
612
+ return this._asymmetricKeyType;
621
613
  }
622
614
 
623
615
  // get asymmetricKeyDetails() {
624
- // switch (this.asymmetricKeyType) {
616
+ // switch (this._asymmetricKeyType) {
625
617
  // case 'rsa':
626
618
  // case 'rsa-pss':
627
619
  // case 'dsa':
@@ -676,3 +668,7 @@ export class PrivateKeyObject extends AsymmetricKeyObject {
676
668
  return this.handle.export(format, type, cipher, passphrase);
677
669
  }
678
670
  }
671
+
672
+ export const isCryptoKey = (obj: any): boolean => {
673
+ return obj !== null && obj?.keyObject !== undefined;
674
+ };
package/src/random.ts CHANGED
@@ -1,18 +1,9 @@
1
1
  import { NativeQuickCrypto } from './NativeQuickCrypto/NativeQuickCrypto';
2
2
  import { Buffer } from '@craftzdog/react-native-buffer';
3
+ import type { TypedArray } from './Utils';
3
4
 
4
5
  const random = NativeQuickCrypto.random;
5
6
 
6
- type TypedArray =
7
- | Uint8Array
8
- | Uint8ClampedArray
9
- | Uint16Array
10
- | Uint32Array
11
- | Int8Array
12
- | Int16Array
13
- | Int32Array
14
- | Float32Array
15
- | Float64Array;
16
7
  type ArrayBufferView = TypedArray | DataView | ArrayBufferLike | Buffer;
17
8
 
18
9
  export function randomFill<T extends ArrayBufferView>(
@@ -266,7 +257,6 @@ function asyncRefillRandomIntCache() {
266
257
  });
267
258
  }
268
259
 
269
- // Really just the Web Crypto API alternative
270
260
  // to require('crypto').randomFillSync() with an
271
261
  // additional limitation that the input buffer is
272
262
  // not allowed to exceed 65536 bytes, and can only
package/src/subtle.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  createSecretKey,
8
8
  type AnyAlgorithm,
9
9
  type JWK,
10
+ type CryptoKeyPair,
10
11
  } from './keys';
11
12
  import {
12
13
  hasAnyNotIn,
@@ -16,8 +17,9 @@ import {
16
17
  lazyDOMException,
17
18
  normalizeHashName,
18
19
  HashContext,
20
+ type Operation,
19
21
  } from './Utils';
20
- import { ecImportKey, ecExportKey } from './ec';
22
+ import { ecImportKey, ecExportKey, ecGenerateKey, ecdsaSignVerify } from './ec';
21
23
  import { pbkdf2DeriveBits } from './pbkdf2';
22
24
  import { asyncDigest } from './Hash';
23
25
  import { aesImportKey, getAlgorithmName } from './aes';
@@ -202,6 +204,87 @@ const importGenericSecretKey = async (
202
204
  throw new Error(`Unable to import ${name} key with format ${format}`);
203
205
  };
204
206
 
207
+ // const checkCryptoKeyUsages = (key: CryptoKey) => {
208
+ // if (
209
+ // (key.type === 'secret' || key.type === 'private') &&
210
+ // key.usages.length === 0
211
+ // ) {
212
+ // throw lazyDOMException(
213
+ // 'Usages cannot be empty when creating a key.',
214
+ // 'SyntaxError'
215
+ // );
216
+ // }
217
+ // };
218
+
219
+ const checkCryptoKeyPairUsages = (pair: CryptoKeyPair) => {
220
+ if (
221
+ !(pair.privateKey instanceof Buffer) &&
222
+ pair.privateKey &&
223
+ pair.privateKey.hasOwnProperty('keyUsages')
224
+ ) {
225
+ const priv = pair.privateKey as CryptoKey;
226
+ if (priv.usages.length > 0) {
227
+ return;
228
+ }
229
+ }
230
+ console.log(pair.privateKey);
231
+ throw lazyDOMException(
232
+ 'Usages cannot be empty when creating a key.',
233
+ 'SyntaxError'
234
+ );
235
+ };
236
+
237
+ const signVerify = (
238
+ algorithm: SubtleAlgorithm,
239
+ key: CryptoKey,
240
+ data: BufferLike,
241
+ signature?: BufferLike
242
+ ): ArrayBuffer | boolean => {
243
+ const usage: Operation = signature === undefined ? 'sign' : 'verify';
244
+ algorithm = normalizeAlgorithm(algorithm, usage);
245
+
246
+ if (!key.usages.includes(usage) || algorithm.name !== key.algorithm.name) {
247
+ throw lazyDOMException(
248
+ `Unable to use this key to ${usage}`,
249
+ 'InvalidAccessError'
250
+ );
251
+ }
252
+
253
+ switch (algorithm.name) {
254
+ // case 'RSA-PSS':
255
+ // // Fall through
256
+ // case 'RSASSA-PKCS1-v1_5':
257
+ // return require('internal/crypto/rsa').rsaSignVerify(
258
+ // key,
259
+ // data,
260
+ // algorithm,
261
+ // signature
262
+ // );
263
+ case 'ECDSA':
264
+ return ecdsaSignVerify(key, data, algorithm, signature);
265
+ // case 'Ed25519':
266
+ // // Fall through
267
+ // case 'Ed448':
268
+ // return require('internal/crypto/cfrg').eddsaSignVerify(
269
+ // key,
270
+ // data,
271
+ // algorithm,
272
+ // signature
273
+ // );
274
+ // case 'HMAC':
275
+ // return require('internal/crypto/mac').hmacSignVerify(
276
+ // key,
277
+ // data,
278
+ // algorithm,
279
+ // signature
280
+ // );
281
+ }
282
+ throw lazyDOMException(
283
+ `Unrecognized algorithm name '${algorithm}' for '${usage}'`,
284
+ 'NotSupportedError'
285
+ );
286
+ };
287
+
205
288
  class Subtle {
206
289
  async digest(
207
290
  algorithm: SubtleAlgorithm | AnyAlgorithm,
@@ -360,6 +443,79 @@ class Subtle {
360
443
  }
361
444
  throw new Error(`'subtle.exportKey()' is not implemented for ${format}`);
362
445
  }
446
+
447
+ async generateKey(
448
+ algorithm: SubtleAlgorithm,
449
+ extractable: boolean,
450
+ keyUsages: KeyUsage[]
451
+ ): Promise<CryptoKey | CryptoKeyPair> {
452
+ algorithm = normalizeAlgorithm(algorithm, 'generateKey');
453
+ let result: CryptoKey | CryptoKeyPair;
454
+ switch (algorithm.name) {
455
+ // case 'RSASSA-PKCS1-v1_5':
456
+ // // Fall through
457
+ // case 'RSA-PSS':
458
+ // // Fall through
459
+ // case 'RSA-OAEP':
460
+ // resultType = 'CryptoKeyPair';
461
+ // result = await rsaKeyGenerate(algorithm, extractable, keyUsages);
462
+ // break;
463
+ // case 'Ed25519':
464
+ // // Fall through
465
+ // case 'Ed448':
466
+ // // Fall through
467
+ // case 'X25519':
468
+ // // Fall through
469
+ // case 'X448':
470
+ // resultType = 'CryptoKeyPair';
471
+ // result = await cfrgGenerateKey(algorithm, extractable, keyUsages);
472
+ // break;
473
+ case 'ECDSA':
474
+ // Fall through
475
+ case 'ECDH':
476
+ result = await ecGenerateKey(algorithm, extractable, keyUsages);
477
+ checkCryptoKeyPairUsages(result);
478
+ break;
479
+ // case 'HMAC':
480
+ // resultType = 'CryptoKey';
481
+ // result = await hmacGenerateKey(algorithm, extractable, keyUsages);
482
+ // break;
483
+ // case 'AES-CTR':
484
+ // // Fall through
485
+ // case 'AES-CBC':
486
+ // // Fall through
487
+ // case 'AES-GCM':
488
+ // // Fall through
489
+ // case 'AES-KW':
490
+ // resultType = 'CryptoKey';
491
+ // result = await aesGenerateKey(algorithm, extractable, keyUsages);
492
+ // break;
493
+ default:
494
+ throw new Error(
495
+ `'subtle.generateKey()' is not implemented for ${algorithm.name}.
496
+ Unrecognized algorithm name`
497
+ );
498
+ }
499
+
500
+ return result;
501
+ }
502
+
503
+ async sign(
504
+ algorithm: SubtleAlgorithm,
505
+ key: CryptoKey,
506
+ data: BufferLike
507
+ ): Promise<ArrayBuffer> {
508
+ return signVerify(algorithm, key, data) as ArrayBuffer;
509
+ }
510
+
511
+ async verify(
512
+ algorithm: SubtleAlgorithm,
513
+ key: CryptoKey,
514
+ signature: BufferLike,
515
+ data: BufferLike
516
+ ): Promise<ArrayBuffer> {
517
+ return signVerify(algorithm, key, data, signature) as ArrayBuffer;
518
+ }
363
519
  }
364
520
 
365
521
  export const subtle = new Subtle();