@ohos-ports/react-native-quick-crypto 0.0.0-stage → 1.1.8-beta.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 (1027) hide show
  1. package/QuickCrypto.podspec +259 -0
  2. package/README.md +170 -2
  3. package/android/CMakeLists.txt +155 -0
  4. package/android/build.gradle +176 -0
  5. package/android/gradle.properties +6 -0
  6. package/android/src/main/AndroidManifest.xml +3 -0
  7. package/android/src/main/cpp/cpp-adapter.cpp +8 -0
  8. package/android/src/main/java/com/margelo/nitro/quickcrypto/QuickCryptoPackage.java +41 -0
  9. package/app.plugin.js +3 -0
  10. package/cpp/argon2/HybridArgon2.cpp +110 -0
  11. package/cpp/argon2/HybridArgon2.hpp +32 -0
  12. package/cpp/blake3/HybridBlake3.cpp +120 -0
  13. package/cpp/blake3/HybridBlake3.hpp +35 -0
  14. package/cpp/certificate/HybridCertificate.cpp +42 -0
  15. package/cpp/certificate/HybridCertificate.hpp +16 -0
  16. package/cpp/cipher/CCMCipher.cpp +211 -0
  17. package/cpp/cipher/CCMCipher.hpp +24 -0
  18. package/cpp/cipher/ChaCha20Cipher.cpp +91 -0
  19. package/cpp/cipher/ChaCha20Cipher.hpp +23 -0
  20. package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +175 -0
  21. package/cpp/cipher/ChaCha20Poly1305Cipher.hpp +27 -0
  22. package/cpp/cipher/GCMCipher.cpp +65 -0
  23. package/cpp/cipher/GCMCipher.hpp +14 -0
  24. package/cpp/cipher/HybridCipher.cpp +403 -0
  25. package/cpp/cipher/HybridCipher.hpp +90 -0
  26. package/cpp/cipher/HybridCipherFactory.hpp +119 -0
  27. package/cpp/cipher/HybridRsaCipher.cpp +477 -0
  28. package/cpp/cipher/HybridRsaCipher.hpp +33 -0
  29. package/cpp/cipher/OCBCipher.cpp +55 -0
  30. package/cpp/cipher/OCBCipher.hpp +19 -0
  31. package/cpp/cipher/XChaCha20Poly1305Cipher.cpp +158 -0
  32. package/cpp/cipher/XChaCha20Poly1305Cipher.hpp +42 -0
  33. package/cpp/cipher/XSalsa20Cipher.cpp +127 -0
  34. package/cpp/cipher/XSalsa20Cipher.hpp +55 -0
  35. package/cpp/cipher/XSalsa20Poly1305Cipher.cpp +138 -0
  36. package/cpp/cipher/XSalsa20Poly1305Cipher.hpp +41 -0
  37. package/cpp/dh/HybridDhKeyPair.cpp +179 -0
  38. package/cpp/dh/HybridDhKeyPair.hpp +37 -0
  39. package/cpp/dh/HybridDiffieHellman.cpp +482 -0
  40. package/cpp/dh/HybridDiffieHellman.hpp +42 -0
  41. package/cpp/dsa/HybridDsaKeyPair.cpp +128 -0
  42. package/cpp/dsa/HybridDsaKeyPair.hpp +32 -0
  43. package/cpp/ec/HybridEcKeyPair.cpp +481 -0
  44. package/cpp/ec/HybridEcKeyPair.hpp +45 -0
  45. package/cpp/ecdh/HybridECDH.cpp +251 -0
  46. package/cpp/ecdh/HybridECDH.hpp +43 -0
  47. package/cpp/ed25519/HybridEdKeyPair.cpp +360 -0
  48. package/cpp/ed25519/HybridEdKeyPair.hpp +67 -0
  49. package/cpp/hash/HybridHash.cpp +190 -0
  50. package/cpp/hash/HybridHash.hpp +43 -0
  51. package/cpp/hkdf/HybridHkdf.cpp +115 -0
  52. package/cpp/hkdf/HybridHkdf.hpp +29 -0
  53. package/cpp/hmac/HybridHmac.cpp +102 -0
  54. package/cpp/hmac/HybridHmac.hpp +32 -0
  55. package/cpp/keys/HybridKeyObjectHandle.cpp +1519 -0
  56. package/cpp/keys/HybridKeyObjectHandle.hpp +78 -0
  57. package/cpp/keys/KeyObjectData.cpp +298 -0
  58. package/cpp/keys/KeyObjectData.hpp +73 -0
  59. package/cpp/keys/node.h +5 -0
  60. package/cpp/kmac/HybridKmac.cpp +83 -0
  61. package/cpp/kmac/HybridKmac.hpp +31 -0
  62. package/cpp/mldsa/HybridMlDsaKeyPair.cpp +243 -0
  63. package/cpp/mldsa/HybridMlDsaKeyPair.hpp +49 -0
  64. package/cpp/mlkem/HybridMlKemKeyPair.cpp +315 -0
  65. package/cpp/mlkem/HybridMlKemKeyPair.hpp +48 -0
  66. package/cpp/pbkdf2/HybridPbkdf2.cpp +50 -0
  67. package/cpp/pbkdf2/HybridPbkdf2.hpp +24 -0
  68. package/cpp/prime/HybridPrime.cpp +81 -0
  69. package/cpp/prime/HybridPrime.hpp +20 -0
  70. package/cpp/random/HybridRandom.cpp +48 -0
  71. package/cpp/random/HybridRandom.hpp +32 -0
  72. package/cpp/rsa/HybridRsaKeyPair.cpp +151 -0
  73. package/cpp/rsa/HybridRsaKeyPair.hpp +40 -0
  74. package/cpp/scrypt/HybridScrypt.cpp +64 -0
  75. package/cpp/scrypt/HybridScrypt.hpp +28 -0
  76. package/cpp/sign/HybridSignHandle.cpp +241 -0
  77. package/cpp/sign/HybridSignHandle.hpp +36 -0
  78. package/cpp/sign/HybridVerifyHandle.cpp +207 -0
  79. package/cpp/sign/HybridVerifyHandle.hpp +36 -0
  80. package/cpp/sign/SignUtils.hpp +91 -0
  81. package/cpp/slhdsa/HybridSlhDsaKeyPair.cpp +245 -0
  82. package/cpp/slhdsa/HybridSlhDsaKeyPair.hpp +48 -0
  83. package/cpp/turboshake/HybridTurboShake.cpp +379 -0
  84. package/cpp/turboshake/HybridTurboShake.hpp +28 -0
  85. package/cpp/utils/HybridUtils.cpp +399 -0
  86. package/cpp/utils/HybridUtils.hpp +28 -0
  87. package/cpp/utils/Macros.hpp +68 -0
  88. package/cpp/utils/QuickCryptoUtils.cpp +44 -0
  89. package/cpp/utils/QuickCryptoUtils.hpp +186 -0
  90. package/cpp/utils/base64.h +309 -0
  91. package/cpp/x509/HybridX509Certificate.cpp +174 -0
  92. package/cpp/x509/HybridX509Certificate.hpp +51 -0
  93. package/deps/blake3/LICENSE_A2 +202 -0
  94. package/deps/blake3/LICENSE_A2LLVM +219 -0
  95. package/deps/blake3/LICENSE_CC0 +121 -0
  96. package/deps/blake3/README.md +228 -0
  97. package/deps/blake3/c/README.md +403 -0
  98. package/deps/blake3/c/blake3.c +651 -0
  99. package/deps/blake3/c/blake3.h +86 -0
  100. package/deps/blake3/c/blake3_dispatch.c +332 -0
  101. package/deps/blake3/c/blake3_impl.h +333 -0
  102. package/deps/blake3/c/blake3_neon.c +367 -0
  103. package/deps/blake3/c/blake3_portable.c +160 -0
  104. package/deps/fastpbkdf2/fastpbkdf2.c +356 -0
  105. package/deps/fastpbkdf2/fastpbkdf2.h +68 -0
  106. package/deps/ncrypto/LICENSE +21 -0
  107. package/deps/ncrypto/README.md +18 -0
  108. package/deps/ncrypto/include/dh-primes.h +67 -0
  109. package/deps/ncrypto/include/ncrypto/aead.h +137 -0
  110. package/deps/ncrypto/include/ncrypto/version.h +14 -0
  111. package/deps/ncrypto/include/ncrypto.h +1759 -0
  112. package/deps/ncrypto/src/aead.cpp +302 -0
  113. package/deps/ncrypto/src/engine.cpp +93 -0
  114. package/deps/ncrypto/src/ncrypto.cpp +5426 -0
  115. package/deps/simdutf/LICENSE-APACHE +201 -0
  116. package/deps/simdutf/LICENSE-MIT +18 -0
  117. package/deps/simdutf/README.md +2782 -0
  118. package/deps/simdutf/include/simdutf/avx512.h +79 -0
  119. package/deps/simdutf/include/simdutf/base64_implementation.h +158 -0
  120. package/deps/simdutf/include/simdutf/base64_tables.h +887 -0
  121. package/deps/simdutf/include/simdutf/common_defs.h +186 -0
  122. package/deps/simdutf/include/simdutf/compiler_check.h +50 -0
  123. package/deps/simdutf/include/simdutf/constexpr_ptr.h +138 -0
  124. package/deps/simdutf/include/simdutf/encoding_types.h +189 -0
  125. package/deps/simdutf/include/simdutf/error.h +126 -0
  126. package/deps/simdutf/include/simdutf/implementation.h +7081 -0
  127. package/deps/simdutf/include/simdutf/internal/isadetection.h +325 -0
  128. package/deps/simdutf/include/simdutf/portability.h +285 -0
  129. package/deps/simdutf/include/simdutf/scalar/ascii.h +86 -0
  130. package/deps/simdutf/include/simdutf/scalar/atomic_util.h +105 -0
  131. package/deps/simdutf/include/simdutf/scalar/base64.h +911 -0
  132. package/deps/simdutf/include/simdutf/scalar/latin1.h +26 -0
  133. package/deps/simdutf/include/simdutf/scalar/latin1_to_utf16/latin1_to_utf16.h +52 -0
  134. package/deps/simdutf/include/simdutf/scalar/latin1_to_utf32/latin1_to_utf32.h +27 -0
  135. package/deps/simdutf/include/simdutf/scalar/latin1_to_utf8/latin1_to_utf8.h +191 -0
  136. package/deps/simdutf/include/simdutf/scalar/swap_bytes.h +35 -0
  137. package/deps/simdutf/include/simdutf/scalar/utf16.h +226 -0
  138. package/deps/simdutf/include/simdutf/scalar/utf16_to_latin1/utf16_to_latin1.h +108 -0
  139. package/deps/simdutf/include/simdutf/scalar/utf16_to_latin1/valid_utf16_to_latin1.h +40 -0
  140. package/deps/simdutf/include/simdutf/scalar/utf16_to_utf32/utf16_to_utf32.h +86 -0
  141. package/deps/simdutf/include/simdutf/scalar/utf16_to_utf32/valid_utf16_to_utf32.h +44 -0
  142. package/deps/simdutf/include/simdutf/scalar/utf16_to_utf8/utf16_to_utf8.h +295 -0
  143. package/deps/simdutf/include/simdutf/scalar/utf16_to_utf8/valid_utf16_to_utf8.h +91 -0
  144. package/deps/simdutf/include/simdutf/scalar/utf32.h +82 -0
  145. package/deps/simdutf/include/simdutf/scalar/utf32_to_latin1/utf32_to_latin1.h +68 -0
  146. package/deps/simdutf/include/simdutf/scalar/utf32_to_latin1/valid_utf32_to_latin1.h +67 -0
  147. package/deps/simdutf/include/simdutf/scalar/utf32_to_utf16/utf32_to_utf16.h +84 -0
  148. package/deps/simdutf/include/simdutf/scalar/utf32_to_utf16/valid_utf32_to_utf16.h +44 -0
  149. package/deps/simdutf/include/simdutf/scalar/utf32_to_utf8/utf32_to_utf8.h +142 -0
  150. package/deps/simdutf/include/simdutf/scalar/utf32_to_utf8/valid_utf32_to_utf8.h +72 -0
  151. package/deps/simdutf/include/simdutf/scalar/utf8.h +326 -0
  152. package/deps/simdutf/include/simdutf/scalar/utf8_to_latin1/utf8_to_latin1.h +225 -0
  153. package/deps/simdutf/include/simdutf/scalar/utf8_to_latin1/valid_utf8_to_latin1.h +87 -0
  154. package/deps/simdutf/include/simdutf/scalar/utf8_to_utf16/utf8_to_utf16.h +342 -0
  155. package/deps/simdutf/include/simdutf/scalar/utf8_to_utf16/valid_utf8_to_utf16.h +106 -0
  156. package/deps/simdutf/include/simdutf/scalar/utf8_to_utf32/utf8_to_utf32.h +299 -0
  157. package/deps/simdutf/include/simdutf/scalar/utf8_to_utf32/valid_utf8_to_utf32.h +83 -0
  158. package/deps/simdutf/include/simdutf/simdutf_version.h +26 -0
  159. package/deps/simdutf/include/simdutf.h +26 -0
  160. package/deps/simdutf/include/simdutf_c.h +342 -0
  161. package/deps/simdutf/src/arm64/arm_base64.cpp +791 -0
  162. package/deps/simdutf/src/arm64/arm_convert_latin1_to_utf16.cpp +24 -0
  163. package/deps/simdutf/src/arm64/arm_convert_latin1_to_utf32.cpp +24 -0
  164. package/deps/simdutf/src/arm64/arm_convert_latin1_to_utf8.cpp +70 -0
  165. package/deps/simdutf/src/arm64/arm_convert_utf16_to_latin1.cpp +61 -0
  166. package/deps/simdutf/src/arm64/arm_convert_utf16_to_utf32.cpp +185 -0
  167. package/deps/simdutf/src/arm64/arm_convert_utf16_to_utf8.cpp +780 -0
  168. package/deps/simdutf/src/arm64/arm_convert_utf32_to_latin1.cpp +60 -0
  169. package/deps/simdutf/src/arm64/arm_convert_utf32_to_utf16.cpp +208 -0
  170. package/deps/simdutf/src/arm64/arm_convert_utf32_to_utf8.cpp +505 -0
  171. package/deps/simdutf/src/arm64/arm_convert_utf8_to_latin1.cpp +69 -0
  172. package/deps/simdutf/src/arm64/arm_convert_utf8_to_utf16.cpp +313 -0
  173. package/deps/simdutf/src/arm64/arm_convert_utf8_to_utf32.cpp +179 -0
  174. package/deps/simdutf/src/arm64/arm_find.cpp +199 -0
  175. package/deps/simdutf/src/arm64/arm_utf16fix.cpp +185 -0
  176. package/deps/simdutf/src/arm64/arm_validate_utf16.cpp +165 -0
  177. package/deps/simdutf/src/arm64/arm_validate_utf32le.cpp +65 -0
  178. package/deps/simdutf/src/arm64/implementation.cpp +1442 -0
  179. package/deps/simdutf/src/encoding_types.cpp +67 -0
  180. package/deps/simdutf/src/error.cpp +3 -0
  181. package/deps/simdutf/src/fallback/implementation.cpp +589 -0
  182. package/deps/simdutf/src/generic/ascii_validation.h +50 -0
  183. package/deps/simdutf/src/generic/base64.h +233 -0
  184. package/deps/simdutf/src/generic/base64lengths.h +63 -0
  185. package/deps/simdutf/src/generic/buf_block_reader.h +109 -0
  186. package/deps/simdutf/src/generic/find.h +75 -0
  187. package/deps/simdutf/src/generic/utf16/change_endianness.h +24 -0
  188. package/deps/simdutf/src/generic/utf16/count_code_points_bytemask.h +58 -0
  189. package/deps/simdutf/src/generic/utf16/to_well_formed.h +93 -0
  190. package/deps/simdutf/src/generic/utf16/utf32_length_from_utf16.h +15 -0
  191. package/deps/simdutf/src/generic/utf16/utf8_length_from_utf16.h +35 -0
  192. package/deps/simdutf/src/generic/utf16/utf8_length_from_utf16_bytemask.h +199 -0
  193. package/deps/simdutf/src/generic/utf16.h +73 -0
  194. package/deps/simdutf/src/generic/utf32.h +136 -0
  195. package/deps/simdutf/src/generic/utf8/utf16_length_from_utf8_bytemask.h +53 -0
  196. package/deps/simdutf/src/generic/utf8.h +92 -0
  197. package/deps/simdutf/src/generic/utf8_to_latin1/utf8_to_latin1.h +316 -0
  198. package/deps/simdutf/src/generic/utf8_to_latin1/valid_utf8_to_latin1.h +78 -0
  199. package/deps/simdutf/src/generic/utf8_to_utf16/utf8_to_utf16.h +332 -0
  200. package/deps/simdutf/src/generic/utf8_to_utf16/valid_utf8_to_utf16.h +74 -0
  201. package/deps/simdutf/src/generic/utf8_to_utf32/utf8_to_utf32.h +318 -0
  202. package/deps/simdutf/src/generic/utf8_to_utf32/valid_utf8_to_utf32.h +42 -0
  203. package/deps/simdutf/src/generic/utf8_validation/utf8_lookup4_algorithm.h +223 -0
  204. package/deps/simdutf/src/generic/utf8_validation/utf8_validator.h +84 -0
  205. package/deps/simdutf/src/generic/validate_utf16.h +164 -0
  206. package/deps/simdutf/src/generic/validate_utf32.h +99 -0
  207. package/deps/simdutf/src/haswell/avx2_base64.cpp +837 -0
  208. package/deps/simdutf/src/haswell/avx2_convert_latin1_to_utf16.cpp +28 -0
  209. package/deps/simdutf/src/haswell/avx2_convert_latin1_to_utf32.cpp +20 -0
  210. package/deps/simdutf/src/haswell/avx2_convert_latin1_to_utf8.cpp +83 -0
  211. package/deps/simdutf/src/haswell/avx2_convert_utf16_to_latin1.cpp +83 -0
  212. package/deps/simdutf/src/haswell/avx2_convert_utf16_to_utf32.cpp +210 -0
  213. package/deps/simdutf/src/haswell/avx2_convert_utf16_to_utf8.cpp +602 -0
  214. package/deps/simdutf/src/haswell/avx2_convert_utf32_to_latin1.cpp +116 -0
  215. package/deps/simdutf/src/haswell/avx2_convert_utf32_to_utf16.cpp +164 -0
  216. package/deps/simdutf/src/haswell/avx2_convert_utf32_to_utf8.cpp +569 -0
  217. package/deps/simdutf/src/haswell/avx2_convert_utf8_to_latin1.cpp +60 -0
  218. package/deps/simdutf/src/haswell/avx2_convert_utf8_to_utf16.cpp +195 -0
  219. package/deps/simdutf/src/haswell/avx2_convert_utf8_to_utf32.cpp +135 -0
  220. package/deps/simdutf/src/haswell/avx2_utf16fix.cpp +173 -0
  221. package/deps/simdutf/src/haswell/avx2_validate_utf16.cpp +17 -0
  222. package/deps/simdutf/src/haswell/implementation.cpp +1447 -0
  223. package/deps/simdutf/src/icelake/icelake_ascii_validation.inl.cpp +19 -0
  224. package/deps/simdutf/src/icelake/icelake_base64.inl.cpp +630 -0
  225. package/deps/simdutf/src/icelake/icelake_common.inl.cpp +37 -0
  226. package/deps/simdutf/src/icelake/icelake_convert_latin1_to_utf16.inl.cpp +36 -0
  227. package/deps/simdutf/src/icelake/icelake_convert_latin1_to_utf32.inl.cpp +23 -0
  228. package/deps/simdutf/src/icelake/icelake_convert_latin1_to_utf8.inl.cpp +107 -0
  229. package/deps/simdutf/src/icelake/icelake_convert_utf16_to_latin1.inl.cpp +103 -0
  230. package/deps/simdutf/src/icelake/icelake_convert_utf16_to_utf32.inl.cpp +136 -0
  231. package/deps/simdutf/src/icelake/icelake_convert_utf16_to_utf8.inl.cpp +206 -0
  232. package/deps/simdutf/src/icelake/icelake_convert_utf32_to_latin1.inl.cpp +74 -0
  233. package/deps/simdutf/src/icelake/icelake_convert_utf32_to_utf16.inl.cpp +338 -0
  234. package/deps/simdutf/src/icelake/icelake_convert_utf32_to_utf8.inl.cpp +574 -0
  235. package/deps/simdutf/src/icelake/icelake_convert_utf8_to_latin1.inl.cpp +104 -0
  236. package/deps/simdutf/src/icelake/icelake_convert_utf8_to_utf16.inl.cpp +75 -0
  237. package/deps/simdutf/src/icelake/icelake_convert_valid_utf8_to_latin1.inl.cpp +69 -0
  238. package/deps/simdutf/src/icelake/icelake_find.inl.cpp +146 -0
  239. package/deps/simdutf/src/icelake/icelake_from_utf8.inl.cpp +266 -0
  240. package/deps/simdutf/src/icelake/icelake_from_valid_utf8.inl.cpp +136 -0
  241. package/deps/simdutf/src/icelake/icelake_macros.inl.cpp +143 -0
  242. package/deps/simdutf/src/icelake/icelake_utf16fix.cpp +138 -0
  243. package/deps/simdutf/src/icelake/icelake_utf32_validation.inl.cpp +63 -0
  244. package/deps/simdutf/src/icelake/icelake_utf8_common.inl.cpp +753 -0
  245. package/deps/simdutf/src/icelake/icelake_utf8_length_from_utf16.inl.cpp +269 -0
  246. package/deps/simdutf/src/icelake/icelake_utf8_validation.inl.cpp +116 -0
  247. package/deps/simdutf/src/icelake/implementation.cpp +1903 -0
  248. package/deps/simdutf/src/implementation.cpp +2526 -0
  249. package/deps/simdutf/src/lasx/implementation.cpp +1531 -0
  250. package/deps/simdutf/src/lasx/lasx_base64.cpp +695 -0
  251. package/deps/simdutf/src/lasx/lasx_convert_latin1_to_utf16.cpp +76 -0
  252. package/deps/simdutf/src/lasx/lasx_convert_latin1_to_utf32.cpp +55 -0
  253. package/deps/simdutf/src/lasx/lasx_convert_latin1_to_utf8.cpp +65 -0
  254. package/deps/simdutf/src/lasx/lasx_convert_utf16_to_latin1.cpp +64 -0
  255. package/deps/simdutf/src/lasx/lasx_convert_utf16_to_utf32.cpp +183 -0
  256. package/deps/simdutf/src/lasx/lasx_convert_utf16_to_utf8.cpp +550 -0
  257. package/deps/simdutf/src/lasx/lasx_convert_utf32_to_latin1.cpp +73 -0
  258. package/deps/simdutf/src/lasx/lasx_convert_utf32_to_utf16.cpp +218 -0
  259. package/deps/simdutf/src/lasx/lasx_convert_utf32_to_utf8.cpp +589 -0
  260. package/deps/simdutf/src/lasx/lasx_convert_utf8_to_latin1.cpp +72 -0
  261. package/deps/simdutf/src/lasx/lasx_convert_utf8_to_utf16.cpp +296 -0
  262. package/deps/simdutf/src/lasx/lasx_convert_utf8_to_utf32.cpp +190 -0
  263. package/deps/simdutf/src/lasx/lasx_find.cpp +64 -0
  264. package/deps/simdutf/src/lasx/lasx_validate_utf16.cpp +13 -0
  265. package/deps/simdutf/src/lasx/lasx_validate_utf32le.cpp +84 -0
  266. package/deps/simdutf/src/lsx/implementation.cpp +1417 -0
  267. package/deps/simdutf/src/lsx/lsx_base64.cpp +675 -0
  268. package/deps/simdutf/src/lsx/lsx_convert_latin1_to_utf16.cpp +39 -0
  269. package/deps/simdutf/src/lsx/lsx_convert_latin1_to_utf32.cpp +27 -0
  270. package/deps/simdutf/src/lsx/lsx_convert_latin1_to_utf8.cpp +56 -0
  271. package/deps/simdutf/src/lsx/lsx_convert_utf16_to_latin1.cpp +64 -0
  272. package/deps/simdutf/src/lsx/lsx_convert_utf16_to_utf32.cpp +133 -0
  273. package/deps/simdutf/src/lsx/lsx_convert_utf16_to_utf8.cpp +518 -0
  274. package/deps/simdutf/src/lsx/lsx_convert_utf32_to_latin1.cpp +66 -0
  275. package/deps/simdutf/src/lsx/lsx_convert_utf32_to_utf16.cpp +155 -0
  276. package/deps/simdutf/src/lsx/lsx_convert_utf32_to_utf8.cpp +459 -0
  277. package/deps/simdutf/src/lsx/lsx_convert_utf8_to_latin1.cpp +75 -0
  278. package/deps/simdutf/src/lsx/lsx_convert_utf8_to_utf16.cpp +291 -0
  279. package/deps/simdutf/src/lsx/lsx_convert_utf8_to_utf32.cpp +179 -0
  280. package/deps/simdutf/src/lsx/lsx_find.cpp +60 -0
  281. package/deps/simdutf/src/lsx/lsx_validate_utf16.cpp +13 -0
  282. package/deps/simdutf/src/lsx/lsx_validate_utf32le.cpp +68 -0
  283. package/deps/simdutf/src/ppc64/implementation.cpp +992 -0
  284. package/deps/simdutf/src/ppc64/ppc64_base64.cpp +480 -0
  285. package/deps/simdutf/src/ppc64/ppc64_base64_internal_tests.cpp +401 -0
  286. package/deps/simdutf/src/ppc64/ppc64_convert_latin1_to_utf16.cpp +12 -0
  287. package/deps/simdutf/src/ppc64/ppc64_convert_latin1_to_utf32.cpp +12 -0
  288. package/deps/simdutf/src/ppc64/ppc64_convert_latin1_to_utf8.cpp +149 -0
  289. package/deps/simdutf/src/ppc64/ppc64_convert_utf16_to_latin1.cpp +67 -0
  290. package/deps/simdutf/src/ppc64/ppc64_convert_utf16_to_utf32.cpp +87 -0
  291. package/deps/simdutf/src/ppc64/ppc64_convert_utf16_to_utf8.cpp +296 -0
  292. package/deps/simdutf/src/ppc64/ppc64_convert_utf32_to_latin1.cpp +57 -0
  293. package/deps/simdutf/src/ppc64/ppc64_convert_utf32_to_utf16.cpp +117 -0
  294. package/deps/simdutf/src/ppc64/ppc64_convert_utf32_to_utf8.cpp +166 -0
  295. package/deps/simdutf/src/ppc64/ppc64_convert_utf8_to_latin1.cpp +69 -0
  296. package/deps/simdutf/src/ppc64/ppc64_convert_utf8_to_utf16.cpp +211 -0
  297. package/deps/simdutf/src/ppc64/ppc64_convert_utf8_to_utf32.cpp +153 -0
  298. package/deps/simdutf/src/ppc64/ppc64_utf16_to_utf8_tables.h +1011 -0
  299. package/deps/simdutf/src/ppc64/ppc64_utf8_length_from_latin1.cpp +37 -0
  300. package/deps/simdutf/src/ppc64/ppc64_validate_utf16.cpp +19 -0
  301. package/deps/simdutf/src/ppc64/templates.cpp +91 -0
  302. package/deps/simdutf/src/rvv/implementation.cpp +138 -0
  303. package/deps/simdutf/src/rvv/rvv_find.cpp +27 -0
  304. package/deps/simdutf/src/rvv/rvv_helpers.inl.cpp +23 -0
  305. package/deps/simdutf/src/rvv/rvv_latin1_to.inl.cpp +71 -0
  306. package/deps/simdutf/src/rvv/rvv_length_from.inl.cpp +164 -0
  307. package/deps/simdutf/src/rvv/rvv_utf16_to.inl.cpp +399 -0
  308. package/deps/simdutf/src/rvv/rvv_utf16fix.cpp +110 -0
  309. package/deps/simdutf/src/rvv/rvv_utf32_to.inl.cpp +307 -0
  310. package/deps/simdutf/src/rvv/rvv_utf8_to.inl.cpp +435 -0
  311. package/deps/simdutf/src/rvv/rvv_validate.inl.cpp +275 -0
  312. package/deps/simdutf/src/simdutf/arm64/begin.h +2 -0
  313. package/deps/simdutf/src/simdutf/arm64/bitmanipulation.h +34 -0
  314. package/deps/simdutf/src/simdutf/arm64/end.h +2 -0
  315. package/deps/simdutf/src/simdutf/arm64/implementation.h +307 -0
  316. package/deps/simdutf/src/simdutf/arm64/intrinsics.h +10 -0
  317. package/deps/simdutf/src/simdutf/arm64/simd.h +547 -0
  318. package/deps/simdutf/src/simdutf/arm64/simd16-inl.h +403 -0
  319. package/deps/simdutf/src/simdutf/arm64/simd32-inl.h +129 -0
  320. package/deps/simdutf/src/simdutf/arm64/simd64-inl.h +28 -0
  321. package/deps/simdutf/src/simdutf/arm64.h +43 -0
  322. package/deps/simdutf/src/simdutf/fallback/begin.h +1 -0
  323. package/deps/simdutf/src/simdutf/fallback/bitmanipulation.h +13 -0
  324. package/deps/simdutf/src/simdutf/fallback/end.h +1 -0
  325. package/deps/simdutf/src/simdutf/fallback/implementation.h +331 -0
  326. package/deps/simdutf/src/simdutf/fallback.h +42 -0
  327. package/deps/simdutf/src/simdutf/haswell/begin.h +15 -0
  328. package/deps/simdutf/src/simdutf/haswell/bitmanipulation.h +35 -0
  329. package/deps/simdutf/src/simdutf/haswell/end.h +13 -0
  330. package/deps/simdutf/src/simdutf/haswell/implementation.h +338 -0
  331. package/deps/simdutf/src/simdutf/haswell/intrinsics.h +67 -0
  332. package/deps/simdutf/src/simdutf/haswell/simd.h +363 -0
  333. package/deps/simdutf/src/simdutf/haswell/simd16-inl.h +261 -0
  334. package/deps/simdutf/src/simdutf/haswell/simd32-inl.h +111 -0
  335. package/deps/simdutf/src/simdutf/haswell/simd64-inl.h +34 -0
  336. package/deps/simdutf/src/simdutf/haswell.h +63 -0
  337. package/deps/simdutf/src/simdutf/icelake/begin.h +14 -0
  338. package/deps/simdutf/src/simdutf/icelake/bitmanipulation.h +44 -0
  339. package/deps/simdutf/src/simdutf/icelake/end.h +12 -0
  340. package/deps/simdutf/src/simdutf/icelake/implementation.h +346 -0
  341. package/deps/simdutf/src/simdutf/icelake/intrinsics.h +138 -0
  342. package/deps/simdutf/src/simdutf/icelake/simd.h +17 -0
  343. package/deps/simdutf/src/simdutf/icelake/simd16-inl.h +90 -0
  344. package/deps/simdutf/src/simdutf/icelake/simd32-inl.h +47 -0
  345. package/deps/simdutf/src/simdutf/icelake.h +81 -0
  346. package/deps/simdutf/src/simdutf/lasx/begin.h +8 -0
  347. package/deps/simdutf/src/simdutf/lasx/bitmanipulation.h +25 -0
  348. package/deps/simdutf/src/simdutf/lasx/end.h +8 -0
  349. package/deps/simdutf/src/simdutf/lasx/implementation.h +310 -0
  350. package/deps/simdutf/src/simdutf/lasx/intrinsics.h +319 -0
  351. package/deps/simdutf/src/simdutf/lasx/simd.h +551 -0
  352. package/deps/simdutf/src/simdutf/lasx/simd16-inl.h +234 -0
  353. package/deps/simdutf/src/simdutf/lasx/simd32-inl.h +74 -0
  354. package/deps/simdutf/src/simdutf/lasx/simd64-inl.h +52 -0
  355. package/deps/simdutf/src/simdutf/lasx.h +49 -0
  356. package/deps/simdutf/src/simdutf/lsx/begin.h +2 -0
  357. package/deps/simdutf/src/simdutf/lsx/bitmanipulation.h +25 -0
  358. package/deps/simdutf/src/simdutf/lsx/end.h +2 -0
  359. package/deps/simdutf/src/simdutf/lsx/implementation.h +309 -0
  360. package/deps/simdutf/src/simdutf/lsx/intrinsics.h +196 -0
  361. package/deps/simdutf/src/simdutf/lsx/simd.h +421 -0
  362. package/deps/simdutf/src/simdutf/lsx/simd16-inl.h +242 -0
  363. package/deps/simdutf/src/simdutf/lsx/simd32-inl.h +69 -0
  364. package/deps/simdutf/src/simdutf/lsx/simd64-inl.h +50 -0
  365. package/deps/simdutf/src/simdutf/lsx.h +52 -0
  366. package/deps/simdutf/src/simdutf/ppc64/begin.h +1 -0
  367. package/deps/simdutf/src/simdutf/ppc64/bitmanipulation.h +29 -0
  368. package/deps/simdutf/src/simdutf/ppc64/end.h +1 -0
  369. package/deps/simdutf/src/simdutf/ppc64/implementation.h +348 -0
  370. package/deps/simdutf/src/simdutf/ppc64/intrinsics.h +19 -0
  371. package/deps/simdutf/src/simdutf/ppc64/simd.h +177 -0
  372. package/deps/simdutf/src/simdutf/ppc64/simd16-inl.h +327 -0
  373. package/deps/simdutf/src/simdutf/ppc64/simd32-inl.h +247 -0
  374. package/deps/simdutf/src/simdutf/ppc64/simd8-inl.h +618 -0
  375. package/deps/simdutf/src/simdutf/ppc64.h +40 -0
  376. package/deps/simdutf/src/simdutf/rvv/begin.h +7 -0
  377. package/deps/simdutf/src/simdutf/rvv/end.h +7 -0
  378. package/deps/simdutf/src/simdutf/rvv/implementation.h +321 -0
  379. package/deps/simdutf/src/simdutf/rvv/intrinsics.h +131 -0
  380. package/deps/simdutf/src/simdutf/rvv.h +41 -0
  381. package/deps/simdutf/src/simdutf/westmere/begin.h +8 -0
  382. package/deps/simdutf/src/simdutf/westmere/bitmanipulation.h +37 -0
  383. package/deps/simdutf/src/simdutf/westmere/end.h +8 -0
  384. package/deps/simdutf/src/simdutf/westmere/implementation.h +338 -0
  385. package/deps/simdutf/src/simdutf/westmere/intrinsics.h +38 -0
  386. package/deps/simdutf/src/simdutf/westmere/simd.h +379 -0
  387. package/deps/simdutf/src/simdutf/westmere/simd16-inl.h +242 -0
  388. package/deps/simdutf/src/simdutf/westmere/simd32-inl.h +151 -0
  389. package/deps/simdutf/src/simdutf/westmere/simd64-inl.h +33 -0
  390. package/deps/simdutf/src/simdutf/westmere.h +59 -0
  391. package/deps/simdutf/src/simdutf.cpp +152 -0
  392. package/deps/simdutf/src/simdutf_c.cpp +525 -0
  393. package/deps/simdutf/src/tables/utf16_to_utf8_tables.h +768 -0
  394. package/deps/simdutf/src/tables/utf32_to_utf16_tables.h +53 -0
  395. package/deps/simdutf/src/tables/utf8_to_utf16_tables.h +826 -0
  396. package/deps/simdutf/src/westmere/implementation.cpp +1479 -0
  397. package/deps/simdutf/src/westmere/internal/loader.cpp +7 -0
  398. package/deps/simdutf/src/westmere/internal/write_v_u16_11bits_to_utf8.cpp +66 -0
  399. package/deps/simdutf/src/westmere/sse_base64.cpp +672 -0
  400. package/deps/simdutf/src/westmere/sse_convert_latin1_to_utf16.cpp +21 -0
  401. package/deps/simdutf/src/westmere/sse_convert_latin1_to_utf32.cpp +31 -0
  402. package/deps/simdutf/src/westmere/sse_convert_latin1_to_utf8.cpp +71 -0
  403. package/deps/simdutf/src/westmere/sse_convert_utf16_to_latin1.cpp +70 -0
  404. package/deps/simdutf/src/westmere/sse_convert_utf16_to_utf32.cpp +206 -0
  405. package/deps/simdutf/src/westmere/sse_convert_utf16_to_utf8.cpp +504 -0
  406. package/deps/simdutf/src/westmere/sse_convert_utf32_to_latin1.cpp +82 -0
  407. package/deps/simdutf/src/westmere/sse_convert_utf32_to_utf16.cpp +209 -0
  408. package/deps/simdutf/src/westmere/sse_convert_utf32_to_utf8.cpp +589 -0
  409. package/deps/simdutf/src/westmere/sse_convert_utf8_to_latin1.cpp +58 -0
  410. package/deps/simdutf/src/westmere/sse_convert_utf8_to_utf16.cpp +197 -0
  411. package/deps/simdutf/src/westmere/sse_convert_utf8_to_utf32.cpp +141 -0
  412. package/deps/simdutf/src/westmere/sse_utf16fix.cpp +82 -0
  413. package/deps/simdutf/src/westmere/sse_validate_utf16.cpp +17 -0
  414. package/jest/index.js +16 -0
  415. package/lib/commonjs/argon2.js +88 -0
  416. package/lib/commonjs/argon2.js.map +1 -0
  417. package/lib/commonjs/blake3.js +99 -0
  418. package/lib/commonjs/blake3.js.map +1 -0
  419. package/lib/commonjs/certificate.js +35 -0
  420. package/lib/commonjs/certificate.js.map +1 -0
  421. package/lib/commonjs/cipher.js +299 -0
  422. package/lib/commonjs/cipher.js.map +1 -0
  423. package/lib/commonjs/constants.js +32 -0
  424. package/lib/commonjs/constants.js.map +1 -0
  425. package/lib/commonjs/dh-groups.js +29 -0
  426. package/lib/commonjs/dh-groups.js.map +1 -0
  427. package/lib/commonjs/dhKeyPair.js +112 -0
  428. package/lib/commonjs/dhKeyPair.js.map +1 -0
  429. package/lib/commonjs/diffie-hellman.js +151 -0
  430. package/lib/commonjs/diffie-hellman.js.map +1 -0
  431. package/lib/commonjs/dsa.js +101 -0
  432. package/lib/commonjs/dsa.js.map +1 -0
  433. package/lib/commonjs/ec.js +370 -0
  434. package/lib/commonjs/ec.js.map +1 -0
  435. package/lib/commonjs/ecdh.js +109 -0
  436. package/lib/commonjs/ecdh.js.map +1 -0
  437. package/lib/commonjs/ed.js +443 -0
  438. package/lib/commonjs/ed.js.map +1 -0
  439. package/lib/commonjs/expo-plugin/@types.js +2 -0
  440. package/lib/commonjs/expo-plugin/@types.js.map +1 -0
  441. package/lib/commonjs/expo-plugin/withRNQC.js +25 -0
  442. package/lib/commonjs/expo-plugin/withRNQC.js.map +1 -0
  443. package/lib/commonjs/expo-plugin/withSodiumAndroid.js +25 -0
  444. package/lib/commonjs/expo-plugin/withSodiumAndroid.js.map +1 -0
  445. package/lib/commonjs/expo-plugin/withSodiumIos.js +23 -0
  446. package/lib/commonjs/expo-plugin/withSodiumIos.js.map +1 -0
  447. package/lib/commonjs/expo-plugin/withXCode.js +109 -0
  448. package/lib/commonjs/expo-plugin/withXCode.js.map +1 -0
  449. package/lib/commonjs/hash.js +291 -0
  450. package/lib/commonjs/hash.js.map +1 -0
  451. package/lib/commonjs/hkdf.js +178 -0
  452. package/lib/commonjs/hkdf.js.map +1 -0
  453. package/lib/commonjs/hmac.js +125 -0
  454. package/lib/commonjs/hmac.js.map +1 -0
  455. package/lib/commonjs/index.js +356 -0
  456. package/lib/commonjs/index.js.map +1 -0
  457. package/lib/commonjs/keys/classes.js +280 -0
  458. package/lib/commonjs/keys/classes.js.map +1 -0
  459. package/lib/commonjs/keys/generateKeyPair.js +237 -0
  460. package/lib/commonjs/keys/generateKeyPair.js.map +1 -0
  461. package/lib/commonjs/keys/index.js +381 -0
  462. package/lib/commonjs/keys/index.js.map +1 -0
  463. package/lib/commonjs/keys/publicCipher.js +171 -0
  464. package/lib/commonjs/keys/publicCipher.js.map +1 -0
  465. package/lib/commonjs/keys/signVerify.js +227 -0
  466. package/lib/commonjs/keys/signVerify.js.map +1 -0
  467. package/lib/commonjs/keys/utils.js +181 -0
  468. package/lib/commonjs/keys/utils.js.map +1 -0
  469. package/lib/commonjs/mldsa.js +69 -0
  470. package/lib/commonjs/mldsa.js.map +1 -0
  471. package/lib/commonjs/mlkem.js +219 -0
  472. package/lib/commonjs/mlkem.js.map +1 -0
  473. package/lib/commonjs/native-nitro-bridge.js +344 -0
  474. package/lib/commonjs/nitro-node-shim.js +23 -0
  475. package/lib/commonjs/package.json +1 -0
  476. package/lib/commonjs/pbkdf2.js +106 -0
  477. package/lib/commonjs/pbkdf2.js.map +1 -0
  478. package/lib/commonjs/prime.js +84 -0
  479. package/lib/commonjs/prime.js.map +1 -0
  480. package/lib/commonjs/random.js +296 -0
  481. package/lib/commonjs/random.js.map +1 -0
  482. package/lib/commonjs/rsa.js +213 -0
  483. package/lib/commonjs/rsa.js.map +1 -0
  484. package/lib/commonjs/scrypt.js +139 -0
  485. package/lib/commonjs/scrypt.js.map +1 -0
  486. package/lib/commonjs/slhdsa.js +70 -0
  487. package/lib/commonjs/slhdsa.js.map +1 -0
  488. package/lib/commonjs/specs/argon2.nitro.js +6 -0
  489. package/lib/commonjs/specs/argon2.nitro.js.map +1 -0
  490. package/lib/commonjs/specs/blake3.nitro.js +6 -0
  491. package/lib/commonjs/specs/blake3.nitro.js.map +1 -0
  492. package/lib/commonjs/specs/certificate.nitro.js +6 -0
  493. package/lib/commonjs/specs/certificate.nitro.js.map +1 -0
  494. package/lib/commonjs/specs/cipher.nitro.js +6 -0
  495. package/lib/commonjs/specs/cipher.nitro.js.map +1 -0
  496. package/lib/commonjs/specs/dhKeyPair.nitro.js +6 -0
  497. package/lib/commonjs/specs/dhKeyPair.nitro.js.map +1 -0
  498. package/lib/commonjs/specs/diffie-hellman.nitro.js +6 -0
  499. package/lib/commonjs/specs/diffie-hellman.nitro.js.map +1 -0
  500. package/lib/commonjs/specs/dsaKeyPair.nitro.js +6 -0
  501. package/lib/commonjs/specs/dsaKeyPair.nitro.js.map +1 -0
  502. package/lib/commonjs/specs/ecKeyPair.nitro.js +6 -0
  503. package/lib/commonjs/specs/ecKeyPair.nitro.js.map +1 -0
  504. package/lib/commonjs/specs/ecdh.nitro.js +6 -0
  505. package/lib/commonjs/specs/ecdh.nitro.js.map +1 -0
  506. package/lib/commonjs/specs/edKeyPair.nitro.js +6 -0
  507. package/lib/commonjs/specs/edKeyPair.nitro.js.map +1 -0
  508. package/lib/commonjs/specs/hash.nitro.js +6 -0
  509. package/lib/commonjs/specs/hash.nitro.js.map +1 -0
  510. package/lib/commonjs/specs/hkdf.nitro.js +6 -0
  511. package/lib/commonjs/specs/hkdf.nitro.js.map +1 -0
  512. package/lib/commonjs/specs/hmac.nitro.js +6 -0
  513. package/lib/commonjs/specs/hmac.nitro.js.map +1 -0
  514. package/lib/commonjs/specs/keyObjectHandle.nitro.js +6 -0
  515. package/lib/commonjs/specs/keyObjectHandle.nitro.js.map +1 -0
  516. package/lib/commonjs/specs/kmac.nitro.js +6 -0
  517. package/lib/commonjs/specs/kmac.nitro.js.map +1 -0
  518. package/lib/commonjs/specs/mlDsaKeyPair.nitro.js +6 -0
  519. package/lib/commonjs/specs/mlDsaKeyPair.nitro.js.map +1 -0
  520. package/lib/commonjs/specs/mlKemKeyPair.nitro.js +6 -0
  521. package/lib/commonjs/specs/mlKemKeyPair.nitro.js.map +1 -0
  522. package/lib/commonjs/specs/pbkdf2.nitro.js +6 -0
  523. package/lib/commonjs/specs/pbkdf2.nitro.js.map +1 -0
  524. package/lib/commonjs/specs/prime.nitro.js +6 -0
  525. package/lib/commonjs/specs/prime.nitro.js.map +1 -0
  526. package/lib/commonjs/specs/random.nitro.js +6 -0
  527. package/lib/commonjs/specs/random.nitro.js.map +1 -0
  528. package/lib/commonjs/specs/rsaCipher.nitro.js +6 -0
  529. package/lib/commonjs/specs/rsaCipher.nitro.js.map +1 -0
  530. package/lib/commonjs/specs/rsaKeyPair.nitro.js +6 -0
  531. package/lib/commonjs/specs/rsaKeyPair.nitro.js.map +1 -0
  532. package/lib/commonjs/specs/scrypt.nitro.js +6 -0
  533. package/lib/commonjs/specs/scrypt.nitro.js.map +1 -0
  534. package/lib/commonjs/specs/sign.nitro.js +6 -0
  535. package/lib/commonjs/specs/sign.nitro.js.map +1 -0
  536. package/lib/commonjs/specs/slhDsaKeyPair.nitro.js +6 -0
  537. package/lib/commonjs/specs/slhDsaKeyPair.nitro.js.map +1 -0
  538. package/lib/commonjs/specs/turboshake.nitro.js +6 -0
  539. package/lib/commonjs/specs/turboshake.nitro.js.map +1 -0
  540. package/lib/commonjs/specs/utils.nitro.js +6 -0
  541. package/lib/commonjs/specs/utils.nitro.js.map +1 -0
  542. package/lib/commonjs/specs/x509certificate.nitro.js +6 -0
  543. package/lib/commonjs/specs/x509certificate.nitro.js.map +1 -0
  544. package/lib/commonjs/subtle.js +3211 -0
  545. package/lib/commonjs/subtle.js.map +1 -0
  546. package/lib/commonjs/utils/cipher.js +75 -0
  547. package/lib/commonjs/utils/cipher.js.map +1 -0
  548. package/lib/commonjs/utils/conversion.js +249 -0
  549. package/lib/commonjs/utils/conversion.js.map +1 -0
  550. package/lib/commonjs/utils/errors.js +73 -0
  551. package/lib/commonjs/utils/errors.js.map +1 -0
  552. package/lib/commonjs/utils/hashnames.js +122 -0
  553. package/lib/commonjs/utils/hashnames.js.map +1 -0
  554. package/lib/commonjs/utils/index.js +83 -0
  555. package/lib/commonjs/utils/index.js.map +1 -0
  556. package/lib/commonjs/utils/noble.js +82 -0
  557. package/lib/commonjs/utils/noble.js.map +1 -0
  558. package/lib/commonjs/utils/timingSafeEqual.js +29 -0
  559. package/lib/commonjs/utils/timingSafeEqual.js.map +1 -0
  560. package/lib/commonjs/utils/types.js +55 -0
  561. package/lib/commonjs/utils/types.js.map +1 -0
  562. package/lib/commonjs/utils/validation.js +144 -0
  563. package/lib/commonjs/utils/validation.js.map +1 -0
  564. package/lib/commonjs/x509certificate.js +189 -0
  565. package/lib/commonjs/x509certificate.js.map +1 -0
  566. package/lib/module/argon2.js +83 -0
  567. package/lib/module/argon2.js.map +1 -0
  568. package/lib/module/blake3.js +91 -0
  569. package/lib/module/blake3.js.map +1 -0
  570. package/lib/module/certificate.js +30 -0
  571. package/lib/module/certificate.js.map +1 -0
  572. package/lib/module/cipher.js +291 -0
  573. package/lib/module/cipher.js.map +1 -0
  574. package/lib/module/constants.js +28 -0
  575. package/lib/module/constants.js.map +1 -0
  576. package/lib/module/dh-groups.js +25 -0
  577. package/lib/module/dh-groups.js.map +1 -0
  578. package/lib/module/dhKeyPair.js +105 -0
  579. package/lib/module/dhKeyPair.js.map +1 -0
  580. package/lib/module/diffie-hellman.js +145 -0
  581. package/lib/module/diffie-hellman.js.map +1 -0
  582. package/lib/module/dsa.js +94 -0
  583. package/lib/module/dsa.js.map +1 -0
  584. package/lib/module/ec.js +358 -0
  585. package/lib/module/ec.js.map +1 -0
  586. package/lib/module/ecdh.js +103 -0
  587. package/lib/module/ecdh.js.map +1 -0
  588. package/lib/module/ed.js +433 -0
  589. package/lib/module/ed.js.map +1 -0
  590. package/lib/module/expo-plugin/@types.js +2 -0
  591. package/lib/module/expo-plugin/@types.js.map +1 -0
  592. package/lib/module/expo-plugin/withRNQC.js +21 -0
  593. package/lib/module/expo-plugin/withRNQC.js.map +1 -0
  594. package/lib/module/expo-plugin/withSodiumAndroid.js +20 -0
  595. package/lib/module/expo-plugin/withSodiumAndroid.js.map +1 -0
  596. package/lib/module/expo-plugin/withSodiumIos.js +17 -0
  597. package/lib/module/expo-plugin/withSodiumIos.js.map +1 -0
  598. package/lib/module/expo-plugin/withXCode.js +101 -0
  599. package/lib/module/expo-plugin/withXCode.js.map +1 -0
  600. package/lib/module/hash.js +282 -0
  601. package/lib/module/hash.js.map +1 -0
  602. package/lib/module/hkdf.js +168 -0
  603. package/lib/module/hkdf.js.map +1 -0
  604. package/lib/module/hmac.js +120 -0
  605. package/lib/module/hmac.js.map +1 -0
  606. package/lib/module/index.js +115 -0
  607. package/lib/module/index.js.map +1 -0
  608. package/lib/module/keys/classes.js +271 -0
  609. package/lib/module/keys/classes.js.map +1 -0
  610. package/lib/module/keys/generateKeyPair.js +231 -0
  611. package/lib/module/keys/generateKeyPair.js.map +1 -0
  612. package/lib/module/keys/index.js +246 -0
  613. package/lib/module/keys/index.js.map +1 -0
  614. package/lib/module/keys/publicCipher.js +164 -0
  615. package/lib/module/keys/publicCipher.js.map +1 -0
  616. package/lib/module/keys/signVerify.js +217 -0
  617. package/lib/module/keys/signVerify.js.map +1 -0
  618. package/lib/module/keys/utils.js +170 -0
  619. package/lib/module/keys/utils.js.map +1 -0
  620. package/lib/module/mldsa.js +63 -0
  621. package/lib/module/mldsa.js.map +1 -0
  622. package/lib/module/mlkem.js +211 -0
  623. package/lib/module/mlkem.js.map +1 -0
  624. package/lib/module/pbkdf2.js +100 -0
  625. package/lib/module/pbkdf2.js.map +1 -0
  626. package/lib/module/prime.js +77 -0
  627. package/lib/module/prime.js.map +1 -0
  628. package/lib/module/random.js +284 -0
  629. package/lib/module/random.js.map +1 -0
  630. package/lib/module/rsa.js +205 -0
  631. package/lib/module/rsa.js.map +1 -0
  632. package/lib/module/scrypt.js +134 -0
  633. package/lib/module/scrypt.js.map +1 -0
  634. package/lib/module/slhdsa.js +64 -0
  635. package/lib/module/slhdsa.js.map +1 -0
  636. package/lib/module/specs/argon2.nitro.js +4 -0
  637. package/lib/module/specs/argon2.nitro.js.map +1 -0
  638. package/lib/module/specs/blake3.nitro.js +4 -0
  639. package/lib/module/specs/blake3.nitro.js.map +1 -0
  640. package/lib/module/specs/certificate.nitro.js +4 -0
  641. package/lib/module/specs/certificate.nitro.js.map +1 -0
  642. package/lib/module/specs/cipher.nitro.js +4 -0
  643. package/lib/module/specs/cipher.nitro.js.map +1 -0
  644. package/lib/module/specs/dhKeyPair.nitro.js +4 -0
  645. package/lib/module/specs/dhKeyPair.nitro.js.map +1 -0
  646. package/lib/module/specs/diffie-hellman.nitro.js +4 -0
  647. package/lib/module/specs/diffie-hellman.nitro.js.map +1 -0
  648. package/lib/module/specs/dsaKeyPair.nitro.js +4 -0
  649. package/lib/module/specs/dsaKeyPair.nitro.js.map +1 -0
  650. package/lib/module/specs/ecKeyPair.nitro.js +4 -0
  651. package/lib/module/specs/ecKeyPair.nitro.js.map +1 -0
  652. package/lib/module/specs/ecdh.nitro.js +4 -0
  653. package/lib/module/specs/ecdh.nitro.js.map +1 -0
  654. package/lib/module/specs/edKeyPair.nitro.js +4 -0
  655. package/lib/module/specs/edKeyPair.nitro.js.map +1 -0
  656. package/lib/module/specs/hash.nitro.js +4 -0
  657. package/lib/module/specs/hash.nitro.js.map +1 -0
  658. package/lib/module/specs/hkdf.nitro.js +4 -0
  659. package/lib/module/specs/hkdf.nitro.js.map +1 -0
  660. package/lib/module/specs/hmac.nitro.js +4 -0
  661. package/lib/module/specs/hmac.nitro.js.map +1 -0
  662. package/lib/module/specs/keyObjectHandle.nitro.js +4 -0
  663. package/lib/module/specs/keyObjectHandle.nitro.js.map +1 -0
  664. package/lib/module/specs/kmac.nitro.js +4 -0
  665. package/lib/module/specs/kmac.nitro.js.map +1 -0
  666. package/lib/module/specs/mlDsaKeyPair.nitro.js +4 -0
  667. package/lib/module/specs/mlDsaKeyPair.nitro.js.map +1 -0
  668. package/lib/module/specs/mlKemKeyPair.nitro.js +4 -0
  669. package/lib/module/specs/mlKemKeyPair.nitro.js.map +1 -0
  670. package/lib/module/specs/pbkdf2.nitro.js +4 -0
  671. package/lib/module/specs/pbkdf2.nitro.js.map +1 -0
  672. package/lib/module/specs/prime.nitro.js +4 -0
  673. package/lib/module/specs/prime.nitro.js.map +1 -0
  674. package/lib/module/specs/random.nitro.js +4 -0
  675. package/lib/module/specs/random.nitro.js.map +1 -0
  676. package/lib/module/specs/rsaCipher.nitro.js +4 -0
  677. package/lib/module/specs/rsaCipher.nitro.js.map +1 -0
  678. package/lib/module/specs/rsaKeyPair.nitro.js +4 -0
  679. package/lib/module/specs/rsaKeyPair.nitro.js.map +1 -0
  680. package/lib/module/specs/scrypt.nitro.js +4 -0
  681. package/lib/module/specs/scrypt.nitro.js.map +1 -0
  682. package/lib/module/specs/sign.nitro.js +4 -0
  683. package/lib/module/specs/sign.nitro.js.map +1 -0
  684. package/lib/module/specs/slhDsaKeyPair.nitro.js +4 -0
  685. package/lib/module/specs/slhDsaKeyPair.nitro.js.map +1 -0
  686. package/lib/module/specs/turboshake.nitro.js +4 -0
  687. package/lib/module/specs/turboshake.nitro.js.map +1 -0
  688. package/lib/module/specs/utils.nitro.js +4 -0
  689. package/lib/module/specs/utils.nitro.js.map +1 -0
  690. package/lib/module/specs/x509certificate.nitro.js +4 -0
  691. package/lib/module/specs/x509certificate.nitro.js.map +1 -0
  692. package/lib/module/subtle.js +3205 -0
  693. package/lib/module/subtle.js.map +1 -0
  694. package/lib/module/utils/cipher.js +67 -0
  695. package/lib/module/utils/cipher.js.map +1 -0
  696. package/lib/module/utils/conversion.js +205 -0
  697. package/lib/module/utils/conversion.js.map +1 -0
  698. package/lib/module/utils/errors.js +67 -0
  699. package/lib/module/utils/errors.js.map +1 -0
  700. package/lib/module/utils/hashnames.js +120 -0
  701. package/lib/module/utils/hashnames.js.map +1 -0
  702. package/lib/module/utils/index.js +10 -0
  703. package/lib/module/utils/index.js.map +1 -0
  704. package/lib/module/utils/noble.js +76 -0
  705. package/lib/module/utils/noble.js.map +1 -0
  706. package/lib/module/utils/timingSafeEqual.js +25 -0
  707. package/lib/module/utils/timingSafeEqual.js.map +1 -0
  708. package/lib/module/utils/types.js +57 -0
  709. package/lib/module/utils/types.js.map +1 -0
  710. package/lib/module/utils/validation.js +131 -0
  711. package/lib/module/utils/validation.js.map +1 -0
  712. package/lib/module/x509certificate.js +184 -0
  713. package/lib/module/x509certificate.js.map +1 -0
  714. package/lib/typescript/argon2.d.ts +16 -0
  715. package/lib/typescript/argon2.d.ts.map +1 -0
  716. package/lib/typescript/blake3.d.ts +33 -0
  717. package/lib/typescript/blake3.d.ts.map +1 -0
  718. package/lib/typescript/certificate.d.ts +8 -0
  719. package/lib/typescript/certificate.d.ts.map +1 -0
  720. package/lib/typescript/cipher.d.ts +75 -0
  721. package/lib/typescript/cipher.d.ts.map +1 -0
  722. package/lib/typescript/constants.d.ts +21 -0
  723. package/lib/typescript/constants.d.ts.map +1 -0
  724. package/lib/typescript/dh-groups.d.ts +5 -0
  725. package/lib/typescript/dh-groups.d.ts.map +1 -0
  726. package/lib/typescript/dhKeyPair.d.ts +19 -0
  727. package/lib/typescript/dhKeyPair.d.ts.map +1 -0
  728. package/lib/typescript/diffie-hellman.d.ts +18 -0
  729. package/lib/typescript/diffie-hellman.d.ts.map +1 -0
  730. package/lib/typescript/dsa.d.ts +19 -0
  731. package/lib/typescript/dsa.d.ts.map +1 -0
  732. package/lib/typescript/ec.d.ts +24 -0
  733. package/lib/typescript/ec.d.ts.map +1 -0
  734. package/lib/typescript/ecdh.d.ts +19 -0
  735. package/lib/typescript/ecdh.d.ts.map +1 -0
  736. package/lib/typescript/ed.d.ts +47 -0
  737. package/lib/typescript/ed.d.ts.map +1 -0
  738. package/lib/typescript/expo-plugin/@types.d.ts +8 -0
  739. package/lib/typescript/expo-plugin/@types.d.ts.map +1 -0
  740. package/lib/typescript/expo-plugin/withRNQC.d.ts +4 -0
  741. package/lib/typescript/expo-plugin/withRNQC.d.ts.map +1 -0
  742. package/lib/typescript/expo-plugin/withSodiumAndroid.d.ts +4 -0
  743. package/lib/typescript/expo-plugin/withSodiumAndroid.d.ts.map +1 -0
  744. package/lib/typescript/expo-plugin/withSodiumIos.d.ts +4 -0
  745. package/lib/typescript/expo-plugin/withSodiumIos.d.ts.map +1 -0
  746. package/lib/typescript/expo-plugin/withXCode.d.ts +23 -0
  747. package/lib/typescript/expo-plugin/withXCode.d.ts.map +1 -0
  748. package/lib/typescript/hash.d.ts +126 -0
  749. package/lib/typescript/hash.d.ts.map +1 -0
  750. package/lib/typescript/hkdf.d.ts +26 -0
  751. package/lib/typescript/hkdf.d.ts.map +1 -0
  752. package/lib/typescript/hmac.d.ts +66 -0
  753. package/lib/typescript/hmac.d.ts.map +1 -0
  754. package/lib/typescript/index.d.ts +240 -0
  755. package/lib/typescript/index.d.ts.map +1 -0
  756. package/lib/typescript/keys/classes.d.ts +95 -0
  757. package/lib/typescript/keys/classes.d.ts.map +1 -0
  758. package/lib/typescript/keys/generateKeyPair.d.ts +17 -0
  759. package/lib/typescript/keys/generateKeyPair.d.ts.map +1 -0
  760. package/lib/typescript/keys/index.d.ts +26 -0
  761. package/lib/typescript/keys/index.d.ts.map +1 -0
  762. package/lib/typescript/keys/publicCipher.d.ts +23 -0
  763. package/lib/typescript/keys/publicCipher.d.ts.map +1 -0
  764. package/lib/typescript/keys/signVerify.d.ts +35 -0
  765. package/lib/typescript/keys/signVerify.d.ts.map +1 -0
  766. package/lib/typescript/keys/utils.d.ts +51 -0
  767. package/lib/typescript/keys/utils.d.ts.map +1 -0
  768. package/lib/typescript/mldsa.d.ts +18 -0
  769. package/lib/typescript/mldsa.d.ts.map +1 -0
  770. package/lib/typescript/mlkem.d.ts +30 -0
  771. package/lib/typescript/mlkem.d.ts.map +1 -0
  772. package/lib/typescript/pbkdf2.d.ts +12 -0
  773. package/lib/typescript/pbkdf2.d.ts.map +1 -0
  774. package/lib/typescript/prime.d.ts +19 -0
  775. package/lib/typescript/prime.d.ts.map +1 -0
  776. package/lib/typescript/random.d.ts +31 -0
  777. package/lib/typescript/random.d.ts.map +1 -0
  778. package/lib/typescript/rsa.d.ts +20 -0
  779. package/lib/typescript/rsa.d.ts.map +1 -0
  780. package/lib/typescript/scrypt.d.ts +18 -0
  781. package/lib/typescript/scrypt.d.ts.map +1 -0
  782. package/lib/typescript/slhdsa.d.ts +19 -0
  783. package/lib/typescript/slhdsa.d.ts.map +1 -0
  784. package/lib/typescript/specs/argon2.nitro.d.ts +9 -0
  785. package/lib/typescript/specs/argon2.nitro.d.ts.map +1 -0
  786. package/lib/typescript/specs/blake3.nitro.d.ts +15 -0
  787. package/lib/typescript/specs/blake3.nitro.d.ts.map +1 -0
  788. package/lib/typescript/specs/certificate.nitro.d.ts +10 -0
  789. package/lib/typescript/specs/certificate.nitro.d.ts.map +1 -0
  790. package/lib/typescript/specs/cipher.nitro.d.ts +38 -0
  791. package/lib/typescript/specs/cipher.nitro.d.ts.map +1 -0
  792. package/lib/typescript/specs/dhKeyPair.nitro.d.ts +14 -0
  793. package/lib/typescript/specs/dhKeyPair.nitro.d.ts.map +1 -0
  794. package/lib/typescript/specs/diffie-hellman.nitro.d.ts +18 -0
  795. package/lib/typescript/specs/diffie-hellman.nitro.d.ts.map +1 -0
  796. package/lib/typescript/specs/dsaKeyPair.nitro.d.ts +13 -0
  797. package/lib/typescript/specs/dsaKeyPair.nitro.d.ts.map +1 -0
  798. package/lib/typescript/specs/ecKeyPair.nitro.d.ts +21 -0
  799. package/lib/typescript/specs/ecKeyPair.nitro.d.ts.map +1 -0
  800. package/lib/typescript/specs/ecdh.nitro.d.ts +15 -0
  801. package/lib/typescript/specs/ecdh.nitro.d.ts.map +1 -0
  802. package/lib/typescript/specs/edKeyPair.nitro.d.ts +17 -0
  803. package/lib/typescript/specs/edKeyPair.nitro.d.ts.map +1 -0
  804. package/lib/typescript/specs/hash.nitro.d.ts +13 -0
  805. package/lib/typescript/specs/hash.nitro.d.ts.map +1 -0
  806. package/lib/typescript/specs/hkdf.nitro.d.ts +10 -0
  807. package/lib/typescript/specs/hkdf.nitro.d.ts.map +1 -0
  808. package/lib/typescript/specs/hmac.nitro.d.ts +10 -0
  809. package/lib/typescript/specs/hmac.nitro.d.ts.map +1 -0
  810. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +27 -0
  811. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -0
  812. package/lib/typescript/specs/kmac.nitro.d.ts +10 -0
  813. package/lib/typescript/specs/kmac.nitro.d.ts.map +1 -0
  814. package/lib/typescript/specs/mlDsaKeyPair.nitro.d.ts +16 -0
  815. package/lib/typescript/specs/mlDsaKeyPair.nitro.d.ts.map +1 -0
  816. package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts +18 -0
  817. package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts.map +1 -0
  818. package/lib/typescript/specs/pbkdf2.nitro.d.ts +9 -0
  819. package/lib/typescript/specs/pbkdf2.nitro.d.ts.map +1 -0
  820. package/lib/typescript/specs/prime.nitro.d.ts +11 -0
  821. package/lib/typescript/specs/prime.nitro.d.ts.map +1 -0
  822. package/lib/typescript/specs/random.nitro.d.ts +9 -0
  823. package/lib/typescript/specs/random.nitro.d.ts.map +1 -0
  824. package/lib/typescript/specs/rsaCipher.nitro.d.ts +54 -0
  825. package/lib/typescript/specs/rsaCipher.nitro.d.ts.map +1 -0
  826. package/lib/typescript/specs/rsaKeyPair.nitro.d.ts +20 -0
  827. package/lib/typescript/specs/rsaKeyPair.nitro.d.ts.map +1 -0
  828. package/lib/typescript/specs/scrypt.nitro.d.ts +9 -0
  829. package/lib/typescript/specs/scrypt.nitro.d.ts.map +1 -0
  830. package/lib/typescript/specs/sign.nitro.d.ts +19 -0
  831. package/lib/typescript/specs/sign.nitro.d.ts.map +1 -0
  832. package/lib/typescript/specs/slhDsaKeyPair.nitro.d.ts +16 -0
  833. package/lib/typescript/specs/slhDsaKeyPair.nitro.d.ts.map +1 -0
  834. package/lib/typescript/specs/turboshake.nitro.d.ts +11 -0
  835. package/lib/typescript/specs/turboshake.nitro.d.ts.map +1 -0
  836. package/lib/typescript/specs/utils.nitro.d.ts +8 -0
  837. package/lib/typescript/specs/utils.nitro.d.ts.map +1 -0
  838. package/lib/typescript/specs/x509certificate.nitro.d.ts +34 -0
  839. package/lib/typescript/specs/x509certificate.nitro.d.ts.map +1 -0
  840. package/lib/typescript/subtle.d.ts +33 -0
  841. package/lib/typescript/subtle.d.ts.map +1 -0
  842. package/lib/typescript/utils/cipher.d.ts +19 -0
  843. package/lib/typescript/utils/cipher.d.ts.map +1 -0
  844. package/lib/typescript/utils/conversion.d.ts +36 -0
  845. package/lib/typescript/utils/conversion.d.ts.map +1 -0
  846. package/lib/typescript/utils/errors.d.ts +19 -0
  847. package/lib/typescript/utils/errors.d.ts.map +1 -0
  848. package/lib/typescript/utils/hashnames.d.ts +13 -0
  849. package/lib/typescript/utils/hashnames.d.ts.map +1 -0
  850. package/lib/typescript/utils/index.d.ts +8 -0
  851. package/lib/typescript/utils/index.d.ts.map +1 -0
  852. package/lib/typescript/utils/noble.d.ts +19 -0
  853. package/lib/typescript/utils/noble.d.ts.map +1 -0
  854. package/lib/typescript/utils/timingSafeEqual.d.ts +3 -0
  855. package/lib/typescript/utils/timingSafeEqual.d.ts.map +1 -0
  856. package/lib/typescript/utils/types.d.ts +314 -0
  857. package/lib/typescript/utils/types.d.ts.map +1 -0
  858. package/lib/typescript/utils/validation.d.ts +15 -0
  859. package/lib/typescript/utils/validation.d.ts.map +1 -0
  860. package/lib/typescript/x509certificate.d.ts +64 -0
  861. package/lib/typescript/x509certificate.d.ts.map +1 -0
  862. package/nitrogen/generated/.gitattributes +1 -0
  863. package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +110 -0
  864. package/nitrogen/generated/android/QuickCrypto+autolinking.gradle +27 -0
  865. package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +334 -0
  866. package/nitrogen/generated/android/QuickCryptoOnLoad.hpp +25 -0
  867. package/nitrogen/generated/android/kotlin/com/margelo/nitro/crypto/QuickCryptoOnLoad.kt +35 -0
  868. package/nitrogen/generated/ios/QuickCrypto+autolinking.rb +60 -0
  869. package/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.cpp +17 -0
  870. package/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.hpp +27 -0
  871. package/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Umbrella.hpp +38 -0
  872. package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +325 -0
  873. package/nitrogen/generated/ios/QuickCryptoAutolinking.swift +16 -0
  874. package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +176 -0
  875. package/nitrogen/generated/shared/c++/CipherArgs.hpp +101 -0
  876. package/nitrogen/generated/shared/c++/CipherInfo.hpp +104 -0
  877. package/nitrogen/generated/shared/c++/HkdfMode.hpp +80 -0
  878. package/nitrogen/generated/shared/c++/HybridArgon2Spec.cpp +22 -0
  879. package/nitrogen/generated/shared/c++/HybridArgon2Spec.hpp +66 -0
  880. package/nitrogen/generated/shared/c++/HybridBlake3Spec.cpp +28 -0
  881. package/nitrogen/generated/shared/c++/HybridBlake3Spec.hpp +74 -0
  882. package/nitrogen/generated/shared/c++/HybridCertificateSpec.cpp +23 -0
  883. package/nitrogen/generated/shared/c++/HybridCertificateSpec.hpp +64 -0
  884. package/nitrogen/generated/shared/c++/HybridCipherFactorySpec.cpp +21 -0
  885. package/nitrogen/generated/shared/c++/HybridCipherFactorySpec.hpp +67 -0
  886. package/nitrogen/generated/shared/c++/HybridCipherSpec.cpp +29 -0
  887. package/nitrogen/generated/shared/c++/HybridCipherSpec.hpp +78 -0
  888. package/nitrogen/generated/shared/c++/HybridDhKeyPairSpec.cpp +27 -0
  889. package/nitrogen/generated/shared/c++/HybridDhKeyPairSpec.hpp +69 -0
  890. package/nitrogen/generated/shared/c++/HybridDiffieHellmanSpec.cpp +31 -0
  891. package/nitrogen/generated/shared/c++/HybridDiffieHellmanSpec.hpp +72 -0
  892. package/nitrogen/generated/shared/c++/HybridDsaKeyPairSpec.cpp +26 -0
  893. package/nitrogen/generated/shared/c++/HybridDsaKeyPairSpec.hpp +68 -0
  894. package/nitrogen/generated/shared/c++/HybridECDHSpec.cpp +28 -0
  895. package/nitrogen/generated/shared/c++/HybridECDHSpec.hpp +70 -0
  896. package/nitrogen/generated/shared/c++/HybridEcKeyPairSpec.cpp +30 -0
  897. package/nitrogen/generated/shared/c++/HybridEcKeyPairSpec.hpp +76 -0
  898. package/nitrogen/generated/shared/c++/HybridEdKeyPairSpec.cpp +30 -0
  899. package/nitrogen/generated/shared/c++/HybridEdKeyPairSpec.hpp +74 -0
  900. package/nitrogen/generated/shared/c++/HybridHashSpec.cpp +26 -0
  901. package/nitrogen/generated/shared/c++/HybridHashSpec.hpp +74 -0
  902. package/nitrogen/generated/shared/c++/HybridHkdfSpec.cpp +22 -0
  903. package/nitrogen/generated/shared/c++/HybridHkdfSpec.hpp +67 -0
  904. package/nitrogen/generated/shared/c++/HybridHmacSpec.cpp +23 -0
  905. package/nitrogen/generated/shared/c++/HybridHmacSpec.hpp +66 -0
  906. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +39 -0
  907. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +107 -0
  908. package/nitrogen/generated/shared/c++/HybridKmacSpec.cpp +23 -0
  909. package/nitrogen/generated/shared/c++/HybridKmacSpec.hpp +66 -0
  910. package/nitrogen/generated/shared/c++/HybridMlDsaKeyPairSpec.cpp +29 -0
  911. package/nitrogen/generated/shared/c++/HybridMlDsaKeyPairSpec.hpp +72 -0
  912. package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.cpp +31 -0
  913. package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.hpp +74 -0
  914. package/nitrogen/generated/shared/c++/HybridPbkdf2Spec.cpp +22 -0
  915. package/nitrogen/generated/shared/c++/HybridPbkdf2Spec.hpp +65 -0
  916. package/nitrogen/generated/shared/c++/HybridPrimeSpec.cpp +24 -0
  917. package/nitrogen/generated/shared/c++/HybridPrimeSpec.hpp +67 -0
  918. package/nitrogen/generated/shared/c++/HybridRandomSpec.cpp +22 -0
  919. package/nitrogen/generated/shared/c++/HybridRandomSpec.hpp +64 -0
  920. package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.cpp +25 -0
  921. package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.hpp +71 -0
  922. package/nitrogen/generated/shared/c++/HybridRsaKeyPairSpec.cpp +29 -0
  923. package/nitrogen/generated/shared/c++/HybridRsaKeyPairSpec.hpp +75 -0
  924. package/nitrogen/generated/shared/c++/HybridScryptSpec.cpp +22 -0
  925. package/nitrogen/generated/shared/c++/HybridScryptSpec.hpp +64 -0
  926. package/nitrogen/generated/shared/c++/HybridSignHandleSpec.cpp +23 -0
  927. package/nitrogen/generated/shared/c++/HybridSignHandleSpec.hpp +69 -0
  928. package/nitrogen/generated/shared/c++/HybridSlhDsaKeyPairSpec.cpp +29 -0
  929. package/nitrogen/generated/shared/c++/HybridSlhDsaKeyPairSpec.hpp +72 -0
  930. package/nitrogen/generated/shared/c++/HybridTurboShakeSpec.cpp +22 -0
  931. package/nitrogen/generated/shared/c++/HybridTurboShakeSpec.hpp +70 -0
  932. package/nitrogen/generated/shared/c++/HybridUtilsSpec.cpp +21 -0
  933. package/nitrogen/generated/shared/c++/HybridUtilsSpec.hpp +62 -0
  934. package/nitrogen/generated/shared/c++/HybridVerifyHandleSpec.cpp +23 -0
  935. package/nitrogen/generated/shared/c++/HybridVerifyHandleSpec.hpp +69 -0
  936. package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.cpp +46 -0
  937. package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.hpp +96 -0
  938. package/nitrogen/generated/shared/c++/JWK.hpp +185 -0
  939. package/nitrogen/generated/shared/c++/JWKkty.hpp +92 -0
  940. package/nitrogen/generated/shared/c++/JWKuse.hpp +76 -0
  941. package/nitrogen/generated/shared/c++/KFormatType.hpp +63 -0
  942. package/nitrogen/generated/shared/c++/KangarooTwelveVariant.hpp +76 -0
  943. package/nitrogen/generated/shared/c++/KeyDetail.hpp +108 -0
  944. package/nitrogen/generated/shared/c++/KeyEncoding.hpp +64 -0
  945. package/nitrogen/generated/shared/c++/KeyObject.hpp +83 -0
  946. package/nitrogen/generated/shared/c++/KeyType.hpp +63 -0
  947. package/nitrogen/generated/shared/c++/KeyUsage.hpp +116 -0
  948. package/nitrogen/generated/shared/c++/NamedCurve.hpp +80 -0
  949. package/nitrogen/generated/shared/c++/TurboShakeVariant.hpp +76 -0
  950. package/ohos/binding.gyp +33 -0
  951. package/ohos/build/Release/quick_crypto.node +0 -0
  952. package/ohos/quick_crypto_napi.cpp +1316 -0
  953. package/package.json +158 -4
  954. package/src/argon2.ts +161 -0
  955. package/src/blake3.ts +124 -0
  956. package/src/certificate.ts +41 -0
  957. package/src/cipher.ts +497 -0
  958. package/src/constants.ts +32 -0
  959. package/src/dh-groups.ts +27 -0
  960. package/src/dhKeyPair.ts +164 -0
  961. package/src/diffie-hellman.ts +195 -0
  962. package/src/dsa.ts +146 -0
  963. package/src/ec.ts +580 -0
  964. package/src/ecdh.ts +132 -0
  965. package/src/ed.ts +605 -0
  966. package/src/expo-plugin/@types.ts +7 -0
  967. package/src/expo-plugin/withRNQC.ts +23 -0
  968. package/src/expo-plugin/withSodiumAndroid.ts +24 -0
  969. package/src/expo-plugin/withSodiumIos.ts +25 -0
  970. package/src/expo-plugin/withXCode.ts +134 -0
  971. package/src/hash.ts +433 -0
  972. package/src/hkdf.ts +327 -0
  973. package/src/hmac.ts +150 -0
  974. package/src/index.ts +126 -0
  975. package/src/keys/classes.ts +369 -0
  976. package/src/keys/generateKeyPair.ts +358 -0
  977. package/src/keys/index.ts +383 -0
  978. package/src/keys/publicCipher.ts +256 -0
  979. package/src/keys/signVerify.ts +329 -0
  980. package/src/keys/utils.ts +263 -0
  981. package/src/mldsa.ts +125 -0
  982. package/src/mlkem.ts +350 -0
  983. package/src/pbkdf2.ts +183 -0
  984. package/src/prime.ts +134 -0
  985. package/src/random.ts +427 -0
  986. package/src/rsa.ts +333 -0
  987. package/src/scrypt.ts +201 -0
  988. package/src/slhdsa.ts +146 -0
  989. package/src/specs/argon2.nitro.ts +29 -0
  990. package/src/specs/blake3.nitro.ts +12 -0
  991. package/src/specs/certificate.nitro.ts +8 -0
  992. package/src/specs/cipher.nitro.ts +39 -0
  993. package/src/specs/dhKeyPair.nitro.ts +14 -0
  994. package/src/specs/diffie-hellman.nitro.ts +16 -0
  995. package/src/specs/dsaKeyPair.nitro.ts +13 -0
  996. package/src/specs/ecKeyPair.nitro.ts +40 -0
  997. package/src/specs/ecdh.nitro.ts +12 -0
  998. package/src/specs/edKeyPair.nitro.ts +43 -0
  999. package/src/specs/hash.nitro.ts +10 -0
  1000. package/src/specs/hkdf.nitro.ts +25 -0
  1001. package/src/specs/hmac.nitro.ts +7 -0
  1002. package/src/specs/keyObjectHandle.nitro.ts +56 -0
  1003. package/src/specs/kmac.nitro.ts +12 -0
  1004. package/src/specs/mlDsaKeyPair.nitro.ts +29 -0
  1005. package/src/specs/mlKemKeyPair.nitro.ts +32 -0
  1006. package/src/specs/pbkdf2.nitro.ts +18 -0
  1007. package/src/specs/prime.nitro.ts +18 -0
  1008. package/src/specs/random.nitro.ts +14 -0
  1009. package/src/specs/rsaCipher.nitro.ts +82 -0
  1010. package/src/specs/rsaKeyPair.nitro.ts +33 -0
  1011. package/src/specs/scrypt.nitro.ts +23 -0
  1012. package/src/specs/sign.nitro.ts +31 -0
  1013. package/src/specs/slhDsaKeyPair.nitro.ts +29 -0
  1014. package/src/specs/turboshake.nitro.ts +21 -0
  1015. package/src/specs/utils.nitro.ts +5 -0
  1016. package/src/specs/x509certificate.nitro.ts +38 -0
  1017. package/src/subtle.ts +4545 -0
  1018. package/src/utils/cipher.ts +82 -0
  1019. package/src/utils/conversion.ts +285 -0
  1020. package/src/utils/errors.ts +83 -0
  1021. package/src/utils/hashnames.ts +129 -0
  1022. package/src/utils/index.ts +7 -0
  1023. package/src/utils/noble.ts +85 -0
  1024. package/src/utils/timingSafeEqual.ts +28 -0
  1025. package/src/utils/types.ts +617 -0
  1026. package/src/utils/validation.ts +199 -0
  1027. package/src/x509certificate.ts +276 -0
package/src/subtle.ts ADDED
@@ -0,0 +1,4545 @@
1
+ import { Buffer as SBuffer } from 'safe-buffer';
2
+ import type {
3
+ SubtleAlgorithm,
4
+ KeyUsage,
5
+ BinaryLike,
6
+ BufferLike,
7
+ JWK,
8
+ AnyAlgorithm,
9
+ ImportFormat,
10
+ AesKeyGenParams,
11
+ EncryptDecryptParams,
12
+ Operation,
13
+ AesCtrParams,
14
+ AesCbcParams,
15
+ AesGcmParams,
16
+ AesOcbParams,
17
+ RsaOaepParams,
18
+ ChaCha20Poly1305Params,
19
+ } from './utils';
20
+ import { KFormatType, KeyEncoding, KeyType, kNamedCurveAliases } from './utils';
21
+ import { Buffer } from '@craftzdog/react-native-buffer';
22
+ import {
23
+ CryptoKey,
24
+ KeyObject,
25
+ PublicKeyObject,
26
+ PrivateKeyObject,
27
+ SecretKeyObject,
28
+ } from './keys';
29
+ import type { CryptoKeyPair } from './utils/types';
30
+ import {
31
+ binaryLikeToArrayBuffer,
32
+ bufferLikeToArrayBuffer,
33
+ } from './utils/conversion';
34
+ import { argon2Sync } from './argon2';
35
+ import { lazyDOMException } from './utils/errors';
36
+ import { normalizeHashName, HashContext } from './utils/hashnames';
37
+ import {
38
+ validateJwkStructure,
39
+ validateMaxBufferLength,
40
+ } from './utils/validation';
41
+ import { asyncDigest } from './hash';
42
+ import { createSecretKey, createPublicKey } from './keys';
43
+ import { NitroModules } from 'react-native-nitro-modules';
44
+ import type { KeyObjectHandle } from './specs/keyObjectHandle.nitro';
45
+ import type { RsaCipher } from './specs/rsaCipher.nitro';
46
+ import type { CipherFactory } from './specs/cipher.nitro';
47
+ import { pbkdf2DeriveBits } from './pbkdf2';
48
+ import {
49
+ ecImportKey,
50
+ ecdsaSignVerify,
51
+ ec_generateKeyPair,
52
+ ecDeriveBits,
53
+ } from './ec';
54
+ import { rsa_generateKeyPair } from './rsa';
55
+ import { getRandomValues } from './random';
56
+ import { createHmac } from './hmac';
57
+ import type { Kmac } from './specs/kmac.nitro';
58
+ import { timingSafeEqual } from './utils/timingSafeEqual';
59
+ import { createSign, createVerify } from './keys/signVerify';
60
+ import {
61
+ ed_generateKeyPairWebCrypto,
62
+ x_generateKeyPairWebCrypto,
63
+ xDeriveBits,
64
+ Ed,
65
+ } from './ed';
66
+ import { mldsa_generateKeyPairWebCrypto, type MlDsaVariant } from './mldsa';
67
+ import {
68
+ slhdsa_generateKeyPairWebCrypto,
69
+ SLH_DSA_VARIANTS,
70
+ type SlhDsaVariant,
71
+ } from './slhdsa';
72
+ import {
73
+ mlkem_generateKeyPairWebCrypto,
74
+ type MlKemVariant,
75
+ MlKem,
76
+ } from './mlkem';
77
+ import type { EncapsulateResult } from './utils';
78
+ import { hkdfDeriveBits, type HkdfAlgorithm } from './hkdf';
79
+ // Temporary enums that need to be defined
80
+
81
+ enum KWebCryptoKeyFormat {
82
+ kWebCryptoKeyFormatRaw,
83
+ kWebCryptoKeyFormatSPKI,
84
+ kWebCryptoKeyFormatPKCS8,
85
+ }
86
+
87
+ enum CipherOrWrapMode {
88
+ kWebCryptoCipherEncrypt,
89
+ kWebCryptoCipherDecrypt,
90
+ }
91
+
92
+ // Placeholder functions that need to be implemented
93
+ function hasAnyNotIn(usages: KeyUsage[], allowed: KeyUsage[]): boolean {
94
+ return usages.some(usage => !allowed.includes(usage));
95
+ }
96
+
97
+ // Mirrors webidl.requiredArguments. Node throws TypeError when a SubtleCrypto
98
+ // method is called with fewer than the spec-required number of arguments
99
+ // (webcrypto.js:866 etc.); we relied on TypeScript types alone, which apps
100
+ // catching `instanceof TypeError` could not see at runtime.
101
+ function requireArgs(actual: number, required: number, method: string): void {
102
+ if (actual < required) {
103
+ throw new TypeError(
104
+ `Failed to execute '${method}' on 'SubtleCrypto': ${required} arguments required, but only ${actual} present.`,
105
+ );
106
+ }
107
+ }
108
+
109
+ // WebCrypto §18.4.4: algorithm name lookup is case-insensitive, but the
110
+ // canonical mixed-case form is preserved in the resulting `name` field
111
+ // (e.g. "aes-gcm" → "AES-GCM"). This map is built lazily on first call so
112
+ // the registry of canonical names below can stay declared after the
113
+ // function. Without this, callers who pass lowercase strings bypass the
114
+ // downstream `SUPPORTED_ALGORITHMS` set comparisons silently.
115
+ //
116
+ // The map's value type is `AnyAlgorithm` so callers can use the lookup
117
+ // result directly without re-asserting. The `as AnyAlgorithm` at insertion
118
+ // is the single contract boundary: every name in `SUPPORTED_ALGORITHMS` is
119
+ // already a member of `AnyAlgorithm` by construction.
120
+ let _canonicalAlgorithmNames: Map<string, AnyAlgorithm> | null = null;
121
+ function getCanonicalAlgorithmNames(): Map<string, AnyAlgorithm> {
122
+ if (_canonicalAlgorithmNames === null) {
123
+ const map = new Map<string, AnyAlgorithm>();
124
+ for (const set of Object.values(SUPPORTED_ALGORITHMS)) {
125
+ if (!set) continue;
126
+ for (const name of set) {
127
+ map.set(name.toLowerCase(), name as AnyAlgorithm);
128
+ }
129
+ }
130
+ _canonicalAlgorithmNames = map;
131
+ }
132
+ return _canonicalAlgorithmNames;
133
+ }
134
+
135
+ // Per-algorithm WebIDL converter table. Mirrors Node's kAlgorithmDefinitions
136
+ // (lib/internal/crypto/util.js): each (algorithm, operation) pair maps to a
137
+ // dictionary converter name, or null when only the `name` member is required.
138
+ // Operation keys are missing when an algorithm cannot perform that operation,
139
+ // causing `normalizeAlgorithm` to reject the call.
140
+ const kAlgorithmDefinitions: Record<string, Record<string, string | null>> = {
141
+ 'AES-CBC': {
142
+ generateKey: 'AesKeyGenParams',
143
+ exportKey: null,
144
+ importKey: null,
145
+ encrypt: 'AesCbcParams',
146
+ decrypt: 'AesCbcParams',
147
+ 'get key length': 'AesDerivedKeyParams',
148
+ },
149
+ 'AES-CTR': {
150
+ generateKey: 'AesKeyGenParams',
151
+ exportKey: null,
152
+ importKey: null,
153
+ encrypt: 'AesCtrParams',
154
+ decrypt: 'AesCtrParams',
155
+ 'get key length': 'AesDerivedKeyParams',
156
+ },
157
+ 'AES-GCM': {
158
+ generateKey: 'AesKeyGenParams',
159
+ exportKey: null,
160
+ importKey: null,
161
+ encrypt: 'AeadParams',
162
+ decrypt: 'AeadParams',
163
+ 'get key length': 'AesDerivedKeyParams',
164
+ },
165
+ 'AES-KW': {
166
+ generateKey: 'AesKeyGenParams',
167
+ exportKey: null,
168
+ importKey: null,
169
+ 'get key length': 'AesDerivedKeyParams',
170
+ wrapKey: null,
171
+ unwrapKey: null,
172
+ },
173
+ 'AES-OCB': {
174
+ generateKey: 'AesKeyGenParams',
175
+ exportKey: null,
176
+ importKey: null,
177
+ encrypt: 'AeadParams',
178
+ decrypt: 'AeadParams',
179
+ 'get key length': 'AesDerivedKeyParams',
180
+ },
181
+ Argon2d: {
182
+ deriveBits: 'Argon2Params',
183
+ 'get key length': null,
184
+ importKey: null,
185
+ },
186
+ Argon2i: {
187
+ deriveBits: 'Argon2Params',
188
+ 'get key length': null,
189
+ importKey: null,
190
+ },
191
+ Argon2id: {
192
+ deriveBits: 'Argon2Params',
193
+ 'get key length': null,
194
+ importKey: null,
195
+ },
196
+ 'ChaCha20-Poly1305': {
197
+ generateKey: null,
198
+ exportKey: null,
199
+ importKey: null,
200
+ encrypt: 'AeadParams',
201
+ decrypt: 'AeadParams',
202
+ 'get key length': null,
203
+ },
204
+ ECDH: {
205
+ generateKey: 'EcKeyGenParams',
206
+ exportKey: null,
207
+ importKey: 'EcKeyImportParams',
208
+ deriveBits: 'EcdhKeyDeriveParams',
209
+ },
210
+ ECDSA: {
211
+ generateKey: 'EcKeyGenParams',
212
+ exportKey: null,
213
+ importKey: 'EcKeyImportParams',
214
+ sign: 'EcdsaParams',
215
+ verify: 'EcdsaParams',
216
+ },
217
+ Ed25519: {
218
+ generateKey: null,
219
+ exportKey: null,
220
+ importKey: null,
221
+ sign: null,
222
+ verify: null,
223
+ },
224
+ Ed448: {
225
+ generateKey: null,
226
+ exportKey: null,
227
+ importKey: null,
228
+ sign: 'ContextParams',
229
+ verify: 'ContextParams',
230
+ },
231
+ HKDF: {
232
+ importKey: null,
233
+ deriveBits: 'HkdfParams',
234
+ 'get key length': null,
235
+ },
236
+ HMAC: {
237
+ generateKey: 'HmacKeyGenParams',
238
+ exportKey: null,
239
+ importKey: 'HmacImportParams',
240
+ sign: null,
241
+ verify: null,
242
+ 'get key length': 'HmacImportParams',
243
+ },
244
+ KMAC128: {
245
+ generateKey: 'KmacKeyGenParams',
246
+ exportKey: null,
247
+ importKey: 'KmacImportParams',
248
+ sign: 'KmacParams',
249
+ verify: 'KmacParams',
250
+ 'get key length': 'KmacImportParams',
251
+ },
252
+ KMAC256: {
253
+ generateKey: 'KmacKeyGenParams',
254
+ exportKey: null,
255
+ importKey: 'KmacImportParams',
256
+ sign: 'KmacParams',
257
+ verify: 'KmacParams',
258
+ 'get key length': 'KmacImportParams',
259
+ },
260
+ 'ML-DSA-44': {
261
+ generateKey: null,
262
+ exportKey: null,
263
+ importKey: null,
264
+ sign: 'ContextParams',
265
+ verify: 'ContextParams',
266
+ },
267
+ 'ML-DSA-65': {
268
+ generateKey: null,
269
+ exportKey: null,
270
+ importKey: null,
271
+ sign: 'ContextParams',
272
+ verify: 'ContextParams',
273
+ },
274
+ 'ML-DSA-87': {
275
+ generateKey: null,
276
+ exportKey: null,
277
+ importKey: null,
278
+ sign: 'ContextParams',
279
+ verify: 'ContextParams',
280
+ },
281
+ 'ML-KEM-512': {
282
+ generateKey: null,
283
+ exportKey: null,
284
+ importKey: null,
285
+ encapsulateBits: null,
286
+ decapsulateBits: null,
287
+ encapsulateKey: null,
288
+ decapsulateKey: null,
289
+ },
290
+ 'ML-KEM-768': {
291
+ generateKey: null,
292
+ exportKey: null,
293
+ importKey: null,
294
+ encapsulateBits: null,
295
+ decapsulateBits: null,
296
+ encapsulateKey: null,
297
+ decapsulateKey: null,
298
+ },
299
+ 'ML-KEM-1024': {
300
+ generateKey: null,
301
+ exportKey: null,
302
+ importKey: null,
303
+ encapsulateBits: null,
304
+ decapsulateBits: null,
305
+ encapsulateKey: null,
306
+ decapsulateKey: null,
307
+ },
308
+ PBKDF2: {
309
+ importKey: null,
310
+ deriveBits: 'Pbkdf2Params',
311
+ 'get key length': null,
312
+ },
313
+ 'RSA-OAEP': {
314
+ generateKey: 'RsaHashedKeyGenParams',
315
+ exportKey: null,
316
+ importKey: 'RsaHashedImportParams',
317
+ encrypt: 'RsaOaepParams',
318
+ decrypt: 'RsaOaepParams',
319
+ },
320
+ 'RSA-PSS': {
321
+ generateKey: 'RsaHashedKeyGenParams',
322
+ exportKey: null,
323
+ importKey: 'RsaHashedImportParams',
324
+ sign: 'RsaPssParams',
325
+ verify: 'RsaPssParams',
326
+ },
327
+ 'RSASSA-PKCS1-v1_5': {
328
+ generateKey: 'RsaHashedKeyGenParams',
329
+ exportKey: null,
330
+ importKey: 'RsaHashedImportParams',
331
+ sign: null,
332
+ verify: null,
333
+ },
334
+ 'SHA-1': { digest: null },
335
+ 'SHA-256': { digest: null },
336
+ 'SHA-384': { digest: null },
337
+ 'SHA-512': { digest: null },
338
+ 'SHA3-256': { digest: null },
339
+ 'SHA3-384': { digest: null },
340
+ 'SHA3-512': { digest: null },
341
+ cSHAKE128: { digest: 'CShakeParams' },
342
+ cSHAKE256: { digest: 'CShakeParams' },
343
+ KT128: { digest: 'KangarooTwelveParams' },
344
+ KT256: { digest: 'KangarooTwelveParams' },
345
+ TurboSHAKE128: { digest: 'TurboShakeParams' },
346
+ TurboSHAKE256: { digest: 'TurboShakeParams' },
347
+ X25519: {
348
+ generateKey: null,
349
+ exportKey: null,
350
+ importKey: null,
351
+ deriveBits: 'EcdhKeyDeriveParams',
352
+ },
353
+ X448: {
354
+ generateKey: null,
355
+ exportKey: null,
356
+ importKey: null,
357
+ deriveBits: 'EcdhKeyDeriveParams',
358
+ },
359
+ };
360
+
361
+ for (const v of SLH_DSA_VARIANTS) {
362
+ kAlgorithmDefinitions[v] = {
363
+ generateKey: null,
364
+ exportKey: null,
365
+ importKey: null,
366
+ sign: null,
367
+ verify: null,
368
+ };
369
+ }
370
+
371
+ // WebIDL dictionary member specs. Mirrors Node's per-converter
372
+ // `createDictionaryConverter` definitions in lib/internal/crypto/webidl.js.
373
+ // `required: true` causes `normalizeAlgorithm` to throw a TypeError when the
374
+ // member is missing — matching the spec'd WebCrypto behavior that
375
+ // `SubtleCrypto.supports` relies on via try/catch.
376
+ interface IdlField {
377
+ key: string;
378
+ required?: boolean;
379
+ }
380
+
381
+ type NormalizedAlgorithmRecord = SubtleAlgorithm & Record<string, unknown>;
382
+
383
+ const kRequiredFields: Record<string, IdlField[]> = {
384
+ AesKeyGenParams: [{ key: 'length', required: true }],
385
+ AesDerivedKeyParams: [{ key: 'length', required: true }],
386
+ AesCbcParams: [{ key: 'iv', required: true }],
387
+ AesCtrParams: [
388
+ { key: 'counter', required: true },
389
+ { key: 'length', required: true },
390
+ ],
391
+ AeadParams: [
392
+ { key: 'iv', required: true },
393
+ { key: 'tagLength' },
394
+ { key: 'additionalData' },
395
+ ],
396
+ EcKeyGenParams: [{ key: 'namedCurve', required: true }],
397
+ EcKeyImportParams: [{ key: 'namedCurve', required: true }],
398
+ EcdsaParams: [{ key: 'hash', required: true }],
399
+ EcdhKeyDeriveParams: [{ key: 'public', required: true }],
400
+ HmacKeyGenParams: [{ key: 'hash', required: true }, { key: 'length' }],
401
+ HmacImportParams: [{ key: 'hash', required: true }, { key: 'length' }],
402
+ HkdfParams: [
403
+ { key: 'hash', required: true },
404
+ { key: 'salt', required: true },
405
+ { key: 'info', required: true },
406
+ ],
407
+ Pbkdf2Params: [
408
+ { key: 'hash', required: true },
409
+ { key: 'iterations', required: true },
410
+ { key: 'salt', required: true },
411
+ ],
412
+ RsaHashedKeyGenParams: [
413
+ { key: 'modulusLength', required: true },
414
+ { key: 'publicExponent', required: true },
415
+ { key: 'hash', required: true },
416
+ ],
417
+ RsaHashedImportParams: [{ key: 'hash', required: true }],
418
+ RsaOaepParams: [{ key: 'label' }],
419
+ RsaPssParams: [{ key: 'saltLength', required: true }],
420
+ ContextParams: [{ key: 'context' }],
421
+ Argon2Params: [
422
+ { key: 'nonce', required: true },
423
+ { key: 'parallelism', required: true },
424
+ { key: 'memory', required: true },
425
+ { key: 'passes', required: true },
426
+ { key: 'version' },
427
+ { key: 'secretValue' },
428
+ { key: 'associatedData' },
429
+ ],
430
+ KmacKeyGenParams: [{ key: 'length' }],
431
+ KmacImportParams: [{ key: 'length' }],
432
+ KmacParams: [
433
+ { key: 'outputLength', required: true },
434
+ { key: 'customization' },
435
+ ],
436
+ CShakeParams: [
437
+ { key: 'outputLength', required: true },
438
+ { key: 'functionName' },
439
+ { key: 'customization' },
440
+ ],
441
+ KangarooTwelveParams: [
442
+ { key: 'outputLength', required: true },
443
+ { key: 'customization' },
444
+ ],
445
+ TurboShakeParams: [
446
+ { key: 'outputLength', required: true },
447
+ { key: 'domainSeparation' },
448
+ ],
449
+ };
450
+
451
+ function isBufferSource(value: unknown): value is BufferLike {
452
+ return value instanceof ArrayBuffer || ArrayBuffer.isView(value);
453
+ }
454
+
455
+ function validateBufferSource(
456
+ algorithm: NormalizedAlgorithmRecord,
457
+ key: string,
458
+ ): ArrayBuffer | undefined {
459
+ const value = algorithm[key];
460
+ if (value === undefined) return undefined;
461
+ if (!isBufferSource(value)) {
462
+ throw new TypeError(
463
+ `Failed to normalize algorithm: '${key}' must be a BufferSource`,
464
+ );
465
+ }
466
+ return bufferLikeToArrayBuffer(value);
467
+ }
468
+
469
+ function validateBinaryLike(
470
+ algorithm: NormalizedAlgorithmRecord,
471
+ key: string,
472
+ ): ArrayBuffer | undefined {
473
+ const value = algorithm[key];
474
+ if (value === undefined) return undefined;
475
+ try {
476
+ return binaryLikeToArrayBuffer(value as BinaryLike);
477
+ } catch {
478
+ throw new TypeError(
479
+ `Failed to normalize algorithm: '${key}' must be a BufferSource`,
480
+ );
481
+ }
482
+ }
483
+
484
+ function validateByteLength(
485
+ buffer: ArrayBuffer | undefined,
486
+ key: string,
487
+ length: number,
488
+ message?: string,
489
+ ): void {
490
+ if (buffer !== undefined && buffer.byteLength !== length) {
491
+ throw lazyDOMException(
492
+ message ?? `${key} must be ${length} bytes`,
493
+ 'OperationError',
494
+ );
495
+ }
496
+ }
497
+
498
+ function validateUnsignedInteger(
499
+ algorithm: NormalizedAlgorithmRecord,
500
+ key: string,
501
+ ): number | undefined {
502
+ const value = algorithm[key];
503
+ if (value === undefined) return undefined;
504
+ const numberValue = Number(value);
505
+ if (
506
+ !Number.isFinite(numberValue) ||
507
+ !Number.isInteger(numberValue) ||
508
+ numberValue < 0
509
+ ) {
510
+ throw new TypeError(
511
+ `Failed to normalize algorithm: '${key}' must be an unsigned integer`,
512
+ );
513
+ }
514
+ algorithm[key] = numberValue;
515
+ return numberValue;
516
+ }
517
+
518
+ function validateHashAlgorithm(
519
+ algorithm: NormalizedAlgorithmRecord,
520
+ converterName: string,
521
+ ): void {
522
+ const hash = algorithm.hash as string | { name: string } | undefined;
523
+ if (hash === undefined) return;
524
+ const normalizedHash = normalizeHashName(hash, HashContext.WebCrypto);
525
+ if (
526
+ ![
527
+ 'SHA-1',
528
+ 'SHA-256',
529
+ 'SHA-384',
530
+ 'SHA-512',
531
+ 'SHA3-256',
532
+ 'SHA3-384',
533
+ 'SHA3-512',
534
+ ].includes(normalizedHash)
535
+ ) {
536
+ throw lazyDOMException(
537
+ `Unsupported ${converterName}.hash`,
538
+ 'NotSupportedError',
539
+ );
540
+ }
541
+ algorithm.hash = { name: normalizedHash };
542
+ }
543
+
544
+ function validateAesLength(length: number | undefined): void {
545
+ if (
546
+ length !== undefined &&
547
+ length !== 128 &&
548
+ length !== 192 &&
549
+ length !== 256
550
+ ) {
551
+ throw lazyDOMException('Invalid key length', 'OperationError');
552
+ }
553
+ }
554
+
555
+ function validateMacLength(
556
+ algorithm: NormalizedAlgorithmRecord,
557
+ key: string,
558
+ zeroError: 'DataError' | 'OperationError',
559
+ ): void {
560
+ const length = validateUnsignedInteger(algorithm, key);
561
+ if (length === undefined) return;
562
+ if (length === 0) {
563
+ throw lazyDOMException(`${key} cannot be 0`, zeroError);
564
+ }
565
+ if (length % 8) {
566
+ throw lazyDOMException(`Unsupported ${key}`, 'NotSupportedError');
567
+ }
568
+ }
569
+
570
+ function validateAeadParams(algorithm: NormalizedAlgorithmRecord): void {
571
+ const iv = validateBufferSource(algorithm, 'iv');
572
+ const tagLength = validateUnsignedInteger(algorithm, 'tagLength');
573
+ validateBufferSource(algorithm, 'additionalData');
574
+
575
+ switch (algorithm.name) {
576
+ case 'AES-GCM':
577
+ if (
578
+ tagLength !== undefined &&
579
+ ![32, 64, 96, 104, 112, 120, 128].includes(tagLength)
580
+ ) {
581
+ throw lazyDOMException(
582
+ `${tagLength} is not a valid AES-GCM tag length`,
583
+ 'OperationError',
584
+ );
585
+ }
586
+ break;
587
+ case 'AES-OCB':
588
+ if (iv !== undefined && (iv.byteLength < 1 || iv.byteLength > 15)) {
589
+ throw lazyDOMException(
590
+ 'AES-OCB algorithm.iv must be between 1 and 15 bytes',
591
+ 'OperationError',
592
+ );
593
+ }
594
+ if (tagLength !== undefined && ![64, 96, 128].includes(tagLength)) {
595
+ throw lazyDOMException(
596
+ `${tagLength} is not a valid AES-OCB tag length`,
597
+ 'OperationError',
598
+ );
599
+ }
600
+ break;
601
+ case 'ChaCha20-Poly1305':
602
+ validateByteLength(
603
+ iv,
604
+ 'algorithm.iv',
605
+ 12,
606
+ 'ChaCha20-Poly1305 IV must be exactly 12 bytes',
607
+ );
608
+ if (tagLength !== undefined && tagLength !== 128) {
609
+ throw lazyDOMException(
610
+ `${tagLength} is not a valid ChaCha20-Poly1305 tag length`,
611
+ 'OperationError',
612
+ );
613
+ }
614
+ break;
615
+ }
616
+ }
617
+
618
+ function validateNormalizedAlgorithm(
619
+ converterName: string,
620
+ algorithm: NormalizedAlgorithmRecord,
621
+ ): void {
622
+ switch (converterName) {
623
+ case 'AesKeyGenParams':
624
+ case 'AesDerivedKeyParams':
625
+ validateAesLength(validateUnsignedInteger(algorithm, 'length'));
626
+ break;
627
+ case 'AesCbcParams':
628
+ validateByteLength(
629
+ validateBufferSource(algorithm, 'iv'),
630
+ 'algorithm.iv',
631
+ 16,
632
+ 'algorithm.iv must contain exactly 16 bytes',
633
+ );
634
+ break;
635
+ case 'AesCtrParams': {
636
+ validateByteLength(
637
+ validateBufferSource(algorithm, 'counter'),
638
+ 'algorithm.counter',
639
+ 16,
640
+ );
641
+ const length = validateUnsignedInteger(algorithm, 'length');
642
+ if (length !== undefined && (length === 0 || length > 128)) {
643
+ throw lazyDOMException(
644
+ 'AES-CTR algorithm.length must be between 1 and 128',
645
+ 'OperationError',
646
+ );
647
+ }
648
+ break;
649
+ }
650
+ case 'AeadParams':
651
+ validateAeadParams(algorithm);
652
+ break;
653
+ case 'EcdsaParams':
654
+ case 'HmacKeyGenParams':
655
+ case 'HmacImportParams':
656
+ case 'HkdfParams':
657
+ case 'Pbkdf2Params':
658
+ case 'RsaHashedKeyGenParams':
659
+ case 'RsaHashedImportParams':
660
+ validateHashAlgorithm(algorithm, converterName);
661
+ if (converterName === 'HmacKeyGenParams') {
662
+ validateMacLength(algorithm, 'length', 'OperationError');
663
+ }
664
+ if (converterName === 'HkdfParams') {
665
+ validateBinaryLike(algorithm, 'salt');
666
+ validateBinaryLike(algorithm, 'info');
667
+ } else if (converterName === 'Pbkdf2Params') {
668
+ const iterations = validateUnsignedInteger(algorithm, 'iterations');
669
+ if (iterations === 0) {
670
+ throw lazyDOMException('iterations cannot be zero', 'OperationError');
671
+ }
672
+ validateBinaryLike(algorithm, 'salt');
673
+ } else if (converterName === 'RsaHashedKeyGenParams') {
674
+ validateUnsignedInteger(algorithm, 'modulusLength');
675
+ validateBufferSource(algorithm, 'publicExponent');
676
+ }
677
+ break;
678
+ case 'RsaPssParams':
679
+ validateUnsignedInteger(algorithm, 'saltLength');
680
+ break;
681
+ case 'RsaOaepParams':
682
+ validateBufferSource(algorithm, 'label');
683
+ break;
684
+ case 'ContextParams':
685
+ validateBufferSource(algorithm, 'context');
686
+ break;
687
+ case 'EcdhKeyDeriveParams':
688
+ if (!(algorithm.public instanceof CryptoKey)) {
689
+ throw lazyDOMException(
690
+ 'algorithm.public must be a public key',
691
+ 'InvalidAccessError',
692
+ );
693
+ }
694
+ break;
695
+ case 'Argon2Params': {
696
+ validateBufferSource(algorithm, 'nonce');
697
+ const parallelism = validateUnsignedInteger(algorithm, 'parallelism');
698
+ const memory = validateUnsignedInteger(algorithm, 'memory');
699
+ validateUnsignedInteger(algorithm, 'passes');
700
+ const version = validateUnsignedInteger(algorithm, 'version');
701
+ validateBufferSource(algorithm, 'secretValue');
702
+ validateBufferSource(algorithm, 'associatedData');
703
+ if (
704
+ parallelism !== undefined &&
705
+ (parallelism === 0 || parallelism > 2 ** 24 - 1)
706
+ ) {
707
+ throw lazyDOMException(
708
+ 'parallelism must be > 0 and < 16777215',
709
+ 'OperationError',
710
+ );
711
+ }
712
+ if (
713
+ memory !== undefined &&
714
+ parallelism !== undefined &&
715
+ memory < 8 * parallelism
716
+ ) {
717
+ throw lazyDOMException(
718
+ 'memory must be at least 8 times the degree of parallelism',
719
+ 'OperationError',
720
+ );
721
+ }
722
+ if (version !== undefined && version !== 0x13) {
723
+ throw lazyDOMException(
724
+ `${version} is not a valid Argon2 version`,
725
+ 'OperationError',
726
+ );
727
+ }
728
+ break;
729
+ }
730
+ case 'KmacKeyGenParams':
731
+ validateMacLength(algorithm, 'length', 'OperationError');
732
+ break;
733
+ case 'KmacImportParams':
734
+ validateMacLength(algorithm, 'length', 'DataError');
735
+ break;
736
+ case 'KmacParams':
737
+ validateMacLength(algorithm, 'outputLength', 'OperationError');
738
+ validateBufferSource(algorithm, 'customization');
739
+ break;
740
+ case 'CShakeParams':
741
+ case 'KangarooTwelveParams': {
742
+ const outputLength = validateUnsignedInteger(algorithm, 'outputLength');
743
+ if (
744
+ outputLength !== undefined &&
745
+ (outputLength === 0 || outputLength % 8)
746
+ ) {
747
+ throw lazyDOMException(
748
+ `Invalid ${converterName} outputLength`,
749
+ 'OperationError',
750
+ );
751
+ }
752
+ validateBufferSource(algorithm, 'functionName');
753
+ validateBufferSource(algorithm, 'customization');
754
+ break;
755
+ }
756
+ case 'TurboShakeParams': {
757
+ const outputLength = validateUnsignedInteger(algorithm, 'outputLength');
758
+ const domainSeparation = validateUnsignedInteger(
759
+ algorithm,
760
+ 'domainSeparation',
761
+ );
762
+ if (
763
+ outputLength !== undefined &&
764
+ (outputLength === 0 || outputLength % 8)
765
+ ) {
766
+ throw lazyDOMException(
767
+ 'Invalid TurboShakeParams outputLength',
768
+ 'OperationError',
769
+ );
770
+ }
771
+ if (
772
+ domainSeparation !== undefined &&
773
+ (domainSeparation < 0x01 || domainSeparation > 0x7f)
774
+ ) {
775
+ throw lazyDOMException(
776
+ 'TurboShakeParams.domainSeparation must be in range 0x01-0x7f',
777
+ 'OperationError',
778
+ );
779
+ }
780
+ break;
781
+ }
782
+ }
783
+ }
784
+
785
+ // WebCrypto §18.4.4 algorithm normalization. Mirrors Node's normalizeAlgorithm
786
+ // in lib/internal/crypto/util.js: canonicalizes `name`, looks up the
787
+ // (name, op) → converter mapping, and rejects inputs that omit required
788
+ // dictionary members. Callers in Subtle.supports rely on this throwing for
789
+ // invalid params — without it, supports() over-reports capability (#1025).
790
+ function normalizeAlgorithm(
791
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
792
+ operation: Operation | string,
793
+ ): SubtleAlgorithm {
794
+ if (typeof algorithm === 'string') {
795
+ return normalizeAlgorithm({ name: algorithm }, operation);
796
+ }
797
+ const name = (algorithm as { name?: unknown }).name;
798
+ if (typeof name !== 'string') {
799
+ throw new TypeError("Algorithm: 'name' is required");
800
+ }
801
+ const map = getCanonicalAlgorithmNames();
802
+ const canonical = map.get(name.toLowerCase());
803
+ if (canonical === undefined) {
804
+ throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
805
+ }
806
+ const opMap = kAlgorithmDefinitions[canonical];
807
+ if (!opMap || !(operation in opMap)) {
808
+ throw lazyDOMException('Unrecognized algorithm name', 'NotSupportedError');
809
+ }
810
+ const converterName = opMap[operation];
811
+ if (converterName == null) {
812
+ return { name: canonical };
813
+ }
814
+ const fields = kRequiredFields[converterName];
815
+ if (!fields) {
816
+ return { ...algorithm, name: canonical };
817
+ }
818
+ const out = { name: canonical } as NormalizedAlgorithmRecord;
819
+ const src = algorithm as Record<string, unknown>;
820
+ for (const field of fields) {
821
+ const value = src[field.key];
822
+ if (value === undefined) {
823
+ if (field.required) {
824
+ throw new TypeError(
825
+ `Failed to normalize algorithm: '${field.key}' is required in '${converterName}'`,
826
+ );
827
+ }
828
+ continue;
829
+ }
830
+ (out as Record<string, unknown>)[field.key] = value;
831
+ }
832
+ validateNormalizedAlgorithm(converterName, out);
833
+ return out;
834
+ }
835
+
836
+ function getAlgorithmName(name: string, length: number): string {
837
+ switch (name) {
838
+ case 'AES-CBC':
839
+ return `A${length}CBC`;
840
+ case 'AES-CTR':
841
+ return `A${length}CTR`;
842
+ case 'AES-GCM':
843
+ return `A${length}GCM`;
844
+ case 'AES-KW':
845
+ return `A${length}KW`;
846
+ case 'AES-OCB':
847
+ return `A${length}OCB`;
848
+ case 'ChaCha20-Poly1305':
849
+ return 'C20P';
850
+ default:
851
+ return `${name}${length}`;
852
+ }
853
+ }
854
+
855
+ // Mirrors Node's aliasKeyFormat (lib/internal/crypto/webcrypto.js): for
856
+ // algorithms whose import/export accepts both 'raw' and the disambiguated
857
+ // 'raw-secret' / 'raw-public', collapse the latter to 'raw'. Used per-algorithm
858
+ // — algorithms that demand the disambiguated form (KMAC, AES-OCB,
859
+ // ChaCha20-Poly1305, Argon2*, ML-DSA, ML-KEM) MUST NOT alias.
860
+ function aliasKeyFormat(format: ImportFormat): ImportFormat {
861
+ if (format === 'raw-secret' || format === 'raw-public') return 'raw';
862
+ return format;
863
+ }
864
+
865
+ const kUncompressedSpkiLength: Record<string, number> = {
866
+ 'P-256': 91,
867
+ 'P-384': 120,
868
+ 'P-521': 158,
869
+ };
870
+
871
+ function ecExportKey(key: CryptoKey, format: KWebCryptoKeyFormat): ArrayBuffer {
872
+ const keyObject = key.keyObject;
873
+
874
+ if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatRaw) {
875
+ return bufferLikeToArrayBuffer(keyObject.handle.exportKey());
876
+ } else if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI) {
877
+ const exported = bufferLikeToArrayBuffer(
878
+ keyObject.export({ format: 'der', type: 'spki' }),
879
+ );
880
+
881
+ // WebCrypto requires uncompressed point format for SPKI exports.
882
+ // If the key was imported in compressed form, re-export as uncompressed
883
+ // by reconstructing the point from the JWK x,y coordinates and
884
+ // round-tripping through initECRaw.
885
+ const namedCurve = key.algorithm.namedCurve;
886
+ const expected =
887
+ namedCurve === undefined
888
+ ? undefined
889
+ : kUncompressedSpkiLength[namedCurve];
890
+ if (expected !== undefined && exported.byteLength !== expected) {
891
+ const jwk = keyObject.handle.exportJwk({}, false);
892
+ if (!jwk.x || !jwk.y) {
893
+ throw lazyDOMException(
894
+ 'Failed to re-export EC public key as uncompressed SPKI',
895
+ 'OperationError',
896
+ );
897
+ }
898
+ const x = Buffer.from(jwk.x, 'base64url');
899
+ const y = Buffer.from(jwk.y, 'base64url');
900
+ const raw = new Uint8Array(1 + x.length + y.length);
901
+ raw[0] = 0x04;
902
+ raw.set(x, 1);
903
+ raw.set(y, 1 + x.length);
904
+ const tmp =
905
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
906
+ const curveAlias =
907
+ kNamedCurveAliases[namedCurve as keyof typeof kNamedCurveAliases];
908
+ if (!tmp.initECRaw(curveAlias, raw.buffer as ArrayBuffer)) {
909
+ throw lazyDOMException(
910
+ 'Failed to re-export EC public key as uncompressed SPKI',
911
+ 'OperationError',
912
+ );
913
+ }
914
+ return bufferLikeToArrayBuffer(
915
+ tmp.exportKey(KFormatType.DER, KeyEncoding.SPKI),
916
+ );
917
+ }
918
+ return exported;
919
+ } else if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8) {
920
+ const exported = keyObject.export({ format: 'der', type: 'pkcs8' });
921
+ return bufferLikeToArrayBuffer(exported);
922
+ } else {
923
+ throw new Error(`Unsupported EC export format: ${format}`);
924
+ }
925
+ }
926
+
927
+ function rsaExportKey(
928
+ key: CryptoKey,
929
+ format: KWebCryptoKeyFormat,
930
+ ): ArrayBuffer {
931
+ const keyObject = key.keyObject;
932
+
933
+ if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI) {
934
+ // Export public key in SPKI format
935
+ const exported = keyObject.export({ format: 'der', type: 'spki' });
936
+ return bufferLikeToArrayBuffer(exported);
937
+ } else if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8) {
938
+ // Export private key in PKCS8 format
939
+ const exported = keyObject.export({ format: 'der', type: 'pkcs8' });
940
+ return bufferLikeToArrayBuffer(exported);
941
+ } else {
942
+ throw new Error(`Unsupported RSA export format: ${format}`);
943
+ }
944
+ }
945
+
946
+ async function rsaCipher(
947
+ mode: CipherOrWrapMode,
948
+ key: CryptoKey,
949
+ data: ArrayBuffer,
950
+ algorithm: EncryptDecryptParams,
951
+ ): Promise<ArrayBuffer> {
952
+ const rsaParams = algorithm as RsaOaepParams;
953
+
954
+ // Validate key type matches operation
955
+ const expectedType =
956
+ mode === CipherOrWrapMode.kWebCryptoCipherEncrypt ? 'public' : 'private';
957
+ if (key.type !== expectedType) {
958
+ throw lazyDOMException(
959
+ 'The requested operation is not valid for the provided key',
960
+ 'InvalidAccessError',
961
+ );
962
+ }
963
+
964
+ // Get hash algorithm from key
965
+ const hashAlgorithm = normalizeHashName(key.algorithm.hash);
966
+
967
+ // Prepare label (optional)
968
+ const label = rsaParams.label
969
+ ? bufferLikeToArrayBuffer(rsaParams.label)
970
+ : undefined;
971
+
972
+ // Create RSA cipher instance
973
+ const rsaCipherModule =
974
+ NitroModules.createHybridObject<RsaCipher>('RsaCipher');
975
+
976
+ // RSA-OAEP padding constant = 4
977
+ const RSA_PKCS1_OAEP_PADDING = 4;
978
+
979
+ if (mode === CipherOrWrapMode.kWebCryptoCipherEncrypt) {
980
+ // Encrypt with public key
981
+ return rsaCipherModule.encrypt(
982
+ key.keyObject.handle,
983
+ data,
984
+ RSA_PKCS1_OAEP_PADDING,
985
+ hashAlgorithm,
986
+ label,
987
+ );
988
+ } else {
989
+ // Decrypt with private key
990
+ return rsaCipherModule.decrypt(
991
+ key.keyObject.handle,
992
+ data,
993
+ RSA_PKCS1_OAEP_PADDING,
994
+ hashAlgorithm,
995
+ label,
996
+ );
997
+ }
998
+ }
999
+
1000
+ async function aesCipher(
1001
+ mode: CipherOrWrapMode,
1002
+ key: CryptoKey,
1003
+ data: ArrayBuffer,
1004
+ algorithm: EncryptDecryptParams,
1005
+ ): Promise<ArrayBuffer> {
1006
+ const { name } = algorithm;
1007
+
1008
+ switch (name) {
1009
+ case 'AES-CTR':
1010
+ return aesCtrCipher(mode, key, data, algorithm as AesCtrParams);
1011
+ case 'AES-CBC':
1012
+ return aesCbcCipher(mode, key, data, algorithm as AesCbcParams);
1013
+ case 'AES-GCM':
1014
+ return aesGcmCipher(mode, key, data, algorithm as AesGcmParams);
1015
+ case 'AES-OCB':
1016
+ return aesOcbCipher(mode, key, data, algorithm as AesOcbParams);
1017
+ default:
1018
+ throw lazyDOMException(
1019
+ `Unsupported AES algorithm: ${name}`,
1020
+ 'NotSupportedError',
1021
+ );
1022
+ }
1023
+ }
1024
+
1025
+ async function aesCtrCipher(
1026
+ mode: CipherOrWrapMode,
1027
+ key: CryptoKey,
1028
+ data: ArrayBuffer,
1029
+ algorithm: AesCtrParams,
1030
+ ): Promise<ArrayBuffer> {
1031
+ // Validate counter and length
1032
+ if (!algorithm.counter || algorithm.counter.byteLength !== 16) {
1033
+ throw lazyDOMException(
1034
+ 'AES-CTR algorithm.counter must be 16 bytes',
1035
+ 'OperationError',
1036
+ );
1037
+ }
1038
+
1039
+ if (algorithm.length < 1 || algorithm.length > 128) {
1040
+ throw lazyDOMException(
1041
+ 'AES-CTR algorithm.length must be between 1 and 128',
1042
+ 'OperationError',
1043
+ );
1044
+ }
1045
+
1046
+ // Get cipher type based on key length
1047
+ const keyLength = (key.algorithm as { length: number }).length;
1048
+ const cipherType = `aes-${keyLength}-ctr`;
1049
+
1050
+ // Create cipher
1051
+ const factory =
1052
+ NitroModules.createHybridObject<CipherFactory>('CipherFactory');
1053
+ const cipher = factory.createCipher({
1054
+ isCipher: mode === CipherOrWrapMode.kWebCryptoCipherEncrypt,
1055
+ cipherType,
1056
+ cipherKey: bufferLikeToArrayBuffer(key.keyObject.export()),
1057
+ iv: bufferLikeToArrayBuffer(algorithm.counter),
1058
+ });
1059
+
1060
+ // Process data
1061
+ const updated = cipher.update(data);
1062
+ const final = cipher.final();
1063
+
1064
+ // Concatenate results
1065
+ const result = new Uint8Array(updated.byteLength + final.byteLength);
1066
+ result.set(new Uint8Array(updated), 0);
1067
+ result.set(new Uint8Array(final), updated.byteLength);
1068
+
1069
+ return result.buffer;
1070
+ }
1071
+
1072
+ async function aesCbcCipher(
1073
+ mode: CipherOrWrapMode,
1074
+ key: CryptoKey,
1075
+ data: ArrayBuffer,
1076
+ algorithm: AesCbcParams,
1077
+ ): Promise<ArrayBuffer> {
1078
+ // Validate IV
1079
+ const iv = bufferLikeToArrayBuffer(algorithm.iv);
1080
+ if (iv.byteLength !== 16) {
1081
+ throw lazyDOMException(
1082
+ 'algorithm.iv must contain exactly 16 bytes',
1083
+ 'OperationError',
1084
+ );
1085
+ }
1086
+
1087
+ // Get cipher type based on key length
1088
+ const keyLength = (key.algorithm as { length: number }).length;
1089
+ const cipherType = `aes-${keyLength}-cbc`;
1090
+
1091
+ // Create cipher
1092
+ const factory =
1093
+ NitroModules.createHybridObject<CipherFactory>('CipherFactory');
1094
+ const cipher = factory.createCipher({
1095
+ isCipher: mode === CipherOrWrapMode.kWebCryptoCipherEncrypt,
1096
+ cipherType,
1097
+ cipherKey: bufferLikeToArrayBuffer(key.keyObject.export()),
1098
+ iv,
1099
+ });
1100
+
1101
+ // Process data
1102
+ const updated = cipher.update(data);
1103
+ const final = cipher.final();
1104
+
1105
+ // Concatenate results
1106
+ const result = new Uint8Array(updated.byteLength + final.byteLength);
1107
+ result.set(new Uint8Array(updated), 0);
1108
+ result.set(new Uint8Array(final), updated.byteLength);
1109
+
1110
+ return result.buffer;
1111
+ }
1112
+
1113
+ interface AeadCipherConfig {
1114
+ algorithmName: string;
1115
+ validTagLengths: number[];
1116
+ cipherSuffix: string;
1117
+ iv: ArrayBuffer;
1118
+ }
1119
+
1120
+ async function aesAeadCipher(
1121
+ mode: CipherOrWrapMode,
1122
+ key: CryptoKey,
1123
+ data: ArrayBuffer,
1124
+ config: AeadCipherConfig,
1125
+ additionalData?: BufferLike,
1126
+ tagLength: number = 128,
1127
+ ): Promise<ArrayBuffer> {
1128
+ if (!config.validTagLengths.includes(tagLength)) {
1129
+ throw lazyDOMException(
1130
+ `${tagLength} is not a valid ${config.algorithmName} tag length`,
1131
+ 'OperationError',
1132
+ );
1133
+ }
1134
+
1135
+ const tagByteLength = tagLength / 8;
1136
+ const keyLength = (key.algorithm as { length: number }).length;
1137
+ const cipherType = `aes-${keyLength}-${config.cipherSuffix}`;
1138
+
1139
+ const factory =
1140
+ NitroModules.createHybridObject<CipherFactory>('CipherFactory');
1141
+ const cipher = factory.createCipher({
1142
+ isCipher: mode === CipherOrWrapMode.kWebCryptoCipherEncrypt,
1143
+ cipherType,
1144
+ cipherKey: bufferLikeToArrayBuffer(key.keyObject.export()),
1145
+ iv: config.iv,
1146
+ authTagLen: tagByteLength,
1147
+ });
1148
+
1149
+ let processData: ArrayBuffer;
1150
+
1151
+ if (mode === CipherOrWrapMode.kWebCryptoCipherDecrypt) {
1152
+ const dataView = new Uint8Array(data);
1153
+
1154
+ if (dataView.byteLength < tagByteLength) {
1155
+ throw lazyDOMException(
1156
+ 'The provided data is too small.',
1157
+ 'OperationError',
1158
+ );
1159
+ }
1160
+
1161
+ const ciphertextLength = dataView.byteLength - tagByteLength;
1162
+ processData = dataView.slice(0, ciphertextLength).buffer;
1163
+ const authTag = dataView.slice(ciphertextLength).buffer;
1164
+ cipher.setAuthTag(authTag);
1165
+ } else {
1166
+ processData = data;
1167
+ }
1168
+
1169
+ if (additionalData) {
1170
+ cipher.setAAD(bufferLikeToArrayBuffer(additionalData));
1171
+ }
1172
+
1173
+ const updated = cipher.update(processData);
1174
+ const final = cipher.final();
1175
+
1176
+ if (mode === CipherOrWrapMode.kWebCryptoCipherEncrypt) {
1177
+ const tag = cipher.getAuthTag();
1178
+ const result = new Uint8Array(
1179
+ updated.byteLength + final.byteLength + tag.byteLength,
1180
+ );
1181
+ result.set(new Uint8Array(updated), 0);
1182
+ result.set(new Uint8Array(final), updated.byteLength);
1183
+ result.set(new Uint8Array(tag), updated.byteLength + final.byteLength);
1184
+ return result.buffer;
1185
+ } else {
1186
+ const result = new Uint8Array(updated.byteLength + final.byteLength);
1187
+ result.set(new Uint8Array(updated), 0);
1188
+ result.set(new Uint8Array(final), updated.byteLength);
1189
+ return result.buffer;
1190
+ }
1191
+ }
1192
+
1193
+ async function aesGcmCipher(
1194
+ mode: CipherOrWrapMode,
1195
+ key: CryptoKey,
1196
+ data: ArrayBuffer,
1197
+ algorithm: AesGcmParams,
1198
+ ): Promise<ArrayBuffer> {
1199
+ return aesAeadCipher(
1200
+ mode,
1201
+ key,
1202
+ data,
1203
+ {
1204
+ algorithmName: 'AES-GCM',
1205
+ validTagLengths: [32, 64, 96, 104, 112, 120, 128],
1206
+ cipherSuffix: 'gcm',
1207
+ iv: bufferLikeToArrayBuffer(algorithm.iv),
1208
+ },
1209
+ algorithm.additionalData,
1210
+ algorithm.tagLength,
1211
+ );
1212
+ }
1213
+
1214
+ async function aesOcbCipher(
1215
+ mode: CipherOrWrapMode,
1216
+ key: CryptoKey,
1217
+ data: ArrayBuffer,
1218
+ algorithm: AesOcbParams,
1219
+ ): Promise<ArrayBuffer> {
1220
+ const ivBuffer = bufferLikeToArrayBuffer(algorithm.iv);
1221
+ if (ivBuffer.byteLength < 1 || ivBuffer.byteLength > 15) {
1222
+ throw lazyDOMException(
1223
+ 'AES-OCB algorithm.iv must be between 1 and 15 bytes',
1224
+ 'OperationError',
1225
+ );
1226
+ }
1227
+
1228
+ return aesAeadCipher(
1229
+ mode,
1230
+ key,
1231
+ data,
1232
+ {
1233
+ algorithmName: 'AES-OCB',
1234
+ validTagLengths: [64, 96, 128],
1235
+ cipherSuffix: 'ocb',
1236
+ iv: ivBuffer,
1237
+ },
1238
+ algorithm.additionalData,
1239
+ algorithm.tagLength,
1240
+ );
1241
+ }
1242
+
1243
+ async function aesKwCipher(
1244
+ mode: CipherOrWrapMode,
1245
+ key: CryptoKey,
1246
+ data: ArrayBuffer,
1247
+ ): Promise<ArrayBuffer> {
1248
+ const isWrap = mode === CipherOrWrapMode.kWebCryptoCipherEncrypt;
1249
+
1250
+ // AES-KW requires input to be a multiple of 8 bytes (64 bits)
1251
+ if (data.byteLength % 8 !== 0) {
1252
+ throw lazyDOMException(
1253
+ `AES-KW input length must be a multiple of 8 bytes, got ${data.byteLength}`,
1254
+ 'OperationError',
1255
+ );
1256
+ }
1257
+
1258
+ // AES-KW requires at least 16 bytes of input (128 bits)
1259
+ if (isWrap && data.byteLength < 16) {
1260
+ throw lazyDOMException(
1261
+ `AES-KW input must be at least 16 bytes, got ${data.byteLength}`,
1262
+ 'OperationError',
1263
+ );
1264
+ }
1265
+
1266
+ // Get cipher type based on key length
1267
+ const keyLength = (key.algorithm as { length: number }).length;
1268
+ // Use aes*-wrap for both operations (matching Node.js)
1269
+ const cipherType = `aes${keyLength}-wrap`;
1270
+
1271
+ // Export key material
1272
+ const exportedKey = key.keyObject.export();
1273
+ const cipherKey = bufferLikeToArrayBuffer(exportedKey);
1274
+
1275
+ // AES-KW uses a default IV as specified in RFC 3394
1276
+ const defaultWrapIV = new Uint8Array([
1277
+ 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
1278
+ ]);
1279
+
1280
+ const factory =
1281
+ NitroModules.createHybridObject<CipherFactory>('CipherFactory');
1282
+
1283
+ const cipher = factory.createCipher({
1284
+ isCipher: isWrap,
1285
+ cipherType,
1286
+ cipherKey,
1287
+ iv: defaultWrapIV.buffer, // RFC 3394 default IV for AES-KW
1288
+ });
1289
+
1290
+ // Process data
1291
+ const updated = cipher.update(data);
1292
+ const final = cipher.final();
1293
+
1294
+ // Concatenate results
1295
+ const result = new Uint8Array(updated.byteLength + final.byteLength);
1296
+ result.set(new Uint8Array(updated), 0);
1297
+ result.set(new Uint8Array(final), updated.byteLength);
1298
+
1299
+ return result.buffer;
1300
+ }
1301
+
1302
+ async function chaCha20Poly1305Cipher(
1303
+ mode: CipherOrWrapMode,
1304
+ key: CryptoKey,
1305
+ data: ArrayBuffer,
1306
+ algorithm: ChaCha20Poly1305Params,
1307
+ ): Promise<ArrayBuffer> {
1308
+ const { iv, additionalData, tagLength = 128 } = algorithm;
1309
+
1310
+ // Validate IV (must be 12 bytes for ChaCha20-Poly1305)
1311
+ const ivBuffer = bufferLikeToArrayBuffer(iv);
1312
+ if (!ivBuffer || ivBuffer.byteLength !== 12) {
1313
+ throw lazyDOMException(
1314
+ 'ChaCha20-Poly1305 IV must be exactly 12 bytes',
1315
+ 'OperationError',
1316
+ );
1317
+ }
1318
+
1319
+ // Validate tag length (only 128-bit supported)
1320
+ if (tagLength !== 128) {
1321
+ throw lazyDOMException(
1322
+ 'ChaCha20-Poly1305 only supports 128-bit auth tags',
1323
+ 'NotSupportedError',
1324
+ );
1325
+ }
1326
+
1327
+ const tagByteLength = 16; // 128 bits = 16 bytes
1328
+
1329
+ // Create cipher using existing ChaCha20-Poly1305 implementation
1330
+ const factory =
1331
+ NitroModules.createHybridObject<CipherFactory>('CipherFactory');
1332
+ const cipher = factory.createCipher({
1333
+ isCipher: mode === CipherOrWrapMode.kWebCryptoCipherEncrypt,
1334
+ cipherType: 'chacha20-poly1305',
1335
+ cipherKey: bufferLikeToArrayBuffer(key.keyObject.export()),
1336
+ iv: ivBuffer,
1337
+ authTagLen: tagByteLength,
1338
+ });
1339
+
1340
+ let processData: ArrayBuffer;
1341
+ let authTag: ArrayBuffer | undefined;
1342
+
1343
+ if (mode === CipherOrWrapMode.kWebCryptoCipherDecrypt) {
1344
+ // For decryption, extract auth tag from end of data
1345
+ const dataView = new Uint8Array(data);
1346
+
1347
+ if (dataView.byteLength < tagByteLength) {
1348
+ throw lazyDOMException(
1349
+ 'The provided data is too small.',
1350
+ 'OperationError',
1351
+ );
1352
+ }
1353
+
1354
+ // Split data and tag
1355
+ const ciphertextLength = dataView.byteLength - tagByteLength;
1356
+ processData = dataView.slice(0, ciphertextLength).buffer;
1357
+ authTag = dataView.slice(ciphertextLength).buffer;
1358
+
1359
+ // Set auth tag for verification
1360
+ cipher.setAuthTag(authTag);
1361
+ } else {
1362
+ processData = data;
1363
+ }
1364
+
1365
+ // Set additional authenticated data if provided
1366
+ if (additionalData) {
1367
+ cipher.setAAD(bufferLikeToArrayBuffer(additionalData));
1368
+ }
1369
+
1370
+ // Process data
1371
+ const updated = cipher.update(processData);
1372
+ const final = cipher.final();
1373
+
1374
+ if (mode === CipherOrWrapMode.kWebCryptoCipherEncrypt) {
1375
+ // For encryption, append auth tag to result
1376
+ const tag = cipher.getAuthTag();
1377
+ const result = new Uint8Array(
1378
+ updated.byteLength + final.byteLength + tag.byteLength,
1379
+ );
1380
+ result.set(new Uint8Array(updated), 0);
1381
+ result.set(new Uint8Array(final), updated.byteLength);
1382
+ result.set(new Uint8Array(tag), updated.byteLength + final.byteLength);
1383
+ return result.buffer;
1384
+ } else {
1385
+ // For decryption, just concatenate plaintext
1386
+ const result = new Uint8Array(updated.byteLength + final.byteLength);
1387
+ result.set(new Uint8Array(updated), 0);
1388
+ result.set(new Uint8Array(final), updated.byteLength);
1389
+ return result.buffer;
1390
+ }
1391
+ }
1392
+
1393
+ async function aesGenerateKey(
1394
+ algorithm: AesKeyGenParams,
1395
+ extractable: boolean,
1396
+ keyUsages: KeyUsage[],
1397
+ ): Promise<CryptoKey> {
1398
+ const { length } = algorithm;
1399
+ const name = algorithm.name;
1400
+
1401
+ if (!name) {
1402
+ throw lazyDOMException('Algorithm name is required', 'OperationError');
1403
+ }
1404
+
1405
+ // Validate key length
1406
+ if (![128, 192, 256].includes(length)) {
1407
+ throw lazyDOMException(
1408
+ `Invalid AES key length: ${length}. Must be 128, 192, or 256.`,
1409
+ 'OperationError',
1410
+ );
1411
+ }
1412
+
1413
+ // Validate usages
1414
+ const validUsages: KeyUsage[] = [
1415
+ 'encrypt',
1416
+ 'decrypt',
1417
+ 'wrapKey',
1418
+ 'unwrapKey',
1419
+ ];
1420
+ if (hasAnyNotIn(keyUsages, validUsages)) {
1421
+ throw lazyDOMException(`Unsupported key usage for ${name}`, 'SyntaxError');
1422
+ }
1423
+
1424
+ // Generate random key bytes
1425
+ const keyBytes = new Uint8Array(length / 8);
1426
+ getRandomValues(keyBytes);
1427
+
1428
+ // Create secret key
1429
+ const keyObject = createSecretKey(keyBytes);
1430
+
1431
+ // Construct algorithm object with guaranteed name
1432
+ const keyAlgorithm: SubtleAlgorithm = { name, length };
1433
+
1434
+ return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
1435
+ }
1436
+
1437
+ async function hmacGenerateKey(
1438
+ algorithm: SubtleAlgorithm,
1439
+ extractable: boolean,
1440
+ keyUsages: KeyUsage[],
1441
+ ): Promise<CryptoKey> {
1442
+ // Validate usages
1443
+ if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
1444
+ throw lazyDOMException('Unsupported key usage for HMAC key', 'SyntaxError');
1445
+ }
1446
+
1447
+ // Get hash algorithm
1448
+ const hash = algorithm.hash;
1449
+ if (!hash) {
1450
+ throw lazyDOMException(
1451
+ 'HMAC algorithm requires a hash parameter',
1452
+ 'TypeError',
1453
+ );
1454
+ }
1455
+
1456
+ const hashName = normalizeHashName(hash);
1457
+
1458
+ // Determine key length
1459
+ let length = algorithm.length;
1460
+ if (length === undefined) {
1461
+ // Use hash output length as default key length
1462
+ switch (hashName) {
1463
+ case 'SHA-1':
1464
+ length = 160;
1465
+ break;
1466
+ case 'SHA-256':
1467
+ length = 256;
1468
+ break;
1469
+ case 'SHA-384':
1470
+ length = 384;
1471
+ break;
1472
+ case 'SHA-512':
1473
+ length = 512;
1474
+ break;
1475
+ default:
1476
+ length = 256; // Default to 256 bits
1477
+ }
1478
+ }
1479
+
1480
+ if (length === 0) {
1481
+ throw lazyDOMException(
1482
+ 'Zero-length key is not supported',
1483
+ 'OperationError',
1484
+ );
1485
+ }
1486
+
1487
+ // Generate random key bytes
1488
+ const keyBytes = new Uint8Array(Math.ceil(length / 8));
1489
+ getRandomValues(keyBytes);
1490
+
1491
+ // Create secret key
1492
+ const keyObject = createSecretKey(keyBytes);
1493
+
1494
+ // Construct algorithm object with hash normalized to { name: string } format per WebCrypto spec
1495
+ const webCryptoHashName = normalizeHashName(hash, HashContext.WebCrypto);
1496
+ const keyAlgorithm: SubtleAlgorithm = {
1497
+ name: 'HMAC',
1498
+ hash: { name: webCryptoHashName },
1499
+ length,
1500
+ };
1501
+
1502
+ return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
1503
+ }
1504
+
1505
+ async function kmacGenerateKey(
1506
+ algorithm: SubtleAlgorithm,
1507
+ extractable: boolean,
1508
+ keyUsages: KeyUsage[],
1509
+ ): Promise<CryptoKey> {
1510
+ const { name } = algorithm;
1511
+
1512
+ if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
1513
+ throw lazyDOMException(
1514
+ `Unsupported key usage for ${name} key`,
1515
+ 'SyntaxError',
1516
+ );
1517
+ }
1518
+
1519
+ const defaultLength = name === 'KMAC128' ? 128 : 256;
1520
+ const length = algorithm.length ?? defaultLength;
1521
+
1522
+ if (length === 0) {
1523
+ throw lazyDOMException(
1524
+ 'Zero-length key is not supported',
1525
+ 'OperationError',
1526
+ );
1527
+ }
1528
+
1529
+ const keyBytes = new Uint8Array(Math.ceil(length / 8));
1530
+ getRandomValues(keyBytes);
1531
+
1532
+ const keyObject = createSecretKey(keyBytes);
1533
+
1534
+ const keyAlgorithm: SubtleAlgorithm = { name: name as AnyAlgorithm, length };
1535
+
1536
+ return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
1537
+ }
1538
+
1539
+ function kmacSignVerify(
1540
+ key: CryptoKey,
1541
+ data: BufferLike,
1542
+ algorithm: SubtleAlgorithm,
1543
+ signature?: BufferLike,
1544
+ ): ArrayBuffer | boolean {
1545
+ const { name } = algorithm;
1546
+
1547
+ // KmacParams.outputLength is required per
1548
+ // https://wicg.github.io/webcrypto-modern-algos/#KmacParams-dictionary
1549
+ // and the rename from `length` (commit ab8dc2b84c2). Mirror Node's
1550
+ // mac.js:213-223 by reading `outputLength` (in bits).
1551
+ if (typeof algorithm.outputLength !== 'number') {
1552
+ throw lazyDOMException(
1553
+ `${name}Params.outputLength is required`,
1554
+ 'OperationError',
1555
+ );
1556
+ }
1557
+ const outputLengthBits = algorithm.outputLength;
1558
+
1559
+ if (outputLengthBits % 8 !== 0) {
1560
+ throw lazyDOMException(
1561
+ `Unsupported ${name}Params outputLength`,
1562
+ 'NotSupportedError',
1563
+ );
1564
+ }
1565
+
1566
+ const outputLengthBytes = outputLengthBits / 8;
1567
+
1568
+ const keyData = key.keyObject.export();
1569
+
1570
+ const kmac = NitroModules.createHybridObject<Kmac>('Kmac');
1571
+
1572
+ let customizationBuffer: ArrayBuffer | undefined;
1573
+ if (algorithm.customization !== undefined) {
1574
+ customizationBuffer = bufferLikeToArrayBuffer(algorithm.customization);
1575
+ }
1576
+
1577
+ kmac.createKmac(
1578
+ name,
1579
+ bufferLikeToArrayBuffer(keyData),
1580
+ outputLengthBytes,
1581
+ customizationBuffer,
1582
+ );
1583
+ kmac.update(bufferLikeToArrayBuffer(data));
1584
+ const computed = kmac.digest();
1585
+
1586
+ if (signature === undefined) {
1587
+ return computed;
1588
+ }
1589
+
1590
+ const sigBuffer = bufferLikeToArrayBuffer(signature);
1591
+ if (computed.byteLength !== sigBuffer.byteLength) {
1592
+ return false;
1593
+ }
1594
+
1595
+ return timingSafeEqual(new Uint8Array(computed), new Uint8Array(sigBuffer));
1596
+ }
1597
+
1598
+ async function kmacImportKey(
1599
+ algorithm: SubtleAlgorithm,
1600
+ format: ImportFormat,
1601
+ data: BufferLike | JWK,
1602
+ extractable: boolean,
1603
+ keyUsages: KeyUsage[],
1604
+ ): Promise<CryptoKey> {
1605
+ const { name } = algorithm;
1606
+
1607
+ let keyObject: KeyObject;
1608
+
1609
+ if (format === 'jwk') {
1610
+ const jwk = data as JWK;
1611
+
1612
+ if (!jwk || typeof jwk !== 'object') {
1613
+ throw lazyDOMException('Invalid keyData', 'DataError');
1614
+ }
1615
+ if (jwk.kty !== 'oct') {
1616
+ throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError');
1617
+ }
1618
+ validateJwkStructure(jwk, extractable, keyUsages, 'sig');
1619
+
1620
+ const expectedAlg = name === 'KMAC128' ? 'K128' : 'K256';
1621
+ if (jwk.alg !== undefined && jwk.alg !== expectedAlg) {
1622
+ throw lazyDOMException(
1623
+ 'JWK "alg" Parameter and algorithm name mismatch',
1624
+ 'DataError',
1625
+ );
1626
+ }
1627
+
1628
+ if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
1629
+ throw lazyDOMException(
1630
+ `Unsupported key usage for ${name} key`,
1631
+ 'SyntaxError',
1632
+ );
1633
+ }
1634
+
1635
+ const handle =
1636
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
1637
+ let keyType: KeyType | undefined;
1638
+ try {
1639
+ keyType = handle.initJwk(jwk, undefined);
1640
+ } catch (err) {
1641
+ throw lazyDOMException('Invalid keyData', {
1642
+ name: 'DataError',
1643
+ cause: err,
1644
+ });
1645
+ }
1646
+ if (keyType === undefined || keyType !== 0) {
1647
+ throw lazyDOMException('Invalid keyData', 'DataError');
1648
+ }
1649
+
1650
+ keyObject = new SecretKeyObject(handle);
1651
+ } else if (format === 'raw-secret') {
1652
+ // KMAC accepts only the disambiguated 'raw-secret' form (Node mac.js:141-145
1653
+ // returns undefined for plain 'raw' when not HMAC).
1654
+ if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
1655
+ throw lazyDOMException(
1656
+ `Unsupported key usage for ${name} key`,
1657
+ 'SyntaxError',
1658
+ );
1659
+ }
1660
+ keyObject = createSecretKey(data as BinaryLike);
1661
+ } else {
1662
+ throw lazyDOMException(
1663
+ `Unable to import ${name} key with format ${format}`,
1664
+ 'NotSupportedError',
1665
+ );
1666
+ }
1667
+
1668
+ const exported = keyObject.export();
1669
+ const keyLength = exported.byteLength * 8;
1670
+
1671
+ if (keyLength === 0) {
1672
+ throw lazyDOMException('Zero-length key is not supported', 'DataError');
1673
+ }
1674
+
1675
+ if (algorithm.length !== undefined && algorithm.length !== keyLength) {
1676
+ throw lazyDOMException('Invalid key length', 'DataError');
1677
+ }
1678
+
1679
+ const keyAlgorithm: SubtleAlgorithm = {
1680
+ name: name as AnyAlgorithm,
1681
+ length: keyLength,
1682
+ };
1683
+
1684
+ return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
1685
+ }
1686
+
1687
+ function rsaImportKey(
1688
+ format: ImportFormat,
1689
+ data: BufferLike | JWK,
1690
+ algorithm: SubtleAlgorithm,
1691
+ extractable: boolean,
1692
+ keyUsages: KeyUsage[],
1693
+ ): CryptoKey {
1694
+ const { name } = algorithm;
1695
+
1696
+ let checkSet: KeyUsage[];
1697
+ switch (name) {
1698
+ case 'RSASSA-PKCS1-v1_5':
1699
+ case 'RSA-PSS':
1700
+ checkSet = ['sign', 'verify'];
1701
+ break;
1702
+ case 'RSA-OAEP':
1703
+ checkSet = ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'];
1704
+ break;
1705
+ default:
1706
+ throw new Error(`Unsupported RSA algorithm: ${name}`);
1707
+ }
1708
+ const checkUsages = (): void => {
1709
+ if (hasAnyNotIn(keyUsages, checkSet)) {
1710
+ throw lazyDOMException(
1711
+ `Unsupported key usage for ${name} key`,
1712
+ 'SyntaxError',
1713
+ );
1714
+ }
1715
+ };
1716
+
1717
+ let keyObject: KeyObject;
1718
+
1719
+ if (format === 'jwk') {
1720
+ const jwk = data as JWK;
1721
+
1722
+ if (!jwk || typeof jwk !== 'object') {
1723
+ throw lazyDOMException('Invalid keyData', 'DataError');
1724
+ }
1725
+ if (jwk.kty !== 'RSA') {
1726
+ throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError');
1727
+ }
1728
+ const expectedUse = name === 'RSA-OAEP' ? 'enc' : 'sig';
1729
+ validateJwkStructure(jwk, extractable, keyUsages, expectedUse);
1730
+ checkUsages();
1731
+
1732
+ if (jwk.alg !== undefined) {
1733
+ let jwkContext: HashContext;
1734
+ switch (name) {
1735
+ case 'RSASSA-PKCS1-v1_5':
1736
+ jwkContext = HashContext.JwkRsa;
1737
+ break;
1738
+ case 'RSA-PSS':
1739
+ jwkContext = HashContext.JwkRsaPss;
1740
+ break;
1741
+ default:
1742
+ jwkContext = HashContext.JwkRsaOaep;
1743
+ }
1744
+ const expectedAlg = normalizeHashName(algorithm.hash, jwkContext);
1745
+ if (jwk.alg !== expectedAlg) {
1746
+ throw lazyDOMException(
1747
+ 'JWK "alg" does not match the requested algorithm',
1748
+ 'DataError',
1749
+ );
1750
+ }
1751
+ }
1752
+
1753
+ const handle =
1754
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
1755
+ let keyType: KeyType | undefined;
1756
+ try {
1757
+ keyType = handle.initJwk(jwk, undefined);
1758
+ } catch (err) {
1759
+ throw lazyDOMException('Invalid keyData', {
1760
+ name: 'DataError',
1761
+ cause: err,
1762
+ });
1763
+ }
1764
+ if (keyType === undefined) {
1765
+ throw lazyDOMException('Invalid keyData', 'DataError');
1766
+ }
1767
+
1768
+ if (keyType === KeyType.PUBLIC) {
1769
+ keyObject = new PublicKeyObject(handle);
1770
+ } else if (keyType === KeyType.PRIVATE) {
1771
+ keyObject = new PrivateKeyObject(handle);
1772
+ } else {
1773
+ throw lazyDOMException('Invalid keyData', 'DataError');
1774
+ }
1775
+ } else if (format === 'spki') {
1776
+ checkUsages();
1777
+ const keyData = bufferLikeToArrayBuffer(data as BufferLike);
1778
+ keyObject = KeyObject.createKeyObject(
1779
+ 'public',
1780
+ keyData,
1781
+ KFormatType.DER,
1782
+ KeyEncoding.SPKI,
1783
+ );
1784
+ } else if (format === 'pkcs8') {
1785
+ checkUsages();
1786
+ const keyData = bufferLikeToArrayBuffer(data as BufferLike);
1787
+ keyObject = KeyObject.createKeyObject(
1788
+ 'private',
1789
+ keyData,
1790
+ KFormatType.DER,
1791
+ KeyEncoding.PKCS8,
1792
+ );
1793
+ } else {
1794
+ throw lazyDOMException(
1795
+ `Unsupported format for ${name} import: ${format}`,
1796
+ 'NotSupportedError',
1797
+ );
1798
+ }
1799
+
1800
+ // Get the modulus length from the key and add it to the algorithm
1801
+ const keyDetails = (keyObject as PublicKeyObject | PrivateKeyObject)
1802
+ .asymmetricKeyDetails;
1803
+
1804
+ // Convert publicExponent number to big-endian byte array
1805
+ let publicExponentBytes: Uint8Array | undefined;
1806
+ if (keyDetails?.publicExponent) {
1807
+ const exp = keyDetails.publicExponent;
1808
+ // Convert number to big-endian bytes
1809
+ const bytes: number[] = [];
1810
+ let value = exp;
1811
+ while (value > 0) {
1812
+ bytes.unshift(value & 0xff);
1813
+ value = Math.floor(value / 256);
1814
+ }
1815
+ publicExponentBytes = new Uint8Array(bytes.length > 0 ? bytes : [0]);
1816
+ }
1817
+
1818
+ // Normalize hash to { name: string } format per WebCrypto spec
1819
+ const hashName = normalizeHashName(algorithm.hash, HashContext.WebCrypto);
1820
+ const normalizedHash = { name: hashName };
1821
+
1822
+ const algorithmWithDetails = {
1823
+ ...algorithm,
1824
+ modulusLength: keyDetails?.modulusLength,
1825
+ publicExponent: publicExponentBytes,
1826
+ hash: normalizedHash,
1827
+ };
1828
+
1829
+ return new CryptoKey(keyObject, algorithmWithDetails, keyUsages, extractable);
1830
+ }
1831
+
1832
+ async function hmacImportKey(
1833
+ algorithm: SubtleAlgorithm,
1834
+ format: ImportFormat,
1835
+ data: BufferLike | JWK,
1836
+ extractable: boolean,
1837
+ keyUsages: KeyUsage[],
1838
+ ): Promise<CryptoKey> {
1839
+ const checkUsages = (): void => {
1840
+ if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
1841
+ throw new Error('Unsupported key usage for an HMAC key');
1842
+ }
1843
+ };
1844
+
1845
+ let keyObject: KeyObject;
1846
+
1847
+ if (format === 'jwk') {
1848
+ const jwk = data as JWK;
1849
+
1850
+ if (!jwk || typeof jwk !== 'object') {
1851
+ throw new Error('Invalid keyData');
1852
+ }
1853
+ if (jwk.kty !== 'oct') {
1854
+ throw new Error('Invalid JWK format for HMAC key');
1855
+ }
1856
+ validateJwkStructure(jwk, extractable, keyUsages, 'sig');
1857
+ checkUsages();
1858
+
1859
+ if (algorithm.length !== undefined) {
1860
+ if (!jwk.k) {
1861
+ throw new Error('JWK missing key data');
1862
+ }
1863
+ const decoded = SBuffer.from(jwk.k, 'base64');
1864
+ const keyBitLength = decoded.length * 8;
1865
+ if (algorithm.length === 0) {
1866
+ throw new Error('Zero-length key is not supported');
1867
+ }
1868
+ if (algorithm.length !== keyBitLength) {
1869
+ throw new Error('Invalid key length');
1870
+ }
1871
+ }
1872
+
1873
+ const handle =
1874
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
1875
+ let keyType: KeyType | undefined;
1876
+ try {
1877
+ keyType = handle.initJwk(jwk, undefined);
1878
+ } catch (err) {
1879
+ throw lazyDOMException('Invalid keyData', {
1880
+ name: 'DataError',
1881
+ cause: err,
1882
+ });
1883
+ }
1884
+ if (keyType === undefined || keyType !== 0) {
1885
+ throw lazyDOMException('Invalid keyData', 'DataError');
1886
+ }
1887
+
1888
+ keyObject = new SecretKeyObject(handle);
1889
+ } else if (format === 'raw' || format === 'raw-secret') {
1890
+ // HMAC accepts both 'raw' and 'raw-secret' (Node mac.js:141-145).
1891
+ checkUsages();
1892
+ keyObject = createSecretKey(data as BinaryLike);
1893
+ } else {
1894
+ throw lazyDOMException(
1895
+ `Unable to import HMAC key with format ${format}`,
1896
+ 'NotSupportedError',
1897
+ );
1898
+ }
1899
+
1900
+ // Normalize hash to { name: string } format per WebCrypto spec
1901
+ const hashName = normalizeHashName(algorithm.hash, HashContext.WebCrypto);
1902
+ const normalizedAlgorithm: SubtleAlgorithm = {
1903
+ ...algorithm,
1904
+ name: 'HMAC',
1905
+ hash: { name: hashName },
1906
+ };
1907
+
1908
+ return new CryptoKey(keyObject, normalizedAlgorithm, keyUsages, extractable);
1909
+ }
1910
+
1911
+ async function aesImportKey(
1912
+ algorithm: SubtleAlgorithm,
1913
+ format: ImportFormat,
1914
+ data: BufferLike | JWK,
1915
+ extractable: boolean,
1916
+ keyUsages: KeyUsage[],
1917
+ ): Promise<CryptoKey> {
1918
+ const { name, length } = algorithm;
1919
+
1920
+ const validUsages: KeyUsage[] = [
1921
+ 'encrypt',
1922
+ 'decrypt',
1923
+ 'wrapKey',
1924
+ 'unwrapKey',
1925
+ ];
1926
+ const checkUsages = (): void => {
1927
+ if (hasAnyNotIn(keyUsages, validUsages)) {
1928
+ throw new Error(`Unsupported key usage for ${name}`);
1929
+ }
1930
+ };
1931
+
1932
+ // AES-OCB and ChaCha20-Poly1305 require the disambiguated 'raw-secret' form
1933
+ // and reject 'raw' (Node aes.js:243-249, chacha20_poly1305.js:104-134).
1934
+ // Other AES variants accept both 'raw' and 'raw-secret'.
1935
+ const requiresRawSecret = name === 'AES-OCB' || name === 'ChaCha20-Poly1305';
1936
+ const acceptsRaw =
1937
+ format === 'raw-secret' || (format === 'raw' && !requiresRawSecret);
1938
+
1939
+ let keyObject: KeyObject;
1940
+ let actualLength: number;
1941
+
1942
+ if (format === 'jwk') {
1943
+ const jwk = data as JWK;
1944
+
1945
+ if (jwk.kty !== 'oct') {
1946
+ throw new Error('Invalid JWK format for AES key');
1947
+ }
1948
+ validateJwkStructure(jwk, extractable, keyUsages, 'enc');
1949
+ checkUsages();
1950
+
1951
+ const handle =
1952
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
1953
+ let keyType: KeyType | undefined;
1954
+ try {
1955
+ keyType = handle.initJwk(jwk, undefined);
1956
+ } catch (err) {
1957
+ throw lazyDOMException('Invalid keyData', {
1958
+ name: 'DataError',
1959
+ cause: err,
1960
+ });
1961
+ }
1962
+ if (keyType === undefined || keyType !== 0) {
1963
+ throw lazyDOMException('Invalid keyData', 'DataError');
1964
+ }
1965
+
1966
+ keyObject = new SecretKeyObject(handle);
1967
+
1968
+ const exported = keyObject.export();
1969
+ actualLength = exported.byteLength * 8;
1970
+ } else if (acceptsRaw) {
1971
+ checkUsages();
1972
+ const keyData = bufferLikeToArrayBuffer(data as BufferLike);
1973
+ actualLength = keyData.byteLength * 8;
1974
+
1975
+ if (name === 'ChaCha20-Poly1305') {
1976
+ if (actualLength !== 256) {
1977
+ throw lazyDOMException(
1978
+ 'Invalid ChaCha20-Poly1305 key length',
1979
+ 'DataError',
1980
+ );
1981
+ }
1982
+ } else if (![128, 192, 256].includes(actualLength)) {
1983
+ throw new Error('Invalid AES key length');
1984
+ }
1985
+
1986
+ keyObject = createSecretKey(keyData);
1987
+ } else {
1988
+ throw lazyDOMException(
1989
+ `Unable to import ${name} key with format ${format}`,
1990
+ 'NotSupportedError',
1991
+ );
1992
+ }
1993
+
1994
+ // Validate length if specified
1995
+ if (length !== undefined && length !== actualLength) {
1996
+ throw new Error(
1997
+ `Key length mismatch: expected ${length}, got ${actualLength}`,
1998
+ );
1999
+ }
2000
+
2001
+ return new CryptoKey(
2002
+ keyObject,
2003
+ { name, length: actualLength },
2004
+ keyUsages,
2005
+ extractable,
2006
+ );
2007
+ }
2008
+
2009
+ function edImportKey(
2010
+ format: ImportFormat,
2011
+ data: BufferLike | JWK,
2012
+ algorithm: SubtleAlgorithm,
2013
+ extractable: boolean,
2014
+ keyUsages: KeyUsage[],
2015
+ ): CryptoKey {
2016
+ const { name } = algorithm;
2017
+
2018
+ const isX = name === 'X25519' || name === 'X448';
2019
+ const allowedUsages: KeyUsage[] = isX
2020
+ ? ['deriveKey', 'deriveBits']
2021
+ : ['sign', 'verify'];
2022
+ const checkUsages = (): void => {
2023
+ if (hasAnyNotIn(keyUsages, allowedUsages)) {
2024
+ throw lazyDOMException(
2025
+ `Unsupported key usage for ${name} key`,
2026
+ 'SyntaxError',
2027
+ );
2028
+ }
2029
+ };
2030
+
2031
+ let keyObject: KeyObject;
2032
+
2033
+ if (format === 'spki') {
2034
+ checkUsages();
2035
+ const keyData = bufferLikeToArrayBuffer(data as BufferLike);
2036
+ keyObject = KeyObject.createKeyObject(
2037
+ 'public',
2038
+ keyData,
2039
+ KFormatType.DER,
2040
+ KeyEncoding.SPKI,
2041
+ );
2042
+ } else if (format === 'pkcs8') {
2043
+ checkUsages();
2044
+ const keyData = bufferLikeToArrayBuffer(data as BufferLike);
2045
+ keyObject = KeyObject.createKeyObject(
2046
+ 'private',
2047
+ keyData,
2048
+ KFormatType.DER,
2049
+ KeyEncoding.PKCS8,
2050
+ );
2051
+ } else if (format === 'raw') {
2052
+ checkUsages();
2053
+ const keyData = bufferLikeToArrayBuffer(data as BufferLike);
2054
+ const handle =
2055
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
2056
+ handle.init(1, keyData);
2057
+ keyObject = new PublicKeyObject(handle);
2058
+ } else if (format === 'jwk') {
2059
+ const jwkData = data as JWK;
2060
+ if (!jwkData || typeof jwkData !== 'object') {
2061
+ throw lazyDOMException('Invalid keyData', 'DataError');
2062
+ }
2063
+ if (jwkData.kty !== 'OKP') {
2064
+ throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError');
2065
+ }
2066
+ const expectedUse = isX ? 'enc' : 'sig';
2067
+ validateJwkStructure(jwkData, extractable, keyUsages, expectedUse);
2068
+
2069
+ if (jwkData.crv !== name) {
2070
+ throw lazyDOMException(
2071
+ 'JWK "crv" Parameter and algorithm name mismatch',
2072
+ 'DataError',
2073
+ );
2074
+ }
2075
+
2076
+ if (!isX && jwkData.alg !== undefined) {
2077
+ if (jwkData.alg !== name && jwkData.alg !== 'EdDSA') {
2078
+ throw lazyDOMException(
2079
+ 'JWK "alg" does not match the requested algorithm',
2080
+ 'DataError',
2081
+ );
2082
+ }
2083
+ }
2084
+
2085
+ checkUsages();
2086
+ const handle =
2087
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
2088
+ let keyType: KeyType | undefined;
2089
+ try {
2090
+ keyType = handle.initJwk(jwkData);
2091
+ } catch (err) {
2092
+ throw lazyDOMException('Invalid JWK data', {
2093
+ name: 'DataError',
2094
+ cause: err,
2095
+ });
2096
+ }
2097
+ if (keyType === undefined) {
2098
+ throw lazyDOMException('Invalid JWK data', 'DataError');
2099
+ }
2100
+ if (keyType === KeyType.PRIVATE) {
2101
+ keyObject = new PrivateKeyObject(handle);
2102
+ } else {
2103
+ keyObject = new PublicKeyObject(handle);
2104
+ }
2105
+ } else {
2106
+ throw lazyDOMException(
2107
+ `Unsupported format for ${name} import: ${format}`,
2108
+ 'NotSupportedError',
2109
+ );
2110
+ }
2111
+
2112
+ return new CryptoKey(keyObject, { name }, keyUsages, extractable);
2113
+ }
2114
+
2115
+ // Lengths (in bytes) of seedless ML-DSA / ML-KEM PKCS#8 encodings. A PKCS#8
2116
+ // blob of exactly this length contains only the expanded private key with no
2117
+ // seed; Node rejects these to keep cross-implementation interop intact.
2118
+ // Refs: node lib/internal/crypto/ml_dsa.js (mlDsaImportKey, pkcs8 case)
2119
+ // node lib/internal/crypto/ml_kem.js (mlKemImportKey, pkcs8 case)
2120
+ export const PQC_SEEDLESS_PKCS8_LENGTHS: Readonly<Record<string, number>> = {
2121
+ 'ML-DSA-44': 2588,
2122
+ 'ML-DSA-65': 4060,
2123
+ 'ML-DSA-87': 4924,
2124
+ 'ML-KEM-512': 1660,
2125
+ 'ML-KEM-768': 2428,
2126
+ 'ML-KEM-1024': 3196,
2127
+ };
2128
+
2129
+ // Map from PQC algorithm name to display family. Used to render the
2130
+ // import-rejection error message in the same form Node emits.
2131
+ const PQC_FAMILY: Readonly<Record<string, 'ML-DSA' | 'ML-KEM' | 'SLH-DSA'>> = {
2132
+ 'ML-DSA-44': 'ML-DSA',
2133
+ 'ML-DSA-65': 'ML-DSA',
2134
+ 'ML-DSA-87': 'ML-DSA',
2135
+ 'ML-KEM-512': 'ML-KEM',
2136
+ 'ML-KEM-768': 'ML-KEM',
2137
+ 'ML-KEM-1024': 'ML-KEM',
2138
+ 'SLH-DSA-SHA2-128s': 'SLH-DSA',
2139
+ 'SLH-DSA-SHA2-128f': 'SLH-DSA',
2140
+ 'SLH-DSA-SHA2-192s': 'SLH-DSA',
2141
+ 'SLH-DSA-SHA2-192f': 'SLH-DSA',
2142
+ 'SLH-DSA-SHA2-256s': 'SLH-DSA',
2143
+ 'SLH-DSA-SHA2-256f': 'SLH-DSA',
2144
+ 'SLH-DSA-SHAKE-128s': 'SLH-DSA',
2145
+ 'SLH-DSA-SHAKE-128f': 'SLH-DSA',
2146
+ 'SLH-DSA-SHAKE-192s': 'SLH-DSA',
2147
+ 'SLH-DSA-SHAKE-192f': 'SLH-DSA',
2148
+ 'SLH-DSA-SHAKE-256s': 'SLH-DSA',
2149
+ 'SLH-DSA-SHAKE-256f': 'SLH-DSA',
2150
+ };
2151
+
2152
+ function pqcImportKeyObject(
2153
+ format: ImportFormat,
2154
+ data: BufferLike | JWK,
2155
+ name: string,
2156
+ ): { keyObject: KeyObject; isPublic: boolean } {
2157
+ if (format === 'spki') {
2158
+ return {
2159
+ keyObject: KeyObject.createKeyObject(
2160
+ 'public',
2161
+ bufferLikeToArrayBuffer(data as BufferLike),
2162
+ KFormatType.DER,
2163
+ KeyEncoding.SPKI,
2164
+ ),
2165
+ isPublic: true,
2166
+ };
2167
+ } else if (format === 'pkcs8') {
2168
+ const ab = bufferLikeToArrayBuffer(data as BufferLike);
2169
+ const family = PQC_FAMILY[name];
2170
+ if (
2171
+ family !== undefined &&
2172
+ ab.byteLength === PQC_SEEDLESS_PKCS8_LENGTHS[name]
2173
+ ) {
2174
+ throw lazyDOMException(
2175
+ `Importing an ${family} PKCS#8 key without a seed is not supported`,
2176
+ 'NotSupportedError',
2177
+ );
2178
+ }
2179
+ return {
2180
+ keyObject: KeyObject.createKeyObject(
2181
+ 'private',
2182
+ ab,
2183
+ KFormatType.DER,
2184
+ KeyEncoding.PKCS8,
2185
+ ),
2186
+ isPublic: false,
2187
+ };
2188
+ } else if (format === 'raw-public') {
2189
+ // ML-DSA / ML-KEM reject plain 'raw' — only 'raw-public' is accepted for
2190
+ // public-key import (Node webcrypto.js:493-499, 506-511).
2191
+ const handle =
2192
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
2193
+ if (
2194
+ !handle.initPqcRaw(
2195
+ name,
2196
+ bufferLikeToArrayBuffer(data as BufferLike),
2197
+ true,
2198
+ )
2199
+ ) {
2200
+ throw lazyDOMException(
2201
+ `Failed to import ${name} raw public key`,
2202
+ 'DataError',
2203
+ );
2204
+ }
2205
+ return { keyObject: new PublicKeyObject(handle), isPublic: true };
2206
+ } else if (format === 'raw-seed') {
2207
+ const handle =
2208
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
2209
+ if (
2210
+ !handle.initPqcRaw(
2211
+ name,
2212
+ bufferLikeToArrayBuffer(data as BufferLike),
2213
+ false,
2214
+ )
2215
+ ) {
2216
+ throw lazyDOMException(`Failed to import ${name} raw seed`, 'DataError');
2217
+ }
2218
+ return { keyObject: new PrivateKeyObject(handle), isPublic: false };
2219
+ } else if (format === 'jwk') {
2220
+ const jwkData = data as JWK;
2221
+ const isPublic = jwkData.priv === undefined;
2222
+ const handle =
2223
+ NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
2224
+ let keyType: KeyType | undefined;
2225
+ try {
2226
+ keyType = handle.initJwk(jwkData);
2227
+ } catch (err) {
2228
+ throw lazyDOMException('Invalid JWK data', {
2229
+ name: 'DataError',
2230
+ cause: err,
2231
+ });
2232
+ }
2233
+ if (keyType === undefined) {
2234
+ throw lazyDOMException('Invalid JWK data', 'DataError');
2235
+ }
2236
+ return {
2237
+ keyObject: isPublic
2238
+ ? new PublicKeyObject(handle)
2239
+ : new PrivateKeyObject(handle),
2240
+ isPublic,
2241
+ };
2242
+ }
2243
+ throw lazyDOMException(
2244
+ `Unsupported format for ${name} import: ${format}`,
2245
+ 'NotSupportedError',
2246
+ );
2247
+ }
2248
+
2249
+ // Per WebCrypto AKP JWK rules, public-vs-private is determined by the presence
2250
+ // of `priv`. For binary formats it follows from the format itself.
2251
+ function pqcIsPublicImport(
2252
+ format: ImportFormat,
2253
+ data: BufferLike | JWK,
2254
+ ): boolean {
2255
+ if (format === 'jwk') {
2256
+ return (
2257
+ typeof data === 'object' &&
2258
+ data !== null &&
2259
+ (data as JWK).priv === undefined
2260
+ );
2261
+ }
2262
+ return format === 'spki' || format === 'raw-public';
2263
+ }
2264
+
2265
+ function validatePqcJwk(
2266
+ data: BufferLike | JWK,
2267
+ name: string,
2268
+ extractable: boolean,
2269
+ keyUsages: KeyUsage[],
2270
+ expectedUse: 'sig' | 'enc',
2271
+ ): void {
2272
+ if (typeof data !== 'object' || data === null) {
2273
+ throw lazyDOMException('Invalid keyData', 'DataError');
2274
+ }
2275
+ const jwk = data as JWK;
2276
+ if (jwk.kty !== 'AKP') {
2277
+ throw lazyDOMException('Invalid JWK "kty" Parameter', 'DataError');
2278
+ }
2279
+ validateJwkStructure(jwk, extractable, keyUsages, expectedUse);
2280
+ if (jwk.alg !== name) {
2281
+ throw lazyDOMException(
2282
+ 'JWK "alg" Parameter and algorithm name mismatch',
2283
+ 'DataError',
2284
+ );
2285
+ }
2286
+ }
2287
+
2288
+ // Validates that `format` is one of the formats PQC algorithms accept; rejects
2289
+ // plain 'raw' early so the format error wins over usage-based errors.
2290
+ function validatePqcFormat(format: ImportFormat, name: string): void {
2291
+ if (
2292
+ format !== 'spki' &&
2293
+ format !== 'pkcs8' &&
2294
+ format !== 'raw-public' &&
2295
+ format !== 'raw-seed' &&
2296
+ format !== 'jwk'
2297
+ ) {
2298
+ throw lazyDOMException(
2299
+ `Unsupported format for ${name} import: ${format}`,
2300
+ 'NotSupportedError',
2301
+ );
2302
+ }
2303
+ }
2304
+
2305
+ function mldsaImportKey(
2306
+ format: ImportFormat,
2307
+ data: BufferLike | JWK,
2308
+ algorithm: SubtleAlgorithm,
2309
+ extractable: boolean,
2310
+ keyUsages: KeyUsage[],
2311
+ ): CryptoKey {
2312
+ const { name } = algorithm;
2313
+ validatePqcFormat(format, name);
2314
+ if (format === 'jwk') {
2315
+ validatePqcJwk(data, name, extractable, keyUsages, 'sig');
2316
+ }
2317
+ const isPublic = pqcIsPublicImport(format, data);
2318
+ if (hasAnyNotIn(keyUsages, isPublic ? ['verify'] : ['sign'])) {
2319
+ throw lazyDOMException(
2320
+ `Unsupported key usage for ${name} key`,
2321
+ 'SyntaxError',
2322
+ );
2323
+ }
2324
+ const { keyObject } = pqcImportKeyObject(format, data, name);
2325
+ return new CryptoKey(keyObject, { name }, keyUsages, extractable);
2326
+ }
2327
+
2328
+ function slhdsaImportKey(
2329
+ format: ImportFormat,
2330
+ data: BufferLike | JWK,
2331
+ algorithm: SubtleAlgorithm,
2332
+ extractable: boolean,
2333
+ keyUsages: KeyUsage[],
2334
+ ): CryptoKey {
2335
+ return mldsaImportKey(format, data, algorithm, extractable, keyUsages);
2336
+ }
2337
+
2338
+ function mlkemImportKey(
2339
+ format: ImportFormat,
2340
+ data: BufferLike | JWK,
2341
+ algorithm: SubtleAlgorithm,
2342
+ extractable: boolean,
2343
+ keyUsages: KeyUsage[],
2344
+ ): CryptoKey {
2345
+ const { name } = algorithm;
2346
+ validatePqcFormat(format, name);
2347
+ if (format === 'jwk') {
2348
+ validatePqcJwk(data, name, extractable, keyUsages, 'enc');
2349
+ }
2350
+ const isPublic = pqcIsPublicImport(format, data);
2351
+ const allowedUsages: KeyUsage[] = isPublic
2352
+ ? ['encapsulateBits', 'encapsulateKey']
2353
+ : ['decapsulateBits', 'decapsulateKey'];
2354
+ if (hasAnyNotIn(keyUsages, allowedUsages)) {
2355
+ throw lazyDOMException(
2356
+ `Unsupported key usage for ${name} key`,
2357
+ 'SyntaxError',
2358
+ );
2359
+ }
2360
+ const { keyObject } = pqcImportKeyObject(format, data, name);
2361
+ return new CryptoKey(keyObject, { name }, keyUsages, extractable);
2362
+ }
2363
+
2364
+ const exportKeySpki = async (
2365
+ key: CryptoKey,
2366
+ ): Promise<ArrayBuffer | unknown> => {
2367
+ switch (key.algorithm.name) {
2368
+ case 'RSASSA-PKCS1-v1_5':
2369
+ // Fall through
2370
+ case 'RSA-PSS':
2371
+ // Fall through
2372
+ case 'RSA-OAEP':
2373
+ if (key.type === 'public') {
2374
+ return rsaExportKey(key, KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI);
2375
+ }
2376
+ break;
2377
+ case 'ECDSA':
2378
+ // Fall through
2379
+ case 'ECDH':
2380
+ if (key.type === 'public') {
2381
+ return ecExportKey(key, KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI);
2382
+ }
2383
+ break;
2384
+ case 'Ed25519':
2385
+ // Fall through
2386
+ case 'Ed448':
2387
+ // Fall through
2388
+ case 'X25519':
2389
+ // Fall through
2390
+ case 'X448':
2391
+ if (key.type === 'public') {
2392
+ // Export Ed/X key in SPKI DER format
2393
+ return bufferLikeToArrayBuffer(
2394
+ key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI),
2395
+ );
2396
+ }
2397
+ break;
2398
+ case 'ML-DSA-44':
2399
+ // Fall through
2400
+ case 'ML-DSA-65':
2401
+ // Fall through
2402
+ case 'ML-DSA-87':
2403
+ // Fall through
2404
+ case 'SLH-DSA-SHA2-128s':
2405
+ case 'SLH-DSA-SHA2-128f':
2406
+ case 'SLH-DSA-SHA2-192s':
2407
+ case 'SLH-DSA-SHA2-192f':
2408
+ case 'SLH-DSA-SHA2-256s':
2409
+ case 'SLH-DSA-SHA2-256f':
2410
+ case 'SLH-DSA-SHAKE-128s':
2411
+ case 'SLH-DSA-SHAKE-128f':
2412
+ case 'SLH-DSA-SHAKE-192s':
2413
+ case 'SLH-DSA-SHAKE-192f':
2414
+ case 'SLH-DSA-SHAKE-256s':
2415
+ case 'SLH-DSA-SHAKE-256f':
2416
+ if (key.type === 'public') {
2417
+ // Export ML-DSA / SLH-DSA key in SPKI DER format
2418
+ return bufferLikeToArrayBuffer(
2419
+ key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI),
2420
+ );
2421
+ }
2422
+ break;
2423
+ case 'ML-KEM-512':
2424
+ // Fall through
2425
+ case 'ML-KEM-768':
2426
+ // Fall through
2427
+ case 'ML-KEM-1024':
2428
+ if (key.type === 'public') {
2429
+ return bufferLikeToArrayBuffer(
2430
+ key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI),
2431
+ );
2432
+ }
2433
+ break;
2434
+ }
2435
+
2436
+ throw new Error(
2437
+ `Unable to export a spki ${key.algorithm.name} ${key.type} key`,
2438
+ );
2439
+ };
2440
+
2441
+ const exportKeyPkcs8 = async (
2442
+ key: CryptoKey,
2443
+ ): Promise<ArrayBuffer | unknown> => {
2444
+ switch (key.algorithm.name) {
2445
+ case 'RSASSA-PKCS1-v1_5':
2446
+ // Fall through
2447
+ case 'RSA-PSS':
2448
+ // Fall through
2449
+ case 'RSA-OAEP':
2450
+ if (key.type === 'private') {
2451
+ return rsaExportKey(key, KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8);
2452
+ }
2453
+ break;
2454
+ case 'ECDSA':
2455
+ // Fall through
2456
+ case 'ECDH':
2457
+ if (key.type === 'private') {
2458
+ return ecExportKey(key, KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8);
2459
+ }
2460
+ break;
2461
+ case 'Ed25519':
2462
+ // Fall through
2463
+ case 'Ed448':
2464
+ // Fall through
2465
+ case 'X25519':
2466
+ // Fall through
2467
+ case 'X448':
2468
+ if (key.type === 'private') {
2469
+ // Export Ed/X key in PKCS8 DER format
2470
+ return bufferLikeToArrayBuffer(
2471
+ key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8),
2472
+ );
2473
+ }
2474
+ break;
2475
+ case 'ML-DSA-44':
2476
+ // Fall through
2477
+ case 'ML-DSA-65':
2478
+ // Fall through
2479
+ case 'ML-DSA-87':
2480
+ // Fall through
2481
+ case 'ML-KEM-512':
2482
+ // Fall through
2483
+ case 'ML-KEM-768':
2484
+ // Fall through
2485
+ case 'ML-KEM-1024':
2486
+ if (key.type === 'private') {
2487
+ const ab = bufferLikeToArrayBuffer(
2488
+ key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8),
2489
+ );
2490
+ // 22 bytes of PKCS#8 ASN.1 + seed (32 ML-DSA, 64 ML-KEM). Guards
2491
+ // against a seedless KeyObject that was wrapped via toCryptoKey.
2492
+ const expected = key.algorithm.name.startsWith('ML-DSA') ? 54 : 86;
2493
+ if (ab.byteLength !== expected) {
2494
+ throw lazyDOMException(
2495
+ 'The operation failed for an operation-specific reason',
2496
+ 'OperationError',
2497
+ );
2498
+ }
2499
+ return ab;
2500
+ }
2501
+ break;
2502
+ case 'SLH-DSA-SHA2-128s':
2503
+ case 'SLH-DSA-SHA2-128f':
2504
+ case 'SLH-DSA-SHA2-192s':
2505
+ case 'SLH-DSA-SHA2-192f':
2506
+ case 'SLH-DSA-SHA2-256s':
2507
+ case 'SLH-DSA-SHA2-256f':
2508
+ case 'SLH-DSA-SHAKE-128s':
2509
+ case 'SLH-DSA-SHAKE-128f':
2510
+ case 'SLH-DSA-SHAKE-192s':
2511
+ case 'SLH-DSA-SHAKE-192f':
2512
+ case 'SLH-DSA-SHAKE-256s':
2513
+ case 'SLH-DSA-SHAKE-256f':
2514
+ if (key.type === 'private') {
2515
+ return bufferLikeToArrayBuffer(
2516
+ key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8),
2517
+ );
2518
+ }
2519
+ break;
2520
+ }
2521
+
2522
+ throw new Error(
2523
+ `Unable to export a pkcs8 ${key.algorithm.name} ${key.type} key`,
2524
+ );
2525
+ };
2526
+
2527
+ // Mirrors Node's export key matrix (lib/internal/crypto/webcrypto.js
2528
+ // exportKeyRawSecret / exportKeyRawPublic, lines 472-563):
2529
+ //
2530
+ // raw — AES-CTR/CBC/GCM/KW + HMAC (secret); ECDSA/ECDH/Ed/X (public)
2531
+ // raw-secret — AES-CTR/CBC/GCM/KW + HMAC + AES-OCB + KMAC + ChaCha20-Poly1305
2532
+ // raw-public — ECDSA/ECDH + Ed/X + ML-DSA + ML-KEM (public)
2533
+ const exportKeyRaw = (
2534
+ key: CryptoKey,
2535
+ format: 'raw' | 'raw-secret' | 'raw-public',
2536
+ ): ArrayBuffer => {
2537
+ const name = key.algorithm.name;
2538
+ const isPublic = key.type === 'public';
2539
+ const isSecret = key.type === 'secret';
2540
+
2541
+ const exportSecret = (): ArrayBuffer => {
2542
+ const exported = key.keyObject.export();
2543
+ return exported.buffer.slice(
2544
+ exported.byteOffset,
2545
+ exported.byteOffset + exported.byteLength,
2546
+ ) as ArrayBuffer;
2547
+ };
2548
+ const exportRawPublic = (): ArrayBuffer =>
2549
+ bufferLikeToArrayBuffer(key.keyObject.handle.exportKey());
2550
+
2551
+ const fail = (): never => {
2552
+ throw lazyDOMException(
2553
+ `Unable to export ${name} ${key.type} key using ${format} format`,
2554
+ 'NotSupportedError',
2555
+ );
2556
+ };
2557
+
2558
+ // Symmetric: AES-CTR/CBC/GCM/KW and HMAC accept both 'raw' and 'raw-secret';
2559
+ // AES-OCB / KMAC* / ChaCha20-Poly1305 only 'raw-secret'.
2560
+ switch (name) {
2561
+ case 'AES-CTR':
2562
+ case 'AES-CBC':
2563
+ case 'AES-GCM':
2564
+ case 'AES-KW':
2565
+ case 'HMAC':
2566
+ if (!isSecret) return fail();
2567
+ if (format === 'raw' || format === 'raw-secret') return exportSecret();
2568
+ return fail();
2569
+ case 'AES-OCB':
2570
+ case 'KMAC128':
2571
+ case 'KMAC256':
2572
+ case 'ChaCha20-Poly1305':
2573
+ if (!isSecret) return fail();
2574
+ if (format === 'raw-secret') return exportSecret();
2575
+ return fail();
2576
+ case 'ECDSA':
2577
+ case 'ECDH':
2578
+ if (!isPublic) return fail();
2579
+ if (format === 'raw' || format === 'raw-public') {
2580
+ return ecExportKey(key, KWebCryptoKeyFormat.kWebCryptoKeyFormatRaw);
2581
+ }
2582
+ return fail();
2583
+ case 'Ed25519':
2584
+ case 'Ed448':
2585
+ case 'X25519':
2586
+ case 'X448':
2587
+ if (!isPublic) return fail();
2588
+ if (format === 'raw' || format === 'raw-public') return exportRawPublic();
2589
+ return fail();
2590
+ case 'ML-DSA-44':
2591
+ case 'ML-DSA-65':
2592
+ case 'ML-DSA-87':
2593
+ case 'ML-KEM-512':
2594
+ case 'ML-KEM-768':
2595
+ case 'ML-KEM-1024':
2596
+ case 'SLH-DSA-SHA2-128s':
2597
+ case 'SLH-DSA-SHA2-128f':
2598
+ case 'SLH-DSA-SHA2-192s':
2599
+ case 'SLH-DSA-SHA2-192f':
2600
+ case 'SLH-DSA-SHA2-256s':
2601
+ case 'SLH-DSA-SHA2-256f':
2602
+ case 'SLH-DSA-SHAKE-128s':
2603
+ case 'SLH-DSA-SHAKE-128f':
2604
+ case 'SLH-DSA-SHAKE-192s':
2605
+ case 'SLH-DSA-SHAKE-192f':
2606
+ case 'SLH-DSA-SHAKE-256s':
2607
+ case 'SLH-DSA-SHAKE-256f':
2608
+ // ML-DSA / ML-KEM / SLH-DSA keys do not recognize plain 'raw' (Node
2609
+ // webcrypto.js lines 488-510).
2610
+ if (!isPublic) return fail();
2611
+ if (format === 'raw-public') return exportRawPublic();
2612
+ return fail();
2613
+ }
2614
+
2615
+ return fail();
2616
+ };
2617
+
2618
+ const exportKeyJWK = (key: CryptoKey): ArrayBuffer | unknown => {
2619
+ const jwk = key.keyObject.handle.exportJwk(
2620
+ {
2621
+ key_ops: [...key.usages],
2622
+ ext: key.extractable,
2623
+ },
2624
+ true,
2625
+ );
2626
+ switch (key.algorithm.name) {
2627
+ case 'RSASSA-PKCS1-v1_5':
2628
+ jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkRsa);
2629
+ return jwk;
2630
+ case 'RSA-PSS':
2631
+ jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkRsaPss);
2632
+ return jwk;
2633
+ case 'RSA-OAEP':
2634
+ jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkRsaOaep);
2635
+ return jwk;
2636
+ case 'HMAC':
2637
+ jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkHmac);
2638
+ return jwk;
2639
+ case 'KMAC128':
2640
+ jwk.alg = 'K128';
2641
+ return jwk;
2642
+ case 'KMAC256':
2643
+ jwk.alg = 'K256';
2644
+ return jwk;
2645
+ case 'ECDSA':
2646
+ // Fall through
2647
+ case 'ECDH':
2648
+ jwk.crv ||= key.algorithm.namedCurve;
2649
+ return jwk;
2650
+ case 'Ed25519':
2651
+ // Fall through
2652
+ case 'Ed448':
2653
+ // Fall through
2654
+ case 'X25519':
2655
+ // Fall through
2656
+ case 'X448':
2657
+ return jwk;
2658
+ case 'ML-DSA-44':
2659
+ // Fall through
2660
+ case 'ML-DSA-65':
2661
+ // Fall through
2662
+ case 'ML-DSA-87':
2663
+ // Fall through
2664
+ case 'ML-KEM-512':
2665
+ // Fall through
2666
+ case 'ML-KEM-768':
2667
+ // Fall through
2668
+ case 'ML-KEM-1024':
2669
+ // Fall through
2670
+ case 'SLH-DSA-SHA2-128s':
2671
+ case 'SLH-DSA-SHA2-128f':
2672
+ case 'SLH-DSA-SHA2-192s':
2673
+ case 'SLH-DSA-SHA2-192f':
2674
+ case 'SLH-DSA-SHA2-256s':
2675
+ case 'SLH-DSA-SHA2-256f':
2676
+ case 'SLH-DSA-SHAKE-128s':
2677
+ case 'SLH-DSA-SHAKE-128f':
2678
+ case 'SLH-DSA-SHAKE-192s':
2679
+ case 'SLH-DSA-SHAKE-192f':
2680
+ case 'SLH-DSA-SHAKE-256s':
2681
+ case 'SLH-DSA-SHAKE-256f':
2682
+ return jwk;
2683
+ case 'AES-CTR':
2684
+ // Fall through
2685
+ case 'AES-CBC':
2686
+ // Fall through
2687
+ case 'AES-GCM':
2688
+ // Fall through
2689
+ case 'AES-KW':
2690
+ // Fall through
2691
+ case 'AES-OCB':
2692
+ // Fall through
2693
+ case 'ChaCha20-Poly1305':
2694
+ if (key.algorithm.length === undefined) {
2695
+ throw lazyDOMException(
2696
+ `Algorithm ${key.algorithm.name} missing required length property`,
2697
+ 'InvalidAccessError',
2698
+ );
2699
+ }
2700
+ jwk.alg = getAlgorithmName(key.algorithm.name, key.algorithm.length);
2701
+ return jwk;
2702
+ default:
2703
+ // Fall through
2704
+ }
2705
+
2706
+ throw lazyDOMException(
2707
+ `JWK export not yet supported: ${key.algorithm.name}`,
2708
+ 'NotSupportedError',
2709
+ );
2710
+ };
2711
+
2712
+ // PBKDF2 import. Mirrors Node's importGenericSecretKey ordering
2713
+ // (keys.js:945-971): extractable → usage → format → length. Callers pre-alias
2714
+ // 'raw-secret' / 'raw-public' to 'raw' via aliasKeyFormat
2715
+ // (webcrypto.js:798-808).
2716
+ const pbkdf2ImportKey = async (
2717
+ { name, length }: SubtleAlgorithm,
2718
+ format: ImportFormat,
2719
+ keyData: BufferLike | BinaryLike,
2720
+ extractable: boolean,
2721
+ keyUsages: KeyUsage[],
2722
+ ): Promise<CryptoKey> => {
2723
+ if (extractable) {
2724
+ throw lazyDOMException(`${name} keys are not extractable`, 'SyntaxError');
2725
+ }
2726
+ if (hasAnyNotIn(keyUsages, ['deriveKey', 'deriveBits'])) {
2727
+ throw lazyDOMException(
2728
+ `Unsupported key usage for a ${name} key`,
2729
+ 'SyntaxError',
2730
+ );
2731
+ }
2732
+ if (format !== 'raw') {
2733
+ throw lazyDOMException(
2734
+ `Unable to import ${name} key with format ${format}`,
2735
+ 'NotSupportedError',
2736
+ );
2737
+ }
2738
+
2739
+ const checkLength =
2740
+ typeof keyData === 'string' || SBuffer.isBuffer(keyData)
2741
+ ? keyData.length * 8
2742
+ : keyData.byteLength * 8;
2743
+ if (length !== undefined && length !== checkLength) {
2744
+ throw lazyDOMException('Invalid key length', 'DataError');
2745
+ }
2746
+
2747
+ const keyObject = createSecretKey(keyData as BinaryLike);
2748
+ return new CryptoKey(keyObject, { name }, keyUsages, false);
2749
+ };
2750
+
2751
+ // Argon2 import. Node gates the format at the dispatcher level — only
2752
+ // 'raw-secret' enters importGenericSecretKey (webcrypto.js:813-822). To match
2753
+ // that, format is the first check here; remaining ordering matches Node's
2754
+ // importGenericSecretKey.
2755
+ const argon2ImportKey = async (
2756
+ { name, length }: SubtleAlgorithm,
2757
+ format: ImportFormat,
2758
+ keyData: BufferLike | BinaryLike,
2759
+ extractable: boolean,
2760
+ keyUsages: KeyUsage[],
2761
+ ): Promise<CryptoKey> => {
2762
+ if (format !== 'raw-secret') {
2763
+ throw lazyDOMException(
2764
+ `Unable to import ${name} key with format ${format}`,
2765
+ 'NotSupportedError',
2766
+ );
2767
+ }
2768
+ if (extractable) {
2769
+ throw lazyDOMException(`${name} keys are not extractable`, 'SyntaxError');
2770
+ }
2771
+ if (hasAnyNotIn(keyUsages, ['deriveKey', 'deriveBits'])) {
2772
+ throw lazyDOMException(
2773
+ `Unsupported key usage for a ${name} key`,
2774
+ 'SyntaxError',
2775
+ );
2776
+ }
2777
+
2778
+ const checkLength =
2779
+ typeof keyData === 'string' || SBuffer.isBuffer(keyData)
2780
+ ? keyData.length * 8
2781
+ : keyData.byteLength * 8;
2782
+ if (length !== undefined && length !== checkLength) {
2783
+ throw lazyDOMException('Invalid key length', 'DataError');
2784
+ }
2785
+
2786
+ const keyObject = createSecretKey(keyData as BinaryLike);
2787
+ return new CryptoKey(keyObject, { name }, keyUsages, false);
2788
+ };
2789
+
2790
+ const hkdfImportKey = async (
2791
+ format: ImportFormat,
2792
+ keyData: BufferLike | BinaryLike,
2793
+ algorithm: SubtleAlgorithm,
2794
+ extractable: boolean,
2795
+ keyUsages: KeyUsage[],
2796
+ ): Promise<CryptoKey> => {
2797
+ const { name } = algorithm;
2798
+ // WebCrypto §28.7.6: HKDF keys are never extractable. The previous
2799
+ // implementation passed `extractable` through verbatim, allowing callers
2800
+ // to round-trip the input keying material via `exportKey` — defeating
2801
+ // the whole point of the deriveBits-only usage.
2802
+ if (extractable) {
2803
+ throw lazyDOMException(`${name} keys are not extractable`, 'SyntaxError');
2804
+ }
2805
+ if (hasAnyNotIn(keyUsages, ['deriveKey', 'deriveBits'])) {
2806
+ throw new Error(`Unsupported key usage for a ${name} key`);
2807
+ }
2808
+
2809
+ switch (format) {
2810
+ case 'raw': {
2811
+ const keyObject = createSecretKey(keyData as BinaryLike);
2812
+ return new CryptoKey(keyObject, { name }, keyUsages, false);
2813
+ }
2814
+ default:
2815
+ throw new Error(`Unable to import ${name} key with format ${format}`);
2816
+ }
2817
+ };
2818
+
2819
+ const checkCryptoKeyPairUsages = (pair: CryptoKeyPair) => {
2820
+ if (
2821
+ pair.privateKey &&
2822
+ pair.privateKey instanceof CryptoKey &&
2823
+ pair.privateKey.keyUsages &&
2824
+ pair.privateKey.keyUsages.length > 0
2825
+ ) {
2826
+ return;
2827
+ }
2828
+ throw lazyDOMException(
2829
+ 'Usages cannot be empty when creating a key.',
2830
+ 'SyntaxError',
2831
+ );
2832
+ };
2833
+
2834
+ function argon2DeriveBits(
2835
+ algorithm: SubtleAlgorithm,
2836
+ baseKey: CryptoKey,
2837
+ length: number,
2838
+ ): ArrayBuffer {
2839
+ if (length === 0 || length % 8 !== 0) {
2840
+ throw lazyDOMException(
2841
+ 'Invalid Argon2 derived key length',
2842
+ 'OperationError',
2843
+ );
2844
+ }
2845
+ if (length < 32) {
2846
+ throw lazyDOMException(
2847
+ 'Argon2 derived key length must be at least 32 bits',
2848
+ 'OperationError',
2849
+ );
2850
+ }
2851
+
2852
+ const { nonce, parallelism, memory, passes, secretValue, associatedData } =
2853
+ algorithm;
2854
+ const tagLength = length / 8;
2855
+ const message = baseKey.keyObject.export();
2856
+ const algName = algorithm.name.toLowerCase();
2857
+
2858
+ const result = argon2Sync(algName, {
2859
+ message,
2860
+ nonce: nonce ?? new Uint8Array(0),
2861
+ parallelism: parallelism ?? 1,
2862
+ tagLength,
2863
+ memory: memory ?? 65536,
2864
+ passes: passes ?? 3,
2865
+ secret: secretValue,
2866
+ associatedData,
2867
+ version: algorithm.version,
2868
+ });
2869
+
2870
+ return bufferLikeToArrayBuffer(result);
2871
+ }
2872
+
2873
+ // Type guard to check if result is CryptoKeyPair
2874
+ export function isCryptoKeyPair(
2875
+ result: CryptoKey | CryptoKeyPair,
2876
+ ): result is CryptoKeyPair {
2877
+ return 'publicKey' in result && 'privateKey' in result;
2878
+ }
2879
+
2880
+ function hmacSignVerify(
2881
+ key: CryptoKey,
2882
+ data: BufferLike,
2883
+ signature?: BufferLike,
2884
+ ): ArrayBuffer | boolean {
2885
+ // Get hash algorithm from key
2886
+ const hashName = normalizeHashName(key.algorithm.hash);
2887
+
2888
+ // Export the secret key material
2889
+ const keyData = key.keyObject.export();
2890
+
2891
+ // Create HMAC and compute digest
2892
+ const hmac = createHmac(hashName, keyData);
2893
+ hmac.update(bufferLikeToArrayBuffer(data));
2894
+ const computed = hmac.digest();
2895
+
2896
+ if (signature === undefined) {
2897
+ // Sign operation - return the HMAC as ArrayBuffer
2898
+ return computed.buffer.slice(
2899
+ computed.byteOffset,
2900
+ computed.byteOffset + computed.byteLength,
2901
+ );
2902
+ }
2903
+
2904
+ const sigBuffer = bufferLikeToArrayBuffer(signature);
2905
+ const computedBuffer = computed.buffer.slice(
2906
+ computed.byteOffset,
2907
+ computed.byteOffset + computed.byteLength,
2908
+ );
2909
+
2910
+ if (computedBuffer.byteLength !== sigBuffer.byteLength) {
2911
+ return false;
2912
+ }
2913
+
2914
+ return timingSafeEqual(
2915
+ new Uint8Array(computedBuffer),
2916
+ new Uint8Array(sigBuffer),
2917
+ );
2918
+ }
2919
+
2920
+ function rsaSignVerify(
2921
+ key: CryptoKey,
2922
+ data: BufferLike,
2923
+ padding: 'pkcs1' | 'pss',
2924
+ signature?: BufferLike,
2925
+ saltLength?: number,
2926
+ ): ArrayBuffer | boolean {
2927
+ // Get hash algorithm from key
2928
+ const hashName = normalizeHashName(key.algorithm.hash);
2929
+
2930
+ // Determine RSA padding constant
2931
+ const RSA_PKCS1_PADDING = 1;
2932
+ const RSA_PKCS1_PSS_PADDING = 6;
2933
+ const paddingValue =
2934
+ padding === 'pss' ? RSA_PKCS1_PSS_PADDING : RSA_PKCS1_PADDING;
2935
+
2936
+ if (signature === undefined) {
2937
+ // Sign operation
2938
+ const signer = createSign(hashName);
2939
+ signer.update(data);
2940
+ const sig = signer.sign({
2941
+ key: key,
2942
+ padding: paddingValue,
2943
+ saltLength,
2944
+ });
2945
+ return sig.buffer.slice(sig.byteOffset, sig.byteOffset + sig.byteLength);
2946
+ }
2947
+
2948
+ // Verify operation
2949
+ const verifier = createVerify(hashName);
2950
+ verifier.update(data);
2951
+ return verifier.verify(
2952
+ {
2953
+ key: key,
2954
+ padding: paddingValue,
2955
+ saltLength,
2956
+ },
2957
+ signature,
2958
+ );
2959
+ }
2960
+
2961
+ function edSignVerify(
2962
+ key: CryptoKey,
2963
+ data: BufferLike,
2964
+ signature?: BufferLike,
2965
+ ): ArrayBuffer | boolean {
2966
+ const isSign = signature === undefined;
2967
+ const expectedKeyType = isSign ? 'private' : 'public';
2968
+
2969
+ if (key.type !== expectedKeyType) {
2970
+ throw lazyDOMException(
2971
+ `Key must be a ${expectedKeyType} key`,
2972
+ 'InvalidAccessError',
2973
+ );
2974
+ }
2975
+
2976
+ // Get curve type from algorithm name (Ed25519 or Ed448)
2977
+ const algorithmName = key.algorithm.name;
2978
+ const curveType = algorithmName.toLowerCase() as 'ed25519' | 'ed448';
2979
+
2980
+ // Create Ed instance with the curve
2981
+ const ed = new Ed(curveType, {});
2982
+
2983
+ // Export raw key bytes (exportKey with no format returns raw for Ed keys)
2984
+ const rawKey = key.keyObject.handle.exportKey();
2985
+ const dataBuffer = bufferLikeToArrayBuffer(data);
2986
+
2987
+ if (isSign) {
2988
+ // Sign operation - use raw private key
2989
+ const sig = ed.signSync(dataBuffer, rawKey);
2990
+ return sig;
2991
+ } else {
2992
+ // Verify operation - use raw public key
2993
+ const signatureBuffer = bufferLikeToArrayBuffer(signature!);
2994
+ return ed.verifySync(signatureBuffer, dataBuffer, rawKey);
2995
+ }
2996
+ }
2997
+
2998
+ function mldsaSignVerify(
2999
+ key: CryptoKey,
3000
+ data: BufferLike,
3001
+ signature?: BufferLike,
3002
+ ): ArrayBuffer | boolean {
3003
+ const isSign = signature === undefined;
3004
+ const expectedKeyType = isSign ? 'private' : 'public';
3005
+
3006
+ if (key.type !== expectedKeyType) {
3007
+ throw lazyDOMException(
3008
+ `Key must be a ${expectedKeyType} key`,
3009
+ 'InvalidAccessError',
3010
+ );
3011
+ }
3012
+
3013
+ const dataBuffer = bufferLikeToArrayBuffer(data);
3014
+
3015
+ if (isSign) {
3016
+ const signer = createSign('');
3017
+ signer.update(dataBuffer);
3018
+ const sig = signer.sign({ key: key });
3019
+ return sig.buffer.slice(sig.byteOffset, sig.byteOffset + sig.byteLength);
3020
+ } else {
3021
+ const signatureBuffer = bufferLikeToArrayBuffer(signature!);
3022
+ const verifier = createVerify('');
3023
+ verifier.update(dataBuffer);
3024
+ return verifier.verify({ key: key }, signatureBuffer);
3025
+ }
3026
+ }
3027
+
3028
+ const signVerify = (
3029
+ algorithm: SubtleAlgorithm,
3030
+ key: CryptoKey,
3031
+ data: BufferLike,
3032
+ signature?: BufferLike,
3033
+ ): ArrayBuffer | boolean => {
3034
+ const usage: Operation = signature === undefined ? 'sign' : 'verify';
3035
+ algorithm = normalizeAlgorithm(algorithm, usage);
3036
+
3037
+ if (algorithm.name !== key.algorithm.name) {
3038
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
3039
+ }
3040
+
3041
+ if (!key.usages.includes(usage)) {
3042
+ throw lazyDOMException(
3043
+ `Unable to use this key to ${usage}`,
3044
+ 'InvalidAccessError',
3045
+ );
3046
+ }
3047
+
3048
+ switch (algorithm.name) {
3049
+ case 'ECDSA':
3050
+ return ecdsaSignVerify(key, data, algorithm, signature);
3051
+ case 'HMAC':
3052
+ return hmacSignVerify(key, data, signature);
3053
+ case 'RSASSA-PKCS1-v1_5':
3054
+ return rsaSignVerify(key, data, 'pkcs1', signature);
3055
+ case 'RSA-PSS':
3056
+ return rsaSignVerify(key, data, 'pss', signature, algorithm.saltLength);
3057
+ case 'Ed25519':
3058
+ case 'Ed448':
3059
+ return edSignVerify(key, data, signature);
3060
+ case 'ML-DSA-44':
3061
+ case 'ML-DSA-65':
3062
+ case 'ML-DSA-87':
3063
+ case 'SLH-DSA-SHA2-128s':
3064
+ case 'SLH-DSA-SHA2-128f':
3065
+ case 'SLH-DSA-SHA2-192s':
3066
+ case 'SLH-DSA-SHA2-192f':
3067
+ case 'SLH-DSA-SHA2-256s':
3068
+ case 'SLH-DSA-SHA2-256f':
3069
+ case 'SLH-DSA-SHAKE-128s':
3070
+ case 'SLH-DSA-SHAKE-128f':
3071
+ case 'SLH-DSA-SHAKE-192s':
3072
+ case 'SLH-DSA-SHAKE-192f':
3073
+ case 'SLH-DSA-SHAKE-256s':
3074
+ case 'SLH-DSA-SHAKE-256f':
3075
+ return mldsaSignVerify(key, data, signature);
3076
+ case 'KMAC128':
3077
+ case 'KMAC256':
3078
+ return kmacSignVerify(key, data, algorithm, signature);
3079
+ }
3080
+ throw lazyDOMException(
3081
+ `Unrecognized algorithm name '${algorithm.name}' for '${usage}'`,
3082
+ 'NotSupportedError',
3083
+ );
3084
+ };
3085
+
3086
+ // Algorithm-mismatch and usage checks live at the public-method call sites
3087
+ // (encrypt / decrypt / wrapKey / unwrapKey) so spec-mandated message and
3088
+ // ordering — algorithm-mismatch first, then usage — is preserved
3089
+ // (Node webcrypto.js, commit 4cb1f284136).
3090
+ const cipherOrWrap = async (
3091
+ mode: CipherOrWrapMode,
3092
+ algorithm: EncryptDecryptParams,
3093
+ key: CryptoKey,
3094
+ data: ArrayBuffer,
3095
+ ): Promise<ArrayBuffer> => {
3096
+ validateMaxBufferLength(data, 'data');
3097
+
3098
+ switch (algorithm.name) {
3099
+ case 'RSA-OAEP':
3100
+ return rsaCipher(mode, key, data, algorithm);
3101
+ case 'AES-CTR':
3102
+ // Fall through
3103
+ case 'AES-CBC':
3104
+ // Fall through
3105
+ case 'AES-GCM':
3106
+ // Fall through
3107
+ case 'AES-OCB':
3108
+ return aesCipher(mode, key, data, algorithm);
3109
+ case 'AES-KW':
3110
+ return aesKwCipher(mode, key, data);
3111
+ case 'ChaCha20-Poly1305':
3112
+ return chaCha20Poly1305Cipher(
3113
+ mode,
3114
+ key,
3115
+ data,
3116
+ algorithm as ChaCha20Poly1305Params,
3117
+ );
3118
+ }
3119
+ };
3120
+
3121
+ const SUPPORTED_ALGORITHMS: Record<string, Set<string>> = {
3122
+ encrypt: new Set([
3123
+ 'RSA-OAEP',
3124
+ 'AES-CTR',
3125
+ 'AES-CBC',
3126
+ 'AES-GCM',
3127
+ 'AES-OCB',
3128
+ 'ChaCha20-Poly1305',
3129
+ ]),
3130
+ decrypt: new Set([
3131
+ 'RSA-OAEP',
3132
+ 'AES-CTR',
3133
+ 'AES-CBC',
3134
+ 'AES-GCM',
3135
+ 'AES-OCB',
3136
+ 'ChaCha20-Poly1305',
3137
+ ]),
3138
+ sign: new Set([
3139
+ 'RSASSA-PKCS1-v1_5',
3140
+ 'RSA-PSS',
3141
+ 'ECDSA',
3142
+ 'HMAC',
3143
+ 'KMAC128',
3144
+ 'KMAC256',
3145
+ 'Ed25519',
3146
+ 'Ed448',
3147
+ 'ML-DSA-44',
3148
+ 'ML-DSA-65',
3149
+ 'ML-DSA-87',
3150
+ ...SLH_DSA_VARIANTS,
3151
+ ]),
3152
+ verify: new Set([
3153
+ 'RSASSA-PKCS1-v1_5',
3154
+ 'RSA-PSS',
3155
+ 'ECDSA',
3156
+ 'HMAC',
3157
+ 'KMAC128',
3158
+ 'KMAC256',
3159
+ 'Ed25519',
3160
+ 'Ed448',
3161
+ 'ML-DSA-44',
3162
+ 'ML-DSA-65',
3163
+ 'ML-DSA-87',
3164
+ ...SLH_DSA_VARIANTS,
3165
+ ]),
3166
+ digest: new Set([
3167
+ 'SHA-1',
3168
+ 'SHA-256',
3169
+ 'SHA-384',
3170
+ 'SHA-512',
3171
+ 'SHA3-256',
3172
+ 'SHA3-384',
3173
+ 'SHA3-512',
3174
+ 'cSHAKE128',
3175
+ 'cSHAKE256',
3176
+ 'TurboSHAKE128',
3177
+ 'TurboSHAKE256',
3178
+ 'KT128',
3179
+ 'KT256',
3180
+ ]),
3181
+ generateKey: new Set([
3182
+ 'RSASSA-PKCS1-v1_5',
3183
+ 'RSA-PSS',
3184
+ 'RSA-OAEP',
3185
+ 'ECDSA',
3186
+ 'ECDH',
3187
+ 'Ed25519',
3188
+ 'Ed448',
3189
+ 'X25519',
3190
+ 'X448',
3191
+ 'AES-CTR',
3192
+ 'AES-CBC',
3193
+ 'AES-GCM',
3194
+ 'AES-KW',
3195
+ 'AES-OCB',
3196
+ 'ChaCha20-Poly1305',
3197
+ 'HMAC',
3198
+ 'KMAC128',
3199
+ 'KMAC256',
3200
+ 'ML-DSA-44',
3201
+ 'ML-DSA-65',
3202
+ 'ML-DSA-87',
3203
+ 'ML-KEM-512',
3204
+ 'ML-KEM-768',
3205
+ 'ML-KEM-1024',
3206
+ ...SLH_DSA_VARIANTS,
3207
+ ]),
3208
+ importKey: new Set([
3209
+ 'RSASSA-PKCS1-v1_5',
3210
+ 'RSA-PSS',
3211
+ 'RSA-OAEP',
3212
+ 'ECDSA',
3213
+ 'ECDH',
3214
+ 'Ed25519',
3215
+ 'Ed448',
3216
+ 'X25519',
3217
+ 'X448',
3218
+ 'AES-CTR',
3219
+ 'AES-CBC',
3220
+ 'AES-GCM',
3221
+ 'AES-KW',
3222
+ 'AES-OCB',
3223
+ 'ChaCha20-Poly1305',
3224
+ 'HMAC',
3225
+ 'KMAC128',
3226
+ 'KMAC256',
3227
+ 'HKDF',
3228
+ 'PBKDF2',
3229
+ 'Argon2d',
3230
+ 'Argon2i',
3231
+ 'Argon2id',
3232
+ 'ML-DSA-44',
3233
+ 'ML-DSA-65',
3234
+ 'ML-DSA-87',
3235
+ 'ML-KEM-512',
3236
+ 'ML-KEM-768',
3237
+ 'ML-KEM-1024',
3238
+ ...SLH_DSA_VARIANTS,
3239
+ ]),
3240
+ exportKey: new Set([
3241
+ 'RSASSA-PKCS1-v1_5',
3242
+ 'RSA-PSS',
3243
+ 'RSA-OAEP',
3244
+ 'ECDSA',
3245
+ 'ECDH',
3246
+ 'Ed25519',
3247
+ 'Ed448',
3248
+ 'X25519',
3249
+ 'X448',
3250
+ 'AES-CTR',
3251
+ 'AES-CBC',
3252
+ 'AES-GCM',
3253
+ 'AES-KW',
3254
+ 'AES-OCB',
3255
+ 'ChaCha20-Poly1305',
3256
+ 'HMAC',
3257
+ 'KMAC128',
3258
+ 'KMAC256',
3259
+ 'ML-DSA-44',
3260
+ 'ML-DSA-65',
3261
+ 'ML-DSA-87',
3262
+ 'ML-KEM-512',
3263
+ 'ML-KEM-768',
3264
+ 'ML-KEM-1024',
3265
+ ...SLH_DSA_VARIANTS,
3266
+ ]),
3267
+ deriveBits: new Set([
3268
+ 'PBKDF2',
3269
+ 'HKDF',
3270
+ 'ECDH',
3271
+ 'X25519',
3272
+ 'X448',
3273
+ 'Argon2d',
3274
+ 'Argon2i',
3275
+ 'Argon2id',
3276
+ ]),
3277
+ wrapKey: new Set([
3278
+ 'AES-CTR',
3279
+ 'AES-CBC',
3280
+ 'AES-GCM',
3281
+ 'AES-KW',
3282
+ 'AES-OCB',
3283
+ 'ChaCha20-Poly1305',
3284
+ 'RSA-OAEP',
3285
+ ]),
3286
+ unwrapKey: new Set([
3287
+ 'AES-CTR',
3288
+ 'AES-CBC',
3289
+ 'AES-GCM',
3290
+ 'AES-KW',
3291
+ 'AES-OCB',
3292
+ 'ChaCha20-Poly1305',
3293
+ 'RSA-OAEP',
3294
+ ]),
3295
+ encapsulateBits: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
3296
+ decapsulateBits: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
3297
+ encapsulateKey: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
3298
+ decapsulateKey: new Set(['ML-KEM-512', 'ML-KEM-768', 'ML-KEM-1024']),
3299
+ };
3300
+
3301
+ const ASYMMETRIC_ALGORITHMS = new Set<string>([
3302
+ 'RSASSA-PKCS1-v1_5',
3303
+ 'RSA-PSS',
3304
+ 'RSA-OAEP',
3305
+ 'ECDSA',
3306
+ 'ECDH',
3307
+ 'Ed25519',
3308
+ 'Ed448',
3309
+ 'X25519',
3310
+ 'X448',
3311
+ 'ML-DSA-44',
3312
+ 'ML-DSA-65',
3313
+ 'ML-DSA-87',
3314
+ 'ML-KEM-512',
3315
+ 'ML-KEM-768',
3316
+ 'ML-KEM-1024',
3317
+ ...SLH_DSA_VARIANTS,
3318
+ ]);
3319
+
3320
+ // Per-algorithm validators for deriveBits (mirrors Node's hkdf.js:141-149,
3321
+ // pbkdf2.js:96-105, argon2.js:194-209). Used by Subtle.supports to reject
3322
+ // length values that the actual deriveBits implementation would reject.
3323
+ function validateKdfDeriveBitsLength(
3324
+ length: number | null | undefined,
3325
+ algName: string,
3326
+ ): void {
3327
+ if (length === null || length === undefined) {
3328
+ throw lazyDOMException('length cannot be null', 'OperationError');
3329
+ }
3330
+ if (length % 8) {
3331
+ throw lazyDOMException('length must be a multiple of 8', 'OperationError');
3332
+ }
3333
+ if (algName.startsWith('Argon2') && length < 32) {
3334
+ throw lazyDOMException('length must be >= 32', 'OperationError');
3335
+ }
3336
+ }
3337
+
3338
+ // Mirrors Node's webcrypto.js:1652-1731 `check`. Normalizes the algorithm,
3339
+ // looks it up in SUPPORTED_ALGORITHMS, and runs per-algorithm validation
3340
+ // (deriveBits length validators, HMAC+SHA3 generateKey rejection).
3341
+ // `op` is the operation key in SUPPORTED_ALGORITHMS — wrapKey/unwrapKey fall
3342
+ // back to encrypt/decrypt to mirror Node's normalize fallback.
3343
+ function supportsCheck(
3344
+ op: string,
3345
+ alg: SubtleAlgorithm | AnyAlgorithm,
3346
+ length?: number | null,
3347
+ ): boolean {
3348
+ let normalizedAlgorithm: SubtleAlgorithm;
3349
+ try {
3350
+ normalizedAlgorithm = normalizeAlgorithm(alg, op as Operation);
3351
+ } catch {
3352
+ if (op === 'wrapKey') return supportsCheck('encrypt', alg);
3353
+ if (op === 'unwrapKey') return supportsCheck('decrypt', alg);
3354
+ return false;
3355
+ }
3356
+
3357
+ const supported = SUPPORTED_ALGORITHMS[op];
3358
+ if (!supported || !supported.has(normalizedAlgorithm.name)) {
3359
+ if (op === 'wrapKey') return supportsCheck('encrypt', alg);
3360
+ if (op === 'unwrapKey') return supportsCheck('decrypt', alg);
3361
+ return false;
3362
+ }
3363
+
3364
+ if (op === 'deriveBits') {
3365
+ const name = normalizedAlgorithm.name;
3366
+ if (name === 'HKDF' || name === 'PBKDF2' || name.startsWith('Argon2')) {
3367
+ try {
3368
+ validateKdfDeriveBitsLength(length, name);
3369
+ } catch {
3370
+ return false;
3371
+ }
3372
+ }
3373
+ }
3374
+
3375
+ if (op === 'generateKey' && normalizedAlgorithm.name === 'HMAC') {
3376
+ const hashName =
3377
+ typeof normalizedAlgorithm.hash === 'string'
3378
+ ? normalizedAlgorithm.hash
3379
+ : (normalizedAlgorithm.hash as { name?: string } | undefined)?.name;
3380
+ if (
3381
+ normalizedAlgorithm.length === undefined &&
3382
+ typeof hashName === 'string' &&
3383
+ hashName.startsWith('SHA3-')
3384
+ ) {
3385
+ return false;
3386
+ }
3387
+ }
3388
+
3389
+ return true;
3390
+ }
3391
+
3392
+ function supportsImpl(
3393
+ operation: string,
3394
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
3395
+ lengthOrAdditionalAlgorithm: unknown,
3396
+ ): boolean {
3397
+ switch (operation) {
3398
+ case 'decapsulateBits':
3399
+ case 'decapsulateKey':
3400
+ case 'decrypt':
3401
+ case 'deriveBits':
3402
+ case 'deriveKey':
3403
+ case 'digest':
3404
+ case 'encapsulateBits':
3405
+ case 'encapsulateKey':
3406
+ case 'encrypt':
3407
+ case 'exportKey':
3408
+ case 'generateKey':
3409
+ case 'getPublicKey':
3410
+ case 'importKey':
3411
+ case 'sign':
3412
+ case 'unwrapKey':
3413
+ case 'verify':
3414
+ case 'wrapKey':
3415
+ break;
3416
+ default:
3417
+ return false;
3418
+ }
3419
+
3420
+ let length: number | null | undefined;
3421
+
3422
+ if (operation === 'deriveKey') {
3423
+ // deriveKey decomposes to importKey of derived alg + deriveBits with that
3424
+ // alg's key length. Node webcrypto.js:1547-1563.
3425
+ if (lengthOrAdditionalAlgorithm != null) {
3426
+ const additional = lengthOrAdditionalAlgorithm as
3427
+ | SubtleAlgorithm
3428
+ | AnyAlgorithm;
3429
+ if (!supportsCheck('importKey', additional)) return false;
3430
+ try {
3431
+ length = getKeyLength(normalizeAlgorithm(additional, 'get key length'));
3432
+ } catch {
3433
+ return false;
3434
+ }
3435
+ return supportsCheck('deriveBits', algorithm, length);
3436
+ }
3437
+ // No additional algorithm given — only check the deriveBits side.
3438
+ return supportsCheck('deriveBits', algorithm);
3439
+ }
3440
+
3441
+ if (operation === 'wrapKey') {
3442
+ // wrapKey decomposes to encrypt of wrapping alg + exportKey of wrapped alg.
3443
+ // Node webcrypto.js:1564-1572.
3444
+ if (lengthOrAdditionalAlgorithm != null) {
3445
+ const additional = lengthOrAdditionalAlgorithm as
3446
+ | SubtleAlgorithm
3447
+ | AnyAlgorithm;
3448
+ if (!supportsCheck('exportKey', additional)) return false;
3449
+ }
3450
+ return supportsCheck('wrapKey', algorithm);
3451
+ }
3452
+
3453
+ if (operation === 'unwrapKey') {
3454
+ // unwrapKey decomposes to decrypt of wrapping alg + importKey of wrapped
3455
+ // alg. Node webcrypto.js:1573-1581.
3456
+ if (lengthOrAdditionalAlgorithm != null) {
3457
+ const additional = lengthOrAdditionalAlgorithm as
3458
+ | SubtleAlgorithm
3459
+ | AnyAlgorithm;
3460
+ if (!supportsCheck('importKey', additional)) return false;
3461
+ }
3462
+ return supportsCheck('unwrapKey', algorithm);
3463
+ }
3464
+
3465
+ if (operation === 'deriveBits') {
3466
+ if (lengthOrAdditionalAlgorithm == null) {
3467
+ length = null;
3468
+ } else if (typeof lengthOrAdditionalAlgorithm === 'number') {
3469
+ length = lengthOrAdditionalAlgorithm;
3470
+ } else {
3471
+ return false;
3472
+ }
3473
+ return supportsCheck('deriveBits', algorithm, length);
3474
+ }
3475
+
3476
+ if (operation === 'getPublicKey') {
3477
+ let normalized: SubtleAlgorithm;
3478
+ try {
3479
+ normalized = normalizeAlgorithm(algorithm, 'exportKey');
3480
+ } catch {
3481
+ return false;
3482
+ }
3483
+ return ASYMMETRIC_ALGORITHMS.has(normalized.name);
3484
+ }
3485
+
3486
+ if (operation === 'encapsulateKey' || operation === 'decapsulateKey') {
3487
+ // sharedKeyAlgorithm must support importKey, with HMAC/KMAC limited to
3488
+ // length === undefined or 256 (Node webcrypto.js:1610-1645).
3489
+ const additional = lengthOrAdditionalAlgorithm as
3490
+ | SubtleAlgorithm
3491
+ | AnyAlgorithm;
3492
+ let normalizedAdd: SubtleAlgorithm;
3493
+ try {
3494
+ normalizedAdd = normalizeAlgorithm(additional, 'importKey');
3495
+ } catch {
3496
+ return false;
3497
+ }
3498
+ switch (normalizedAdd.name) {
3499
+ case 'AES-OCB':
3500
+ case 'AES-KW':
3501
+ case 'AES-GCM':
3502
+ case 'AES-CTR':
3503
+ case 'AES-CBC':
3504
+ case 'ChaCha20-Poly1305':
3505
+ case 'HKDF':
3506
+ case 'PBKDF2':
3507
+ case 'Argon2i':
3508
+ case 'Argon2d':
3509
+ case 'Argon2id':
3510
+ break;
3511
+ case 'HMAC':
3512
+ case 'KMAC128':
3513
+ case 'KMAC256': {
3514
+ const addLen = normalizedAdd.length;
3515
+ if (addLen !== undefined && addLen !== 256) return false;
3516
+ break;
3517
+ }
3518
+ default:
3519
+ return false;
3520
+ }
3521
+ return supportsCheck(operation, algorithm);
3522
+ }
3523
+
3524
+ return supportsCheck(operation, algorithm);
3525
+ }
3526
+
3527
+ export class Subtle {
3528
+ // Spec-compliant capability detector. Mirrors Node's webcrypto.js:1506-1649
3529
+ // `SubtleCrypto.supports`, including:
3530
+ // • composed-operation decomposition (deriveKey, wrapKey, unwrapKey,
3531
+ // encapsulateKey, decapsulateKey, getPublicKey)
3532
+ // • per-algorithm length validators for deriveBits (HKDF/PBKDF2/Argon2)
3533
+ // • HMAC + SHA3 generateKey with no length → false
3534
+ // Static-only per the WICG spec.
3535
+ static supports(
3536
+ operation: string,
3537
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
3538
+ lengthOrAdditionalAlgorithm: unknown = null,
3539
+ ): boolean {
3540
+ return supportsImpl(operation, algorithm, lengthOrAdditionalAlgorithm);
3541
+ }
3542
+
3543
+ async decrypt(
3544
+ algorithm: EncryptDecryptParams | AnyAlgorithm,
3545
+ key: CryptoKey,
3546
+ data: BufferLike,
3547
+ ): Promise<ArrayBuffer> {
3548
+ requireArgs(arguments.length, 3, 'decrypt');
3549
+ const normalizedAlgorithm = normalizeAlgorithm(
3550
+ algorithm,
3551
+ 'decrypt',
3552
+ ) as EncryptDecryptParams;
3553
+ if (normalizedAlgorithm.name !== key.algorithm.name) {
3554
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
3555
+ }
3556
+ if (!key.usages.includes('decrypt')) {
3557
+ throw lazyDOMException(
3558
+ 'Unable to use this key to decrypt',
3559
+ 'InvalidAccessError',
3560
+ );
3561
+ }
3562
+ return cipherOrWrap(
3563
+ CipherOrWrapMode.kWebCryptoCipherDecrypt,
3564
+ normalizedAlgorithm,
3565
+ key,
3566
+ bufferLikeToArrayBuffer(data),
3567
+ );
3568
+ }
3569
+
3570
+ async digest(
3571
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
3572
+ data: BufferLike,
3573
+ ): Promise<ArrayBuffer> {
3574
+ requireArgs(arguments.length, 2, 'digest');
3575
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'digest');
3576
+ return asyncDigest(normalizedAlgorithm, data);
3577
+ }
3578
+
3579
+ async deriveBits(
3580
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
3581
+ baseKey: CryptoKey,
3582
+ length: number | null = null,
3583
+ ): Promise<ArrayBuffer> {
3584
+ requireArgs(arguments.length, 2, 'deriveBits');
3585
+ // WebCrypto §SubtleCrypto.deriveBits step 11: throw InvalidAccessError
3586
+ // unless `baseKey.[[usages]]` contains "deriveBits" specifically. The
3587
+ // previous `deriveBits || deriveKey` accept-either branch silently
3588
+ // promoted deriveKey-only keys into deriveBits use, contradicting the
3589
+ // spec usage gate.
3590
+ if (!baseKey.usages.includes('deriveBits')) {
3591
+ throw lazyDOMException(
3592
+ 'baseKey does not have deriveBits usage',
3593
+ 'InvalidAccessError',
3594
+ );
3595
+ }
3596
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'deriveBits');
3597
+ if (baseKey.algorithm.name !== normalizedAlgorithm.name) {
3598
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
3599
+ }
3600
+ switch (normalizedAlgorithm.name) {
3601
+ case 'PBKDF2':
3602
+ if (length === null) {
3603
+ throw lazyDOMException('length cannot be null', 'OperationError');
3604
+ }
3605
+ return pbkdf2DeriveBits(normalizedAlgorithm, baseKey, length);
3606
+ case 'X25519':
3607
+ // Fall through
3608
+ case 'X448':
3609
+ return xDeriveBits(normalizedAlgorithm, baseKey, length);
3610
+ case 'ECDH':
3611
+ return ecDeriveBits(normalizedAlgorithm, baseKey, length);
3612
+ case 'HKDF':
3613
+ if (length === null) {
3614
+ throw lazyDOMException('length cannot be null', 'OperationError');
3615
+ }
3616
+ return hkdfDeriveBits(
3617
+ normalizedAlgorithm as unknown as HkdfAlgorithm,
3618
+ baseKey,
3619
+ length,
3620
+ );
3621
+ case 'Argon2d':
3622
+ case 'Argon2i':
3623
+ case 'Argon2id':
3624
+ if (length === null) {
3625
+ throw lazyDOMException('length cannot be null', 'OperationError');
3626
+ }
3627
+ return argon2DeriveBits(normalizedAlgorithm, baseKey, length);
3628
+ }
3629
+ throw lazyDOMException(
3630
+ `'subtle.deriveBits()' for ${normalizedAlgorithm.name} is not implemented.`,
3631
+ 'NotSupportedError',
3632
+ );
3633
+ }
3634
+
3635
+ async deriveKey(
3636
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
3637
+ baseKey: CryptoKey,
3638
+ derivedKeyAlgorithm: SubtleAlgorithm | AnyAlgorithm,
3639
+ extractable: boolean,
3640
+ keyUsages: KeyUsage[],
3641
+ ): Promise<CryptoKey> {
3642
+ requireArgs(arguments.length, 5, 'deriveKey');
3643
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'deriveBits');
3644
+ // Validate the derived-key algorithm up front (mirrors Node webcrypto.js:341).
3645
+ // The normalized form is unused — `this.importKey` re-normalizes below.
3646
+ normalizeAlgorithm(derivedKeyAlgorithm, 'importKey');
3647
+
3648
+ // Validate baseKey usage
3649
+ if (!baseKey.usages.includes('deriveKey')) {
3650
+ throw lazyDOMException(
3651
+ 'baseKey does not have deriveKey usage',
3652
+ 'InvalidAccessError',
3653
+ );
3654
+ }
3655
+
3656
+ if (baseKey.algorithm.name !== normalizedAlgorithm.name) {
3657
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
3658
+ }
3659
+
3660
+ // Calculate required key length (may be null for KDF-derived material).
3661
+ // Mirrors Node webcrypto.js:350 — uses the raw derivedKeyAlgorithm with
3662
+ // op='get key length' so AES `length` survives normalization (the
3663
+ // 'importKey' converter for AES is null and strips dictionary members).
3664
+ const length = getKeyLength(
3665
+ normalizeAlgorithm(derivedKeyAlgorithm, 'get key length'),
3666
+ );
3667
+
3668
+ // Step 1: Derive bits
3669
+ let derivedBits: ArrayBuffer;
3670
+ switch (normalizedAlgorithm.name) {
3671
+ case 'PBKDF2':
3672
+ if (length === null) {
3673
+ throw lazyDOMException('length cannot be null', 'OperationError');
3674
+ }
3675
+ derivedBits = await pbkdf2DeriveBits(
3676
+ normalizedAlgorithm,
3677
+ baseKey,
3678
+ length,
3679
+ );
3680
+ break;
3681
+ case 'X25519':
3682
+ // Fall through
3683
+ case 'X448':
3684
+ derivedBits = await xDeriveBits(normalizedAlgorithm, baseKey, length);
3685
+ break;
3686
+ case 'ECDH':
3687
+ derivedBits = await ecDeriveBits(normalizedAlgorithm, baseKey, length);
3688
+ break;
3689
+ case 'HKDF':
3690
+ if (length === null) {
3691
+ throw lazyDOMException('length cannot be null', 'OperationError');
3692
+ }
3693
+ derivedBits = hkdfDeriveBits(
3694
+ normalizedAlgorithm as unknown as HkdfAlgorithm,
3695
+ baseKey,
3696
+ length,
3697
+ );
3698
+ break;
3699
+ case 'Argon2d':
3700
+ case 'Argon2i':
3701
+ case 'Argon2id':
3702
+ if (length === null) {
3703
+ throw lazyDOMException('length cannot be null', 'OperationError');
3704
+ }
3705
+ derivedBits = argon2DeriveBits(normalizedAlgorithm, baseKey, length);
3706
+ break;
3707
+ default:
3708
+ throw lazyDOMException(
3709
+ `'subtle.deriveKey()' for ${normalizedAlgorithm.name} is not implemented.`,
3710
+ 'NotSupportedError',
3711
+ );
3712
+ }
3713
+
3714
+ // Step 2: Import as key. Use 'raw-secret' so derived material flows into
3715
+ // AEADs / KMAC correctly — they reject plain 'raw' (Node webcrypto.js:381-385).
3716
+ return this.importKey(
3717
+ 'raw-secret',
3718
+ derivedBits,
3719
+ derivedKeyAlgorithm,
3720
+ extractable,
3721
+ keyUsages,
3722
+ );
3723
+ }
3724
+
3725
+ async encrypt(
3726
+ algorithm: EncryptDecryptParams | AnyAlgorithm,
3727
+ key: CryptoKey,
3728
+ data: BufferLike,
3729
+ ): Promise<ArrayBuffer> {
3730
+ requireArgs(arguments.length, 3, 'encrypt');
3731
+ const normalizedAlgorithm = normalizeAlgorithm(
3732
+ algorithm,
3733
+ 'encrypt',
3734
+ ) as EncryptDecryptParams;
3735
+ if (normalizedAlgorithm.name !== key.algorithm.name) {
3736
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
3737
+ }
3738
+ if (!key.usages.includes('encrypt')) {
3739
+ throw lazyDOMException(
3740
+ 'Unable to use this key to encrypt',
3741
+ 'InvalidAccessError',
3742
+ );
3743
+ }
3744
+ return cipherOrWrap(
3745
+ CipherOrWrapMode.kWebCryptoCipherEncrypt,
3746
+ normalizedAlgorithm,
3747
+ key,
3748
+ bufferLikeToArrayBuffer(data),
3749
+ );
3750
+ }
3751
+
3752
+ async exportKey(
3753
+ format: ImportFormat,
3754
+ key: CryptoKey,
3755
+ ): Promise<ArrayBuffer | JWK> {
3756
+ requireArgs(arguments.length, 2, 'exportKey');
3757
+ if (!key.extractable)
3758
+ throw lazyDOMException('key is not extractable', 'InvalidAccessError');
3759
+
3760
+ if (format === 'raw-seed') {
3761
+ const pqcAlgos: string[] = [
3762
+ 'ML-KEM-512',
3763
+ 'ML-KEM-768',
3764
+ 'ML-KEM-1024',
3765
+ 'ML-DSA-44',
3766
+ 'ML-DSA-65',
3767
+ 'ML-DSA-87',
3768
+ ...SLH_DSA_VARIANTS,
3769
+ ];
3770
+ if (!pqcAlgos.includes(key.algorithm.name)) {
3771
+ throw lazyDOMException(
3772
+ 'raw-seed export only supported for PQC keys',
3773
+ 'NotSupportedError',
3774
+ );
3775
+ }
3776
+ if (key.type !== 'private') {
3777
+ throw lazyDOMException(
3778
+ 'raw-seed export requires a private key',
3779
+ 'InvalidAccessError',
3780
+ );
3781
+ }
3782
+ return bufferLikeToArrayBuffer(key.keyObject.handle.exportKey());
3783
+ }
3784
+
3785
+ switch (format) {
3786
+ case 'spki':
3787
+ return (await exportKeySpki(key)) as ArrayBuffer;
3788
+ case 'pkcs8':
3789
+ return (await exportKeyPkcs8(key)) as ArrayBuffer;
3790
+ case 'jwk':
3791
+ return exportKeyJWK(key) as JWK;
3792
+ case 'raw':
3793
+ case 'raw-secret':
3794
+ case 'raw-public':
3795
+ return exportKeyRaw(key, format) as ArrayBuffer;
3796
+ }
3797
+ }
3798
+
3799
+ async wrapKey(
3800
+ format: ImportFormat,
3801
+ key: CryptoKey,
3802
+ wrappingKey: CryptoKey,
3803
+ wrapAlgorithm: EncryptDecryptParams | AnyAlgorithm,
3804
+ ): Promise<ArrayBuffer> {
3805
+ requireArgs(arguments.length, 4, 'wrapKey');
3806
+ // Mirrors Node webcrypto.js:923-927: prefer the 'wrapKey' op (only
3807
+ // AES-KW defines it) and fall back to 'encrypt' for cipher-based wrap
3808
+ // algorithms like AES-GCM and RSA-OAEP.
3809
+ let normalizedWrapAlgorithm: EncryptDecryptParams;
3810
+ try {
3811
+ normalizedWrapAlgorithm = normalizeAlgorithm(
3812
+ wrapAlgorithm,
3813
+ 'wrapKey',
3814
+ ) as EncryptDecryptParams;
3815
+ } catch {
3816
+ normalizedWrapAlgorithm = normalizeAlgorithm(
3817
+ wrapAlgorithm,
3818
+ 'encrypt',
3819
+ ) as EncryptDecryptParams;
3820
+ }
3821
+
3822
+ if (normalizedWrapAlgorithm.name !== wrappingKey.algorithm.name) {
3823
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
3824
+ }
3825
+ if (!wrappingKey.usages.includes('wrapKey')) {
3826
+ throw lazyDOMException(
3827
+ 'Unable to use this key to wrapKey',
3828
+ 'InvalidAccessError',
3829
+ );
3830
+ }
3831
+
3832
+ // Step 1: Export the key
3833
+ const exported = await this.exportKey(format, key);
3834
+
3835
+ // Step 2: Convert to ArrayBuffer if JWK
3836
+ let keyData: ArrayBuffer;
3837
+ if (format === 'jwk') {
3838
+ const jwkString = JSON.stringify(exported);
3839
+ const buffer = SBuffer.from(jwkString, 'utf8');
3840
+
3841
+ // For AES-KW, pad to multiple of 8 bytes (accounting for null terminator)
3842
+ if (normalizedWrapAlgorithm.name === 'AES-KW') {
3843
+ const length = buffer.length;
3844
+ // Add 1 for null terminator, then pad to multiple of 8
3845
+ const paddedLength = Math.ceil((length + 1) / 8) * 8;
3846
+ const paddedBuffer = SBuffer.alloc(paddedLength);
3847
+ buffer.copy(paddedBuffer);
3848
+ // Null terminator for JSON string (remaining bytes are already zeros from alloc)
3849
+ paddedBuffer.writeUInt8(0, length);
3850
+ keyData = bufferLikeToArrayBuffer(paddedBuffer);
3851
+ } else {
3852
+ keyData = bufferLikeToArrayBuffer(buffer);
3853
+ }
3854
+ } else {
3855
+ keyData = exported as ArrayBuffer;
3856
+ }
3857
+
3858
+ // Step 3: Encrypt the exported key
3859
+ return cipherOrWrap(
3860
+ CipherOrWrapMode.kWebCryptoCipherEncrypt,
3861
+ normalizedWrapAlgorithm,
3862
+ wrappingKey,
3863
+ keyData,
3864
+ );
3865
+ }
3866
+
3867
+ async unwrapKey(
3868
+ format: ImportFormat,
3869
+ wrappedKey: BufferLike,
3870
+ unwrappingKey: CryptoKey,
3871
+ unwrapAlgorithm: EncryptDecryptParams | AnyAlgorithm,
3872
+ unwrappedKeyAlgorithm: SubtleAlgorithm | AnyAlgorithm,
3873
+ extractable: boolean,
3874
+ keyUsages: KeyUsage[],
3875
+ ): Promise<CryptoKey> {
3876
+ requireArgs(arguments.length, 7, 'unwrapKey');
3877
+ // Mirrors Node webcrypto.js:1006-1010: prefer 'unwrapKey', fall back to
3878
+ // 'decrypt' for cipher-based unwrap algorithms.
3879
+ let normalizedUnwrapAlgorithm: EncryptDecryptParams;
3880
+ try {
3881
+ normalizedUnwrapAlgorithm = normalizeAlgorithm(
3882
+ unwrapAlgorithm,
3883
+ 'unwrapKey',
3884
+ ) as EncryptDecryptParams;
3885
+ } catch {
3886
+ normalizedUnwrapAlgorithm = normalizeAlgorithm(
3887
+ unwrapAlgorithm,
3888
+ 'decrypt',
3889
+ ) as EncryptDecryptParams;
3890
+ }
3891
+
3892
+ if (normalizedUnwrapAlgorithm.name !== unwrappingKey.algorithm.name) {
3893
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
3894
+ }
3895
+ if (!unwrappingKey.usages.includes('unwrapKey')) {
3896
+ throw lazyDOMException(
3897
+ 'Unable to use this key to unwrapKey',
3898
+ 'InvalidAccessError',
3899
+ );
3900
+ }
3901
+
3902
+ // Step 1: Decrypt the wrapped key
3903
+ const decrypted = await cipherOrWrap(
3904
+ CipherOrWrapMode.kWebCryptoCipherDecrypt,
3905
+ normalizedUnwrapAlgorithm,
3906
+ unwrappingKey,
3907
+ bufferLikeToArrayBuffer(wrappedKey),
3908
+ );
3909
+
3910
+ // Step 2: Convert to appropriate format
3911
+ let keyData: BufferLike | JWK;
3912
+ if (format === 'jwk') {
3913
+ const buffer = SBuffer.from(decrypted);
3914
+ // For AES-KW, the data may be padded - find the null terminator
3915
+ let jwkString: string;
3916
+ if (normalizedUnwrapAlgorithm.name === 'AES-KW') {
3917
+ // Find the null terminator (if present) to get the original string
3918
+ const nullIndex = buffer.indexOf(0);
3919
+ if (nullIndex !== -1) {
3920
+ jwkString = buffer.toString('utf8', 0, nullIndex);
3921
+ } else {
3922
+ // No null terminator, try to parse the whole buffer
3923
+ jwkString = buffer.toString('utf8').trim();
3924
+ }
3925
+ } else {
3926
+ jwkString = buffer.toString('utf8');
3927
+ }
3928
+ keyData = JSON.parse(jwkString) as JWK;
3929
+ } else {
3930
+ keyData = decrypted;
3931
+ }
3932
+
3933
+ // Step 3: Import the key
3934
+ return this.importKey(
3935
+ format,
3936
+ keyData,
3937
+ unwrappedKeyAlgorithm,
3938
+ extractable,
3939
+ keyUsages,
3940
+ );
3941
+ }
3942
+
3943
+ async generateKey(
3944
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
3945
+ extractable: boolean,
3946
+ keyUsages: KeyUsage[],
3947
+ ): Promise<CryptoKey | CryptoKeyPair> {
3948
+ requireArgs(arguments.length, 3, 'generateKey');
3949
+ algorithm = normalizeAlgorithm(algorithm, 'generateKey');
3950
+ let result: CryptoKey | CryptoKeyPair;
3951
+ switch (algorithm.name) {
3952
+ case 'RSASSA-PKCS1-v1_5':
3953
+ // Fall through
3954
+ case 'RSA-PSS':
3955
+ // Fall through
3956
+ case 'RSA-OAEP':
3957
+ result = await rsa_generateKeyPair(algorithm, extractable, keyUsages);
3958
+ break;
3959
+ case 'ECDSA':
3960
+ // Fall through
3961
+ case 'ECDH':
3962
+ result = await ec_generateKeyPair(
3963
+ algorithm.name,
3964
+ algorithm.namedCurve!,
3965
+ extractable,
3966
+ keyUsages,
3967
+ );
3968
+ checkCryptoKeyPairUsages(result as CryptoKeyPair);
3969
+ break;
3970
+ case 'AES-CTR':
3971
+ // Fall through
3972
+ case 'AES-CBC':
3973
+ // Fall through
3974
+ case 'AES-GCM':
3975
+ // Fall through
3976
+ case 'AES-KW':
3977
+ // Fall through
3978
+ case 'AES-OCB':
3979
+ result = await aesGenerateKey(
3980
+ algorithm as AesKeyGenParams,
3981
+ extractable,
3982
+ keyUsages,
3983
+ );
3984
+ break;
3985
+ case 'ChaCha20-Poly1305': {
3986
+ const length = (algorithm as AesKeyGenParams).length ?? 256;
3987
+
3988
+ if (length !== 256) {
3989
+ throw lazyDOMException(
3990
+ 'ChaCha20-Poly1305 only supports 256-bit keys',
3991
+ 'NotSupportedError',
3992
+ );
3993
+ }
3994
+
3995
+ result = await aesGenerateKey(
3996
+ {
3997
+ name: 'ChaCha20-Poly1305',
3998
+ length: 256,
3999
+ } as unknown as AesKeyGenParams,
4000
+ extractable,
4001
+ keyUsages,
4002
+ );
4003
+ break;
4004
+ }
4005
+ case 'HMAC':
4006
+ result = await hmacGenerateKey(algorithm, extractable, keyUsages);
4007
+ break;
4008
+ case 'KMAC128':
4009
+ // Fall through
4010
+ case 'KMAC256':
4011
+ result = await kmacGenerateKey(algorithm, extractable, keyUsages);
4012
+ break;
4013
+ case 'Ed25519':
4014
+ // Fall through
4015
+ case 'Ed448':
4016
+ result = await ed_generateKeyPairWebCrypto(
4017
+ algorithm.name.toLowerCase() as 'ed25519' | 'ed448',
4018
+ extractable,
4019
+ keyUsages,
4020
+ );
4021
+ checkCryptoKeyPairUsages(result as CryptoKeyPair);
4022
+ break;
4023
+ case 'ML-DSA-44':
4024
+ // Fall through
4025
+ case 'ML-DSA-65':
4026
+ // Fall through
4027
+ case 'ML-DSA-87':
4028
+ result = await mldsa_generateKeyPairWebCrypto(
4029
+ algorithm.name as MlDsaVariant,
4030
+ extractable,
4031
+ keyUsages,
4032
+ );
4033
+ checkCryptoKeyPairUsages(result as CryptoKeyPair);
4034
+ break;
4035
+ case 'SLH-DSA-SHA2-128s':
4036
+ case 'SLH-DSA-SHA2-128f':
4037
+ case 'SLH-DSA-SHA2-192s':
4038
+ case 'SLH-DSA-SHA2-192f':
4039
+ case 'SLH-DSA-SHA2-256s':
4040
+ case 'SLH-DSA-SHA2-256f':
4041
+ case 'SLH-DSA-SHAKE-128s':
4042
+ case 'SLH-DSA-SHAKE-128f':
4043
+ case 'SLH-DSA-SHAKE-192s':
4044
+ case 'SLH-DSA-SHAKE-192f':
4045
+ case 'SLH-DSA-SHAKE-256s':
4046
+ case 'SLH-DSA-SHAKE-256f':
4047
+ result = await slhdsa_generateKeyPairWebCrypto(
4048
+ algorithm.name as SlhDsaVariant,
4049
+ extractable,
4050
+ keyUsages,
4051
+ );
4052
+ checkCryptoKeyPairUsages(result as CryptoKeyPair);
4053
+ break;
4054
+ case 'X25519':
4055
+ // Fall through
4056
+ case 'X448':
4057
+ result = await x_generateKeyPairWebCrypto(
4058
+ algorithm.name.toLowerCase() as 'x25519' | 'x448',
4059
+ extractable,
4060
+ keyUsages,
4061
+ );
4062
+ checkCryptoKeyPairUsages(result as CryptoKeyPair);
4063
+ break;
4064
+ case 'ML-KEM-512':
4065
+ // Fall through
4066
+ case 'ML-KEM-768':
4067
+ // Fall through
4068
+ case 'ML-KEM-1024':
4069
+ result = await mlkem_generateKeyPairWebCrypto(
4070
+ algorithm.name as MlKemVariant,
4071
+ extractable,
4072
+ keyUsages,
4073
+ );
4074
+ checkCryptoKeyPairUsages(result as CryptoKeyPair);
4075
+ break;
4076
+ default:
4077
+ throw new Error(
4078
+ `'subtle.generateKey()' is not implemented for ${algorithm.name}.
4079
+ Unrecognized algorithm name`,
4080
+ );
4081
+ }
4082
+
4083
+ return result;
4084
+ }
4085
+
4086
+ async getPublicKey(
4087
+ key: CryptoKey,
4088
+ keyUsages: KeyUsage[],
4089
+ ): Promise<CryptoKey> {
4090
+ requireArgs(arguments.length, 2, 'getPublicKey');
4091
+ if (key.type === 'secret') {
4092
+ throw lazyDOMException('key must be a private key', 'NotSupportedError');
4093
+ }
4094
+ if (key.type !== 'private') {
4095
+ throw lazyDOMException('key must be a private key', 'InvalidAccessError');
4096
+ }
4097
+
4098
+ const publicKeyObject = createPublicKey(key.keyObject);
4099
+ return publicKeyObject.toCryptoKey(key.algorithm, true, keyUsages);
4100
+ }
4101
+
4102
+ async importKey(
4103
+ format: ImportFormat,
4104
+ data: BufferLike | BinaryLike | JWK,
4105
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
4106
+ extractable: boolean,
4107
+ keyUsages: KeyUsage[],
4108
+ ): Promise<CryptoKey> {
4109
+ requireArgs(arguments.length, 5, 'importKey');
4110
+ // Per-algorithm format handling. Some algorithms alias raw-secret/raw-public
4111
+ // to 'raw' (RSA, EC, Ed/X, HMAC, HKDF, PBKDF2); others demand the
4112
+ // disambiguated form (KMAC, AES-OCB, ChaCha20-Poly1305, Argon2, ML-DSA,
4113
+ // ML-KEM). 'raw-seed' is never normalized — PQC import handles it directly.
4114
+ const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'importKey');
4115
+ let result: CryptoKey;
4116
+ switch (normalizedAlgorithm.name) {
4117
+ case 'RSASSA-PKCS1-v1_5':
4118
+ // Fall through
4119
+ case 'RSA-PSS':
4120
+ // Fall through
4121
+ case 'RSA-OAEP':
4122
+ result = rsaImportKey(
4123
+ aliasKeyFormat(format),
4124
+ data as BufferLike | JWK,
4125
+ normalizedAlgorithm,
4126
+ extractable,
4127
+ keyUsages,
4128
+ );
4129
+ break;
4130
+ case 'ECDSA':
4131
+ // Fall through
4132
+ case 'ECDH':
4133
+ result = ecImportKey(
4134
+ aliasKeyFormat(format),
4135
+ data,
4136
+ normalizedAlgorithm,
4137
+ extractable,
4138
+ keyUsages,
4139
+ );
4140
+ break;
4141
+ case 'HMAC':
4142
+ // No aliasing — Node routes HMAC straight into mac.js, which accepts
4143
+ // 'raw' / 'raw-secret' / 'jwk' and rejects everything else
4144
+ // (webcrypto.js:774-781, mac.js:136-174).
4145
+ result = await hmacImportKey(
4146
+ normalizedAlgorithm,
4147
+ format,
4148
+ data as BufferLike | JWK,
4149
+ extractable,
4150
+ keyUsages,
4151
+ );
4152
+ break;
4153
+ case 'KMAC128':
4154
+ // Fall through
4155
+ case 'KMAC256':
4156
+ result = await kmacImportKey(
4157
+ normalizedAlgorithm,
4158
+ format,
4159
+ data as BufferLike | JWK,
4160
+ extractable,
4161
+ keyUsages,
4162
+ );
4163
+ break;
4164
+ case 'AES-CTR':
4165
+ // Fall through
4166
+ case 'AES-CBC':
4167
+ // Fall through
4168
+ case 'AES-GCM':
4169
+ // Fall through
4170
+ case 'AES-KW':
4171
+ // Fall through
4172
+ case 'AES-OCB':
4173
+ // Fall through
4174
+ case 'ChaCha20-Poly1305':
4175
+ result = await aesImportKey(
4176
+ normalizedAlgorithm,
4177
+ format,
4178
+ data as BufferLike | JWK,
4179
+ extractable,
4180
+ keyUsages,
4181
+ );
4182
+ break;
4183
+ case 'PBKDF2':
4184
+ result = await pbkdf2ImportKey(
4185
+ normalizedAlgorithm,
4186
+ aliasKeyFormat(format),
4187
+ data as BufferLike | BinaryLike,
4188
+ extractable,
4189
+ keyUsages,
4190
+ );
4191
+ break;
4192
+ case 'Argon2d':
4193
+ case 'Argon2i':
4194
+ case 'Argon2id':
4195
+ result = await argon2ImportKey(
4196
+ normalizedAlgorithm,
4197
+ format,
4198
+ data as BufferLike | BinaryLike,
4199
+ extractable,
4200
+ keyUsages,
4201
+ );
4202
+ break;
4203
+ case 'HKDF':
4204
+ result = await hkdfImportKey(
4205
+ aliasKeyFormat(format),
4206
+ data as BufferLike | BinaryLike,
4207
+ normalizedAlgorithm,
4208
+ extractable,
4209
+ keyUsages,
4210
+ );
4211
+ break;
4212
+ case 'X25519':
4213
+ // Fall through
4214
+ case 'X448':
4215
+ // Fall through
4216
+ case 'Ed25519':
4217
+ // Fall through
4218
+ case 'Ed448':
4219
+ result = edImportKey(
4220
+ aliasKeyFormat(format),
4221
+ data as BufferLike | JWK,
4222
+ normalizedAlgorithm,
4223
+ extractable,
4224
+ keyUsages,
4225
+ );
4226
+ break;
4227
+ case 'SLH-DSA-SHA2-128s':
4228
+ case 'SLH-DSA-SHA2-128f':
4229
+ case 'SLH-DSA-SHA2-192s':
4230
+ case 'SLH-DSA-SHA2-192f':
4231
+ case 'SLH-DSA-SHA2-256s':
4232
+ case 'SLH-DSA-SHA2-256f':
4233
+ case 'SLH-DSA-SHAKE-128s':
4234
+ case 'SLH-DSA-SHAKE-128f':
4235
+ case 'SLH-DSA-SHAKE-192s':
4236
+ case 'SLH-DSA-SHAKE-192f':
4237
+ case 'SLH-DSA-SHAKE-256s':
4238
+ case 'SLH-DSA-SHAKE-256f':
4239
+ result = slhdsaImportKey(
4240
+ format,
4241
+ data as BufferLike | JWK,
4242
+ normalizedAlgorithm,
4243
+ extractable,
4244
+ keyUsages,
4245
+ );
4246
+ break;
4247
+ case 'ML-DSA-44':
4248
+ // Fall through
4249
+ case 'ML-DSA-65':
4250
+ // Fall through
4251
+ case 'ML-DSA-87':
4252
+ result = mldsaImportKey(
4253
+ format,
4254
+ data as BufferLike | JWK,
4255
+ normalizedAlgorithm,
4256
+ extractable,
4257
+ keyUsages,
4258
+ );
4259
+ break;
4260
+ case 'ML-KEM-512':
4261
+ // Fall through
4262
+ case 'ML-KEM-768':
4263
+ // Fall through
4264
+ case 'ML-KEM-1024':
4265
+ result = mlkemImportKey(
4266
+ format,
4267
+ data as BufferLike | JWK,
4268
+ normalizedAlgorithm,
4269
+ extractable,
4270
+ keyUsages,
4271
+ );
4272
+ break;
4273
+ default:
4274
+ throw new Error(
4275
+ `"subtle.importKey()" is not implemented for ${normalizedAlgorithm.name}`,
4276
+ );
4277
+ }
4278
+
4279
+ if (
4280
+ (result.type === 'secret' || result.type === 'private') &&
4281
+ result.usages.length === 0
4282
+ ) {
4283
+ throw new Error(
4284
+ `Usages cannot be empty when importing a ${result.type} key.`,
4285
+ );
4286
+ }
4287
+
4288
+ return result;
4289
+ }
4290
+
4291
+ async sign(
4292
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
4293
+ key: CryptoKey,
4294
+ data: BufferLike,
4295
+ ): Promise<ArrayBuffer> {
4296
+ requireArgs(arguments.length, 3, 'sign');
4297
+ return signVerify(
4298
+ normalizeAlgorithm(algorithm, 'sign'),
4299
+ key,
4300
+ data,
4301
+ ) as ArrayBuffer;
4302
+ }
4303
+
4304
+ async verify(
4305
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
4306
+ key: CryptoKey,
4307
+ signature: BufferLike,
4308
+ data: BufferLike,
4309
+ ): Promise<boolean> {
4310
+ requireArgs(arguments.length, 4, 'verify');
4311
+ return signVerify(
4312
+ normalizeAlgorithm(algorithm, 'verify'),
4313
+ key,
4314
+ data,
4315
+ signature,
4316
+ ) as boolean;
4317
+ }
4318
+
4319
+ private _encapsulateCore(
4320
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
4321
+ key: CryptoKey,
4322
+ ): EncapsulateResult {
4323
+ const normalizedAlgorithm = normalizeAlgorithm(
4324
+ algorithm,
4325
+ 'encapsulateBits' as Operation,
4326
+ );
4327
+
4328
+ if (key.algorithm.name !== normalizedAlgorithm.name) {
4329
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
4330
+ }
4331
+
4332
+ const variant = normalizedAlgorithm.name as MlKemVariant;
4333
+ const mlkem = new MlKem(variant);
4334
+
4335
+ const keyData = key.keyObject.handle.exportKey(
4336
+ KFormatType.DER,
4337
+ KeyEncoding.SPKI,
4338
+ );
4339
+ mlkem.setPublicKey(
4340
+ bufferLikeToArrayBuffer(keyData),
4341
+ KFormatType.DER,
4342
+ KeyEncoding.SPKI,
4343
+ );
4344
+
4345
+ return mlkem.encapsulateSync();
4346
+ }
4347
+
4348
+ private _decapsulateCore(
4349
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
4350
+ key: CryptoKey,
4351
+ ciphertext: BufferLike,
4352
+ ): ArrayBuffer {
4353
+ const normalizedAlgorithm = normalizeAlgorithm(
4354
+ algorithm,
4355
+ 'decapsulateBits' as Operation,
4356
+ );
4357
+
4358
+ if (key.algorithm.name !== normalizedAlgorithm.name) {
4359
+ throw lazyDOMException('Key algorithm mismatch', 'InvalidAccessError');
4360
+ }
4361
+
4362
+ const variant = normalizedAlgorithm.name as MlKemVariant;
4363
+ const mlkem = new MlKem(variant);
4364
+
4365
+ const keyData = key.keyObject.handle.exportKey(
4366
+ KFormatType.DER,
4367
+ KeyEncoding.PKCS8,
4368
+ );
4369
+ mlkem.setPrivateKey(
4370
+ bufferLikeToArrayBuffer(keyData),
4371
+ KFormatType.DER,
4372
+ KeyEncoding.PKCS8,
4373
+ );
4374
+
4375
+ return mlkem.decapsulateSync(bufferLikeToArrayBuffer(ciphertext));
4376
+ }
4377
+
4378
+ async encapsulateBits(
4379
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
4380
+ key: CryptoKey,
4381
+ ): Promise<EncapsulateResult> {
4382
+ requireArgs(arguments.length, 2, 'encapsulateBits');
4383
+ if (!key.usages.includes('encapsulateBits')) {
4384
+ throw lazyDOMException(
4385
+ 'Key does not have encapsulateBits usage',
4386
+ 'InvalidAccessError',
4387
+ );
4388
+ }
4389
+
4390
+ return this._encapsulateCore(algorithm, key);
4391
+ }
4392
+
4393
+ async encapsulateKey(
4394
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
4395
+ key: CryptoKey,
4396
+ sharedKeyAlgorithm: SubtleAlgorithm | AnyAlgorithm,
4397
+ extractable: boolean,
4398
+ usages: KeyUsage[],
4399
+ ): Promise<{ key: CryptoKey; ciphertext: ArrayBuffer }> {
4400
+ requireArgs(arguments.length, 5, 'encapsulateKey');
4401
+ if (!key.usages.includes('encapsulateKey')) {
4402
+ throw lazyDOMException(
4403
+ 'Key does not have encapsulateKey usage',
4404
+ 'InvalidAccessError',
4405
+ );
4406
+ }
4407
+
4408
+ const { sharedKey, ciphertext } = this._encapsulateCore(algorithm, key);
4409
+ // Node imports the encapsulated shared bits as 'raw-secret'
4410
+ // (webcrypto.js:1370-1374) so AEADs / KMAC accept the result.
4411
+ const importedKey = await this.importKey(
4412
+ 'raw-secret',
4413
+ sharedKey,
4414
+ sharedKeyAlgorithm,
4415
+ extractable,
4416
+ usages,
4417
+ );
4418
+
4419
+ return { key: importedKey, ciphertext };
4420
+ }
4421
+
4422
+ async decapsulateBits(
4423
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
4424
+ key: CryptoKey,
4425
+ ciphertext: BufferLike,
4426
+ ): Promise<ArrayBuffer> {
4427
+ requireArgs(arguments.length, 3, 'decapsulateBits');
4428
+ if (!key.usages.includes('decapsulateBits')) {
4429
+ throw lazyDOMException(
4430
+ 'Key does not have decapsulateBits usage',
4431
+ 'InvalidAccessError',
4432
+ );
4433
+ }
4434
+
4435
+ return this._decapsulateCore(algorithm, key, ciphertext);
4436
+ }
4437
+
4438
+ async decapsulateKey(
4439
+ algorithm: SubtleAlgorithm | AnyAlgorithm,
4440
+ key: CryptoKey,
4441
+ ciphertext: BufferLike,
4442
+ sharedKeyAlgorithm: SubtleAlgorithm | AnyAlgorithm,
4443
+ extractable: boolean,
4444
+ usages: KeyUsage[],
4445
+ ): Promise<CryptoKey> {
4446
+ requireArgs(arguments.length, 6, 'decapsulateKey');
4447
+ if (!key.usages.includes('decapsulateKey')) {
4448
+ throw lazyDOMException(
4449
+ 'Key does not have decapsulateKey usage',
4450
+ 'InvalidAccessError',
4451
+ );
4452
+ }
4453
+
4454
+ const sharedKey = this._decapsulateCore(algorithm, key, ciphertext);
4455
+ // Node imports the decapsulated shared bits as 'raw-secret'
4456
+ // (webcrypto.js:1490-1494).
4457
+ return this.importKey(
4458
+ 'raw-secret',
4459
+ sharedKey,
4460
+ sharedKeyAlgorithm,
4461
+ extractable,
4462
+ usages,
4463
+ );
4464
+ }
4465
+ }
4466
+
4467
+ export const subtle = new Subtle();
4468
+
4469
+ // Returns the number of bits to derive for an `importKey` algorithm, mirroring
4470
+ // Node's webcrypto.js:269-306 `getKeyLength`. Returns null for KDF algorithms
4471
+ // (HKDF / PBKDF2 / Argon2) — those carry their full derived secret without a
4472
+ // fixed key length. Throws OperationError on invalid AES / HMAC inputs rather
4473
+ // than silently coercing to a default (Node commit 4cb1f284136 behavior).
4474
+ function getKeyLength(algorithm: SubtleAlgorithm): number | null {
4475
+ const name = algorithm.name;
4476
+ const length = (algorithm as { length?: number }).length;
4477
+
4478
+ switch (name) {
4479
+ case 'AES-CTR':
4480
+ case 'AES-CBC':
4481
+ case 'AES-GCM':
4482
+ case 'AES-KW':
4483
+ case 'AES-OCB':
4484
+ if (length !== 128 && length !== 192 && length !== 256) {
4485
+ throw lazyDOMException('Invalid key length', 'OperationError');
4486
+ }
4487
+ return length;
4488
+
4489
+ case 'HMAC': {
4490
+ if (length === undefined) {
4491
+ return getHmacBlockSize(
4492
+ (algorithm.hash as { name?: string } | undefined)?.name ??
4493
+ (algorithm.hash as string | undefined),
4494
+ );
4495
+ }
4496
+ if (typeof length === 'number' && length !== 0) {
4497
+ return length;
4498
+ }
4499
+ throw lazyDOMException('Invalid key length', 'OperationError');
4500
+ }
4501
+
4502
+ case 'KMAC128':
4503
+ return typeof length === 'number' ? length : 128;
4504
+ case 'KMAC256':
4505
+ return typeof length === 'number' ? length : 256;
4506
+
4507
+ case 'ChaCha20-Poly1305':
4508
+ return 256;
4509
+
4510
+ case 'HKDF':
4511
+ case 'PBKDF2':
4512
+ case 'Argon2d':
4513
+ case 'Argon2i':
4514
+ case 'Argon2id':
4515
+ return null;
4516
+
4517
+ default:
4518
+ throw lazyDOMException(
4519
+ `Cannot determine key length for ${name}`,
4520
+ 'NotSupportedError',
4521
+ );
4522
+ }
4523
+ }
4524
+
4525
+ function getHmacBlockSize(name: string | undefined): number {
4526
+ switch (name) {
4527
+ case 'SHA-1':
4528
+ case 'SHA-256':
4529
+ return 512;
4530
+ case 'SHA-384':
4531
+ case 'SHA-512':
4532
+ return 1024;
4533
+ case 'SHA3-256':
4534
+ case 'SHA3-384':
4535
+ case 'SHA3-512':
4536
+ // SHA-3 / HMAC interaction undefined — Node throws here too
4537
+ // (webcrypto-modern-algos issue #23).
4538
+ throw lazyDOMException(
4539
+ 'Explicit algorithm length member is required',
4540
+ 'NotSupportedError',
4541
+ );
4542
+ default:
4543
+ throw lazyDOMException('Invalid key length', 'OperationError');
4544
+ }
4545
+ }