react-native-quick-crypto 1.0.10 → 1.0.12

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 (293) hide show
  1. package/android/CMakeLists.txt +16 -0
  2. package/cpp/argon2/HybridArgon2.cpp +103 -0
  3. package/cpp/argon2/HybridArgon2.hpp +32 -0
  4. package/cpp/certificate/HybridCertificate.cpp +42 -0
  5. package/cpp/certificate/HybridCertificate.hpp +16 -0
  6. package/cpp/cipher/CCMCipher.cpp +4 -1
  7. package/cpp/cipher/ChaCha20Cipher.cpp +3 -1
  8. package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +5 -5
  9. package/cpp/cipher/ChaCha20Poly1305Cipher.hpp +1 -2
  10. package/cpp/cipher/HybridCipher.cpp +68 -1
  11. package/cpp/cipher/HybridCipher.hpp +6 -0
  12. package/cpp/cipher/HybridRsaCipher.cpp +0 -13
  13. package/cpp/cipher/XChaCha20Poly1305Cipher.cpp +7 -5
  14. package/cpp/cipher/XChaCha20Poly1305Cipher.hpp +1 -2
  15. package/cpp/cipher/XSalsa20Cipher.cpp +4 -0
  16. package/cpp/cipher/XSalsa20Poly1305Cipher.cpp +7 -5
  17. package/cpp/cipher/XSalsa20Poly1305Cipher.hpp +1 -2
  18. package/cpp/dh/HybridDhKeyPair.cpp +179 -0
  19. package/cpp/dh/HybridDhKeyPair.hpp +37 -0
  20. package/cpp/dsa/HybridDsaKeyPair.cpp +128 -0
  21. package/cpp/dsa/HybridDsaKeyPair.hpp +32 -0
  22. package/cpp/ecdh/HybridECDH.cpp +42 -120
  23. package/cpp/ecdh/HybridECDH.hpp +1 -0
  24. package/cpp/keys/HybridKeyObjectHandle.cpp +150 -128
  25. package/cpp/keys/HybridKeyObjectHandle.hpp +6 -3
  26. package/cpp/keys/KeyObjectData.hpp +2 -0
  27. package/cpp/kmac/HybridKmac.cpp +83 -0
  28. package/cpp/kmac/HybridKmac.hpp +31 -0
  29. package/cpp/mldsa/HybridMlDsaKeyPair.cpp +11 -20
  30. package/cpp/mldsa/HybridMlDsaKeyPair.hpp +4 -2
  31. package/cpp/mlkem/HybridMlKemKeyPair.cpp +319 -0
  32. package/cpp/mlkem/HybridMlKemKeyPair.hpp +48 -0
  33. package/cpp/prime/HybridPrime.cpp +81 -0
  34. package/cpp/prime/HybridPrime.hpp +20 -0
  35. package/cpp/sign/SignUtils.hpp +9 -26
  36. package/cpp/utils/QuickCryptoUtils.cpp +44 -0
  37. package/cpp/utils/QuickCryptoUtils.hpp +39 -0
  38. package/cpp/x509/HybridX509Certificate.cpp +174 -0
  39. package/cpp/x509/HybridX509Certificate.hpp +51 -0
  40. package/lib/commonjs/argon2.js +39 -0
  41. package/lib/commonjs/argon2.js.map +1 -0
  42. package/lib/commonjs/certificate.js +35 -0
  43. package/lib/commonjs/certificate.js.map +1 -0
  44. package/lib/commonjs/cipher.js +23 -2
  45. package/lib/commonjs/cipher.js.map +1 -1
  46. package/lib/commonjs/dhKeyPair.js +109 -0
  47. package/lib/commonjs/dhKeyPair.js.map +1 -0
  48. package/lib/commonjs/dsa.js +92 -0
  49. package/lib/commonjs/dsa.js.map +1 -0
  50. package/lib/commonjs/ec.js +18 -18
  51. package/lib/commonjs/ec.js.map +1 -1
  52. package/lib/commonjs/ecdh.js +37 -0
  53. package/lib/commonjs/ecdh.js.map +1 -1
  54. package/lib/commonjs/ed.js +9 -9
  55. package/lib/commonjs/ed.js.map +1 -1
  56. package/lib/commonjs/hash.js +17 -12
  57. package/lib/commonjs/hash.js.map +1 -1
  58. package/lib/commonjs/hkdf.js.map +1 -1
  59. package/lib/commonjs/index.js +57 -0
  60. package/lib/commonjs/index.js.map +1 -1
  61. package/lib/commonjs/keys/classes.js +11 -9
  62. package/lib/commonjs/keys/classes.js.map +1 -1
  63. package/lib/commonjs/keys/generateKeyPair.js +11 -0
  64. package/lib/commonjs/keys/generateKeyPair.js.map +1 -1
  65. package/lib/commonjs/keys/index.js +24 -0
  66. package/lib/commonjs/keys/index.js.map +1 -1
  67. package/lib/commonjs/keys/signVerify.js +0 -2
  68. package/lib/commonjs/keys/signVerify.js.map +1 -1
  69. package/lib/commonjs/mlkem.js +219 -0
  70. package/lib/commonjs/mlkem.js.map +1 -0
  71. package/lib/commonjs/pbkdf2.js +18 -1
  72. package/lib/commonjs/pbkdf2.js.map +1 -1
  73. package/lib/commonjs/prime.js +84 -0
  74. package/lib/commonjs/prime.js.map +1 -0
  75. package/lib/commonjs/rsa.js +7 -7
  76. package/lib/commonjs/rsa.js.map +1 -1
  77. package/lib/commonjs/specs/argon2.nitro.js +6 -0
  78. package/lib/commonjs/specs/argon2.nitro.js.map +1 -0
  79. package/lib/commonjs/specs/certificate.nitro.js +6 -0
  80. package/lib/commonjs/specs/certificate.nitro.js.map +1 -0
  81. package/lib/commonjs/specs/dhKeyPair.nitro.js +6 -0
  82. package/lib/commonjs/specs/dhKeyPair.nitro.js.map +1 -0
  83. package/lib/commonjs/specs/dsaKeyPair.nitro.js +6 -0
  84. package/lib/commonjs/specs/dsaKeyPair.nitro.js.map +1 -0
  85. package/lib/commonjs/specs/kmac.nitro.js +6 -0
  86. package/lib/commonjs/specs/kmac.nitro.js.map +1 -0
  87. package/lib/commonjs/specs/mlKemKeyPair.nitro.js +6 -0
  88. package/lib/commonjs/specs/mlKemKeyPair.nitro.js.map +1 -0
  89. package/lib/commonjs/specs/prime.nitro.js +6 -0
  90. package/lib/commonjs/specs/prime.nitro.js.map +1 -0
  91. package/lib/commonjs/specs/x509certificate.nitro.js +6 -0
  92. package/lib/commonjs/specs/x509certificate.nitro.js.map +1 -0
  93. package/lib/commonjs/subtle.js +385 -114
  94. package/lib/commonjs/subtle.js.map +1 -1
  95. package/lib/commonjs/utils/conversion.js +3 -3
  96. package/lib/commonjs/utils/conversion.js.map +1 -1
  97. package/lib/commonjs/utils/hashnames.js +31 -0
  98. package/lib/commonjs/utils/hashnames.js.map +1 -1
  99. package/lib/commonjs/utils/types.js.map +1 -1
  100. package/lib/commonjs/x509certificate.js +189 -0
  101. package/lib/commonjs/x509certificate.js.map +1 -0
  102. package/lib/module/argon2.js +34 -0
  103. package/lib/module/argon2.js.map +1 -0
  104. package/lib/module/certificate.js +30 -0
  105. package/lib/module/certificate.js.map +1 -0
  106. package/lib/module/cipher.js +23 -3
  107. package/lib/module/cipher.js.map +1 -1
  108. package/lib/module/dhKeyPair.js +102 -0
  109. package/lib/module/dhKeyPair.js.map +1 -0
  110. package/lib/module/dsa.js +85 -0
  111. package/lib/module/dsa.js.map +1 -0
  112. package/lib/module/ec.js +6 -6
  113. package/lib/module/ec.js.map +1 -1
  114. package/lib/module/ecdh.js +37 -0
  115. package/lib/module/ecdh.js.map +1 -1
  116. package/lib/module/ed.js +1 -1
  117. package/lib/module/ed.js.map +1 -1
  118. package/lib/module/hash.js +17 -12
  119. package/lib/module/hash.js.map +1 -1
  120. package/lib/module/hkdf.js.map +1 -1
  121. package/lib/module/index.js +15 -0
  122. package/lib/module/index.js.map +1 -1
  123. package/lib/module/keys/classes.js +11 -9
  124. package/lib/module/keys/classes.js.map +1 -1
  125. package/lib/module/keys/generateKeyPair.js +11 -0
  126. package/lib/module/keys/generateKeyPair.js.map +1 -1
  127. package/lib/module/keys/index.js +25 -1
  128. package/lib/module/keys/index.js.map +1 -1
  129. package/lib/module/keys/signVerify.js +0 -2
  130. package/lib/module/keys/signVerify.js.map +1 -1
  131. package/lib/module/mlkem.js +211 -0
  132. package/lib/module/mlkem.js.map +1 -0
  133. package/lib/module/pbkdf2.js +18 -1
  134. package/lib/module/pbkdf2.js.map +1 -1
  135. package/lib/module/prime.js +77 -0
  136. package/lib/module/prime.js.map +1 -0
  137. package/lib/module/rsa.js +1 -1
  138. package/lib/module/rsa.js.map +1 -1
  139. package/lib/module/specs/argon2.nitro.js +4 -0
  140. package/lib/module/specs/argon2.nitro.js.map +1 -0
  141. package/lib/module/specs/certificate.nitro.js +4 -0
  142. package/lib/module/specs/certificate.nitro.js.map +1 -0
  143. package/lib/module/specs/dhKeyPair.nitro.js +4 -0
  144. package/lib/module/specs/dhKeyPair.nitro.js.map +1 -0
  145. package/lib/module/specs/dsaKeyPair.nitro.js +4 -0
  146. package/lib/module/specs/dsaKeyPair.nitro.js.map +1 -0
  147. package/lib/module/specs/kmac.nitro.js +4 -0
  148. package/lib/module/specs/kmac.nitro.js.map +1 -0
  149. package/lib/module/specs/mlKemKeyPair.nitro.js +4 -0
  150. package/lib/module/specs/mlKemKeyPair.nitro.js.map +1 -0
  151. package/lib/module/specs/prime.nitro.js +4 -0
  152. package/lib/module/specs/prime.nitro.js.map +1 -0
  153. package/lib/module/specs/x509certificate.nitro.js +4 -0
  154. package/lib/module/specs/x509certificate.nitro.js.map +1 -0
  155. package/lib/module/subtle.js +386 -116
  156. package/lib/module/subtle.js.map +1 -1
  157. package/lib/module/utils/conversion.js +3 -4
  158. package/lib/module/utils/conversion.js.map +1 -1
  159. package/lib/module/utils/hashnames.js +31 -0
  160. package/lib/module/utils/hashnames.js.map +1 -1
  161. package/lib/module/utils/types.js.map +1 -1
  162. package/lib/module/x509certificate.js +184 -0
  163. package/lib/module/x509certificate.js.map +1 -0
  164. package/lib/tsconfig.tsbuildinfo +1 -1
  165. package/lib/typescript/argon2.d.ts +16 -0
  166. package/lib/typescript/argon2.d.ts.map +1 -0
  167. package/lib/typescript/certificate.d.ts +8 -0
  168. package/lib/typescript/certificate.d.ts.map +1 -0
  169. package/lib/typescript/cipher.d.ts +15 -0
  170. package/lib/typescript/cipher.d.ts.map +1 -1
  171. package/lib/typescript/dhKeyPair.d.ts +19 -0
  172. package/lib/typescript/dhKeyPair.d.ts.map +1 -0
  173. package/lib/typescript/dsa.d.ts +19 -0
  174. package/lib/typescript/dsa.d.ts.map +1 -0
  175. package/lib/typescript/ec.d.ts +1 -1
  176. package/lib/typescript/ec.d.ts.map +1 -1
  177. package/lib/typescript/ecdh.d.ts +3 -0
  178. package/lib/typescript/ecdh.d.ts.map +1 -1
  179. package/lib/typescript/ed.d.ts +1 -1
  180. package/lib/typescript/ed.d.ts.map +1 -1
  181. package/lib/typescript/hash.d.ts.map +1 -1
  182. package/lib/typescript/hkdf.d.ts +2 -6
  183. package/lib/typescript/hkdf.d.ts.map +1 -1
  184. package/lib/typescript/index.d.ts +32 -4
  185. package/lib/typescript/index.d.ts.map +1 -1
  186. package/lib/typescript/keys/classes.d.ts +7 -5
  187. package/lib/typescript/keys/classes.d.ts.map +1 -1
  188. package/lib/typescript/keys/generateKeyPair.d.ts.map +1 -1
  189. package/lib/typescript/keys/index.d.ts +2 -2
  190. package/lib/typescript/keys/index.d.ts.map +1 -1
  191. package/lib/typescript/keys/signVerify.d.ts.map +1 -1
  192. package/lib/typescript/mlkem.d.ts +30 -0
  193. package/lib/typescript/mlkem.d.ts.map +1 -0
  194. package/lib/typescript/pbkdf2.d.ts +2 -2
  195. package/lib/typescript/pbkdf2.d.ts.map +1 -1
  196. package/lib/typescript/prime.d.ts +19 -0
  197. package/lib/typescript/prime.d.ts.map +1 -0
  198. package/lib/typescript/rsa.d.ts +1 -1
  199. package/lib/typescript/rsa.d.ts.map +1 -1
  200. package/lib/typescript/specs/argon2.nitro.d.ts +9 -0
  201. package/lib/typescript/specs/argon2.nitro.d.ts.map +1 -0
  202. package/lib/typescript/specs/certificate.nitro.d.ts +10 -0
  203. package/lib/typescript/specs/certificate.nitro.d.ts.map +1 -0
  204. package/lib/typescript/specs/cipher.nitro.d.ts +9 -0
  205. package/lib/typescript/specs/cipher.nitro.d.ts.map +1 -1
  206. package/lib/typescript/specs/dhKeyPair.nitro.d.ts +14 -0
  207. package/lib/typescript/specs/dhKeyPair.nitro.d.ts.map +1 -0
  208. package/lib/typescript/specs/dsaKeyPair.nitro.d.ts +13 -0
  209. package/lib/typescript/specs/dsaKeyPair.nitro.d.ts.map +1 -0
  210. package/lib/typescript/specs/ecdh.nitro.d.ts +1 -0
  211. package/lib/typescript/specs/ecdh.nitro.d.ts.map +1 -1
  212. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +1 -0
  213. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
  214. package/lib/typescript/specs/kmac.nitro.d.ts +10 -0
  215. package/lib/typescript/specs/kmac.nitro.d.ts.map +1 -0
  216. package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts +18 -0
  217. package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts.map +1 -0
  218. package/lib/typescript/specs/prime.nitro.d.ts +11 -0
  219. package/lib/typescript/specs/prime.nitro.d.ts.map +1 -0
  220. package/lib/typescript/specs/x509certificate.nitro.d.ts +34 -0
  221. package/lib/typescript/specs/x509certificate.nitro.d.ts.map +1 -0
  222. package/lib/typescript/subtle.d.ts +12 -0
  223. package/lib/typescript/subtle.d.ts.map +1 -1
  224. package/lib/typescript/utils/conversion.d.ts.map +1 -1
  225. package/lib/typescript/utils/hashnames.d.ts +1 -1
  226. package/lib/typescript/utils/hashnames.d.ts.map +1 -1
  227. package/lib/typescript/utils/types.d.ts +25 -9
  228. package/lib/typescript/utils/types.d.ts.map +1 -1
  229. package/lib/typescript/x509certificate.d.ts +64 -0
  230. package/lib/typescript/x509certificate.d.ts.map +1 -0
  231. package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +8 -0
  232. package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +80 -0
  233. package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +80 -0
  234. package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +12 -0
  235. package/nitrogen/generated/shared/c++/CipherInfo.hpp +104 -0
  236. package/nitrogen/generated/shared/c++/HybridArgon2Spec.cpp +22 -0
  237. package/nitrogen/generated/shared/c++/HybridArgon2Spec.hpp +66 -0
  238. package/nitrogen/generated/shared/c++/HybridCertificateSpec.cpp +23 -0
  239. package/nitrogen/generated/shared/c++/HybridCertificateSpec.hpp +64 -0
  240. package/nitrogen/generated/shared/c++/HybridCipherSpec.cpp +1 -0
  241. package/nitrogen/generated/shared/c++/HybridCipherSpec.hpp +4 -0
  242. package/nitrogen/generated/shared/c++/HybridDhKeyPairSpec.cpp +27 -0
  243. package/nitrogen/generated/shared/c++/HybridDhKeyPairSpec.hpp +69 -0
  244. package/nitrogen/generated/shared/c++/HybridDsaKeyPairSpec.cpp +26 -0
  245. package/nitrogen/generated/shared/c++/HybridDsaKeyPairSpec.hpp +68 -0
  246. package/nitrogen/generated/shared/c++/HybridECDHSpec.cpp +1 -0
  247. package/nitrogen/generated/shared/c++/HybridECDHSpec.hpp +1 -0
  248. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +1 -0
  249. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +1 -0
  250. package/nitrogen/generated/shared/c++/HybridKmacSpec.cpp +23 -0
  251. package/nitrogen/generated/shared/c++/HybridKmacSpec.hpp +66 -0
  252. package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.cpp +31 -0
  253. package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.hpp +74 -0
  254. package/nitrogen/generated/shared/c++/HybridPrimeSpec.cpp +24 -0
  255. package/nitrogen/generated/shared/c++/HybridPrimeSpec.hpp +67 -0
  256. package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.cpp +46 -0
  257. package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.hpp +96 -0
  258. package/package.json +4 -1
  259. package/src/argon2.ts +83 -0
  260. package/src/certificate.ts +41 -0
  261. package/src/cipher.ts +41 -3
  262. package/src/dhKeyPair.ts +156 -0
  263. package/src/dsa.ts +129 -0
  264. package/src/ec.ts +9 -9
  265. package/src/ecdh.ts +59 -0
  266. package/src/ed.ts +2 -2
  267. package/src/hash.ts +34 -11
  268. package/src/hkdf.ts +2 -7
  269. package/src/index.ts +16 -0
  270. package/src/keys/classes.ts +26 -14
  271. package/src/keys/generateKeyPair.ts +14 -0
  272. package/src/keys/index.ts +37 -2
  273. package/src/keys/signVerify.ts +0 -5
  274. package/src/mlkem.ts +350 -0
  275. package/src/pbkdf2.ts +34 -5
  276. package/src/prime.ts +134 -0
  277. package/src/rsa.ts +1 -1
  278. package/src/specs/argon2.nitro.ts +29 -0
  279. package/src/specs/certificate.nitro.ts +8 -0
  280. package/src/specs/cipher.nitro.ts +14 -0
  281. package/src/specs/dhKeyPair.nitro.ts +14 -0
  282. package/src/specs/dsaKeyPair.nitro.ts +13 -0
  283. package/src/specs/ecdh.nitro.ts +1 -0
  284. package/src/specs/keyObjectHandle.nitro.ts +5 -0
  285. package/src/specs/kmac.nitro.ts +12 -0
  286. package/src/specs/mlKemKeyPair.nitro.ts +32 -0
  287. package/src/specs/prime.nitro.ts +18 -0
  288. package/src/specs/x509certificate.nitro.ts +38 -0
  289. package/src/subtle.ts +821 -136
  290. package/src/utils/conversion.ts +10 -4
  291. package/src/utils/hashnames.ts +33 -2
  292. package/src/utils/types.ts +64 -8
  293. package/src/x509certificate.ts +277 -0
package/src/subtle.ts CHANGED
@@ -28,11 +28,12 @@ import {
28
28
  } from './keys';
29
29
  import type { CryptoKeyPair } from './utils/types';
30
30
  import { bufferLikeToArrayBuffer } from './utils/conversion';
31
+ import { argon2Sync } from './argon2';
31
32
  import { lazyDOMException } from './utils/errors';
32
33
  import { normalizeHashName, HashContext } from './utils/hashnames';
33
34
  import { validateMaxBufferLength } from './utils/validation';
34
35
  import { asyncDigest } from './hash';
35
- import { createSecretKey } from './keys';
36
+ import { createSecretKey, createPublicKey } from './keys';
36
37
  import { NitroModules } from 'react-native-nitro-modules';
37
38
  import type { KeyObjectHandle } from './specs/keyObjectHandle.nitro';
38
39
  import type { RsaCipher } from './specs/rsaCipher.nitro';
@@ -47,6 +48,8 @@ import {
47
48
  import { rsa_generateKeyPair } from './rsa';
48
49
  import { getRandomValues } from './random';
49
50
  import { createHmac } from './hmac';
51
+ import type { Kmac } from './specs/kmac.nitro';
52
+ import { timingSafeEqual } from './utils/timingSafeEqual';
50
53
  import { createSign, createVerify } from './keys/signVerify';
51
54
  import {
52
55
  ed_generateKeyPairWebCrypto,
@@ -55,13 +58,13 @@ import {
55
58
  Ed,
56
59
  } from './ed';
57
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';
58
67
  import { hkdfDeriveBits, type HkdfAlgorithm } from './hkdf';
59
- // import { pbkdf2DeriveBits } from './pbkdf2';
60
- // import { aesCipher, aesGenerateKey, aesImportKey, getAlgorithmName } from './aes';
61
- // import { rsaCipher, rsaExportKey, rsaImportKey, rsaKeyGenerate } from './rsa';
62
- // import { normalizeAlgorithm, type Operation } from './algorithms';
63
- // import { hmacImportKey } from './mac';
64
-
65
68
  // Temporary enums that need to be defined
66
69
 
67
70
  enum KWebCryptoKeyFormat {
@@ -113,12 +116,12 @@ function getAlgorithmName(name: string, length: number): string {
113
116
  function ecExportKey(key: CryptoKey, format: KWebCryptoKeyFormat): ArrayBuffer {
114
117
  const keyObject = key.keyObject;
115
118
 
116
- if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI) {
117
- // Export public key in SPKI format
119
+ if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatRaw) {
120
+ return bufferLikeToArrayBuffer(keyObject.handle.exportKey());
121
+ } else if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI) {
118
122
  const exported = keyObject.export({ format: 'der', type: 'spki' });
119
123
  return bufferLikeToArrayBuffer(exported);
120
124
  } else if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8) {
121
- // Export private key in PKCS8 format
122
125
  const exported = keyObject.export({ format: 'der', type: 'pkcs8' });
123
126
  return bufferLikeToArrayBuffer(exported);
124
127
  } else {
@@ -704,6 +707,164 @@ async function hmacGenerateKey(
704
707
  return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
705
708
  }
706
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
+
707
868
  function rsaImportKey(
708
869
  format: ImportFormat,
709
870
  data: BufferLike | JWK,
@@ -1024,6 +1185,49 @@ function edImportKey(
1024
1185
  return new CryptoKey(keyObject, { name }, keyUsages, extractable);
1025
1186
  }
1026
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
+
1027
1231
  function mldsaImportKey(
1028
1232
  format: ImportFormat,
1029
1233
  data: BufferLike,
@@ -1032,43 +1236,45 @@ function mldsaImportKey(
1032
1236
  keyUsages: KeyUsage[],
1033
1237
  ): CryptoKey {
1034
1238
  const { name } = algorithm;
1035
-
1036
- // Validate usages
1037
- if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
1239
+ const isPublicFormat = format === 'spki' || format === 'raw';
1240
+ if (hasAnyNotIn(keyUsages, isPublicFormat ? ['verify'] : ['sign'])) {
1038
1241
  throw lazyDOMException(
1039
1242
  `Unsupported key usage for ${name} key`,
1040
1243
  'SyntaxError',
1041
1244
  );
1042
1245
  }
1246
+ return new CryptoKey(
1247
+ pqcImportKeyObject(format, data, name),
1248
+ { name },
1249
+ keyUsages,
1250
+ extractable,
1251
+ );
1252
+ }
1043
1253
 
1044
- let keyObject: KeyObject;
1045
-
1046
- if (format === 'spki') {
1047
- // Import public key
1048
- const keyData = bufferLikeToArrayBuffer(data);
1049
- keyObject = KeyObject.createKeyObject(
1050
- 'public',
1051
- keyData,
1052
- KFormatType.DER,
1053
- KeyEncoding.SPKI,
1054
- );
1055
- } else if (format === 'pkcs8') {
1056
- // Import private key
1057
- const keyData = bufferLikeToArrayBuffer(data);
1058
- keyObject = KeyObject.createKeyObject(
1059
- 'private',
1060
- keyData,
1061
- KFormatType.DER,
1062
- KeyEncoding.PKCS8,
1063
- );
1064
- } 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)) {
1065
1267
  throw lazyDOMException(
1066
- `Unsupported format for ${name} import: ${format}`,
1067
- 'NotSupportedError',
1268
+ `Unsupported key usage for ${name} key`,
1269
+ 'SyntaxError',
1068
1270
  );
1069
1271
  }
1070
-
1071
- return new CryptoKey(keyObject, { name }, keyUsages, extractable);
1272
+ return new CryptoKey(
1273
+ pqcImportKeyObject(format, data, name),
1274
+ { name },
1275
+ keyUsages,
1276
+ extractable,
1277
+ );
1072
1278
  }
1073
1279
 
1074
1280
  const exportKeySpki = async (
@@ -1117,6 +1323,17 @@ const exportKeySpki = async (
1117
1323
  );
1118
1324
  }
1119
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;
1120
1337
  }
1121
1338
 
1122
1339
  throw new Error(
@@ -1170,6 +1387,17 @@ const exportKeyPkcs8 = async (
1170
1387
  );
1171
1388
  }
1172
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;
1173
1401
  }
1174
1402
 
1175
1403
  throw new Error(
@@ -1194,7 +1422,22 @@ const exportKeyRaw = (key: CryptoKey): ArrayBuffer | unknown => {
1194
1422
  // Fall through
1195
1423
  case 'X448':
1196
1424
  if (key.type === 'public') {
1197
- // 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') {
1198
1441
  const exported = key.keyObject.handle.exportKey();
1199
1442
  return bufferLikeToArrayBuffer(exported);
1200
1443
  }
@@ -1211,7 +1454,11 @@ const exportKeyRaw = (key: CryptoKey): ArrayBuffer | unknown => {
1211
1454
  // Fall through
1212
1455
  case 'ChaCha20-Poly1305':
1213
1456
  // Fall through
1214
- case 'HMAC': {
1457
+ case 'HMAC':
1458
+ // Fall through
1459
+ case 'KMAC128':
1460
+ // Fall through
1461
+ case 'KMAC256': {
1215
1462
  const exported = key.keyObject.export();
1216
1463
  // Convert Buffer to ArrayBuffer
1217
1464
  return exported.buffer.slice(
@@ -1248,6 +1495,12 @@ const exportKeyJWK = (key: CryptoKey): ArrayBuffer | unknown => {
1248
1495
  case 'HMAC':
1249
1496
  jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkHmac);
1250
1497
  return jwk;
1498
+ case 'KMAC128':
1499
+ jwk.alg = 'K128';
1500
+ return jwk;
1501
+ case 'KMAC256':
1502
+ jwk.alg = 'K256';
1503
+ return jwk;
1251
1504
  case 'ECDSA':
1252
1505
  // Fall through
1253
1506
  case 'ECDH':
@@ -1364,6 +1617,45 @@ const checkCryptoKeyPairUsages = (pair: CryptoKeyPair) => {
1364
1617
  );
1365
1618
  };
1366
1619
 
1620
+ function argon2DeriveBits(
1621
+ algorithm: SubtleAlgorithm,
1622
+ baseKey: CryptoKey,
1623
+ length: number,
1624
+ ): ArrayBuffer {
1625
+ if (length === 0 || length % 8 !== 0) {
1626
+ throw lazyDOMException(
1627
+ 'Invalid Argon2 derived key length',
1628
+ 'OperationError',
1629
+ );
1630
+ }
1631
+ if (length < 32) {
1632
+ throw lazyDOMException(
1633
+ 'Argon2 derived key length must be at least 32 bits',
1634
+ 'OperationError',
1635
+ );
1636
+ }
1637
+
1638
+ const { nonce, parallelism, memory, passes, secretValue, associatedData } =
1639
+ algorithm;
1640
+ const tagLength = length / 8;
1641
+ const message = baseKey.keyObject.export();
1642
+ const algName = algorithm.name.toLowerCase();
1643
+
1644
+ const result = argon2Sync(algName, {
1645
+ message,
1646
+ nonce: nonce ?? new Uint8Array(0),
1647
+ parallelism: parallelism ?? 1,
1648
+ tagLength,
1649
+ memory: memory ?? 65536,
1650
+ passes: passes ?? 3,
1651
+ secret: secretValue,
1652
+ associatedData,
1653
+ version: algorithm.version,
1654
+ });
1655
+
1656
+ return bufferLikeToArrayBuffer(result);
1657
+ }
1658
+
1367
1659
  // Type guard to check if result is CryptoKeyPair
1368
1660
  export function isCryptoKeyPair(
1369
1661
  result: CryptoKey | CryptoKeyPair,
@@ -1395,24 +1687,20 @@ function hmacSignVerify(
1395
1687
  );
1396
1688
  }
1397
1689
 
1398
- // Verify operation - compare computed HMAC with provided signature
1399
- const sigBytes = new Uint8Array(bufferLikeToArrayBuffer(signature));
1400
- const computedBytes = new Uint8Array(
1401
- computed.buffer,
1690
+ const sigBuffer = bufferLikeToArrayBuffer(signature);
1691
+ const computedBuffer = computed.buffer.slice(
1402
1692
  computed.byteOffset,
1403
- computed.byteLength,
1693
+ computed.byteOffset + computed.byteLength,
1404
1694
  );
1405
1695
 
1406
- if (computedBytes.length !== sigBytes.length) {
1696
+ if (computedBuffer.byteLength !== sigBuffer.byteLength) {
1407
1697
  return false;
1408
1698
  }
1409
1699
 
1410
- // Constant-time comparison to prevent timing attacks
1411
- let result = 0;
1412
- for (let i = 0; i < computedBytes.length; i++) {
1413
- result |= computedBytes[i]! ^ sigBytes[i]!;
1414
- }
1415
- return result === 0;
1700
+ return timingSafeEqual(
1701
+ new Uint8Array(computedBuffer),
1702
+ new Uint8Array(sigBuffer),
1703
+ );
1416
1704
  }
1417
1705
 
1418
1706
  function rsaSignVerify(
@@ -1555,6 +1843,9 @@ const signVerify = (
1555
1843
  case 'ML-DSA-65':
1556
1844
  case 'ML-DSA-87':
1557
1845
  return mldsaSignVerify(key, data, signature);
1846
+ case 'KMAC128':
1847
+ case 'KMAC256':
1848
+ return kmacSignVerify(key, data, algorithm, signature);
1558
1849
  }
1559
1850
  throw lazyDOMException(
1560
1851
  `Unrecognized algorithm name '${algorithm.name}' for '${usage}'`,
@@ -1604,7 +1895,241 @@ const cipherOrWrap = async (
1604
1895
  }
1605
1896
  };
1606
1897
 
1898
+ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
1899
+ encrypt: new Set([
1900
+ 'RSA-OAEP',
1901
+ 'AES-CTR',
1902
+ 'AES-CBC',
1903
+ 'AES-GCM',
1904
+ 'AES-OCB',
1905
+ 'ChaCha20-Poly1305',
1906
+ ]),
1907
+ decrypt: new Set([
1908
+ 'RSA-OAEP',
1909
+ 'AES-CTR',
1910
+ 'AES-CBC',
1911
+ 'AES-GCM',
1912
+ 'AES-OCB',
1913
+ 'ChaCha20-Poly1305',
1914
+ ]),
1915
+ sign: new Set([
1916
+ 'RSASSA-PKCS1-v1_5',
1917
+ 'RSA-PSS',
1918
+ 'ECDSA',
1919
+ 'HMAC',
1920
+ 'KMAC128',
1921
+ 'KMAC256',
1922
+ 'Ed25519',
1923
+ 'Ed448',
1924
+ 'ML-DSA-44',
1925
+ 'ML-DSA-65',
1926
+ 'ML-DSA-87',
1927
+ ]),
1928
+ verify: new Set([
1929
+ 'RSASSA-PKCS1-v1_5',
1930
+ 'RSA-PSS',
1931
+ 'ECDSA',
1932
+ 'HMAC',
1933
+ 'KMAC128',
1934
+ 'KMAC256',
1935
+ 'Ed25519',
1936
+ 'Ed448',
1937
+ 'ML-DSA-44',
1938
+ 'ML-DSA-65',
1939
+ 'ML-DSA-87',
1940
+ ]),
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
+ ]),
1952
+ generateKey: new Set([
1953
+ 'RSASSA-PKCS1-v1_5',
1954
+ 'RSA-PSS',
1955
+ 'RSA-OAEP',
1956
+ 'ECDSA',
1957
+ 'ECDH',
1958
+ 'Ed25519',
1959
+ 'Ed448',
1960
+ 'X25519',
1961
+ 'X448',
1962
+ 'AES-CTR',
1963
+ 'AES-CBC',
1964
+ 'AES-GCM',
1965
+ 'AES-KW',
1966
+ 'AES-OCB',
1967
+ 'ChaCha20-Poly1305',
1968
+ 'HMAC',
1969
+ 'KMAC128',
1970
+ 'KMAC256',
1971
+ 'ML-DSA-44',
1972
+ 'ML-DSA-65',
1973
+ 'ML-DSA-87',
1974
+ 'ML-KEM-512',
1975
+ 'ML-KEM-768',
1976
+ 'ML-KEM-1024',
1977
+ ]),
1978
+ importKey: new Set([
1979
+ 'RSASSA-PKCS1-v1_5',
1980
+ 'RSA-PSS',
1981
+ 'RSA-OAEP',
1982
+ 'ECDSA',
1983
+ 'ECDH',
1984
+ 'Ed25519',
1985
+ 'Ed448',
1986
+ 'X25519',
1987
+ 'X448',
1988
+ 'AES-CTR',
1989
+ 'AES-CBC',
1990
+ 'AES-GCM',
1991
+ 'AES-KW',
1992
+ 'AES-OCB',
1993
+ 'ChaCha20-Poly1305',
1994
+ 'HMAC',
1995
+ 'KMAC128',
1996
+ 'KMAC256',
1997
+ 'HKDF',
1998
+ 'PBKDF2',
1999
+ 'Argon2d',
2000
+ 'Argon2i',
2001
+ 'Argon2id',
2002
+ 'ML-DSA-44',
2003
+ 'ML-DSA-65',
2004
+ 'ML-DSA-87',
2005
+ 'ML-KEM-512',
2006
+ 'ML-KEM-768',
2007
+ 'ML-KEM-1024',
2008
+ ]),
2009
+ exportKey: new Set([
2010
+ 'RSASSA-PKCS1-v1_5',
2011
+ 'RSA-PSS',
2012
+ 'RSA-OAEP',
2013
+ 'ECDSA',
2014
+ 'ECDH',
2015
+ 'Ed25519',
2016
+ 'Ed448',
2017
+ 'X25519',
2018
+ 'X448',
2019
+ 'AES-CTR',
2020
+ 'AES-CBC',
2021
+ 'AES-GCM',
2022
+ 'AES-KW',
2023
+ 'AES-OCB',
2024
+ 'ChaCha20-Poly1305',
2025
+ 'HMAC',
2026
+ 'KMAC128',
2027
+ 'KMAC256',
2028
+ 'ML-DSA-44',
2029
+ 'ML-DSA-65',
2030
+ 'ML-DSA-87',
2031
+ 'ML-KEM-512',
2032
+ 'ML-KEM-768',
2033
+ 'ML-KEM-1024',
2034
+ ]),
2035
+ deriveBits: new Set([
2036
+ 'PBKDF2',
2037
+ 'HKDF',
2038
+ 'ECDH',
2039
+ 'X25519',
2040
+ 'X448',
2041
+ 'Argon2d',
2042
+ 'Argon2i',
2043
+ 'Argon2id',
2044
+ ]),
2045
+ wrapKey: new Set([
2046
+ 'AES-CTR',
2047
+ 'AES-CBC',
2048
+ 'AES-GCM',
2049
+ 'AES-KW',
2050
+ 'AES-OCB',
2051
+ 'ChaCha20-Poly1305',
2052
+ 'RSA-OAEP',
2053
+ ]),
2054
+ unwrapKey: new Set([
2055
+ 'AES-CTR',
2056
+ 'AES-CBC',
2057
+ 'AES-GCM',
2058
+ 'AES-KW',
2059
+ 'AES-OCB',
2060
+ 'ChaCha20-Poly1305',
2061
+ 'RSA-OAEP',
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']),
2067
+ };
2068
+
2069
+ const ASYMMETRIC_ALGORITHMS = new Set([
2070
+ 'RSASSA-PKCS1-v1_5',
2071
+ 'RSA-PSS',
2072
+ 'RSA-OAEP',
2073
+ 'ECDSA',
2074
+ 'ECDH',
2075
+ 'Ed25519',
2076
+ 'Ed448',
2077
+ 'X25519',
2078
+ 'X448',
2079
+ 'ML-DSA-44',
2080
+ 'ML-DSA-65',
2081
+ 'ML-DSA-87',
2082
+ 'ML-KEM-512',
2083
+ 'ML-KEM-768',
2084
+ 'ML-KEM-1024',
2085
+ ]);
2086
+
1607
2087
  export class Subtle {
2088
+ static supports(
2089
+ operation: string,
2090
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
2091
+ _lengthOrAdditionalAlgorithm?: unknown,
2092
+ ): boolean {
2093
+ let normalizedAlgorithm: SubtleAlgorithm;
2094
+ try {
2095
+ normalizedAlgorithm = normalizeAlgorithm(
2096
+ algorithm,
2097
+ (operation === 'getPublicKey' ? 'exportKey' : operation) as Operation,
2098
+ );
2099
+ } catch {
2100
+ return false;
2101
+ }
2102
+
2103
+ const name = normalizedAlgorithm.name;
2104
+
2105
+ if (operation === 'getPublicKey') {
2106
+ return ASYMMETRIC_ALGORITHMS.has(name);
2107
+ }
2108
+
2109
+ if (operation === 'deriveKey') {
2110
+ // deriveKey decomposes to deriveBits + importKey of additional algorithm
2111
+ if (!SUPPORTED_ALGORITHMS.deriveBits?.has(name)) return false;
2112
+ if (_lengthOrAdditionalAlgorithm != null) {
2113
+ try {
2114
+ const additionalAlg = normalizeAlgorithm(
2115
+ _lengthOrAdditionalAlgorithm as SubtleAlgorithm | AnyAlgorithm,
2116
+ 'importKey',
2117
+ );
2118
+ return (
2119
+ SUPPORTED_ALGORITHMS.importKey?.has(additionalAlg.name) ?? false
2120
+ );
2121
+ } catch {
2122
+ return false;
2123
+ }
2124
+ }
2125
+ return true;
2126
+ }
2127
+
2128
+ const supported = SUPPORTED_ALGORITHMS[operation];
2129
+ if (!supported) return false;
2130
+ return supported.has(name);
2131
+ }
2132
+
1608
2133
  async decrypt(
1609
2134
  algorithm: EncryptDecryptParams,
1610
2135
  key: CryptoKey,
@@ -1660,6 +2185,10 @@ export class Subtle {
1660
2185
  baseKey,
1661
2186
  length,
1662
2187
  );
2188
+ case 'Argon2d':
2189
+ case 'Argon2i':
2190
+ case 'Argon2id':
2191
+ return argon2DeriveBits(algorithm, baseKey, length);
1663
2192
  }
1664
2193
  throw new Error(
1665
2194
  `'subtle.deriveBits()' for ${algorithm.name} is not implemented.`,
@@ -1711,6 +2240,11 @@ export class Subtle {
1711
2240
  length,
1712
2241
  );
1713
2242
  break;
2243
+ case 'Argon2d':
2244
+ case 'Argon2i':
2245
+ case 'Argon2id':
2246
+ derivedBits = argon2DeriveBits(algorithm, baseKey, length);
2247
+ break;
1714
2248
  default:
1715
2249
  throw new Error(
1716
2250
  `'subtle.deriveKey()' for ${algorithm.name} is not implemented.`,
@@ -1748,7 +2282,32 @@ export class Subtle {
1748
2282
  ): Promise<ArrayBuffer | JWK> {
1749
2283
  if (!key.extractable) throw new Error('key is not extractable');
1750
2284
 
1751
- if (format === 'raw-secret') format = 'raw';
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
2310
+ if (format === 'raw-secret' || format === 'raw-public') format = 'raw';
1752
2311
 
1753
2312
  switch (format) {
1754
2313
  case 'spki':
@@ -1935,6 +2494,11 @@ export class Subtle {
1935
2494
  case 'HMAC':
1936
2495
  result = await hmacGenerateKey(algorithm, extractable, keyUsages);
1937
2496
  break;
2497
+ case 'KMAC128':
2498
+ // Fall through
2499
+ case 'KMAC256':
2500
+ result = await kmacGenerateKey(algorithm, extractable, keyUsages);
2501
+ break;
1938
2502
  case 'Ed25519':
1939
2503
  // Fall through
1940
2504
  case 'Ed448':
@@ -1967,6 +2531,18 @@ export class Subtle {
1967
2531
  );
1968
2532
  checkCryptoKeyPairUsages(result as CryptoKeyPair);
1969
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;
1970
2546
  default:
1971
2547
  throw new Error(
1972
2548
  `'subtle.generateKey()' is not implemented for ${algorithm.name}.
@@ -1977,6 +2553,21 @@ export class Subtle {
1977
2553
  return result;
1978
2554
  }
1979
2555
 
2556
+ async getPublicKey(
2557
+ key: CryptoKey,
2558
+ keyUsages: KeyUsage[],
2559
+ ): Promise<CryptoKey> {
2560
+ if (key.type === 'secret') {
2561
+ throw lazyDOMException('key must be a private key', 'NotSupportedError');
2562
+ }
2563
+ if (key.type !== 'private') {
2564
+ throw lazyDOMException('key must be a private key', 'InvalidAccessError');
2565
+ }
2566
+
2567
+ const publicKeyObject = createPublicKey(key.keyObject);
2568
+ return publicKeyObject.toCryptoKey(key.algorithm, true, keyUsages);
2569
+ }
2570
+
1980
2571
  async importKey(
1981
2572
  format: ImportFormat,
1982
2573
  data: BufferLike | BinaryLike | JWK,
@@ -1984,7 +2575,8 @@ export class Subtle {
1984
2575
  extractable: boolean,
1985
2576
  keyUsages: KeyUsage[],
1986
2577
  ): Promise<CryptoKey> {
1987
- if (format === 'raw-secret') format = 'raw';
2578
+ // Note: 'raw-seed' is NOT normalized — PQC import functions handle it directly
2579
+ if (format === 'raw-secret' || format === 'raw-public') format = 'raw';
1988
2580
  const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'importKey');
1989
2581
  let result: CryptoKey;
1990
2582
  switch (normalizedAlgorithm.name) {
@@ -2021,6 +2613,17 @@ export class Subtle {
2021
2613
  keyUsages,
2022
2614
  );
2023
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;
2024
2627
  case 'AES-CTR':
2025
2628
  // Fall through
2026
2629
  case 'AES-CBC':
@@ -2041,6 +2644,9 @@ export class Subtle {
2041
2644
  );
2042
2645
  break;
2043
2646
  case 'PBKDF2':
2647
+ case 'Argon2d':
2648
+ case 'Argon2i':
2649
+ case 'Argon2id':
2044
2650
  result = await importGenericSecretKey(
2045
2651
  normalizedAlgorithm,
2046
2652
  format,
@@ -2086,6 +2692,19 @@ export class Subtle {
2086
2692
  keyUsages,
2087
2693
  );
2088
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;
2089
2708
  default:
2090
2709
  throw new Error(
2091
2710
  `"subtle.importKey()" is not implemented for ${normalizedAlgorithm.name}`,
@@ -2109,103 +2728,164 @@ export class Subtle {
2109
2728
  key: CryptoKey,
2110
2729
  data: BufferLike,
2111
2730
  ): Promise<ArrayBuffer> {
2112
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'sign');
2731
+ return signVerify(
2732
+ normalizeAlgorithm(algorithm, 'sign'),
2733
+ key,
2734
+ data,
2735
+ ) as ArrayBuffer;
2736
+ }
2113
2737
 
2114
- if (normalizedAlgorithm.name === 'HMAC') {
2115
- // Validate key usage
2116
- if (!key.usages.includes('sign')) {
2117
- throw lazyDOMException(
2118
- 'Key does not have sign usage',
2119
- 'InvalidAccessError',
2120
- );
2121
- }
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
+ }
2122
2751
 
2123
- // Get hash algorithm from key or algorithm params
2124
- // Hash can be either a string or an object with name property
2125
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2126
- const alg = normalizedAlgorithm as any;
2127
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2128
- const keyAlg = key.algorithm as any;
2129
- let hashAlgorithm = 'SHA-256';
2130
-
2131
- if (typeof alg.hash === 'string') {
2132
- hashAlgorithm = alg.hash;
2133
- } else if (alg.hash?.name) {
2134
- hashAlgorithm = alg.hash.name;
2135
- } else if (typeof keyAlg.hash === 'string') {
2136
- hashAlgorithm = keyAlg.hash;
2137
- } else if (keyAlg.hash?.name) {
2138
- hashAlgorithm = keyAlg.hash.name;
2139
- }
2752
+ private _encapsulateCore(
2753
+ algorithm: SubtleAlgorithm,
2754
+ key: CryptoKey,
2755
+ ): EncapsulateResult {
2756
+ const normalizedAlgorithm = normalizeAlgorithm(
2757
+ algorithm,
2758
+ 'encapsulateBits' as Operation,
2759
+ );
2140
2760
 
2141
- // Create HMAC and sign
2142
- const keyData = key.keyObject.export();
2143
- const hmac = createHmac(hashAlgorithm, keyData);
2144
- hmac.update(bufferLikeToArrayBuffer(data));
2145
- return bufferLikeToArrayBuffer(hmac.digest());
2761
+ if (key.algorithm.name !== normalizedAlgorithm.name) {
2762
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
2146
2763
  }
2147
2764
 
2148
- 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();
2149
2779
  }
2150
2780
 
2151
- async verify(
2781
+ private _decapsulateCore(
2152
2782
  algorithm: SubtleAlgorithm,
2153
2783
  key: CryptoKey,
2154
- signature: BufferLike,
2155
- data: BufferLike,
2156
- ): Promise<boolean> {
2157
- const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'verify');
2784
+ ciphertext: BufferLike,
2785
+ ): ArrayBuffer {
2786
+ const normalizedAlgorithm = normalizeAlgorithm(
2787
+ algorithm,
2788
+ 'decapsulateBits' as Operation,
2789
+ );
2158
2790
 
2159
- if (normalizedAlgorithm.name === 'HMAC') {
2160
- // Validate key usage
2161
- if (!key.usages.includes('verify')) {
2162
- throw lazyDOMException(
2163
- 'Key does not have verify usage',
2164
- 'InvalidAccessError',
2165
- );
2166
- }
2791
+ if (key.algorithm.name !== normalizedAlgorithm.name) {
2792
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
2793
+ }
2167
2794
 
2168
- // Get hash algorithm
2169
- // Hash can be either a string or an object with name property
2170
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2171
- const alg = normalizedAlgorithm as any;
2172
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2173
- const keyAlg = key.algorithm as any;
2174
- let hashAlgorithm = 'SHA-256';
2175
-
2176
- if (typeof alg.hash === 'string') {
2177
- hashAlgorithm = alg.hash;
2178
- } else if (alg.hash?.name) {
2179
- hashAlgorithm = alg.hash.name;
2180
- } else if (typeof keyAlg.hash === 'string') {
2181
- hashAlgorithm = keyAlg.hash;
2182
- } else if (keyAlg.hash?.name) {
2183
- hashAlgorithm = keyAlg.hash.name;
2184
- }
2795
+ const variant = normalizedAlgorithm.name as MlKemVariant;
2796
+ const mlkem = new MlKem(variant);
2185
2797
 
2186
- // Create HMAC and compute expected signature
2187
- const keyData = key.keyObject.export();
2188
- const hmac = createHmac(hashAlgorithm, keyData);
2189
- const dataBuffer = bufferLikeToArrayBuffer(data);
2190
- hmac.update(dataBuffer);
2191
- const expectedDigest = hmac.digest();
2192
- const expected = new Uint8Array(bufferLikeToArrayBuffer(expectedDigest));
2193
-
2194
- // Constant-time comparison
2195
- const signatureArray = new Uint8Array(bufferLikeToArrayBuffer(signature));
2196
- if (expected.length !== signatureArray.length) {
2197
- return false;
2198
- }
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
+ );
2199
2807
 
2200
- // Manual constant-time comparison
2201
- let result = 0;
2202
- for (let i = 0; i < expected.length; i++) {
2203
- result |= expected[i]! ^ signatureArray[i]!;
2204
- }
2205
- 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
+ );
2820
+ }
2821
+
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
+ );
2206
2861
  }
2207
2862
 
2208
- return signVerify(normalizedAlgorithm, key, data, signature) as boolean;
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
+ );
2209
2889
  }
2210
2890
  }
2211
2891
 
@@ -2228,6 +2908,11 @@ function getKeyLength(algorithm: SubtleAlgorithm): number {
2228
2908
  return hmacAlg.length || 256;
2229
2909
  }
2230
2910
 
2911
+ case 'KMAC128':
2912
+ return algorithm.length || 128;
2913
+ case 'KMAC256':
2914
+ return algorithm.length || 256;
2915
+
2231
2916
  default:
2232
2917
  throw lazyDOMException(
2233
2918
  `Cannot determine key length for ${name}`,