react-native-quick-crypto 1.0.11 → 1.0.13

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 (197) hide show
  1. package/android/CMakeLists.txt +7 -0
  2. package/cpp/cipher/CCMCipher.cpp +4 -1
  3. package/cpp/cipher/ChaCha20Cipher.cpp +3 -1
  4. package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +5 -5
  5. package/cpp/cipher/ChaCha20Poly1305Cipher.hpp +1 -2
  6. package/cpp/cipher/HybridCipher.cpp +10 -1
  7. package/cpp/cipher/HybridCipher.hpp +2 -0
  8. package/cpp/cipher/HybridRsaCipher.cpp +0 -13
  9. package/cpp/cipher/XChaCha20Poly1305Cipher.cpp +7 -5
  10. package/cpp/cipher/XChaCha20Poly1305Cipher.hpp +1 -2
  11. package/cpp/cipher/XSalsa20Cipher.cpp +4 -0
  12. package/cpp/cipher/XSalsa20Poly1305Cipher.cpp +7 -5
  13. package/cpp/cipher/XSalsa20Poly1305Cipher.hpp +1 -2
  14. package/cpp/ecdh/HybridECDH.cpp +20 -133
  15. package/cpp/keys/HybridKeyObjectHandle.cpp +144 -141
  16. package/cpp/keys/HybridKeyObjectHandle.hpp +6 -3
  17. package/cpp/keys/KeyObjectData.hpp +2 -0
  18. package/cpp/kmac/HybridKmac.cpp +83 -0
  19. package/cpp/kmac/HybridKmac.hpp +31 -0
  20. package/cpp/mldsa/HybridMlDsaKeyPair.cpp +11 -20
  21. package/cpp/mldsa/HybridMlDsaKeyPair.hpp +4 -2
  22. package/cpp/mlkem/HybridMlKemKeyPair.cpp +319 -0
  23. package/cpp/mlkem/HybridMlKemKeyPair.hpp +48 -0
  24. package/cpp/sign/SignUtils.hpp +9 -26
  25. package/cpp/utils/QuickCryptoUtils.cpp +44 -0
  26. package/cpp/utils/QuickCryptoUtils.hpp +39 -0
  27. package/cpp/x509/HybridX509Certificate.cpp +174 -0
  28. package/cpp/x509/HybridX509Certificate.hpp +51 -0
  29. package/lib/commonjs/cipher.js +15 -2
  30. package/lib/commonjs/cipher.js.map +1 -1
  31. package/lib/commonjs/dhKeyPair.js +3 -3
  32. package/lib/commonjs/dhKeyPair.js.map +1 -1
  33. package/lib/commonjs/dsa.js +3 -3
  34. package/lib/commonjs/dsa.js.map +1 -1
  35. package/lib/commonjs/ec.js +18 -18
  36. package/lib/commonjs/ec.js.map +1 -1
  37. package/lib/commonjs/ed.js +9 -9
  38. package/lib/commonjs/ed.js.map +1 -1
  39. package/lib/commonjs/hash.js +17 -12
  40. package/lib/commonjs/hash.js.map +1 -1
  41. package/lib/commonjs/hkdf.js.map +1 -1
  42. package/lib/commonjs/index.js +22 -0
  43. package/lib/commonjs/index.js.map +1 -1
  44. package/lib/commonjs/keys/classes.js +2 -2
  45. package/lib/commonjs/keys/classes.js.map +1 -1
  46. package/lib/commonjs/keys/index.js +24 -0
  47. package/lib/commonjs/keys/index.js.map +1 -1
  48. package/lib/commonjs/keys/publicCipher.js +2 -2
  49. package/lib/commonjs/keys/publicCipher.js.map +1 -1
  50. package/lib/commonjs/keys/signVerify.js +0 -2
  51. package/lib/commonjs/keys/signVerify.js.map +1 -1
  52. package/lib/commonjs/mlkem.js +219 -0
  53. package/lib/commonjs/mlkem.js.map +1 -0
  54. package/lib/commonjs/pbkdf2.js +18 -1
  55. package/lib/commonjs/pbkdf2.js.map +1 -1
  56. package/lib/commonjs/rsa.js +7 -7
  57. package/lib/commonjs/rsa.js.map +1 -1
  58. package/lib/commonjs/specs/kmac.nitro.js +6 -0
  59. package/lib/commonjs/specs/kmac.nitro.js.map +1 -0
  60. package/lib/commonjs/specs/mlKemKeyPair.nitro.js +6 -0
  61. package/lib/commonjs/specs/mlKemKeyPair.nitro.js.map +1 -0
  62. package/lib/commonjs/specs/x509certificate.nitro.js +6 -0
  63. package/lib/commonjs/specs/x509certificate.nitro.js.map +1 -0
  64. package/lib/commonjs/subtle.js +292 -112
  65. package/lib/commonjs/subtle.js.map +1 -1
  66. package/lib/commonjs/utils/conversion.js +3 -3
  67. package/lib/commonjs/utils/conversion.js.map +1 -1
  68. package/lib/commonjs/utils/hashnames.js +31 -0
  69. package/lib/commonjs/utils/hashnames.js.map +1 -1
  70. package/lib/commonjs/utils/types.js.map +1 -1
  71. package/lib/commonjs/x509certificate.js +189 -0
  72. package/lib/commonjs/x509certificate.js.map +1 -0
  73. package/lib/module/cipher.js +16 -3
  74. package/lib/module/cipher.js.map +1 -1
  75. package/lib/module/dhKeyPair.js +1 -1
  76. package/lib/module/dhKeyPair.js.map +1 -1
  77. package/lib/module/dsa.js +1 -1
  78. package/lib/module/dsa.js.map +1 -1
  79. package/lib/module/ec.js +6 -6
  80. package/lib/module/ec.js.map +1 -1
  81. package/lib/module/ed.js +1 -1
  82. package/lib/module/ed.js.map +1 -1
  83. package/lib/module/hash.js +17 -12
  84. package/lib/module/hash.js.map +1 -1
  85. package/lib/module/hkdf.js.map +1 -1
  86. package/lib/module/index.js +6 -0
  87. package/lib/module/index.js.map +1 -1
  88. package/lib/module/keys/classes.js +2 -2
  89. package/lib/module/keys/classes.js.map +1 -1
  90. package/lib/module/keys/index.js +25 -1
  91. package/lib/module/keys/index.js.map +1 -1
  92. package/lib/module/keys/publicCipher.js +2 -2
  93. package/lib/module/keys/publicCipher.js.map +1 -1
  94. package/lib/module/keys/signVerify.js +0 -2
  95. package/lib/module/keys/signVerify.js.map +1 -1
  96. package/lib/module/mlkem.js +211 -0
  97. package/lib/module/mlkem.js.map +1 -0
  98. package/lib/module/pbkdf2.js +18 -1
  99. package/lib/module/pbkdf2.js.map +1 -1
  100. package/lib/module/rsa.js +1 -1
  101. package/lib/module/rsa.js.map +1 -1
  102. package/lib/module/specs/kmac.nitro.js +4 -0
  103. package/lib/module/specs/kmac.nitro.js.map +1 -0
  104. package/lib/module/specs/mlKemKeyPair.nitro.js +4 -0
  105. package/lib/module/specs/mlKemKeyPair.nitro.js.map +1 -0
  106. package/lib/module/specs/x509certificate.nitro.js +4 -0
  107. package/lib/module/specs/x509certificate.nitro.js.map +1 -0
  108. package/lib/module/subtle.js +292 -112
  109. package/lib/module/subtle.js.map +1 -1
  110. package/lib/module/utils/conversion.js +3 -4
  111. package/lib/module/utils/conversion.js.map +1 -1
  112. package/lib/module/utils/hashnames.js +31 -0
  113. package/lib/module/utils/hashnames.js.map +1 -1
  114. package/lib/module/utils/types.js.map +1 -1
  115. package/lib/module/x509certificate.js +184 -0
  116. package/lib/module/x509certificate.js.map +1 -0
  117. package/lib/tsconfig.tsbuildinfo +1 -1
  118. package/lib/typescript/cipher.d.ts +3 -0
  119. package/lib/typescript/cipher.d.ts.map +1 -1
  120. package/lib/typescript/dhKeyPair.d.ts +1 -1
  121. package/lib/typescript/dhKeyPair.d.ts.map +1 -1
  122. package/lib/typescript/dsa.d.ts +1 -1
  123. package/lib/typescript/dsa.d.ts.map +1 -1
  124. package/lib/typescript/ec.d.ts +1 -1
  125. package/lib/typescript/ec.d.ts.map +1 -1
  126. package/lib/typescript/ed.d.ts +1 -1
  127. package/lib/typescript/ed.d.ts.map +1 -1
  128. package/lib/typescript/hash.d.ts.map +1 -1
  129. package/lib/typescript/hkdf.d.ts +2 -6
  130. package/lib/typescript/hkdf.d.ts.map +1 -1
  131. package/lib/typescript/index.d.ts +15 -4
  132. package/lib/typescript/index.d.ts.map +1 -1
  133. package/lib/typescript/keys/classes.d.ts +5 -5
  134. package/lib/typescript/keys/classes.d.ts.map +1 -1
  135. package/lib/typescript/keys/index.d.ts +2 -2
  136. package/lib/typescript/keys/index.d.ts.map +1 -1
  137. package/lib/typescript/keys/signVerify.d.ts.map +1 -1
  138. package/lib/typescript/mlkem.d.ts +30 -0
  139. package/lib/typescript/mlkem.d.ts.map +1 -0
  140. package/lib/typescript/pbkdf2.d.ts +2 -2
  141. package/lib/typescript/pbkdf2.d.ts.map +1 -1
  142. package/lib/typescript/rsa.d.ts +1 -1
  143. package/lib/typescript/rsa.d.ts.map +1 -1
  144. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +1 -0
  145. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
  146. package/lib/typescript/specs/kmac.nitro.d.ts +10 -0
  147. package/lib/typescript/specs/kmac.nitro.d.ts.map +1 -0
  148. package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts +18 -0
  149. package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts.map +1 -0
  150. package/lib/typescript/specs/x509certificate.nitro.d.ts +34 -0
  151. package/lib/typescript/specs/x509certificate.nitro.d.ts.map +1 -0
  152. package/lib/typescript/subtle.d.ts +10 -0
  153. package/lib/typescript/subtle.d.ts.map +1 -1
  154. package/lib/typescript/utils/conversion.d.ts.map +1 -1
  155. package/lib/typescript/utils/hashnames.d.ts +1 -1
  156. package/lib/typescript/utils/hashnames.d.ts.map +1 -1
  157. package/lib/typescript/utils/types.d.ts +13 -7
  158. package/lib/typescript/utils/types.d.ts.map +1 -1
  159. package/lib/typescript/x509certificate.d.ts +64 -0
  160. package/lib/typescript/x509certificate.d.ts.map +1 -0
  161. package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +3 -0
  162. package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +30 -0
  163. package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +30 -0
  164. package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +12 -0
  165. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +1 -0
  166. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +1 -0
  167. package/nitrogen/generated/shared/c++/HybridKmacSpec.cpp +23 -0
  168. package/nitrogen/generated/shared/c++/HybridKmacSpec.hpp +66 -0
  169. package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.cpp +31 -0
  170. package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.hpp +74 -0
  171. package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.cpp +46 -0
  172. package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.hpp +96 -0
  173. package/package.json +4 -1
  174. package/src/cipher.ts +17 -3
  175. package/src/dhKeyPair.ts +1 -1
  176. package/src/dsa.ts +1 -1
  177. package/src/ec.ts +9 -9
  178. package/src/ed.ts +2 -2
  179. package/src/hash.ts +34 -11
  180. package/src/hkdf.ts +2 -7
  181. package/src/index.ts +7 -0
  182. package/src/keys/classes.ts +10 -9
  183. package/src/keys/index.ts +37 -2
  184. package/src/keys/publicCipher.ts +2 -2
  185. package/src/keys/signVerify.ts +0 -5
  186. package/src/mlkem.ts +350 -0
  187. package/src/pbkdf2.ts +34 -5
  188. package/src/rsa.ts +1 -1
  189. package/src/specs/keyObjectHandle.nitro.ts +5 -0
  190. package/src/specs/kmac.nitro.ts +12 -0
  191. package/src/specs/mlKemKeyPair.nitro.ts +32 -0
  192. package/src/specs/x509certificate.nitro.ts +38 -0
  193. package/src/subtle.ts +551 -125
  194. package/src/utils/conversion.ts +10 -4
  195. package/src/utils/hashnames.ts +33 -2
  196. package/src/utils/types.ts +42 -5
  197. package/src/x509certificate.ts +277 -0
package/src/subtle.ts CHANGED
@@ -48,6 +48,8 @@ import {
48
48
  import { rsa_generateKeyPair } from './rsa';
49
49
  import { getRandomValues } from './random';
50
50
  import { createHmac } from './hmac';
51
+ import type { Kmac } from './specs/kmac.nitro';
52
+ import { timingSafeEqual } from './utils/timingSafeEqual';
51
53
  import { createSign, createVerify } from './keys/signVerify';
52
54
  import {
53
55
  ed_generateKeyPairWebCrypto,
@@ -56,6 +58,12 @@ import {
56
58
  Ed,
57
59
  } from './ed';
58
60
  import { mldsa_generateKeyPairWebCrypto, type MlDsaVariant } from './mldsa';
61
+ import {
62
+ mlkem_generateKeyPairWebCrypto,
63
+ type MlKemVariant,
64
+ MlKem,
65
+ } from './mlkem';
66
+ import type { EncapsulateResult } from './utils';
59
67
  import { hkdfDeriveBits, type HkdfAlgorithm } from './hkdf';
60
68
  // Temporary enums that need to be defined
61
69
 
@@ -699,6 +707,164 @@ async function hmacGenerateKey(
699
707
  return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
700
708
  }
701
709
 
710
+ async function kmacGenerateKey(
711
+ algorithm: SubtleAlgorithm,
712
+ extractable: boolean,
713
+ keyUsages: KeyUsage[],
714
+ ): Promise<CryptoKey> {
715
+ const { name } = algorithm;
716
+
717
+ if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
718
+ throw lazyDOMException(
719
+ `Unsupported key usage for ${name} key`,
720
+ 'SyntaxError',
721
+ );
722
+ }
723
+
724
+ const defaultLength = name === 'KMAC128' ? 128 : 256;
725
+ const length = algorithm.length ?? defaultLength;
726
+
727
+ if (length === 0) {
728
+ throw lazyDOMException(
729
+ 'Zero-length key is not supported',
730
+ 'OperationError',
731
+ );
732
+ }
733
+
734
+ const keyBytes = new Uint8Array(Math.ceil(length / 8));
735
+ getRandomValues(keyBytes);
736
+
737
+ const keyObject = createSecretKey(keyBytes);
738
+
739
+ const keyAlgorithm: SubtleAlgorithm = { name: name as AnyAlgorithm, length };
740
+
741
+ return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
742
+ }
743
+
744
+ function kmacSignVerify(
745
+ key: CryptoKey,
746
+ data: BufferLike,
747
+ algorithm: SubtleAlgorithm,
748
+ signature?: BufferLike,
749
+ ): ArrayBuffer | boolean {
750
+ const { name } = algorithm;
751
+
752
+ const defaultLength = name === 'KMAC128' ? 256 : 512;
753
+ const outputLengthBits = algorithm.length ?? defaultLength;
754
+
755
+ if (outputLengthBits % 8 !== 0) {
756
+ throw lazyDOMException(
757
+ 'KMAC output length must be a multiple of 8',
758
+ 'OperationError',
759
+ );
760
+ }
761
+
762
+ const outputLengthBytes = outputLengthBits / 8;
763
+
764
+ const keyData = key.keyObject.export();
765
+
766
+ const kmac = NitroModules.createHybridObject<Kmac>('Kmac');
767
+
768
+ let customizationBuffer: ArrayBuffer | undefined;
769
+ if (algorithm.customization !== undefined) {
770
+ customizationBuffer = bufferLikeToArrayBuffer(algorithm.customization);
771
+ }
772
+
773
+ kmac.createKmac(
774
+ name,
775
+ bufferLikeToArrayBuffer(keyData),
776
+ outputLengthBytes,
777
+ customizationBuffer,
778
+ );
779
+ kmac.update(bufferLikeToArrayBuffer(data));
780
+ const computed = kmac.digest();
781
+
782
+ if (signature === undefined) {
783
+ return computed;
784
+ }
785
+
786
+ const sigBuffer = bufferLikeToArrayBuffer(signature);
787
+ if (computed.byteLength !== sigBuffer.byteLength) {
788
+ return false;
789
+ }
790
+
791
+ return timingSafeEqual(new Uint8Array(computed), new Uint8Array(sigBuffer));
792
+ }
793
+
794
+ async function kmacImportKey(
795
+ algorithm: SubtleAlgorithm,
796
+ format: ImportFormat,
797
+ data: BufferLike | JWK,
798
+ extractable: boolean,
799
+ keyUsages: KeyUsage[],
800
+ ): Promise<CryptoKey> {
801
+ const { name } = algorithm;
802
+
803
+ if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
804
+ throw lazyDOMException(
805
+ `Unsupported key usage for ${name} key`,
806
+ 'SyntaxError',
807
+ );
808
+ }
809
+
810
+ let keyObject: KeyObject;
811
+
812
+ if (format === 'jwk') {
813
+ const jwk = data as JWK;
814
+
815
+ if (!jwk || typeof jwk !== 'object') {
816
+ throw lazyDOMException('Invalid keyData', 'DataError');
817
+ }
818
+
819
+ if (jwk.kty !== 'oct') {
820
+ throw lazyDOMException('Invalid JWK format for KMAC key', 'DataError');
821
+ }
822
+
823
+ const expectedAlg = name === 'KMAC128' ? 'K128' : 'K256';
824
+ if (jwk.alg !== undefined && jwk.alg !== expectedAlg) {
825
+ throw lazyDOMException(
826
+ 'JWK "alg" does not match the requested algorithm',
827
+ 'DataError',
828
+ );
829
+ }
830
+
831
+ const handle =
832
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
833
+ const keyType = handle.initJwk(jwk, undefined);
834
+
835
+ if (keyType === undefined || keyType !== 0) {
836
+ throw lazyDOMException('Failed to import KMAC JWK', 'DataError');
837
+ }
838
+
839
+ keyObject = new SecretKeyObject(handle);
840
+ } else if (format === 'raw' || format === 'raw-secret') {
841
+ keyObject = createSecretKey(data as BinaryLike);
842
+ } else {
843
+ throw lazyDOMException(
844
+ `Unable to import ${name} key with format ${format}`,
845
+ 'NotSupportedError',
846
+ );
847
+ }
848
+
849
+ const exported = keyObject.export();
850
+ const keyLength = exported.byteLength * 8;
851
+
852
+ if (keyLength === 0) {
853
+ throw lazyDOMException('Zero-length key is not supported', 'DataError');
854
+ }
855
+
856
+ if (algorithm.length !== undefined && algorithm.length !== keyLength) {
857
+ throw lazyDOMException('Invalid key length', 'DataError');
858
+ }
859
+
860
+ const keyAlgorithm: SubtleAlgorithm = {
861
+ name: name as AnyAlgorithm,
862
+ length: keyLength,
863
+ };
864
+
865
+ return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
866
+ }
867
+
702
868
  function rsaImportKey(
703
869
  format: ImportFormat,
704
870
  data: BufferLike | JWK,
@@ -1019,6 +1185,49 @@ function edImportKey(
1019
1185
  return new CryptoKey(keyObject, { name }, keyUsages, extractable);
1020
1186
  }
1021
1187
 
1188
+ function pqcImportKeyObject(
1189
+ format: ImportFormat,
1190
+ data: BufferLike,
1191
+ name: string,
1192
+ ): KeyObject {
1193
+ if (format === 'spki') {
1194
+ return KeyObject.createKeyObject(
1195
+ 'public',
1196
+ bufferLikeToArrayBuffer(data),
1197
+ KFormatType.DER,
1198
+ KeyEncoding.SPKI,
1199
+ );
1200
+ } else if (format === 'pkcs8') {
1201
+ return KeyObject.createKeyObject(
1202
+ 'private',
1203
+ bufferLikeToArrayBuffer(data),
1204
+ KFormatType.DER,
1205
+ KeyEncoding.PKCS8,
1206
+ );
1207
+ } else if (format === 'raw') {
1208
+ const handle =
1209
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
1210
+ if (!handle.initPqcRaw(name, bufferLikeToArrayBuffer(data), true)) {
1211
+ throw lazyDOMException(
1212
+ `Failed to import ${name} raw public key`,
1213
+ 'DataError',
1214
+ );
1215
+ }
1216
+ return new PublicKeyObject(handle);
1217
+ } else if (format === 'raw-seed') {
1218
+ const handle =
1219
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
1220
+ if (!handle.initPqcRaw(name, bufferLikeToArrayBuffer(data), false)) {
1221
+ throw lazyDOMException(`Failed to import ${name} raw seed`, 'DataError');
1222
+ }
1223
+ return new PrivateKeyObject(handle);
1224
+ }
1225
+ throw lazyDOMException(
1226
+ `Unsupported format for ${name} import: ${format}`,
1227
+ 'NotSupportedError',
1228
+ );
1229
+ }
1230
+
1022
1231
  function mldsaImportKey(
1023
1232
  format: ImportFormat,
1024
1233
  data: BufferLike,
@@ -1027,43 +1236,45 @@ function mldsaImportKey(
1027
1236
  keyUsages: KeyUsage[],
1028
1237
  ): CryptoKey {
1029
1238
  const { name } = algorithm;
1030
-
1031
- // Validate usages
1032
- if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
1239
+ const isPublicFormat = format === 'spki' || format === 'raw';
1240
+ if (hasAnyNotIn(keyUsages, isPublicFormat ? ['verify'] : ['sign'])) {
1033
1241
  throw lazyDOMException(
1034
1242
  `Unsupported key usage for ${name} key`,
1035
1243
  'SyntaxError',
1036
1244
  );
1037
1245
  }
1246
+ return new CryptoKey(
1247
+ pqcImportKeyObject(format, data, name),
1248
+ { name },
1249
+ keyUsages,
1250
+ extractable,
1251
+ );
1252
+ }
1038
1253
 
1039
- let keyObject: KeyObject;
1040
-
1041
- if (format === 'spki') {
1042
- // Import public key
1043
- const keyData = bufferLikeToArrayBuffer(data);
1044
- keyObject = KeyObject.createKeyObject(
1045
- 'public',
1046
- keyData,
1047
- KFormatType.DER,
1048
- KeyEncoding.SPKI,
1049
- );
1050
- } else if (format === 'pkcs8') {
1051
- // Import private key
1052
- const keyData = bufferLikeToArrayBuffer(data);
1053
- keyObject = KeyObject.createKeyObject(
1054
- 'private',
1055
- keyData,
1056
- KFormatType.DER,
1057
- KeyEncoding.PKCS8,
1058
- );
1059
- } else {
1254
+ function mlkemImportKey(
1255
+ format: ImportFormat,
1256
+ data: BufferLike,
1257
+ algorithm: SubtleAlgorithm,
1258
+ extractable: boolean,
1259
+ keyUsages: KeyUsage[],
1260
+ ): CryptoKey {
1261
+ const { name } = algorithm;
1262
+ const isPublicFormat = format === 'spki' || format === 'raw';
1263
+ const allowedUsages: KeyUsage[] = isPublicFormat
1264
+ ? ['encapsulateBits', 'encapsulateKey']
1265
+ : ['decapsulateBits', 'decapsulateKey'];
1266
+ if (hasAnyNotIn(keyUsages, allowedUsages)) {
1060
1267
  throw lazyDOMException(
1061
- `Unsupported format for ${name} import: ${format}`,
1062
- 'NotSupportedError',
1268
+ `Unsupported key usage for ${name} key`,
1269
+ 'SyntaxError',
1063
1270
  );
1064
1271
  }
1065
-
1066
- return new CryptoKey(keyObject, { name }, keyUsages, extractable);
1272
+ return new CryptoKey(
1273
+ pqcImportKeyObject(format, data, name),
1274
+ { name },
1275
+ keyUsages,
1276
+ extractable,
1277
+ );
1067
1278
  }
1068
1279
 
1069
1280
  const exportKeySpki = async (
@@ -1112,6 +1323,17 @@ const exportKeySpki = async (
1112
1323
  );
1113
1324
  }
1114
1325
  break;
1326
+ case 'ML-KEM-512':
1327
+ // Fall through
1328
+ case 'ML-KEM-768':
1329
+ // Fall through
1330
+ case 'ML-KEM-1024':
1331
+ if (key.type === 'public') {
1332
+ return bufferLikeToArrayBuffer(
1333
+ key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI),
1334
+ );
1335
+ }
1336
+ break;
1115
1337
  }
1116
1338
 
1117
1339
  throw new Error(
@@ -1165,6 +1387,17 @@ const exportKeyPkcs8 = async (
1165
1387
  );
1166
1388
  }
1167
1389
  break;
1390
+ case 'ML-KEM-512':
1391
+ // Fall through
1392
+ case 'ML-KEM-768':
1393
+ // Fall through
1394
+ case 'ML-KEM-1024':
1395
+ if (key.type === 'private') {
1396
+ return bufferLikeToArrayBuffer(
1397
+ key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8),
1398
+ );
1399
+ }
1400
+ break;
1168
1401
  }
1169
1402
 
1170
1403
  throw new Error(
@@ -1189,7 +1422,22 @@ const exportKeyRaw = (key: CryptoKey): ArrayBuffer | unknown => {
1189
1422
  // Fall through
1190
1423
  case 'X448':
1191
1424
  if (key.type === 'public') {
1192
- // Export raw public key
1425
+ const exported = key.keyObject.handle.exportKey();
1426
+ return bufferLikeToArrayBuffer(exported);
1427
+ }
1428
+ break;
1429
+ case 'ML-KEM-512':
1430
+ // Fall through
1431
+ case 'ML-KEM-768':
1432
+ // Fall through
1433
+ case 'ML-KEM-1024':
1434
+ // Fall through
1435
+ case 'ML-DSA-44':
1436
+ // Fall through
1437
+ case 'ML-DSA-65':
1438
+ // Fall through
1439
+ case 'ML-DSA-87':
1440
+ if (key.type === 'public') {
1193
1441
  const exported = key.keyObject.handle.exportKey();
1194
1442
  return bufferLikeToArrayBuffer(exported);
1195
1443
  }
@@ -1206,7 +1454,11 @@ const exportKeyRaw = (key: CryptoKey): ArrayBuffer | unknown => {
1206
1454
  // Fall through
1207
1455
  case 'ChaCha20-Poly1305':
1208
1456
  // Fall through
1209
- case 'HMAC': {
1457
+ case 'HMAC':
1458
+ // Fall through
1459
+ case 'KMAC128':
1460
+ // Fall through
1461
+ case 'KMAC256': {
1210
1462
  const exported = key.keyObject.export();
1211
1463
  // Convert Buffer to ArrayBuffer
1212
1464
  return exported.buffer.slice(
@@ -1243,6 +1495,12 @@ const exportKeyJWK = (key: CryptoKey): ArrayBuffer | unknown => {
1243
1495
  case 'HMAC':
1244
1496
  jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkHmac);
1245
1497
  return jwk;
1498
+ case 'KMAC128':
1499
+ jwk.alg = 'K128';
1500
+ return jwk;
1501
+ case 'KMAC256':
1502
+ jwk.alg = 'K256';
1503
+ return jwk;
1246
1504
  case 'ECDSA':
1247
1505
  // Fall through
1248
1506
  case 'ECDH':
@@ -1429,24 +1687,20 @@ function hmacSignVerify(
1429
1687
  );
1430
1688
  }
1431
1689
 
1432
- // Verify operation - compare computed HMAC with provided signature
1433
- const sigBytes = new Uint8Array(bufferLikeToArrayBuffer(signature));
1434
- const computedBytes = new Uint8Array(
1435
- computed.buffer,
1690
+ const sigBuffer = bufferLikeToArrayBuffer(signature);
1691
+ const computedBuffer = computed.buffer.slice(
1436
1692
  computed.byteOffset,
1437
- computed.byteLength,
1693
+ computed.byteOffset + computed.byteLength,
1438
1694
  );
1439
1695
 
1440
- if (computedBytes.length !== sigBytes.length) {
1696
+ if (computedBuffer.byteLength !== sigBuffer.byteLength) {
1441
1697
  return false;
1442
1698
  }
1443
1699
 
1444
- // Constant-time comparison to prevent timing attacks
1445
- let result = 0;
1446
- for (let i = 0; i < computedBytes.length; i++) {
1447
- result |= computedBytes[i]! ^ sigBytes[i]!;
1448
- }
1449
- return result === 0;
1700
+ return timingSafeEqual(
1701
+ new Uint8Array(computedBuffer),
1702
+ new Uint8Array(sigBuffer),
1703
+ );
1450
1704
  }
1451
1705
 
1452
1706
  function rsaSignVerify(
@@ -1589,6 +1843,9 @@ const signVerify = (
1589
1843
  case 'ML-DSA-65':
1590
1844
  case 'ML-DSA-87':
1591
1845
  return mldsaSignVerify(key, data, signature);
1846
+ case 'KMAC128':
1847
+ case 'KMAC256':
1848
+ return kmacSignVerify(key, data, algorithm, signature);
1592
1849
  }
1593
1850
  throw lazyDOMException(
1594
1851
  `Unrecognized algorithm name '${algorithm.name}' for '${usage}'`,
@@ -1660,6 +1917,8 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
1660
1917
  'RSA-PSS',
1661
1918
  'ECDSA',
1662
1919
  'HMAC',
1920
+ 'KMAC128',
1921
+ 'KMAC256',
1663
1922
  'Ed25519',
1664
1923
  'Ed448',
1665
1924
  'ML-DSA-44',
@@ -1671,13 +1930,25 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
1671
1930
  'RSA-PSS',
1672
1931
  'ECDSA',
1673
1932
  'HMAC',
1933
+ 'KMAC128',
1934
+ 'KMAC256',
1674
1935
  'Ed25519',
1675
1936
  'Ed448',
1676
1937
  'ML-DSA-44',
1677
1938
  'ML-DSA-65',
1678
1939
  'ML-DSA-87',
1679
1940
  ]),
1680
- digest: new Set(['SHA-1', 'SHA-256', 'SHA-384', 'SHA-512']),
1941
+ digest: new Set([
1942
+ 'SHA-1',
1943
+ 'SHA-256',
1944
+ 'SHA-384',
1945
+ 'SHA-512',
1946
+ 'SHA3-256',
1947
+ 'SHA3-384',
1948
+ 'SHA3-512',
1949
+ 'cSHAKE128',
1950
+ 'cSHAKE256',
1951
+ ]),
1681
1952
  generateKey: new Set([
1682
1953
  'RSASSA-PKCS1-v1_5',
1683
1954
  'RSA-PSS',
@@ -1695,9 +1966,14 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
1695
1966
  'AES-OCB',
1696
1967
  'ChaCha20-Poly1305',
1697
1968
  'HMAC',
1969
+ 'KMAC128',
1970
+ 'KMAC256',
1698
1971
  'ML-DSA-44',
1699
1972
  'ML-DSA-65',
1700
1973
  'ML-DSA-87',
1974
+ 'ML-KEM-512',
1975
+ 'ML-KEM-768',
1976
+ 'ML-KEM-1024',
1701
1977
  ]),
1702
1978
  importKey: new Set([
1703
1979
  'RSASSA-PKCS1-v1_5',
@@ -1716,6 +1992,8 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
1716
1992
  'AES-OCB',
1717
1993
  'ChaCha20-Poly1305',
1718
1994
  'HMAC',
1995
+ 'KMAC128',
1996
+ 'KMAC256',
1719
1997
  'HKDF',
1720
1998
  'PBKDF2',
1721
1999
  'Argon2d',
@@ -1724,6 +2002,9 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
1724
2002
  'ML-DSA-44',
1725
2003
  'ML-DSA-65',
1726
2004
  'ML-DSA-87',
2005
+ 'ML-KEM-512',
2006
+ 'ML-KEM-768',
2007
+ 'ML-KEM-1024',
1727
2008
  ]),
1728
2009
  exportKey: new Set([
1729
2010
  'RSASSA-PKCS1-v1_5',
@@ -1742,9 +2023,14 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
1742
2023
  'AES-OCB',
1743
2024
  'ChaCha20-Poly1305',
1744
2025
  'HMAC',
2026
+ 'KMAC128',
2027
+ 'KMAC256',
1745
2028
  'ML-DSA-44',
1746
2029
  'ML-DSA-65',
1747
2030
  'ML-DSA-87',
2031
+ 'ML-KEM-512',
2032
+ 'ML-KEM-768',
2033
+ 'ML-KEM-1024',
1748
2034
  ]),
1749
2035
  deriveBits: new Set([
1750
2036
  'PBKDF2',
@@ -1774,6 +2060,10 @@ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
1774
2060
  'ChaCha20-Poly1305',
1775
2061
  'RSA-OAEP',
1776
2062
  ]),
2063
+ encapsulateBits: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
2064
+ decapsulateBits: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
2065
+ encapsulateKey: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
2066
+ decapsulateKey: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
1777
2067
  };
1778
2068
 
1779
2069
  const ASYMMETRIC_ALGORITHMS = new Set([
@@ -1789,6 +2079,9 @@ const ASYMMETRIC_ALGORITHMS = new Set([
1789
2079
  'ML-DSA-44',
1790
2080
  'ML-DSA-65',
1791
2081
  'ML-DSA-87',
2082
+ 'ML-KEM-512',
2083
+ 'ML-KEM-768',
2084
+ 'ML-KEM-1024',
1792
2085
  ]);
1793
2086
 
1794
2087
  export class Subtle {
@@ -1989,6 +2282,31 @@ export class Subtle {
1989
2282
  ): Promise<ArrayBuffer | JWK> {
1990
2283
  if (!key.extractable) throw new Error('key is not extractable');
1991
2284
 
2285
+ if (format === 'raw-seed') {
2286
+ const pqcAlgos = [
2287
+ 'ML-KEM-512',
2288
+ 'ML-KEM-768',
2289
+ 'ML-KEM-1024',
2290
+ 'ML-DSA-44',
2291
+ 'ML-DSA-65',
2292
+ 'ML-DSA-87',
2293
+ ];
2294
+ if (!pqcAlgos.includes(key.algorithm.name)) {
2295
+ throw lazyDOMException(
2296
+ 'raw-seed export only supported for PQC keys',
2297
+ 'NotSupportedError',
2298
+ );
2299
+ }
2300
+ if (key.type !== 'private') {
2301
+ throw lazyDOMException(
2302
+ 'raw-seed export requires a private key',
2303
+ 'InvalidAccessError',
2304
+ );
2305
+ }
2306
+ return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey());
2307
+ }
2308
+
2309
+ // Note: 'raw-seed' is handled above; do NOT normalize it here
1992
2310
  if (format === 'raw-secret' || format === 'raw-public') format = 'raw';
1993
2311
 
1994
2312
  switch (format) {
@@ -2176,6 +2494,11 @@ export class Subtle {
2176
2494
  case 'HMAC':
2177
2495
  result = await hmacGenerateKey(algorithm, extractable, keyUsages);
2178
2496
  break;
2497
+ case 'KMAC128':
2498
+ // Fall through
2499
+ case 'KMAC256':
2500
+ result = await kmacGenerateKey(algorithm, extractable, keyUsages);
2501
+ break;
2179
2502
  case 'Ed25519':
2180
2503
  // Fall through
2181
2504
  case 'Ed448':
@@ -2208,6 +2531,18 @@ export class Subtle {
2208
2531
  );
2209
2532
  checkCryptoKeyPairUsages(result as CryptoKeyPair);
2210
2533
  break;
2534
+ case 'ML-KEM-512':
2535
+ // Fall through
2536
+ case 'ML-KEM-768':
2537
+ // Fall through
2538
+ case 'ML-KEM-1024':
2539
+ result = await mlkem_generateKeyPairWebCrypto(
2540
+ algorithm.name as MlKemVariant,
2541
+ extractable,
2542
+ keyUsages,
2543
+ );
2544
+ checkCryptoKeyPairUsages(result as CryptoKeyPair);
2545
+ break;
2211
2546
  default:
2212
2547
  throw new Error(
2213
2548
  `'subtle.generateKey()' is not implemented for ${algorithm.name}.
@@ -2240,6 +2575,7 @@ export class Subtle {
2240
2575
  extractable: boolean,
2241
2576
  keyUsages: KeyUsage[],
2242
2577
  ): Promise<CryptoKey> {
2578
+ // Note: 'raw-seed' is NOT normalized — PQC import functions handle it directly
2243
2579
  if (format === 'raw-secret' || format === 'raw-public') format = 'raw';
2244
2580
  const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'importKey');
2245
2581
  let result: CryptoKey;
@@ -2277,6 +2613,17 @@ export class Subtle {
2277
2613
  keyUsages,
2278
2614
  );
2279
2615
  break;
2616
+ case 'KMAC128':
2617
+ // Fall through
2618
+ case 'KMAC256':
2619
+ result = await kmacImportKey(
2620
+ normalizedAlgorithm,
2621
+ format,
2622
+ data as BufferLike | JWK,
2623
+ extractable,
2624
+ keyUsages,
2625
+ );
2626
+ break;
2280
2627
  case 'AES-CTR':
2281
2628
  // Fall through
2282
2629
  case 'AES-CBC':
@@ -2345,6 +2692,19 @@ export class Subtle {
2345
2692
  keyUsages,
2346
2693
  );
2347
2694
  break;
2695
+ case 'ML-KEM-512':
2696
+ // Fall through
2697
+ case 'ML-KEM-768':
2698
+ // Fall through
2699
+ case 'ML-KEM-1024':
2700
+ result = mlkemImportKey(
2701
+ format,
2702
+ data as BufferLike,
2703
+ normalizedAlgorithm,
2704
+ extractable,
2705
+ keyUsages,
2706
+ );
2707
+ break;
2348
2708
  default:
2349
2709
  throw new Error(
2350
2710
  `"subtle.importKey()" is not implemented for ${normalizedAlgorithm.name}`,
@@ -2368,103 +2728,164 @@ export class Subtle {
2368
2728
  key: CryptoKey,
2369
2729
  data: BufferLike,
2370
2730
  ): Promise<ArrayBuffer> {
2371
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'sign');
2731
+ return signVerify(
2732
+ normalizeAlgorithm(algorithm, 'sign'),
2733
+ key,
2734
+ data,
2735
+ ) as ArrayBuffer;
2736
+ }
2372
2737
 
2373
- if (normalizedAlgorithm.name === 'HMAC') {
2374
- // Validate key usage
2375
- if (!key.usages.includes('sign')) {
2376
- throw lazyDOMException(
2377
- 'Key does not have sign usage',
2378
- 'InvalidAccessError',
2379
- );
2380
- }
2738
+ async verify(
2739
+ algorithm: SubtleAlgorithm,
2740
+ key: CryptoKey,
2741
+ signature: BufferLike,
2742
+ data: BufferLike,
2743
+ ): Promise<boolean> {
2744
+ return signVerify(
2745
+ normalizeAlgorithm(algorithm, 'verify'),
2746
+ key,
2747
+ data,
2748
+ signature,
2749
+ ) as boolean;
2750
+ }
2381
2751
 
2382
- // Get hash algorithm from key or algorithm params
2383
- // Hash can be either a string or an object with name property
2384
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2385
- const alg = normalizedAlgorithm as any;
2386
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2387
- const keyAlg = key.algorithm as any;
2388
- let hashAlgorithm = 'SHA-256';
2389
-
2390
- if (typeof alg.hash === 'string') {
2391
- hashAlgorithm = alg.hash;
2392
- } else if (alg.hash?.name) {
2393
- hashAlgorithm = alg.hash.name;
2394
- } else if (typeof keyAlg.hash === 'string') {
2395
- hashAlgorithm = keyAlg.hash;
2396
- } else if (keyAlg.hash?.name) {
2397
- hashAlgorithm = keyAlg.hash.name;
2398
- }
2752
+ private _encapsulateCore(
2753
+ algorithm: SubtleAlgorithm,
2754
+ key: CryptoKey,
2755
+ ): EncapsulateResult {
2756
+ const normalizedAlgorithm = normalizeAlgorithm(
2757
+ algorithm,
2758
+ 'encapsulateBits' as Operation,
2759
+ );
2399
2760
 
2400
- // Create HMAC and sign
2401
- const keyData = key.keyObject.export();
2402
- const hmac = createHmac(hashAlgorithm, keyData);
2403
- hmac.update(bufferLikeToArrayBuffer(data));
2404
- return bufferLikeToArrayBuffer(hmac.digest());
2761
+ if (key.algorithm.name !== normalizedAlgorithm.name) {
2762
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
2405
2763
  }
2406
2764
 
2407
- return signVerify(normalizedAlgorithm, key, data) as ArrayBuffer;
2765
+ const variant = normalizedAlgorithm.name as MlKemVariant;
2766
+ const mlkem = new MlKem(variant);
2767
+
2768
+ const keyData = key.keyObject.handle.exportKey(
2769
+ KFormatType.DER,
2770
+ KeyEncoding.SPKI,
2771
+ );
2772
+ mlkem.setPublicKey(
2773
+ bufferLikeToArrayBuffer(keyData),
2774
+ KFormatType.DER,
2775
+ KeyEncoding.SPKI,
2776
+ );
2777
+
2778
+ return mlkem.encapsulateSync();
2408
2779
  }
2409
2780
 
2410
- async verify(
2781
+ private _decapsulateCore(
2411
2782
  algorithm: SubtleAlgorithm,
2412
2783
  key: CryptoKey,
2413
- signature: BufferLike,
2414
- data: BufferLike,
2415
- ): Promise<boolean> {
2416
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'verify');
2784
+ ciphertext: BufferLike,
2785
+ ): ArrayBuffer {
2786
+ const normalizedAlgorithm = normalizeAlgorithm(
2787
+ algorithm,
2788
+ 'decapsulateBits' as Operation,
2789
+ );
2417
2790
 
2418
- if (normalizedAlgorithm.name === 'HMAC') {
2419
- // Validate key usage
2420
- if (!key.usages.includes('verify')) {
2421
- throw lazyDOMException(
2422
- 'Key does not have verify usage',
2423
- 'InvalidAccessError',
2424
- );
2425
- }
2791
+ if (key.algorithm.name !== normalizedAlgorithm.name) {
2792
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
2793
+ }
2426
2794
 
2427
- // Get hash algorithm
2428
- // Hash can be either a string or an object with name property
2429
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2430
- const alg = normalizedAlgorithm as any;
2431
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2432
- const keyAlg = key.algorithm as any;
2433
- let hashAlgorithm = 'SHA-256';
2434
-
2435
- if (typeof alg.hash === 'string') {
2436
- hashAlgorithm = alg.hash;
2437
- } else if (alg.hash?.name) {
2438
- hashAlgorithm = alg.hash.name;
2439
- } else if (typeof keyAlg.hash === 'string') {
2440
- hashAlgorithm = keyAlg.hash;
2441
- } else if (keyAlg.hash?.name) {
2442
- hashAlgorithm = keyAlg.hash.name;
2443
- }
2795
+ const variant = normalizedAlgorithm.name as MlKemVariant;
2796
+ const mlkem = new MlKem(variant);
2444
2797
 
2445
- // Create HMAC and compute expected signature
2446
- const keyData = key.keyObject.export();
2447
- const hmac = createHmac(hashAlgorithm, keyData);
2448
- const dataBuffer = bufferLikeToArrayBuffer(data);
2449
- hmac.update(dataBuffer);
2450
- const expectedDigest = hmac.digest();
2451
- const expected = new Uint8Array(bufferLikeToArrayBuffer(expectedDigest));
2452
-
2453
- // Constant-time comparison
2454
- const signatureArray = new Uint8Array(bufferLikeToArrayBuffer(signature));
2455
- if (expected.length !== signatureArray.length) {
2456
- return false;
2457
- }
2798
+ const keyData = key.keyObject.handle.exportKey(
2799
+ KFormatType.DER,
2800
+ KeyEncoding.PKCS8,
2801
+ );
2802
+ mlkem.setPrivateKey(
2803
+ bufferLikeToArrayBuffer(keyData),
2804
+ KFormatType.DER,
2805
+ KeyEncoding.PKCS8,
2806
+ );
2458
2807
 
2459
- // Manual constant-time comparison
2460
- let result = 0;
2461
- for (let i = 0; i < expected.length; i++) {
2462
- result |= expected[i]! ^ signatureArray[i]!;
2463
- }
2464
- return result === 0;
2808
+ return mlkem.decapsulateSync(bufferLikeToArrayBuffer(ciphertext));
2809
+ }
2810
+
2811
+ async encapsulateBits(
2812
+ algorithm: SubtleAlgorithm,
2813
+ key: CryptoKey,
2814
+ ): Promise<EncapsulateResult> {
2815
+ if (!key.usages.includes('encapsulateBits')) {
2816
+ throw lazyDOMException(
2817
+ 'Key does not have encapsulateBits usage',
2818
+ 'InvalidAccessError',
2819
+ );
2465
2820
  }
2466
2821
 
2467
- return signVerify(normalizedAlgorithm, key, data, signature) as boolean;
2822
+ return this._encapsulateCore(algorithm, key);
2823
+ }
2824
+
2825
+ async encapsulateKey(
2826
+ algorithm: SubtleAlgorithm,
2827
+ key: CryptoKey,
2828
+ sharedKeyAlgorithm: SubtleAlgorithm | AnyAlgorithm,
2829
+ extractable: boolean,
2830
+ usages: KeyUsage[],
2831
+ ): Promise<{ key: CryptoKey; ciphertext: ArrayBuffer }> {
2832
+ if (!key.usages.includes('encapsulateKey')) {
2833
+ throw lazyDOMException(
2834
+ 'Key does not have encapsulateKey usage',
2835
+ 'InvalidAccessError',
2836
+ );
2837
+ }
2838
+
2839
+ const { sharedKey, ciphertext } = this._encapsulateCore(algorithm, key);
2840
+ const importedKey = await this.importKey(
2841
+ 'raw',
2842
+ sharedKey,
2843
+ sharedKeyAlgorithm,
2844
+ extractable,
2845
+ usages,
2846
+ );
2847
+
2848
+ return { key: importedKey, ciphertext };
2849
+ }
2850
+
2851
+ async decapsulateBits(
2852
+ algorithm: SubtleAlgorithm,
2853
+ key: CryptoKey,
2854
+ ciphertext: BufferLike,
2855
+ ): Promise<ArrayBuffer> {
2856
+ if (!key.usages.includes('decapsulateBits')) {
2857
+ throw lazyDOMException(
2858
+ 'Key does not have decapsulateBits usage',
2859
+ 'InvalidAccessError',
2860
+ );
2861
+ }
2862
+
2863
+ return this._decapsulateCore(algorithm, key, ciphertext);
2864
+ }
2865
+
2866
+ async decapsulateKey(
2867
+ algorithm: SubtleAlgorithm,
2868
+ key: CryptoKey,
2869
+ ciphertext: BufferLike,
2870
+ sharedKeyAlgorithm: SubtleAlgorithm | AnyAlgorithm,
2871
+ extractable: boolean,
2872
+ usages: KeyUsage[],
2873
+ ): Promise<CryptoKey> {
2874
+ if (!key.usages.includes('decapsulateKey')) {
2875
+ throw lazyDOMException(
2876
+ 'Key does not have decapsulateKey usage',
2877
+ 'InvalidAccessError',
2878
+ );
2879
+ }
2880
+
2881
+ const sharedKey = this._decapsulateCore(algorithm, key, ciphertext);
2882
+ return this.importKey(
2883
+ 'raw',
2884
+ sharedKey,
2885
+ sharedKeyAlgorithm,
2886
+ extractable,
2887
+ usages,
2888
+ );
2468
2889
  }
2469
2890
  }
2470
2891
 
@@ -2487,6 +2908,11 @@ function getKeyLength(algorithm: SubtleAlgorithm): number {
2487
2908
  return hmacAlg.length || 256;
2488
2909
  }
2489
2910
 
2911
+ case 'KMAC128':
2912
+ return algorithm.length || 128;
2913
+ case 'KMAC256':
2914
+ return algorithm.length || 256;
2915
+
2490
2916
  default:
2491
2917
  throw lazyDOMException(
2492
2918
  `Cannot determine key length for ${name}`,