react-native-quick-crypto 0.7.0-rc.9 → 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 +10 -24
  26. package/lib/commonjs/keys.js.map +1 -1
  27. package/lib/commonjs/random.js +6 -0
  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 +8 -24
  42. package/lib/module/keys.js.map +1 -1
  43. package/lib/module/random.js +6 -0
  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 +1 -0
  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 +11 -8
  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 +2 -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 +12 -0
  73. package/src/ec.ts +114 -90
  74. package/src/keys.ts +26 -31
  75. package/src/random.ts +12 -1
  76. package/src/subtle.ts +157 -1
package/src/Cipher.ts CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  validateInt32,
15
15
  type BinaryLikeNode,
16
16
  } from './Utils';
17
- import { type InternalCipher, RSAKeyVariant } from './NativeQuickCrypto/Cipher';
17
+ import { type InternalCipher, KeyVariant } from './NativeQuickCrypto/Cipher';
18
18
  import type {
19
19
  CipherCCMOptions,
20
20
  CipherCCMTypes,
@@ -34,11 +34,21 @@ import { Buffer } from '@craftzdog/react-native-buffer';
34
34
  import { Buffer as SBuffer } from 'safe-buffer';
35
35
  import { constants } from './constants';
36
36
  import {
37
+ CryptoKey,
37
38
  parsePrivateKeyEncoding,
38
39
  parsePublicKeyEncoding,
39
40
  preparePrivateKey,
40
41
  preparePublicOrPrivateKey,
42
+ type CryptoKeyPair,
43
+ type KeyPairType,
44
+ type NamedCurve,
41
45
  } from './keys';
46
+ import type { KeyObjectHandle } from './NativeQuickCrypto/webcrypto';
47
+
48
+ export enum ECCurve {
49
+ OPENSSL_EC_EXPLICIT_CURVE,
50
+ OPENSSL_EC_NAMED_CURVE,
51
+ }
42
52
 
43
53
  // make sure that nextTick is there
44
54
  global.process.nextTick = setImmediate;
@@ -428,8 +438,8 @@ export const privateDecrypt = rsaFunctionFor(
428
438
  // \__, |\___|_| |_|\___|_| \__,_|\__\___|_|\_\___|\__, |_| \__,_|_|_|
429
439
  // __/ | __/ |
430
440
  // |___/ |___/
431
- type GenerateKeyPairOptions = {
432
- modulusLength: number; // Key size in bits (RSA, DSA).
441
+ export type GenerateKeyPairOptions = {
442
+ modulusLength?: number; // Key size in bits (RSA, DSA).
433
443
  publicExponent?: number; // Public exponent (RSA). Default: 0x10001.
434
444
  hashAlgorithm?: string; // Name of the message digest (RSA-PSS).
435
445
  mgf1HashAlgorithm?: string; // string Name of the message digest used by MGF1 (RSA-PSS).
@@ -446,11 +456,27 @@ type GenerateKeyPairOptions = {
446
456
  hash?: any;
447
457
  mgf1Hash?: any;
448
458
  };
449
- type GenerateKeyPairCallback = (
450
- error: unknown | null,
451
- publicKey?: Buffer,
452
- privateKey?: Buffer
453
- ) => void;
459
+
460
+ export type KeyPairKey = Buffer | KeyObjectHandle | CryptoKey | undefined;
461
+
462
+ export type GenerateKeyPairReturn = [
463
+ error?: Error,
464
+ privateKey?: KeyPairKey,
465
+ publicKey?: KeyPairKey,
466
+ ];
467
+
468
+ export type GenerateKeyPairCallback = (
469
+ error?: Error,
470
+ publicKey?: KeyPairKey,
471
+ privateKey?: KeyPairKey
472
+ ) => GenerateKeyPairReturn | void;
473
+
474
+ export type KeyPair = {
475
+ publicKey?: KeyPairKey;
476
+ privateKey?: KeyPairKey;
477
+ };
478
+
479
+ export type GenerateKeyPairPromiseReturn = [error?: Error, keypair?: KeyPair];
454
480
 
455
481
  function parseKeyEncoding(
456
482
  keyType: string,
@@ -505,14 +531,15 @@ function parseKeyEncoding(
505
531
  ];
506
532
  }
507
533
 
534
+ /** On node a very complex "job" chain is created, we are going for a far simpler approach and calling
535
+ * an internal function that basically executes the same byte shuffling on the native side
536
+ */
508
537
  function internalGenerateKeyPair(
509
538
  isAsync: boolean,
510
- type: string,
539
+ type: KeyPairType,
511
540
  options: GenerateKeyPairOptions | undefined,
512
- callback: GenerateKeyPairCallback | undefined
513
- ) {
514
- // On node a very complex "job" chain is created, we are going for a far simpler approach and calling
515
- // an internal function that basically executes the same byte shuffling on the native side
541
+ callback?: GenerateKeyPairCallback
542
+ ): GenerateKeyPairReturn | void {
516
543
  const encoding = parseKeyEncoding(type, options);
517
544
 
518
545
  // if (options !== undefined)
@@ -520,11 +547,11 @@ function internalGenerateKeyPair(
520
547
 
521
548
  switch (type) {
522
549
  case 'rsa-pss':
523
- case 'rsa': {
550
+ // fallthrough
551
+ case 'rsa':
524
552
  validateObject<GenerateKeyPairOptions>(options, 'options');
525
553
  const { modulusLength } = options!;
526
- validateUint32(modulusLength, 'options.modulusLength');
527
-
554
+ validateUint32(modulusLength as number, 'options.modulusLength');
528
555
  let { publicExponent } = options!;
529
556
  if (publicExponent == null) {
530
557
  publicExponent = 0x10001;
@@ -535,37 +562,36 @@ function internalGenerateKeyPair(
535
562
  if (type === 'rsa') {
536
563
  if (isAsync) {
537
564
  NativeQuickCrypto.generateKeyPair(
538
- RSAKeyVariant.kKeyVariantRSA_SSA_PKCS1_v1_5,
539
- modulusLength,
565
+ KeyVariant.RSA_SSA_PKCS1_v1_5,
566
+ modulusLength as number,
540
567
  publicExponent,
541
568
  ...encoding
542
569
  )
543
570
  .then(([err, publicKey, privateKey]) => {
544
- if (typeof publicKey === 'object') {
571
+ if (publicKey instanceof Buffer) {
545
572
  publicKey = Buffer.from(publicKey);
546
573
  }
547
- if (typeof privateKey === 'object') {
574
+ if (privateKey instanceof Buffer) {
548
575
  privateKey = Buffer.from(privateKey);
549
576
  }
550
- callback?.(err, publicKey, privateKey);
577
+ callback!(err, publicKey, privateKey);
551
578
  })
552
579
  .catch((err) => {
553
- callback?.(err, undefined, undefined);
580
+ callback!(err, undefined, undefined);
554
581
  });
555
- return;
556
582
  } else {
557
583
  let [err, publicKey, privateKey] =
558
584
  NativeQuickCrypto.generateKeyPairSync(
559
- RSAKeyVariant.kKeyVariantRSA_SSA_PKCS1_v1_5,
560
- modulusLength,
585
+ KeyVariant.RSA_SSA_PKCS1_v1_5,
586
+ modulusLength as number,
561
587
  publicExponent,
562
588
  ...encoding
563
589
  );
564
590
 
565
- if (typeof publicKey === 'object') {
591
+ if (publicKey instanceof Buffer) {
566
592
  publicKey = Buffer.from(publicKey);
567
593
  }
568
- if (typeof privateKey === 'object') {
594
+ if (privateKey instanceof Buffer) {
569
595
  privateKey = Buffer.from(privateKey);
570
596
  }
571
597
 
@@ -609,15 +635,15 @@ function internalGenerateKeyPair(
609
635
  }
610
636
 
611
637
  return NativeQuickCrypto.generateKeyPairSync(
612
- RSAKeyVariant.kKeyVariantRSA_PSS,
613
- modulusLength,
638
+ KeyVariant.RSA_PSS,
639
+ modulusLength as number,
614
640
  publicExponent,
615
641
  hashAlgorithm || hash,
616
642
  mgf1HashAlgorithm || mgf1Hash,
617
643
  saltLength,
618
644
  ...encoding
619
645
  );
620
- }
646
+
621
647
  // case 'dsa': {
622
648
  // validateObject(options, 'options');
623
649
  // const { modulusLength } = options!;
@@ -634,21 +660,57 @@ function internalGenerateKeyPair(
634
660
  // // divisorLength,
635
661
  // // ...encoding);
636
662
  // }
637
- // case 'ec': {
638
- // validateObject(options, 'options');
639
- // const { namedCurve } = options!;
640
- // validateString(namedCurve, 'options.namedCurve');
641
- // let { paramEncoding } = options!;
642
- // if (paramEncoding == null || paramEncoding === 'named')
643
- // paramEncoding = OPENSSL_EC_NAMED_CURVE;
644
- // else if (paramEncoding === 'explicit')
645
- // paramEncoding = OPENSSL_EC_EXPLICIT_CURVE;
646
- // else
647
- // throw new Error(`Invalid Argument options.paramEncoding ${paramEncoding}`);
648
- // // throw new ERR_INVALID_ARG_VALUE('options.paramEncoding', paramEncoding);
649
-
650
- // // return new EcKeyPairGenJob(mode, namedCurve, paramEncoding, ...encoding);
651
- // }
663
+
664
+ case 'ec':
665
+ validateObject<GenerateKeyPairOptions>(options, 'options');
666
+ const { namedCurve } = options!;
667
+ validateString(namedCurve, 'options.namedCurve');
668
+ let paramEncodingFlag = ECCurve.OPENSSL_EC_NAMED_CURVE;
669
+ const { paramEncoding } = options!;
670
+ if (paramEncoding == null || paramEncoding === 'named')
671
+ paramEncodingFlag = ECCurve.OPENSSL_EC_NAMED_CURVE;
672
+ else if (paramEncoding === 'explicit')
673
+ paramEncodingFlag = ECCurve.OPENSSL_EC_EXPLICIT_CURVE;
674
+ else
675
+ throw new Error(
676
+ `Invalid Argument options.paramEncoding ${paramEncoding}`
677
+ );
678
+
679
+ if (isAsync) {
680
+ NativeQuickCrypto.generateKeyPair(
681
+ KeyVariant.EC,
682
+ namedCurve as NamedCurve,
683
+ paramEncodingFlag,
684
+ ...encoding
685
+ )
686
+ .then(([err, publicKey, privateKey]) => {
687
+ if (publicKey instanceof Buffer) {
688
+ publicKey = Buffer.from(publicKey);
689
+ }
690
+ if (privateKey instanceof Buffer) {
691
+ privateKey = Buffer.from(privateKey);
692
+ }
693
+ callback?.(err, publicKey, privateKey);
694
+ })
695
+ .catch((err) => {
696
+ callback?.(err, undefined, undefined);
697
+ });
698
+ }
699
+
700
+ let [err, publicKey, privateKey] = NativeQuickCrypto.generateKeyPairSync(
701
+ KeyVariant.EC,
702
+ namedCurve as NamedCurve,
703
+ paramEncodingFlag,
704
+ ...encoding
705
+ );
706
+ if (publicKey instanceof Buffer) {
707
+ publicKey = Buffer.from(publicKey);
708
+ }
709
+ if (privateKey instanceof Buffer) {
710
+ privateKey = Buffer.from(privateKey);
711
+ }
712
+ return [err, publicKey, privateKey];
713
+
652
714
  // case 'ed25519':
653
715
  // case 'ed448':
654
716
  // case 'x25519':
@@ -712,48 +774,50 @@ function internalGenerateKeyPair(
712
774
  default:
713
775
  // Fall through
714
776
  }
715
- throw new Error(
716
- `Invalid Argument options: ${type} scheme not supported. Currently not all encryption methods are supported in quick-crypto!`
717
- );
777
+ const err = new Error(`
778
+ Invalid Argument options: '${type}' scheme not supported for generateKey().
779
+ Currently not all encryption methods are supported in quick-crypto. Check
780
+ implementation_coverage.md for status.
781
+ `);
782
+ return [err, undefined, undefined];
718
783
  }
719
784
 
720
- // TODO(osp) put correct types (e.g. type -> 'rsa', etc..)
721
- export function generateKeyPair(
722
- type: string,
723
- callback: GenerateKeyPairCallback
724
- ): void;
725
- export function generateKeyPair(
726
- type: string,
785
+ export const generateKeyPair = (
786
+ type: KeyPairType,
727
787
  options: GenerateKeyPairOptions,
728
788
  callback: GenerateKeyPairCallback
729
- ): void;
730
- export function generateKeyPair(
731
- type: string,
732
- options?: GenerateKeyPairCallback | GenerateKeyPairOptions,
733
- callback?: GenerateKeyPairCallback
734
- ) {
735
- if (typeof options === 'function') {
736
- callback = options;
737
- options = undefined;
738
- }
739
-
789
+ ): void => {
740
790
  validateFunction(callback);
741
-
742
791
  internalGenerateKeyPair(true, type, options, callback);
743
- }
792
+ };
744
793
 
745
- export function generateKeyPairSync(type: string): {
746
- publicKey: any;
747
- privateKey: any;
794
+ // Promisify generateKeyPair
795
+ // (attempted to use util.promisify, to no avail)
796
+ export const generateKeyPairPromise = (
797
+ type: KeyPairType,
798
+ options: GenerateKeyPairOptions
799
+ ): Promise<GenerateKeyPairPromiseReturn> => {
800
+ return new Promise((resolve, reject) => {
801
+ generateKeyPair(type, options, (err, publicKey, privateKey) => {
802
+ if (err) {
803
+ reject([err, undefined]);
804
+ } else {
805
+ resolve([undefined, { publicKey, privateKey }]);
806
+ }
807
+ });
808
+ });
748
809
  };
810
+
811
+ // generateKeyPairSync
812
+ export function generateKeyPairSync(type: KeyPairType): CryptoKeyPair;
749
813
  export function generateKeyPairSync(
750
- type: string,
814
+ type: KeyPairType,
751
815
  options: GenerateKeyPairOptions
752
- ): { publicKey: any; privateKey: any };
816
+ ): CryptoKeyPair;
753
817
  export function generateKeyPairSync(
754
- type: string,
818
+ type: KeyPairType,
755
819
  options?: GenerateKeyPairOptions
756
- ): { publicKey: any; privateKey: any } {
820
+ ): CryptoKeyPair {
757
821
  const [_, publicKey, privateKey] = internalGenerateKeyPair(
758
822
  false,
759
823
  type,
@@ -1,12 +1,16 @@
1
+ import type { GenerateKeyPairReturn } from '../Cipher';
1
2
  import type { BinaryLike } from '../Utils';
2
3
  import type { Buffer } from '@craftzdog/react-native-buffer';
3
4
 
4
- // TODO(osp) on node this is defined on the native side
5
- // Need to do the same so that values are always in sync
6
- export enum RSAKeyVariant {
7
- kKeyVariantRSA_SSA_PKCS1_v1_5,
8
- kKeyVariantRSA_PSS,
9
- kKeyVariantRSA_OAEP,
5
+ // TODO: until shared, keep in sync with C++ side (cpp/Utils/MGLUtils.h)
6
+ export enum KeyVariant {
7
+ RSA_SSA_PKCS1_v1_5,
8
+ RSA_PSS,
9
+ RSA_OAEP,
10
+ DSA,
11
+ EC,
12
+ NID,
13
+ DH,
10
14
  }
11
15
 
12
16
  export type InternalCipher = {
@@ -56,15 +60,11 @@ export type PrivateDecryptMethod = (
56
60
  ) => Buffer;
57
61
 
58
62
  export type GenerateKeyPairMethod = (
59
- keyVariant: RSAKeyVariant,
60
- modulusLength: number,
61
- publicExponent: number,
63
+ keyVariant: KeyVariant,
62
64
  ...rest: any[]
63
- ) => Promise<[error: unknown, publicBuffer: any, privateBuffer: any]>;
65
+ ) => Promise<GenerateKeyPairReturn>;
64
66
 
65
67
  export type GenerateKeyPairSyncMethod = (
66
- keyVariant: RSAKeyVariant,
67
- modulusLength: number,
68
- publicExponent: number,
68
+ keyVariant: KeyVariant,
69
69
  ...rest: any[]
70
- ) => [error: unknown, publicBuffer: any, privateBuffer: any];
70
+ ) => GenerateKeyPairReturn;
@@ -1,4 +1,7 @@
1
1
  // TODO Add real types to sign/verify, the problem is that because of encryption schemes
2
+
3
+ import type { KeyObjectHandle } from './webcrypto';
4
+
2
5
  // they will have variable amount of parameters
3
6
  export type InternalSign = {
4
7
  init: (algorithm: string) => void;
@@ -15,3 +18,27 @@ export type InternalVerify = {
15
18
  export type CreateSignMethod = () => InternalSign;
16
19
 
17
20
  export type CreateVerifyMethod = () => InternalVerify;
21
+
22
+ export enum DSASigEnc {
23
+ kSigEncDER,
24
+ kSigEncP1363,
25
+ }
26
+
27
+ export enum SignMode {
28
+ kSignJobModeSign,
29
+ kSignJobModeVerify,
30
+ }
31
+
32
+ export type SignVerify = (
33
+ mode: SignMode,
34
+ handle: KeyObjectHandle,
35
+ unused1: undefined,
36
+ unused2: undefined,
37
+ unused3: undefined,
38
+ data: ArrayBuffer,
39
+ digest: string | undefined,
40
+ salt_length: number | undefined,
41
+ padding: number | undefined,
42
+ dsa_encoding: DSASigEnc | undefined,
43
+ signature: ArrayBuffer | undefined
44
+ ) => ArrayBuffer | boolean;
@@ -7,6 +7,7 @@ import type {
7
7
  KWebCryptoKeyFormat,
8
8
  NamedCurve,
9
9
  } from '../keys';
10
+ import type { SignVerify } from './sig';
10
11
 
11
12
  type KeyDetail = {
12
13
  length?: number;
@@ -43,4 +44,5 @@ type CreateKeyObjectHandle = () => KeyObjectHandle;
43
44
  export type webcrypto = {
44
45
  ecExportKey: ECExportKey;
45
46
  createKeyObjectHandle: CreateKeyObjectHandle;
47
+ signVerify: SignVerify;
46
48
  };
package/src/Utils.ts CHANGED
@@ -508,6 +508,8 @@ export const normalizeAlgorithm = (
508
508
 
509
509
  // 4.
510
510
  let algName = algorithm.name;
511
+ // @ts-expect-error
512
+ if (algName === undefined) return { name: undefined };
511
513
 
512
514
  // 5.
513
515
  let desiredType: string | null | undefined;
@@ -600,6 +602,16 @@ export const validateByteLength = (
600
602
  }
601
603
  };
602
604
 
605
+ export const getUsagesUnion = (usageSet: KeyUsage[], ...usages: KeyUsage[]) => {
606
+ const newset: KeyUsage[] = [];
607
+ for (let n = 0; n < usages.length; n++) {
608
+ if (!usages[n] || usages[n] === undefined) continue;
609
+ if (usageSet.includes(usages[n] as KeyUsage))
610
+ newset.push(usages[n] as KeyUsage);
611
+ }
612
+ return newset;
613
+ };
614
+
603
615
  const kKeyOps: {
604
616
  [key in KeyUsage]: number;
605
617
  } = {
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
+ };