react-native-quick-crypto 1.0.0-beta.8 → 1.0.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.
- package/QuickCrypto.podspec +145 -6
- package/README.md +14 -27
- package/android/CMakeLists.txt +62 -7
- package/android/build.gradle +12 -2
- package/android/src/main/java/com/margelo/nitro/quickcrypto/QuickCryptoPackage.java +0 -2
- package/app.plugin.js +3 -0
- package/cpp/blake3/HybridBlake3.cpp +118 -0
- package/cpp/blake3/HybridBlake3.hpp +35 -0
- package/cpp/cipher/CCMCipher.cpp +199 -0
- package/cpp/cipher/CCMCipher.hpp +26 -0
- package/cpp/cipher/ChaCha20Cipher.cpp +97 -0
- package/cpp/cipher/ChaCha20Cipher.hpp +25 -0
- package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +170 -0
- package/cpp/cipher/ChaCha20Poly1305Cipher.hpp +30 -0
- package/cpp/cipher/GCMCipher.cpp +68 -0
- package/cpp/cipher/GCMCipher.hpp +14 -0
- package/cpp/cipher/HybridCipher.cpp +322 -0
- package/cpp/cipher/HybridCipher.hpp +68 -0
- package/cpp/cipher/HybridCipherFactory.hpp +105 -0
- package/cpp/cipher/HybridRsaCipher.cpp +348 -0
- package/cpp/cipher/HybridRsaCipher.hpp +29 -0
- package/cpp/cipher/OCBCipher.cpp +55 -0
- package/cpp/cipher/OCBCipher.hpp +19 -0
- package/cpp/cipher/XSalsa20Cipher.cpp +61 -0
- package/cpp/cipher/XSalsa20Cipher.hpp +33 -0
- package/cpp/ec/HybridEcKeyPair.cpp +428 -0
- package/cpp/ec/HybridEcKeyPair.hpp +48 -0
- package/cpp/ed25519/HybridEdKeyPair.cpp +228 -98
- package/cpp/ed25519/HybridEdKeyPair.hpp +42 -56
- package/cpp/hash/HybridHash.cpp +185 -0
- package/cpp/hash/HybridHash.hpp +43 -0
- package/cpp/hmac/HybridHmac.cpp +95 -0
- package/cpp/hmac/HybridHmac.hpp +31 -0
- package/cpp/keys/HybridKeyObjectHandle.cpp +749 -0
- package/cpp/keys/HybridKeyObjectHandle.hpp +51 -0
- package/cpp/keys/KeyObjectData.cpp +268 -0
- package/cpp/keys/KeyObjectData.hpp +71 -0
- package/cpp/keys/node.h +5 -0
- package/cpp/pbkdf2/HybridPbkdf2.cpp +34 -55
- package/cpp/pbkdf2/HybridPbkdf2.hpp +5 -16
- package/cpp/random/HybridRandom.cpp +6 -17
- package/cpp/random/HybridRandom.hpp +5 -6
- package/cpp/rsa/HybridRsaKeyPair.cpp +154 -0
- package/cpp/rsa/HybridRsaKeyPair.hpp +43 -0
- package/cpp/sign/HybridSignHandle.cpp +191 -0
- package/cpp/sign/HybridSignHandle.hpp +36 -0
- package/cpp/sign/HybridVerifyHandle.cpp +158 -0
- package/cpp/sign/HybridVerifyHandle.hpp +36 -0
- package/cpp/sign/SignUtils.hpp +108 -0
- package/cpp/utils/Macros.hpp +68 -0
- package/cpp/utils/Utils.hpp +43 -2
- package/cpp/utils/base64.h +309 -0
- package/deps/blake3/.cargo/config.toml +2 -0
- package/deps/blake3/.git-blame-ignore-revs +2 -0
- package/deps/blake3/.github/workflows/build_b3sum.py +38 -0
- package/deps/blake3/.github/workflows/ci.yml +491 -0
- package/deps/blake3/.github/workflows/tag.yml +43 -0
- package/deps/blake3/.github/workflows/upload_github_release_asset.py +73 -0
- package/deps/blake3/CONTRIBUTING.md +31 -0
- package/deps/blake3/Cargo.toml +135 -0
- package/deps/blake3/LICENSE_A2 +202 -0
- package/deps/blake3/LICENSE_A2LLVM +219 -0
- package/deps/blake3/LICENSE_CC0 +121 -0
- package/deps/blake3/README.md +229 -0
- package/deps/blake3/b3sum/Cargo.lock +513 -0
- package/deps/blake3/b3sum/Cargo.toml +26 -0
- package/deps/blake3/b3sum/README.md +72 -0
- package/deps/blake3/b3sum/src/main.rs +564 -0
- package/deps/blake3/b3sum/src/unit_tests.rs +235 -0
- package/deps/blake3/b3sum/tests/cli_tests.rs +680 -0
- package/deps/blake3/b3sum/what_does_check_do.md +176 -0
- package/deps/blake3/benches/bench.rs +623 -0
- package/deps/blake3/build.rs +389 -0
- package/deps/blake3/c/CMakeLists.txt +383 -0
- package/deps/blake3/c/CMakePresets.json +73 -0
- package/deps/blake3/c/Makefile.testing +82 -0
- package/deps/blake3/c/README.md +403 -0
- package/deps/blake3/c/blake3-config.cmake.in +14 -0
- package/deps/blake3/c/blake3.c +650 -0
- package/deps/blake3/c/blake3.h +86 -0
- package/deps/blake3/c/blake3_avx2.c +326 -0
- package/deps/blake3/c/blake3_avx2_x86-64_unix.S +1815 -0
- package/deps/blake3/c/blake3_avx2_x86-64_windows_gnu.S +1817 -0
- package/deps/blake3/c/blake3_avx2_x86-64_windows_msvc.asm +1828 -0
- package/deps/blake3/c/blake3_avx512.c +1388 -0
- package/deps/blake3/c/blake3_avx512_x86-64_unix.S +4824 -0
- package/deps/blake3/c/blake3_avx512_x86-64_windows_gnu.S +2615 -0
- package/deps/blake3/c/blake3_avx512_x86-64_windows_msvc.asm +2634 -0
- package/deps/blake3/c/blake3_c_rust_bindings/Cargo.toml +32 -0
- package/deps/blake3/c/blake3_c_rust_bindings/README.md +4 -0
- package/deps/blake3/c/blake3_c_rust_bindings/benches/bench.rs +477 -0
- package/deps/blake3/c/blake3_c_rust_bindings/build.rs +253 -0
- package/deps/blake3/c/blake3_c_rust_bindings/cross_test.sh +31 -0
- package/deps/blake3/c/blake3_c_rust_bindings/src/lib.rs +333 -0
- package/deps/blake3/c/blake3_c_rust_bindings/src/test.rs +696 -0
- package/deps/blake3/c/blake3_dispatch.c +332 -0
- package/deps/blake3/c/blake3_impl.h +333 -0
- package/deps/blake3/c/blake3_neon.c +366 -0
- package/deps/blake3/c/blake3_portable.c +160 -0
- package/deps/blake3/c/blake3_sse2.c +566 -0
- package/deps/blake3/c/blake3_sse2_x86-64_unix.S +2291 -0
- package/deps/blake3/c/blake3_sse2_x86-64_windows_gnu.S +2332 -0
- package/deps/blake3/c/blake3_sse2_x86-64_windows_msvc.asm +2350 -0
- package/deps/blake3/c/blake3_sse41.c +560 -0
- package/deps/blake3/c/blake3_sse41_x86-64_unix.S +2028 -0
- package/deps/blake3/c/blake3_sse41_x86-64_windows_gnu.S +2069 -0
- package/deps/blake3/c/blake3_sse41_x86-64_windows_msvc.asm +2089 -0
- package/deps/blake3/c/blake3_tbb.cpp +37 -0
- package/deps/blake3/c/dependencies/CMakeLists.txt +3 -0
- package/deps/blake3/c/dependencies/tbb/CMakeLists.txt +28 -0
- package/deps/blake3/c/example.c +36 -0
- package/deps/blake3/c/example_tbb.c +57 -0
- package/deps/blake3/c/libblake3.pc.in +12 -0
- package/deps/blake3/c/main.c +166 -0
- package/deps/blake3/c/test.py +97 -0
- package/deps/blake3/media/B3.svg +70 -0
- package/deps/blake3/media/BLAKE3.svg +85 -0
- package/deps/blake3/media/speed.svg +1474 -0
- package/deps/blake3/reference_impl/Cargo.toml +8 -0
- package/deps/blake3/reference_impl/README.md +14 -0
- package/deps/blake3/reference_impl/reference_impl.rs +374 -0
- package/deps/blake3/src/ffi_avx2.rs +65 -0
- package/deps/blake3/src/ffi_avx512.rs +169 -0
- package/deps/blake3/src/ffi_neon.rs +82 -0
- package/deps/blake3/src/ffi_sse2.rs +126 -0
- package/deps/blake3/src/ffi_sse41.rs +126 -0
- package/deps/blake3/src/guts.rs +60 -0
- package/deps/blake3/src/hazmat.rs +704 -0
- package/deps/blake3/src/io.rs +64 -0
- package/deps/blake3/src/join.rs +92 -0
- package/deps/blake3/src/lib.rs +1835 -0
- package/deps/blake3/src/platform.rs +587 -0
- package/deps/blake3/src/portable.rs +198 -0
- package/deps/blake3/src/rust_avx2.rs +474 -0
- package/deps/blake3/src/rust_sse2.rs +775 -0
- package/deps/blake3/src/rust_sse41.rs +766 -0
- package/deps/blake3/src/test.rs +1049 -0
- package/deps/blake3/src/traits.rs +227 -0
- package/deps/blake3/src/wasm32_simd.rs +794 -0
- package/deps/blake3/test_vectors/Cargo.toml +19 -0
- package/deps/blake3/test_vectors/cross_test.sh +25 -0
- package/deps/blake3/test_vectors/src/bin/generate.rs +4 -0
- package/deps/blake3/test_vectors/src/lib.rs +350 -0
- package/deps/blake3/test_vectors/test_vectors.json +217 -0
- package/deps/blake3/tools/compiler_version/Cargo.toml +7 -0
- package/deps/blake3/tools/compiler_version/build.rs +6 -0
- package/deps/blake3/tools/compiler_version/src/main.rs +27 -0
- package/deps/blake3/tools/instruction_set_support/Cargo.toml +6 -0
- package/deps/blake3/tools/instruction_set_support/src/main.rs +10 -0
- package/deps/blake3/tools/release.md +16 -0
- package/deps/fastpbkdf2/fastpbkdf2.c +5 -1
- package/deps/ncrypto/ncrypto.cc +4679 -0
- package/deps/ncrypto/ncrypto.h +1625 -0
- package/lib/commonjs/blake3.js +98 -0
- package/lib/commonjs/blake3.js.map +1 -0
- package/lib/commonjs/cipher.js +180 -0
- package/lib/commonjs/cipher.js.map +1 -0
- package/lib/commonjs/constants.js +32 -0
- package/lib/commonjs/constants.js.map +1 -0
- package/lib/commonjs/ec.js +480 -0
- package/lib/commonjs/ec.js.map +1 -0
- package/lib/commonjs/ed.js +214 -2
- package/lib/commonjs/ed.js.map +1 -1
- package/lib/commonjs/expo-plugin/@types.js +2 -0
- package/lib/commonjs/expo-plugin/@types.js.map +1 -0
- package/lib/commonjs/expo-plugin/withRNQC.js +25 -0
- package/lib/commonjs/expo-plugin/withRNQC.js.map +1 -0
- package/lib/commonjs/expo-plugin/withSodiumAndroid.js +25 -0
- package/lib/commonjs/expo-plugin/withSodiumAndroid.js.map +1 -0
- package/lib/commonjs/expo-plugin/withSodiumIos.js +26 -0
- package/lib/commonjs/expo-plugin/withSodiumIos.js.map +1 -0
- package/lib/commonjs/expo-plugin/withXCode.js +51 -0
- package/lib/commonjs/expo-plugin/withXCode.js.map +1 -0
- package/lib/commonjs/hash.js +215 -0
- package/lib/commonjs/hash.js.map +1 -0
- package/lib/commonjs/hmac.js +109 -0
- package/lib/commonjs/hmac.js.map +1 -0
- package/lib/commonjs/index.js +102 -24
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/keys/classes.js +109 -52
- package/lib/commonjs/keys/classes.js.map +1 -1
- package/lib/commonjs/keys/generateKeyPair.js +141 -144
- package/lib/commonjs/keys/generateKeyPair.js.map +1 -1
- package/lib/commonjs/keys/index.js +229 -0
- package/lib/commonjs/keys/index.js.map +1 -1
- package/lib/commonjs/keys/publicCipher.js +152 -0
- package/lib/commonjs/keys/publicCipher.js.map +1 -0
- package/lib/commonjs/keys/signVerify.js +178 -39
- package/lib/commonjs/keys/signVerify.js.map +1 -1
- package/lib/commonjs/keys/utils.js +18 -13
- package/lib/commonjs/keys/utils.js.map +1 -1
- package/lib/commonjs/pbkdf2.js.map +1 -1
- package/lib/commonjs/random.js +6 -0
- package/lib/commonjs/random.js.map +1 -1
- package/lib/commonjs/rsa.js +202 -0
- package/lib/commonjs/rsa.js.map +1 -0
- package/lib/commonjs/specs/blake3.nitro.js +6 -0
- package/lib/commonjs/specs/blake3.nitro.js.map +1 -0
- package/lib/commonjs/specs/cipher.nitro.js +6 -0
- package/lib/commonjs/specs/cipher.nitro.js.map +1 -0
- package/lib/commonjs/specs/ecKeyPair.nitro.js +6 -0
- package/lib/commonjs/specs/ecKeyPair.nitro.js.map +1 -0
- package/lib/commonjs/specs/hash.nitro.js +6 -0
- package/lib/commonjs/specs/hash.nitro.js.map +1 -0
- package/lib/commonjs/specs/hmac.nitro.js +6 -0
- package/lib/commonjs/specs/hmac.nitro.js.map +1 -0
- package/lib/commonjs/specs/rsaCipher.nitro.js +6 -0
- package/lib/commonjs/specs/rsaCipher.nitro.js.map +1 -0
- package/lib/commonjs/specs/rsaKeyPair.nitro.js +6 -0
- package/lib/commonjs/specs/rsaKeyPair.nitro.js.map +1 -0
- package/lib/commonjs/specs/sign.nitro.js +6 -0
- package/lib/commonjs/specs/sign.nitro.js.map +1 -0
- package/lib/commonjs/subtle.js +987 -0
- package/lib/commonjs/subtle.js.map +1 -0
- package/lib/commonjs/utils/cipher.js +64 -0
- package/lib/commonjs/utils/cipher.js.map +1 -0
- package/lib/commonjs/utils/conversion.js +44 -5
- package/lib/commonjs/utils/conversion.js.map +1 -1
- package/lib/commonjs/utils/hashnames.js +2 -1
- package/lib/commonjs/utils/hashnames.js.map +1 -1
- package/lib/commonjs/utils/index.js +11 -0
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/commonjs/utils/noble.js +82 -0
- package/lib/commonjs/utils/noble.js.map +1 -0
- package/lib/commonjs/utils/types.js +32 -17
- package/lib/commonjs/utils/types.js.map +1 -1
- package/lib/commonjs/utils/validation.js +74 -1
- package/lib/commonjs/utils/validation.js.map +1 -1
- package/lib/module/blake3.js +90 -0
- package/lib/module/blake3.js.map +1 -0
- package/lib/module/cipher.js +173 -0
- package/lib/module/cipher.js.map +1 -0
- package/lib/module/constants.js +28 -0
- package/lib/module/constants.js.map +1 -0
- package/lib/module/ec.js +470 -0
- package/lib/module/ec.js.map +1 -0
- package/lib/module/ed.js +212 -3
- package/lib/module/ed.js.map +1 -1
- package/lib/module/expo-plugin/@types.js +2 -0
- package/lib/module/expo-plugin/@types.js.map +1 -0
- package/lib/module/expo-plugin/withRNQC.js +21 -0
- package/lib/module/expo-plugin/withRNQC.js.map +1 -0
- package/lib/module/expo-plugin/withSodiumAndroid.js +20 -0
- package/lib/module/expo-plugin/withSodiumAndroid.js.map +1 -0
- package/lib/module/expo-plugin/withSodiumIos.js +20 -0
- package/lib/module/expo-plugin/withSodiumIos.js.map +1 -0
- package/lib/module/expo-plugin/withXCode.js +46 -0
- package/lib/module/expo-plugin/withXCode.js.map +1 -0
- package/lib/module/hash.js +207 -0
- package/lib/module/hash.js.map +1 -0
- package/lib/module/hmac.js +104 -0
- package/lib/module/hmac.js.map +1 -0
- package/lib/module/index.js +21 -21
- package/lib/module/index.js.map +1 -1
- package/lib/module/keys/classes.js +106 -49
- package/lib/module/keys/classes.js.map +1 -1
- package/lib/module/keys/generateKeyPair.js +134 -143
- package/lib/module/keys/generateKeyPair.js.map +1 -1
- package/lib/module/keys/index.js +161 -22
- package/lib/module/keys/index.js.map +1 -1
- package/lib/module/keys/publicCipher.js +145 -0
- package/lib/module/keys/publicCipher.js.map +1 -0
- package/lib/module/keys/signVerify.js +170 -39
- package/lib/module/keys/signVerify.js.map +1 -1
- package/lib/module/keys/utils.js +16 -12
- package/lib/module/keys/utils.js.map +1 -1
- package/lib/module/pbkdf2.js.map +1 -1
- package/lib/module/random.js +6 -0
- package/lib/module/random.js.map +1 -1
- package/lib/module/rsa.js +194 -0
- package/lib/module/rsa.js.map +1 -0
- package/lib/module/specs/blake3.nitro.js +4 -0
- package/lib/module/specs/blake3.nitro.js.map +1 -0
- package/lib/module/specs/cipher.nitro.js +4 -0
- package/lib/module/specs/cipher.nitro.js.map +1 -0
- package/lib/module/specs/ecKeyPair.nitro.js +4 -0
- package/lib/module/specs/ecKeyPair.nitro.js.map +1 -0
- package/lib/module/specs/hash.nitro.js +4 -0
- package/lib/module/specs/hash.nitro.js.map +1 -0
- package/lib/module/specs/hmac.nitro.js +4 -0
- package/lib/module/specs/hmac.nitro.js.map +1 -0
- package/lib/module/specs/rsaCipher.nitro.js +4 -0
- package/lib/module/specs/rsaCipher.nitro.js.map +1 -0
- package/lib/module/specs/rsaKeyPair.nitro.js +4 -0
- package/lib/module/specs/rsaKeyPair.nitro.js.map +1 -0
- package/lib/module/specs/sign.nitro.js +4 -0
- package/lib/module/specs/sign.nitro.js.map +1 -0
- package/lib/module/subtle.js +982 -0
- package/lib/module/subtle.js.map +1 -0
- package/lib/module/utils/cipher.js +56 -0
- package/lib/module/utils/cipher.js.map +1 -0
- package/lib/module/utils/conversion.js +26 -5
- package/lib/module/utils/conversion.js.map +1 -1
- package/lib/module/utils/hashnames.js +2 -1
- package/lib/module/utils/hashnames.js.map +1 -1
- package/lib/module/utils/index.js +1 -0
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/utils/noble.js +76 -0
- package/lib/module/utils/noble.js.map +1 -0
- package/lib/module/utils/types.js +32 -17
- package/lib/module/utils/types.js.map +1 -1
- package/lib/module/utils/validation.js +69 -1
- package/lib/module/utils/validation.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/typescript/blake3.d.ts +33 -0
- package/lib/typescript/blake3.d.ts.map +1 -0
- package/lib/typescript/cipher.d.ts +60 -0
- package/lib/typescript/cipher.d.ts.map +1 -0
- package/lib/typescript/constants.d.ts +21 -0
- package/lib/typescript/constants.d.ts.map +1 -0
- package/lib/typescript/ec.d.ts +22 -0
- package/lib/typescript/ec.d.ts.map +1 -0
- package/lib/typescript/ed.d.ts +28 -1
- package/lib/typescript/ed.d.ts.map +1 -1
- package/lib/typescript/expo-plugin/@types.d.ts +8 -0
- package/lib/typescript/expo-plugin/@types.d.ts.map +1 -0
- package/lib/typescript/expo-plugin/withRNQC.d.ts +4 -0
- package/lib/typescript/expo-plugin/withRNQC.d.ts.map +1 -0
- package/lib/typescript/expo-plugin/withSodiumAndroid.d.ts +4 -0
- package/lib/typescript/expo-plugin/withSodiumAndroid.d.ts.map +1 -0
- package/lib/typescript/expo-plugin/withSodiumIos.d.ts +4 -0
- package/lib/typescript/expo-plugin/withSodiumIos.d.ts.map +1 -0
- package/lib/typescript/expo-plugin/withXCode.d.ts +9 -0
- package/lib/typescript/expo-plugin/withXCode.d.ts.map +1 -0
- package/lib/typescript/hash.d.ts +122 -0
- package/lib/typescript/hash.d.ts.map +1 -0
- package/lib/typescript/hmac.d.ts +66 -0
- package/lib/typescript/hmac.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +102 -10
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keys/classes.d.ts +50 -8
- package/lib/typescript/keys/classes.d.ts.map +1 -1
- package/lib/typescript/keys/generateKeyPair.d.ts +5 -0
- package/lib/typescript/keys/generateKeyPair.d.ts.map +1 -1
- package/lib/typescript/keys/index.d.ts +22 -2
- package/lib/typescript/keys/index.d.ts.map +1 -1
- package/lib/typescript/keys/publicCipher.d.ts +20 -0
- package/lib/typescript/keys/publicCipher.d.ts.map +1 -0
- package/lib/typescript/keys/signVerify.d.ts +28 -0
- package/lib/typescript/keys/signVerify.d.ts.map +1 -1
- package/lib/typescript/keys/utils.d.ts +3 -1
- package/lib/typescript/keys/utils.d.ts.map +1 -1
- package/lib/typescript/pbkdf2.d.ts +1 -1
- package/lib/typescript/pbkdf2.d.ts.map +1 -1
- package/lib/typescript/random.d.ts +6 -0
- package/lib/typescript/random.d.ts.map +1 -1
- package/lib/typescript/rsa.d.ts +19 -0
- package/lib/typescript/rsa.d.ts.map +1 -0
- package/lib/typescript/specs/blake3.nitro.d.ts +15 -0
- package/lib/typescript/specs/blake3.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/cipher.nitro.d.ts +29 -0
- package/lib/typescript/specs/cipher.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/ecKeyPair.nitro.d.ts +20 -0
- package/lib/typescript/specs/ecKeyPair.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/edKeyPair.nitro.d.ts +1 -0
- package/lib/typescript/specs/edKeyPair.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/hash.nitro.d.ts +13 -0
- package/lib/typescript/specs/hash.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/hmac.nitro.d.ts +10 -0
- package/lib/typescript/specs/hmac.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +1 -1
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/rsaCipher.nitro.d.ts +44 -0
- package/lib/typescript/specs/rsaCipher.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/rsaKeyPair.nitro.d.ts +20 -0
- package/lib/typescript/specs/rsaKeyPair.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/sign.nitro.d.ts +19 -0
- package/lib/typescript/specs/sign.nitro.d.ts.map +1 -0
- package/lib/typescript/subtle.d.ts +17 -0
- package/lib/typescript/subtle.d.ts.map +1 -0
- package/lib/typescript/utils/cipher.d.ts +7 -0
- package/lib/typescript/utils/cipher.d.ts.map +1 -0
- package/lib/typescript/utils/conversion.d.ts +1 -0
- package/lib/typescript/utils/conversion.d.ts.map +1 -1
- package/lib/typescript/utils/hashnames.d.ts +3 -1
- package/lib/typescript/utils/hashnames.d.ts.map +1 -1
- package/lib/typescript/utils/index.d.ts +1 -0
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/lib/typescript/utils/noble.d.ts +19 -0
- package/lib/typescript/utils/noble.d.ts.map +1 -0
- package/lib/typescript/utils/types.d.ts +125 -23
- package/lib/typescript/utils/types.d.ts.map +1 -1
- package/lib/typescript/utils/validation.d.ts +5 -0
- package/lib/typescript/utils/validation.d.ts.map +1 -1
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +30 -1
- package/nitrogen/generated/android/QuickCrypto+autolinking.gradle +1 -1
- package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +115 -1
- package/nitrogen/generated/android/QuickCryptoOnLoad.hpp +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/crypto/QuickCryptoOnLoad.kt +35 -0
- package/nitrogen/generated/ios/QuickCrypto+autolinking.rb +3 -1
- package/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.cpp +1 -1
- package/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.hpp +1 -1
- package/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Umbrella.hpp +3 -3
- package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +111 -1
- package/nitrogen/generated/ios/QuickCryptoAutolinking.swift +1 -1
- package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +104 -0
- package/nitrogen/generated/shared/c++/CipherArgs.hpp +86 -0
- package/nitrogen/generated/shared/c++/HybridBlake3Spec.cpp +28 -0
- package/nitrogen/generated/shared/c++/HybridBlake3Spec.hpp +76 -0
- package/nitrogen/generated/shared/c++/HybridCipherFactorySpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridCipherFactorySpec.hpp +67 -0
- package/nitrogen/generated/shared/c++/HybridCipherSpec.cpp +28 -0
- package/nitrogen/generated/shared/c++/HybridCipherSpec.hpp +76 -0
- package/nitrogen/generated/shared/c++/HybridEcKeyPairSpec.cpp +29 -0
- package/nitrogen/generated/shared/c++/HybridEcKeyPairSpec.hpp +77 -0
- package/nitrogen/generated/shared/c++/HybridEdKeyPairSpec.cpp +2 -1
- package/nitrogen/generated/shared/c++/HybridEdKeyPairSpec.hpp +5 -4
- package/nitrogen/generated/shared/c++/HybridHashSpec.cpp +26 -0
- package/nitrogen/generated/shared/c++/HybridHashSpec.hpp +75 -0
- package/nitrogen/generated/shared/c++/HybridHmacSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridHmacSpec.hpp +66 -0
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +8 -8
- package/nitrogen/generated/shared/c++/HybridPbkdf2Spec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridPbkdf2Spec.hpp +3 -3
- package/nitrogen/generated/shared/c++/HybridRandomSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridRandomSpec.hpp +3 -3
- package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.cpp +24 -0
- package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.hpp +72 -0
- package/nitrogen/generated/shared/c++/HybridRsaKeyPairSpec.cpp +29 -0
- package/nitrogen/generated/shared/c++/HybridRsaKeyPairSpec.hpp +77 -0
- package/nitrogen/generated/shared/c++/HybridSignHandleSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridSignHandleSpec.hpp +71 -0
- package/nitrogen/generated/shared/c++/HybridVerifyHandleSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridVerifyHandleSpec.hpp +71 -0
- package/nitrogen/generated/shared/c++/JWK.hpp +17 -18
- package/nitrogen/generated/shared/c++/JWKkty.hpp +12 -14
- package/nitrogen/generated/shared/c++/JWKuse.hpp +8 -10
- package/nitrogen/generated/shared/c++/KFormatType.hpp +14 -16
- package/nitrogen/generated/shared/c++/KeyDetail.hpp +6 -7
- package/nitrogen/generated/shared/c++/KeyEncoding.hpp +15 -17
- package/nitrogen/generated/shared/c++/KeyObject.hpp +67 -0
- package/nitrogen/generated/shared/c++/KeyType.hpp +11 -13
- package/nitrogen/generated/shared/c++/KeyUsage.hpp +38 -24
- package/nitrogen/generated/shared/c++/NamedCurve.hpp +10 -12
- package/package.json +28 -23
- package/src/blake3.ts +123 -0
- package/src/cipher.ts +335 -0
- package/src/constants.ts +32 -0
- package/src/ec.ts +657 -0
- package/src/ed.ts +297 -13
- package/src/expo-plugin/@types.ts +7 -0
- package/src/expo-plugin/withRNQC.ts +23 -0
- package/src/expo-plugin/withSodiumAndroid.ts +24 -0
- package/src/expo-plugin/withSodiumIos.ts +30 -0
- package/src/expo-plugin/withXCode.ts +55 -0
- package/src/hash.ts +274 -0
- package/src/hmac.ts +135 -0
- package/src/index.ts +20 -20
- package/src/keys/classes.ts +148 -55
- package/src/keys/generateKeyPair.ts +177 -134
- package/src/keys/index.ts +226 -14
- package/src/keys/publicCipher.ts +229 -0
- package/src/keys/signVerify.ts +239 -39
- package/src/keys/utils.ts +24 -18
- package/src/pbkdf2.ts +1 -1
- package/src/random.ts +7 -0
- package/src/rsa.ts +310 -0
- package/src/specs/blake3.nitro.ts +12 -0
- package/src/specs/cipher.nitro.ts +25 -0
- package/src/specs/ecKeyPair.nitro.ts +38 -0
- package/src/specs/edKeyPair.nitro.ts +2 -0
- package/src/specs/hash.nitro.ts +10 -0
- package/src/specs/hmac.nitro.ts +7 -0
- package/src/specs/keyObjectHandle.nitro.ts +1 -1
- package/src/specs/rsaCipher.nitro.ts +65 -0
- package/src/specs/rsaKeyPair.nitro.ts +33 -0
- package/src/specs/sign.nitro.ts +31 -0
- package/src/subtle.ts +1436 -0
- package/src/utils/cipher.ts +60 -0
- package/src/utils/conversion.ts +33 -4
- package/src/utils/hashnames.ts +4 -2
- package/src/utils/index.ts +1 -0
- package/src/utils/noble.ts +85 -0
- package/src/utils/types.ts +209 -29
- package/src/utils/validation.ts +96 -1
- package/lib/module/package.json +0 -1
- package/nitrogen/generated/android/QuickCryptoOnLoad.kt +0 -1
- package/nitrogen/generated/shared/c++/CFRGKeyPairType.hpp +0 -86
package/src/subtle.ts
ADDED
|
@@ -0,0 +1,1436 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
2
|
+
import { Buffer as SBuffer } from 'safe-buffer';
|
|
3
|
+
import type {
|
|
4
|
+
SubtleAlgorithm,
|
|
5
|
+
KeyUsage,
|
|
6
|
+
BinaryLike,
|
|
7
|
+
BufferLike,
|
|
8
|
+
JWK,
|
|
9
|
+
AnyAlgorithm,
|
|
10
|
+
ImportFormat,
|
|
11
|
+
AesKeyGenParams,
|
|
12
|
+
EncryptDecryptParams,
|
|
13
|
+
Operation,
|
|
14
|
+
AesCtrParams,
|
|
15
|
+
AesCbcParams,
|
|
16
|
+
AesGcmParams,
|
|
17
|
+
RsaOaepParams,
|
|
18
|
+
} from './utils';
|
|
19
|
+
import { KFormatType, KeyEncoding } from './utils';
|
|
20
|
+
import {
|
|
21
|
+
CryptoKey,
|
|
22
|
+
KeyObject,
|
|
23
|
+
PublicKeyObject,
|
|
24
|
+
PrivateKeyObject,
|
|
25
|
+
SecretKeyObject,
|
|
26
|
+
} from './keys';
|
|
27
|
+
import type { CryptoKeyPair } from './utils/types';
|
|
28
|
+
import { bufferLikeToArrayBuffer } from './utils/conversion';
|
|
29
|
+
import { lazyDOMException } from './utils/errors';
|
|
30
|
+
import { normalizeHashName, HashContext } from './utils/hashnames';
|
|
31
|
+
import { validateMaxBufferLength } from './utils/validation';
|
|
32
|
+
import { asyncDigest } from './hash';
|
|
33
|
+
import { createSecretKey } from './keys';
|
|
34
|
+
import { NitroModules } from 'react-native-nitro-modules';
|
|
35
|
+
import type { KeyObjectHandle } from './specs/keyObjectHandle.nitro';
|
|
36
|
+
import type { RsaCipher } from './specs/rsaCipher.nitro';
|
|
37
|
+
import type { CipherFactory } from './specs/cipher.nitro';
|
|
38
|
+
import { pbkdf2DeriveBits } from './pbkdf2';
|
|
39
|
+
import { ecImportKey, ecdsaSignVerify, ec_generateKeyPair } from './ec';
|
|
40
|
+
import { rsa_generateKeyPair } from './rsa';
|
|
41
|
+
import { getRandomValues } from './random';
|
|
42
|
+
import { createHmac } from './hmac';
|
|
43
|
+
import { createSign, createVerify } from './keys/signVerify';
|
|
44
|
+
import { ed_generateKeyPairWebCrypto, Ed } from './ed';
|
|
45
|
+
// import { pbkdf2DeriveBits } from './pbkdf2';
|
|
46
|
+
// import { aesCipher, aesGenerateKey, aesImportKey, getAlgorithmName } from './aes';
|
|
47
|
+
// import { rsaCipher, rsaExportKey, rsaImportKey, rsaKeyGenerate } from './rsa';
|
|
48
|
+
// import { normalizeAlgorithm, type Operation } from './algorithms';
|
|
49
|
+
// import { hmacImportKey } from './mac';
|
|
50
|
+
|
|
51
|
+
// Temporary enums that need to be defined
|
|
52
|
+
|
|
53
|
+
enum KWebCryptoKeyFormat {
|
|
54
|
+
kWebCryptoKeyFormatRaw,
|
|
55
|
+
kWebCryptoKeyFormatSPKI,
|
|
56
|
+
kWebCryptoKeyFormatPKCS8,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
enum CipherOrWrapMode {
|
|
60
|
+
kWebCryptoCipherEncrypt,
|
|
61
|
+
kWebCryptoCipherDecrypt,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Placeholder functions that need to be implemented
|
|
65
|
+
function hasAnyNotIn(usages: KeyUsage[], allowed: KeyUsage[]): boolean {
|
|
66
|
+
return usages.some(usage => !allowed.includes(usage));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalizeAlgorithm(
|
|
70
|
+
algorithm: SubtleAlgorithm | AnyAlgorithm,
|
|
71
|
+
_operation: Operation,
|
|
72
|
+
): SubtleAlgorithm {
|
|
73
|
+
if (typeof algorithm === 'string') {
|
|
74
|
+
return { name: algorithm };
|
|
75
|
+
}
|
|
76
|
+
return algorithm as SubtleAlgorithm;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getAlgorithmName(name: string, length: number): string {
|
|
80
|
+
return `${name}${length}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Placeholder implementations for missing functions
|
|
84
|
+
function ecExportKey(key: CryptoKey, format: KWebCryptoKeyFormat): ArrayBuffer {
|
|
85
|
+
const keyObject = key.keyObject;
|
|
86
|
+
|
|
87
|
+
if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI) {
|
|
88
|
+
// Export public key in SPKI format
|
|
89
|
+
const exported = keyObject.export({ format: 'der', type: 'spki' });
|
|
90
|
+
return bufferLikeToArrayBuffer(exported);
|
|
91
|
+
} else if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8) {
|
|
92
|
+
// Export private key in PKCS8 format
|
|
93
|
+
const exported = keyObject.export({ format: 'der', type: 'pkcs8' });
|
|
94
|
+
return bufferLikeToArrayBuffer(exported);
|
|
95
|
+
} else {
|
|
96
|
+
throw new Error(`Unsupported EC export format: ${format}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function rsaExportKey(
|
|
101
|
+
key: CryptoKey,
|
|
102
|
+
format: KWebCryptoKeyFormat,
|
|
103
|
+
): ArrayBuffer {
|
|
104
|
+
const keyObject = key.keyObject;
|
|
105
|
+
|
|
106
|
+
if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI) {
|
|
107
|
+
// Export public key in SPKI format
|
|
108
|
+
const exported = keyObject.export({ format: 'der', type: 'spki' });
|
|
109
|
+
return bufferLikeToArrayBuffer(exported);
|
|
110
|
+
} else if (format === KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8) {
|
|
111
|
+
// Export private key in PKCS8 format
|
|
112
|
+
const exported = keyObject.export({ format: 'der', type: 'pkcs8' });
|
|
113
|
+
return bufferLikeToArrayBuffer(exported);
|
|
114
|
+
} else {
|
|
115
|
+
throw new Error(`Unsupported RSA export format: ${format}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function rsaCipher(
|
|
120
|
+
mode: CipherOrWrapMode,
|
|
121
|
+
key: CryptoKey,
|
|
122
|
+
data: ArrayBuffer,
|
|
123
|
+
algorithm: EncryptDecryptParams,
|
|
124
|
+
): Promise<ArrayBuffer> {
|
|
125
|
+
const rsaParams = algorithm as RsaOaepParams;
|
|
126
|
+
|
|
127
|
+
// Validate key type matches operation
|
|
128
|
+
const expectedType =
|
|
129
|
+
mode === CipherOrWrapMode.kWebCryptoCipherEncrypt ? 'public' : 'private';
|
|
130
|
+
if (key.type !== expectedType) {
|
|
131
|
+
throw lazyDOMException(
|
|
132
|
+
'The requested operation is not valid for the provided key',
|
|
133
|
+
'InvalidAccessError',
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Get hash algorithm from key
|
|
138
|
+
const hashAlgorithm = normalizeHashName(key.algorithm.hash);
|
|
139
|
+
|
|
140
|
+
// Prepare label (optional)
|
|
141
|
+
const label = rsaParams.label
|
|
142
|
+
? bufferLikeToArrayBuffer(rsaParams.label)
|
|
143
|
+
: undefined;
|
|
144
|
+
|
|
145
|
+
// Create RSA cipher instance
|
|
146
|
+
const rsaCipherModule =
|
|
147
|
+
NitroModules.createHybridObject<RsaCipher>('RsaCipher');
|
|
148
|
+
|
|
149
|
+
// RSA-OAEP padding constant = 4
|
|
150
|
+
const RSA_PKCS1_OAEP_PADDING = 4;
|
|
151
|
+
|
|
152
|
+
if (mode === CipherOrWrapMode.kWebCryptoCipherEncrypt) {
|
|
153
|
+
// Encrypt with public key
|
|
154
|
+
return rsaCipherModule.encrypt(
|
|
155
|
+
key.keyObject.handle,
|
|
156
|
+
data,
|
|
157
|
+
RSA_PKCS1_OAEP_PADDING,
|
|
158
|
+
hashAlgorithm,
|
|
159
|
+
label,
|
|
160
|
+
);
|
|
161
|
+
} else {
|
|
162
|
+
// Decrypt with private key
|
|
163
|
+
return rsaCipherModule.decrypt(
|
|
164
|
+
key.keyObject.handle,
|
|
165
|
+
data,
|
|
166
|
+
RSA_PKCS1_OAEP_PADDING,
|
|
167
|
+
hashAlgorithm,
|
|
168
|
+
label,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function aesCipher(
|
|
174
|
+
mode: CipherOrWrapMode,
|
|
175
|
+
key: CryptoKey,
|
|
176
|
+
data: ArrayBuffer,
|
|
177
|
+
algorithm: EncryptDecryptParams,
|
|
178
|
+
): Promise<ArrayBuffer> {
|
|
179
|
+
const { name } = algorithm;
|
|
180
|
+
|
|
181
|
+
switch (name) {
|
|
182
|
+
case 'AES-CTR':
|
|
183
|
+
return aesCtrCipher(mode, key, data, algorithm as AesCtrParams);
|
|
184
|
+
case 'AES-CBC':
|
|
185
|
+
return aesCbcCipher(mode, key, data, algorithm as AesCbcParams);
|
|
186
|
+
case 'AES-GCM':
|
|
187
|
+
return aesGcmCipher(mode, key, data, algorithm as AesGcmParams);
|
|
188
|
+
default:
|
|
189
|
+
throw lazyDOMException(
|
|
190
|
+
`Unsupported AES algorithm: ${name}`,
|
|
191
|
+
'NotSupportedError',
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async function aesCtrCipher(
|
|
197
|
+
mode: CipherOrWrapMode,
|
|
198
|
+
key: CryptoKey,
|
|
199
|
+
data: ArrayBuffer,
|
|
200
|
+
algorithm: AesCtrParams,
|
|
201
|
+
): Promise<ArrayBuffer> {
|
|
202
|
+
// Validate counter and length
|
|
203
|
+
if (!algorithm.counter || algorithm.counter.byteLength !== 16) {
|
|
204
|
+
throw lazyDOMException(
|
|
205
|
+
'AES-CTR algorithm.counter must be 16 bytes',
|
|
206
|
+
'OperationError',
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (algorithm.length < 1 || algorithm.length > 128) {
|
|
211
|
+
throw lazyDOMException(
|
|
212
|
+
'AES-CTR algorithm.length must be between 1 and 128',
|
|
213
|
+
'OperationError',
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Get cipher type based on key length
|
|
218
|
+
const keyLength = (key.algorithm as { length: number }).length;
|
|
219
|
+
const cipherType = `aes-${keyLength}-ctr`;
|
|
220
|
+
|
|
221
|
+
// Create cipher
|
|
222
|
+
const factory =
|
|
223
|
+
NitroModules.createHybridObject<CipherFactory>('CipherFactory');
|
|
224
|
+
const cipher = factory.createCipher({
|
|
225
|
+
isCipher: mode === CipherOrWrapMode.kWebCryptoCipherEncrypt,
|
|
226
|
+
cipherType,
|
|
227
|
+
cipherKey: bufferLikeToArrayBuffer(key.keyObject.export()),
|
|
228
|
+
iv: bufferLikeToArrayBuffer(algorithm.counter),
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Process data
|
|
232
|
+
const updated = cipher.update(data);
|
|
233
|
+
const final = cipher.final();
|
|
234
|
+
|
|
235
|
+
// Concatenate results
|
|
236
|
+
const result = new Uint8Array(updated.byteLength + final.byteLength);
|
|
237
|
+
result.set(new Uint8Array(updated), 0);
|
|
238
|
+
result.set(new Uint8Array(final), updated.byteLength);
|
|
239
|
+
|
|
240
|
+
return result.buffer;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async function aesCbcCipher(
|
|
244
|
+
mode: CipherOrWrapMode,
|
|
245
|
+
key: CryptoKey,
|
|
246
|
+
data: ArrayBuffer,
|
|
247
|
+
algorithm: AesCbcParams,
|
|
248
|
+
): Promise<ArrayBuffer> {
|
|
249
|
+
// Validate IV
|
|
250
|
+
const iv = bufferLikeToArrayBuffer(algorithm.iv);
|
|
251
|
+
if (iv.byteLength !== 16) {
|
|
252
|
+
throw lazyDOMException(
|
|
253
|
+
'algorithm.iv must contain exactly 16 bytes',
|
|
254
|
+
'OperationError',
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Get cipher type based on key length
|
|
259
|
+
const keyLength = (key.algorithm as { length: number }).length;
|
|
260
|
+
const cipherType = `aes-${keyLength}-cbc`;
|
|
261
|
+
|
|
262
|
+
// Create cipher
|
|
263
|
+
const factory =
|
|
264
|
+
NitroModules.createHybridObject<CipherFactory>('CipherFactory');
|
|
265
|
+
const cipher = factory.createCipher({
|
|
266
|
+
isCipher: mode === CipherOrWrapMode.kWebCryptoCipherEncrypt,
|
|
267
|
+
cipherType,
|
|
268
|
+
cipherKey: bufferLikeToArrayBuffer(key.keyObject.export()),
|
|
269
|
+
iv,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Process data
|
|
273
|
+
const updated = cipher.update(data);
|
|
274
|
+
const final = cipher.final();
|
|
275
|
+
|
|
276
|
+
// Concatenate results
|
|
277
|
+
const result = new Uint8Array(updated.byteLength + final.byteLength);
|
|
278
|
+
result.set(new Uint8Array(updated), 0);
|
|
279
|
+
result.set(new Uint8Array(final), updated.byteLength);
|
|
280
|
+
|
|
281
|
+
return result.buffer;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async function aesGcmCipher(
|
|
285
|
+
mode: CipherOrWrapMode,
|
|
286
|
+
key: CryptoKey,
|
|
287
|
+
data: ArrayBuffer,
|
|
288
|
+
algorithm: AesGcmParams,
|
|
289
|
+
): Promise<ArrayBuffer> {
|
|
290
|
+
const { tagLength = 128 } = algorithm;
|
|
291
|
+
|
|
292
|
+
// Validate tag length
|
|
293
|
+
const validTagLengths = [32, 64, 96, 104, 112, 120, 128];
|
|
294
|
+
if (!validTagLengths.includes(tagLength)) {
|
|
295
|
+
throw lazyDOMException(
|
|
296
|
+
`${tagLength} is not a valid AES-GCM tag length`,
|
|
297
|
+
'OperationError',
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const tagByteLength = tagLength / 8;
|
|
302
|
+
|
|
303
|
+
// Get cipher type based on key length
|
|
304
|
+
const keyLength = (key.algorithm as { length: number }).length;
|
|
305
|
+
const cipherType = `aes-${keyLength}-gcm`;
|
|
306
|
+
|
|
307
|
+
// Create cipher
|
|
308
|
+
const factory =
|
|
309
|
+
NitroModules.createHybridObject<CipherFactory>('CipherFactory');
|
|
310
|
+
const cipher = factory.createCipher({
|
|
311
|
+
isCipher: mode === CipherOrWrapMode.kWebCryptoCipherEncrypt,
|
|
312
|
+
cipherType,
|
|
313
|
+
cipherKey: bufferLikeToArrayBuffer(key.keyObject.export()),
|
|
314
|
+
iv: bufferLikeToArrayBuffer(algorithm.iv),
|
|
315
|
+
authTagLen: tagByteLength,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
let processData: ArrayBuffer;
|
|
319
|
+
let authTag: ArrayBuffer | undefined;
|
|
320
|
+
|
|
321
|
+
if (mode === CipherOrWrapMode.kWebCryptoCipherDecrypt) {
|
|
322
|
+
// For decryption, extract auth tag from end of data
|
|
323
|
+
const dataView = new Uint8Array(data);
|
|
324
|
+
|
|
325
|
+
if (dataView.byteLength < tagByteLength) {
|
|
326
|
+
throw lazyDOMException(
|
|
327
|
+
'The provided data is too small.',
|
|
328
|
+
'OperationError',
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// Split data and tag
|
|
333
|
+
const ciphertextLength = dataView.byteLength - tagByteLength;
|
|
334
|
+
processData = dataView.slice(0, ciphertextLength).buffer;
|
|
335
|
+
authTag = dataView.slice(ciphertextLength).buffer;
|
|
336
|
+
|
|
337
|
+
// Set auth tag for verification
|
|
338
|
+
cipher.setAuthTag(authTag);
|
|
339
|
+
} else {
|
|
340
|
+
processData = data;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Set additional authenticated data if provided
|
|
344
|
+
if (algorithm.additionalData) {
|
|
345
|
+
cipher.setAAD(bufferLikeToArrayBuffer(algorithm.additionalData));
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Process data
|
|
349
|
+
const updated = cipher.update(processData);
|
|
350
|
+
const final = cipher.final();
|
|
351
|
+
|
|
352
|
+
if (mode === CipherOrWrapMode.kWebCryptoCipherEncrypt) {
|
|
353
|
+
// For encryption, append auth tag to result
|
|
354
|
+
const tag = cipher.getAuthTag();
|
|
355
|
+
const result = new Uint8Array(
|
|
356
|
+
updated.byteLength + final.byteLength + tag.byteLength,
|
|
357
|
+
);
|
|
358
|
+
result.set(new Uint8Array(updated), 0);
|
|
359
|
+
result.set(new Uint8Array(final), updated.byteLength);
|
|
360
|
+
result.set(new Uint8Array(tag), updated.byteLength + final.byteLength);
|
|
361
|
+
return result.buffer;
|
|
362
|
+
} else {
|
|
363
|
+
// For decryption, just concatenate plaintext
|
|
364
|
+
const result = new Uint8Array(updated.byteLength + final.byteLength);
|
|
365
|
+
result.set(new Uint8Array(updated), 0);
|
|
366
|
+
result.set(new Uint8Array(final), updated.byteLength);
|
|
367
|
+
return result.buffer;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
async function aesGenerateKey(
|
|
372
|
+
algorithm: AesKeyGenParams,
|
|
373
|
+
extractable: boolean,
|
|
374
|
+
keyUsages: KeyUsage[],
|
|
375
|
+
): Promise<CryptoKey> {
|
|
376
|
+
const { length } = algorithm;
|
|
377
|
+
const name = algorithm.name;
|
|
378
|
+
|
|
379
|
+
if (!name) {
|
|
380
|
+
throw lazyDOMException('Algorithm name is required', 'OperationError');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Validate key length
|
|
384
|
+
if (![128, 192, 256].includes(length)) {
|
|
385
|
+
throw lazyDOMException(
|
|
386
|
+
`Invalid AES key length: ${length}. Must be 128, 192, or 256.`,
|
|
387
|
+
'OperationError',
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Validate usages
|
|
392
|
+
const validUsages: KeyUsage[] = [
|
|
393
|
+
'encrypt',
|
|
394
|
+
'decrypt',
|
|
395
|
+
'wrapKey',
|
|
396
|
+
'unwrapKey',
|
|
397
|
+
];
|
|
398
|
+
if (hasAnyNotIn(keyUsages, validUsages)) {
|
|
399
|
+
throw lazyDOMException(`Unsupported key usage for ${name}`, 'SyntaxError');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Generate random key bytes
|
|
403
|
+
const keyBytes = new Uint8Array(length / 8);
|
|
404
|
+
getRandomValues(keyBytes);
|
|
405
|
+
|
|
406
|
+
// Create secret key
|
|
407
|
+
const keyObject = createSecretKey(keyBytes);
|
|
408
|
+
|
|
409
|
+
// Construct algorithm object with guaranteed name
|
|
410
|
+
const keyAlgorithm: SubtleAlgorithm = { name, length };
|
|
411
|
+
|
|
412
|
+
return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
async function hmacGenerateKey(
|
|
416
|
+
algorithm: SubtleAlgorithm,
|
|
417
|
+
extractable: boolean,
|
|
418
|
+
keyUsages: KeyUsage[],
|
|
419
|
+
): Promise<CryptoKey> {
|
|
420
|
+
// Validate usages
|
|
421
|
+
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
422
|
+
throw lazyDOMException('Unsupported key usage for HMAC key', 'SyntaxError');
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// Get hash algorithm
|
|
426
|
+
const hash = algorithm.hash;
|
|
427
|
+
if (!hash) {
|
|
428
|
+
throw lazyDOMException(
|
|
429
|
+
'HMAC algorithm requires a hash parameter',
|
|
430
|
+
'TypeError',
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const hashName = normalizeHashName(hash);
|
|
435
|
+
|
|
436
|
+
// Determine key length
|
|
437
|
+
let length = algorithm.length;
|
|
438
|
+
if (length === undefined) {
|
|
439
|
+
// Use hash output length as default key length
|
|
440
|
+
switch (hashName) {
|
|
441
|
+
case 'SHA-1':
|
|
442
|
+
length = 160;
|
|
443
|
+
break;
|
|
444
|
+
case 'SHA-256':
|
|
445
|
+
length = 256;
|
|
446
|
+
break;
|
|
447
|
+
case 'SHA-384':
|
|
448
|
+
length = 384;
|
|
449
|
+
break;
|
|
450
|
+
case 'SHA-512':
|
|
451
|
+
length = 512;
|
|
452
|
+
break;
|
|
453
|
+
default:
|
|
454
|
+
length = 256; // Default to 256 bits
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (length === 0) {
|
|
459
|
+
throw lazyDOMException(
|
|
460
|
+
'Zero-length key is not supported',
|
|
461
|
+
'OperationError',
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Generate random key bytes
|
|
466
|
+
const keyBytes = new Uint8Array(Math.ceil(length / 8));
|
|
467
|
+
getRandomValues(keyBytes);
|
|
468
|
+
|
|
469
|
+
// Create secret key
|
|
470
|
+
const keyObject = createSecretKey(keyBytes);
|
|
471
|
+
|
|
472
|
+
// Construct algorithm object
|
|
473
|
+
const keyAlgorithm: SubtleAlgorithm = {
|
|
474
|
+
name: 'HMAC',
|
|
475
|
+
hash: hashName,
|
|
476
|
+
length,
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
return new CryptoKey(keyObject, keyAlgorithm, keyUsages, extractable);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function rsaImportKey(
|
|
483
|
+
format: ImportFormat,
|
|
484
|
+
data: BufferLike | JWK,
|
|
485
|
+
algorithm: SubtleAlgorithm,
|
|
486
|
+
extractable: boolean,
|
|
487
|
+
keyUsages: KeyUsage[],
|
|
488
|
+
): CryptoKey {
|
|
489
|
+
const { name } = algorithm;
|
|
490
|
+
|
|
491
|
+
// Validate usages
|
|
492
|
+
let checkSet: KeyUsage[];
|
|
493
|
+
switch (name) {
|
|
494
|
+
case 'RSASSA-PKCS1-v1_5':
|
|
495
|
+
case 'RSA-PSS':
|
|
496
|
+
checkSet = ['sign', 'verify'];
|
|
497
|
+
break;
|
|
498
|
+
case 'RSA-OAEP':
|
|
499
|
+
checkSet = ['encrypt', 'decrypt', 'wrapKey', 'unwrapKey'];
|
|
500
|
+
break;
|
|
501
|
+
default:
|
|
502
|
+
throw new Error(`Unsupported RSA algorithm: ${name}`);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
if (hasAnyNotIn(keyUsages, checkSet)) {
|
|
506
|
+
throw new Error(`Unsupported key usage for ${name}`);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
let keyObject: KeyObject;
|
|
510
|
+
|
|
511
|
+
if (format === 'jwk') {
|
|
512
|
+
const jwk = data as JWK;
|
|
513
|
+
|
|
514
|
+
// Validate JWK
|
|
515
|
+
if (jwk.kty !== 'RSA') {
|
|
516
|
+
throw new Error('Invalid JWK format for RSA key');
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const handle =
|
|
520
|
+
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
|
521
|
+
const keyType = handle.initJwk(jwk, undefined);
|
|
522
|
+
|
|
523
|
+
if (keyType === undefined) {
|
|
524
|
+
throw new Error('Failed to import RSA JWK');
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Create the appropriate KeyObject based on type
|
|
528
|
+
if (keyType === 1) {
|
|
529
|
+
keyObject = new PublicKeyObject(handle);
|
|
530
|
+
} else if (keyType === 2) {
|
|
531
|
+
keyObject = new PrivateKeyObject(handle);
|
|
532
|
+
} else {
|
|
533
|
+
throw new Error('Unexpected key type from RSA JWK import');
|
|
534
|
+
}
|
|
535
|
+
} else if (format === 'spki') {
|
|
536
|
+
const keyData = bufferLikeToArrayBuffer(data as BufferLike);
|
|
537
|
+
keyObject = KeyObject.createKeyObject(
|
|
538
|
+
'public',
|
|
539
|
+
keyData,
|
|
540
|
+
KFormatType.DER,
|
|
541
|
+
KeyEncoding.SPKI,
|
|
542
|
+
);
|
|
543
|
+
} else if (format === 'pkcs8') {
|
|
544
|
+
const keyData = bufferLikeToArrayBuffer(data as BufferLike);
|
|
545
|
+
keyObject = KeyObject.createKeyObject(
|
|
546
|
+
'private',
|
|
547
|
+
keyData,
|
|
548
|
+
KFormatType.DER,
|
|
549
|
+
KeyEncoding.PKCS8,
|
|
550
|
+
);
|
|
551
|
+
} else {
|
|
552
|
+
throw new Error(`Unsupported format for RSA import: ${format}`);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Get the modulus length from the key and add it to the algorithm
|
|
556
|
+
const keyDetails = (keyObject as PublicKeyObject | PrivateKeyObject)
|
|
557
|
+
.asymmetricKeyDetails;
|
|
558
|
+
|
|
559
|
+
// Convert publicExponent number to big-endian byte array
|
|
560
|
+
let publicExponentBytes: Uint8Array | undefined;
|
|
561
|
+
if (keyDetails?.publicExponent) {
|
|
562
|
+
const exp = keyDetails.publicExponent;
|
|
563
|
+
// Convert number to big-endian bytes
|
|
564
|
+
const bytes: number[] = [];
|
|
565
|
+
let value = exp;
|
|
566
|
+
while (value > 0) {
|
|
567
|
+
bytes.unshift(value & 0xff);
|
|
568
|
+
value = Math.floor(value / 256);
|
|
569
|
+
}
|
|
570
|
+
publicExponentBytes = new Uint8Array(bytes.length > 0 ? bytes : [0]);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const algorithmWithDetails = {
|
|
574
|
+
...algorithm,
|
|
575
|
+
modulusLength: keyDetails?.modulusLength,
|
|
576
|
+
publicExponent: publicExponentBytes,
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
return new CryptoKey(keyObject, algorithmWithDetails, keyUsages, extractable);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
async function hmacImportKey(
|
|
583
|
+
algorithm: SubtleAlgorithm,
|
|
584
|
+
format: ImportFormat,
|
|
585
|
+
data: BufferLike | JWK,
|
|
586
|
+
extractable: boolean,
|
|
587
|
+
keyUsages: KeyUsage[],
|
|
588
|
+
): Promise<CryptoKey> {
|
|
589
|
+
// Validate usages
|
|
590
|
+
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
591
|
+
throw new Error('Unsupported key usage for an HMAC key');
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
let keyObject: KeyObject;
|
|
595
|
+
|
|
596
|
+
if (format === 'jwk') {
|
|
597
|
+
const jwk = data as JWK;
|
|
598
|
+
|
|
599
|
+
// Validate JWK
|
|
600
|
+
if (!jwk || typeof jwk !== 'object') {
|
|
601
|
+
throw new Error('Invalid keyData');
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
if (jwk.kty !== 'oct') {
|
|
605
|
+
throw new Error('Invalid JWK format for HMAC key');
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Validate key length if specified
|
|
609
|
+
if (algorithm.length !== undefined) {
|
|
610
|
+
if (!jwk.k) {
|
|
611
|
+
throw new Error('JWK missing key data');
|
|
612
|
+
}
|
|
613
|
+
// Decode to check length
|
|
614
|
+
const decoded = SBuffer.from(jwk.k, 'base64');
|
|
615
|
+
const keyBitLength = decoded.length * 8;
|
|
616
|
+
if (algorithm.length === 0) {
|
|
617
|
+
throw new Error('Zero-length key is not supported');
|
|
618
|
+
}
|
|
619
|
+
if (algorithm.length !== keyBitLength) {
|
|
620
|
+
throw new Error('Invalid key length');
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const handle =
|
|
625
|
+
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
|
626
|
+
const keyType = handle.initJwk(jwk, undefined);
|
|
627
|
+
|
|
628
|
+
if (keyType === undefined || keyType !== 0) {
|
|
629
|
+
throw new Error('Failed to import HMAC JWK');
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
keyObject = new SecretKeyObject(handle);
|
|
633
|
+
} else if (format === 'raw') {
|
|
634
|
+
keyObject = createSecretKey(data as BinaryLike);
|
|
635
|
+
} else {
|
|
636
|
+
throw new Error(`Unable to import HMAC key with format ${format}`);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
return new CryptoKey(
|
|
640
|
+
keyObject,
|
|
641
|
+
{ ...algorithm, name: 'HMAC' },
|
|
642
|
+
keyUsages,
|
|
643
|
+
extractable,
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
async function aesImportKey(
|
|
648
|
+
algorithm: SubtleAlgorithm,
|
|
649
|
+
format: ImportFormat,
|
|
650
|
+
data: BufferLike | JWK,
|
|
651
|
+
extractable: boolean,
|
|
652
|
+
keyUsages: KeyUsage[],
|
|
653
|
+
): Promise<CryptoKey> {
|
|
654
|
+
const { name, length } = algorithm;
|
|
655
|
+
|
|
656
|
+
// Validate usages
|
|
657
|
+
const validUsages: KeyUsage[] = [
|
|
658
|
+
'encrypt',
|
|
659
|
+
'decrypt',
|
|
660
|
+
'wrapKey',
|
|
661
|
+
'unwrapKey',
|
|
662
|
+
];
|
|
663
|
+
if (hasAnyNotIn(keyUsages, validUsages)) {
|
|
664
|
+
throw new Error(`Unsupported key usage for ${name}`);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
let keyObject: KeyObject;
|
|
668
|
+
let actualLength: number;
|
|
669
|
+
|
|
670
|
+
if (format === 'jwk') {
|
|
671
|
+
const jwk = data as JWK;
|
|
672
|
+
|
|
673
|
+
// Validate JWK
|
|
674
|
+
if (jwk.kty !== 'oct') {
|
|
675
|
+
throw new Error('Invalid JWK format for AES key');
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
const handle =
|
|
679
|
+
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
|
680
|
+
const keyType = handle.initJwk(jwk, undefined);
|
|
681
|
+
|
|
682
|
+
if (keyType === undefined || keyType !== 0) {
|
|
683
|
+
throw new Error('Failed to import AES JWK');
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
keyObject = new SecretKeyObject(handle);
|
|
687
|
+
|
|
688
|
+
// Get actual key length from imported key
|
|
689
|
+
const exported = keyObject.export();
|
|
690
|
+
actualLength = exported.byteLength * 8;
|
|
691
|
+
} else if (format === 'raw') {
|
|
692
|
+
const keyData = bufferLikeToArrayBuffer(data as BufferLike);
|
|
693
|
+
actualLength = keyData.byteLength * 8;
|
|
694
|
+
|
|
695
|
+
// Validate key length
|
|
696
|
+
if (![128, 192, 256].includes(actualLength)) {
|
|
697
|
+
throw new Error('Invalid AES key length');
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
keyObject = createSecretKey(keyData);
|
|
701
|
+
} else {
|
|
702
|
+
throw new Error(`Unsupported format for AES import: ${format}`);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// Validate length if specified
|
|
706
|
+
if (length !== undefined && length !== actualLength) {
|
|
707
|
+
throw new Error(
|
|
708
|
+
`Key length mismatch: expected ${length}, got ${actualLength}`,
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
return new CryptoKey(
|
|
713
|
+
keyObject,
|
|
714
|
+
{ name, length: actualLength },
|
|
715
|
+
keyUsages,
|
|
716
|
+
extractable,
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
function edImportKey(
|
|
721
|
+
format: ImportFormat,
|
|
722
|
+
data: BufferLike,
|
|
723
|
+
algorithm: SubtleAlgorithm,
|
|
724
|
+
extractable: boolean,
|
|
725
|
+
keyUsages: KeyUsage[],
|
|
726
|
+
): CryptoKey {
|
|
727
|
+
const { name } = algorithm;
|
|
728
|
+
|
|
729
|
+
// Validate usages
|
|
730
|
+
if (hasAnyNotIn(keyUsages, ['sign', 'verify'])) {
|
|
731
|
+
throw lazyDOMException(
|
|
732
|
+
`Unsupported key usage for ${name} key`,
|
|
733
|
+
'SyntaxError',
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
let keyObject: KeyObject;
|
|
738
|
+
|
|
739
|
+
if (format === 'spki') {
|
|
740
|
+
// Import public key
|
|
741
|
+
const keyData = bufferLikeToArrayBuffer(data);
|
|
742
|
+
keyObject = KeyObject.createKeyObject(
|
|
743
|
+
'public',
|
|
744
|
+
keyData,
|
|
745
|
+
KFormatType.DER,
|
|
746
|
+
KeyEncoding.SPKI,
|
|
747
|
+
);
|
|
748
|
+
} else if (format === 'pkcs8') {
|
|
749
|
+
// Import private key
|
|
750
|
+
const keyData = bufferLikeToArrayBuffer(data);
|
|
751
|
+
keyObject = KeyObject.createKeyObject(
|
|
752
|
+
'private',
|
|
753
|
+
keyData,
|
|
754
|
+
KFormatType.DER,
|
|
755
|
+
KeyEncoding.PKCS8,
|
|
756
|
+
);
|
|
757
|
+
} else if (format === 'raw') {
|
|
758
|
+
// Raw format - public key only for Ed keys
|
|
759
|
+
const keyData = bufferLikeToArrayBuffer(data);
|
|
760
|
+
const handle =
|
|
761
|
+
NitroModules.createHybridObject<KeyObjectHandle>('KeyObjectHandle');
|
|
762
|
+
// For raw Ed keys, we need to create them differently
|
|
763
|
+
// Raw public keys are just the key bytes
|
|
764
|
+
handle.init(1, keyData); // 1 = public key type
|
|
765
|
+
keyObject = new PublicKeyObject(handle);
|
|
766
|
+
} else {
|
|
767
|
+
throw lazyDOMException(
|
|
768
|
+
`Unsupported format for ${name} import: ${format}`,
|
|
769
|
+
'NotSupportedError',
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
return new CryptoKey(keyObject, { name }, keyUsages, extractable);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
const exportKeySpki = async (
|
|
777
|
+
key: CryptoKey,
|
|
778
|
+
): Promise<ArrayBuffer | unknown> => {
|
|
779
|
+
switch (key.algorithm.name) {
|
|
780
|
+
case 'RSASSA-PKCS1-v1_5':
|
|
781
|
+
// Fall through
|
|
782
|
+
case 'RSA-PSS':
|
|
783
|
+
// Fall through
|
|
784
|
+
case 'RSA-OAEP':
|
|
785
|
+
if (key.type === 'public') {
|
|
786
|
+
return rsaExportKey(key, KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI);
|
|
787
|
+
}
|
|
788
|
+
break;
|
|
789
|
+
case 'ECDSA':
|
|
790
|
+
// Fall through
|
|
791
|
+
case 'ECDH':
|
|
792
|
+
if (key.type === 'public') {
|
|
793
|
+
return ecExportKey(key, KWebCryptoKeyFormat.kWebCryptoKeyFormatSPKI);
|
|
794
|
+
}
|
|
795
|
+
break;
|
|
796
|
+
case 'Ed25519':
|
|
797
|
+
// Fall through
|
|
798
|
+
case 'Ed448':
|
|
799
|
+
if (key.type === 'public') {
|
|
800
|
+
// Export Ed key in SPKI DER format
|
|
801
|
+
return bufferLikeToArrayBuffer(
|
|
802
|
+
key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.SPKI),
|
|
803
|
+
);
|
|
804
|
+
}
|
|
805
|
+
break;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
throw new Error(
|
|
809
|
+
`Unable to export a spki ${key.algorithm.name} ${key.type} key`,
|
|
810
|
+
);
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
const exportKeyPkcs8 = async (
|
|
814
|
+
key: CryptoKey,
|
|
815
|
+
): Promise<ArrayBuffer | unknown> => {
|
|
816
|
+
switch (key.algorithm.name) {
|
|
817
|
+
case 'RSASSA-PKCS1-v1_5':
|
|
818
|
+
// Fall through
|
|
819
|
+
case 'RSA-PSS':
|
|
820
|
+
// Fall through
|
|
821
|
+
case 'RSA-OAEP':
|
|
822
|
+
if (key.type === 'private') {
|
|
823
|
+
return rsaExportKey(key, KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8);
|
|
824
|
+
}
|
|
825
|
+
break;
|
|
826
|
+
case 'ECDSA':
|
|
827
|
+
// Fall through
|
|
828
|
+
case 'ECDH':
|
|
829
|
+
if (key.type === 'private') {
|
|
830
|
+
return ecExportKey(key, KWebCryptoKeyFormat.kWebCryptoKeyFormatPKCS8);
|
|
831
|
+
}
|
|
832
|
+
break;
|
|
833
|
+
case 'Ed25519':
|
|
834
|
+
// Fall through
|
|
835
|
+
case 'Ed448':
|
|
836
|
+
if (key.type === 'private') {
|
|
837
|
+
// Export Ed key in PKCS8 DER format
|
|
838
|
+
return bufferLikeToArrayBuffer(
|
|
839
|
+
key.keyObject.handle.exportKey(KFormatType.DER, KeyEncoding.PKCS8),
|
|
840
|
+
);
|
|
841
|
+
}
|
|
842
|
+
break;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
throw new Error(
|
|
846
|
+
`Unable to export a pkcs8 ${key.algorithm.name} ${key.type} key`,
|
|
847
|
+
);
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
const exportKeyRaw = (key: CryptoKey): ArrayBuffer | unknown => {
|
|
851
|
+
switch (key.algorithm.name) {
|
|
852
|
+
case 'ECDSA':
|
|
853
|
+
// Fall through
|
|
854
|
+
case 'ECDH':
|
|
855
|
+
if (key.type === 'public') {
|
|
856
|
+
return ecExportKey(key, KWebCryptoKeyFormat.kWebCryptoKeyFormatRaw);
|
|
857
|
+
}
|
|
858
|
+
break;
|
|
859
|
+
case 'AES-CTR':
|
|
860
|
+
// Fall through
|
|
861
|
+
case 'AES-CBC':
|
|
862
|
+
// Fall through
|
|
863
|
+
case 'AES-GCM':
|
|
864
|
+
// Fall through
|
|
865
|
+
case 'AES-KW':
|
|
866
|
+
// Fall through
|
|
867
|
+
case 'HMAC': {
|
|
868
|
+
const exported = key.keyObject.export();
|
|
869
|
+
// Convert Buffer to ArrayBuffer
|
|
870
|
+
return exported.buffer.slice(
|
|
871
|
+
exported.byteOffset,
|
|
872
|
+
exported.byteOffset + exported.byteLength,
|
|
873
|
+
);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
throw lazyDOMException(
|
|
878
|
+
`Unable to export a raw ${key.algorithm.name} ${key.type} key`,
|
|
879
|
+
'InvalidAccessError',
|
|
880
|
+
);
|
|
881
|
+
};
|
|
882
|
+
|
|
883
|
+
const exportKeyJWK = (key: CryptoKey): ArrayBuffer | unknown => {
|
|
884
|
+
const jwk = key.keyObject.handle.exportJwk(
|
|
885
|
+
{
|
|
886
|
+
key_ops: key.usages,
|
|
887
|
+
ext: key.extractable,
|
|
888
|
+
},
|
|
889
|
+
true,
|
|
890
|
+
);
|
|
891
|
+
switch (key.algorithm.name) {
|
|
892
|
+
case 'RSASSA-PKCS1-v1_5':
|
|
893
|
+
jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkRsa);
|
|
894
|
+
return jwk;
|
|
895
|
+
case 'RSA-PSS':
|
|
896
|
+
jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkRsaPss);
|
|
897
|
+
return jwk;
|
|
898
|
+
case 'RSA-OAEP':
|
|
899
|
+
jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkRsaOaep);
|
|
900
|
+
return jwk;
|
|
901
|
+
case 'HMAC':
|
|
902
|
+
jwk.alg = normalizeHashName(key.algorithm.hash, HashContext.JwkHmac);
|
|
903
|
+
return jwk;
|
|
904
|
+
case 'ECDSA':
|
|
905
|
+
// Fall through
|
|
906
|
+
case 'ECDH':
|
|
907
|
+
jwk.crv ||= key.algorithm.namedCurve;
|
|
908
|
+
return jwk;
|
|
909
|
+
case 'AES-CTR':
|
|
910
|
+
// Fall through
|
|
911
|
+
case 'AES-CBC':
|
|
912
|
+
// Fall through
|
|
913
|
+
case 'AES-GCM':
|
|
914
|
+
// Fall through
|
|
915
|
+
case 'AES-KW':
|
|
916
|
+
if (key.algorithm.length === undefined) {
|
|
917
|
+
throw lazyDOMException(
|
|
918
|
+
`Algorithm ${key.algorithm.name} missing required length property`,
|
|
919
|
+
'InvalidAccessError',
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
jwk.alg = getAlgorithmName(key.algorithm.name, key.algorithm.length);
|
|
923
|
+
return jwk;
|
|
924
|
+
default:
|
|
925
|
+
// Fall through
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
throw lazyDOMException(
|
|
929
|
+
`JWK export not yet supported: ${key.algorithm.name}`,
|
|
930
|
+
'NotSupportedError',
|
|
931
|
+
);
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
const importGenericSecretKey = async (
|
|
935
|
+
{ name, length }: SubtleAlgorithm,
|
|
936
|
+
format: ImportFormat,
|
|
937
|
+
keyData: BufferLike | BinaryLike,
|
|
938
|
+
extractable: boolean,
|
|
939
|
+
keyUsages: KeyUsage[],
|
|
940
|
+
): Promise<CryptoKey> => {
|
|
941
|
+
if (extractable) {
|
|
942
|
+
throw new Error(`${name} keys are not extractable`);
|
|
943
|
+
}
|
|
944
|
+
if (hasAnyNotIn(keyUsages, ['deriveKey', 'deriveBits'])) {
|
|
945
|
+
throw new Error(`Unsupported key usage for a ${name} key`);
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
switch (format) {
|
|
949
|
+
case 'raw': {
|
|
950
|
+
if (hasAnyNotIn(keyUsages, ['deriveKey', 'deriveBits'])) {
|
|
951
|
+
throw new Error(`Unsupported key usage for a ${name} key`);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
const checkLength =
|
|
955
|
+
typeof keyData === 'string' || SBuffer.isBuffer(keyData)
|
|
956
|
+
? keyData.length * 8
|
|
957
|
+
: keyData.byteLength * 8;
|
|
958
|
+
|
|
959
|
+
if (length !== undefined && length !== checkLength) {
|
|
960
|
+
throw new Error('Invalid key length');
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
const keyObject = createSecretKey(keyData as BinaryLike);
|
|
964
|
+
return new CryptoKey(keyObject, { name }, keyUsages, false);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
throw new Error(`Unable to import ${name} key with format ${format}`);
|
|
969
|
+
};
|
|
970
|
+
|
|
971
|
+
const checkCryptoKeyPairUsages = (pair: CryptoKeyPair) => {
|
|
972
|
+
if (
|
|
973
|
+
pair.privateKey &&
|
|
974
|
+
pair.privateKey instanceof CryptoKey &&
|
|
975
|
+
pair.privateKey.keyUsages &&
|
|
976
|
+
pair.privateKey.keyUsages.length > 0
|
|
977
|
+
) {
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
throw lazyDOMException(
|
|
981
|
+
'Usages cannot be empty when creating a key.',
|
|
982
|
+
'SyntaxError',
|
|
983
|
+
);
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
// Type guard to check if result is CryptoKeyPair
|
|
987
|
+
export function isCryptoKeyPair(
|
|
988
|
+
result: CryptoKey | CryptoKeyPair,
|
|
989
|
+
): result is CryptoKeyPair {
|
|
990
|
+
return 'publicKey' in result && 'privateKey' in result;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
function hmacSignVerify(
|
|
994
|
+
key: CryptoKey,
|
|
995
|
+
data: BufferLike,
|
|
996
|
+
signature?: BufferLike,
|
|
997
|
+
): ArrayBuffer | boolean {
|
|
998
|
+
// Get hash algorithm from key
|
|
999
|
+
const hashName = normalizeHashName(key.algorithm.hash);
|
|
1000
|
+
|
|
1001
|
+
// Export the secret key material
|
|
1002
|
+
const keyData = key.keyObject.export();
|
|
1003
|
+
|
|
1004
|
+
// Create HMAC and compute digest
|
|
1005
|
+
const hmac = createHmac(hashName, keyData);
|
|
1006
|
+
hmac.update(bufferLikeToArrayBuffer(data));
|
|
1007
|
+
const computed = hmac.digest();
|
|
1008
|
+
|
|
1009
|
+
if (signature === undefined) {
|
|
1010
|
+
// Sign operation - return the HMAC as ArrayBuffer
|
|
1011
|
+
return computed.buffer.slice(
|
|
1012
|
+
computed.byteOffset,
|
|
1013
|
+
computed.byteOffset + computed.byteLength,
|
|
1014
|
+
);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// Verify operation - compare computed HMAC with provided signature
|
|
1018
|
+
const sigBytes = new Uint8Array(bufferLikeToArrayBuffer(signature));
|
|
1019
|
+
const computedBytes = new Uint8Array(
|
|
1020
|
+
computed.buffer,
|
|
1021
|
+
computed.byteOffset,
|
|
1022
|
+
computed.byteLength,
|
|
1023
|
+
);
|
|
1024
|
+
|
|
1025
|
+
if (computedBytes.length !== sigBytes.length) {
|
|
1026
|
+
return false;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
// Constant-time comparison to prevent timing attacks
|
|
1030
|
+
let result = 0;
|
|
1031
|
+
for (let i = 0; i < computedBytes.length; i++) {
|
|
1032
|
+
result |= computedBytes[i]! ^ sigBytes[i]!;
|
|
1033
|
+
}
|
|
1034
|
+
return result === 0;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
function rsaSignVerify(
|
|
1038
|
+
key: CryptoKey,
|
|
1039
|
+
data: BufferLike,
|
|
1040
|
+
padding: 'pkcs1' | 'pss',
|
|
1041
|
+
signature?: BufferLike,
|
|
1042
|
+
saltLength?: number,
|
|
1043
|
+
): ArrayBuffer | boolean {
|
|
1044
|
+
// Get hash algorithm from key
|
|
1045
|
+
const hashName = normalizeHashName(key.algorithm.hash);
|
|
1046
|
+
|
|
1047
|
+
// Determine RSA padding constant
|
|
1048
|
+
const RSA_PKCS1_PADDING = 1;
|
|
1049
|
+
const RSA_PKCS1_PSS_PADDING = 6;
|
|
1050
|
+
const paddingValue =
|
|
1051
|
+
padding === 'pss' ? RSA_PKCS1_PSS_PADDING : RSA_PKCS1_PADDING;
|
|
1052
|
+
|
|
1053
|
+
if (signature === undefined) {
|
|
1054
|
+
// Sign operation
|
|
1055
|
+
const signer = createSign(hashName);
|
|
1056
|
+
signer.update(data);
|
|
1057
|
+
const sig = signer.sign({
|
|
1058
|
+
key: key,
|
|
1059
|
+
padding: paddingValue,
|
|
1060
|
+
saltLength,
|
|
1061
|
+
});
|
|
1062
|
+
return sig.buffer.slice(sig.byteOffset, sig.byteOffset + sig.byteLength);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// Verify operation
|
|
1066
|
+
const verifier = createVerify(hashName);
|
|
1067
|
+
verifier.update(data);
|
|
1068
|
+
return verifier.verify(
|
|
1069
|
+
{
|
|
1070
|
+
key: key,
|
|
1071
|
+
padding: paddingValue,
|
|
1072
|
+
saltLength,
|
|
1073
|
+
},
|
|
1074
|
+
signature,
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
function edSignVerify(
|
|
1079
|
+
key: CryptoKey,
|
|
1080
|
+
data: BufferLike,
|
|
1081
|
+
signature?: BufferLike,
|
|
1082
|
+
): ArrayBuffer | boolean {
|
|
1083
|
+
const isSign = signature === undefined;
|
|
1084
|
+
const expectedKeyType = isSign ? 'private' : 'public';
|
|
1085
|
+
|
|
1086
|
+
if (key.type !== expectedKeyType) {
|
|
1087
|
+
throw lazyDOMException(
|
|
1088
|
+
`Key must be a ${expectedKeyType} key`,
|
|
1089
|
+
'InvalidAccessError',
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
// Get curve type from algorithm name (Ed25519 or Ed448)
|
|
1094
|
+
const algorithmName = key.algorithm.name;
|
|
1095
|
+
const curveType = algorithmName.toLowerCase() as 'ed25519' | 'ed448';
|
|
1096
|
+
|
|
1097
|
+
// Create Ed instance with the curve
|
|
1098
|
+
const ed = new Ed(curveType, {});
|
|
1099
|
+
|
|
1100
|
+
// Export raw key bytes (exportKey with no format returns raw for Ed keys)
|
|
1101
|
+
const rawKey = key.keyObject.handle.exportKey();
|
|
1102
|
+
const dataBuffer = bufferLikeToArrayBuffer(data);
|
|
1103
|
+
|
|
1104
|
+
if (isSign) {
|
|
1105
|
+
// Sign operation - use raw private key
|
|
1106
|
+
const sig = ed.signSync(dataBuffer, rawKey);
|
|
1107
|
+
return sig;
|
|
1108
|
+
} else {
|
|
1109
|
+
// Verify operation - use raw public key
|
|
1110
|
+
const signatureBuffer = bufferLikeToArrayBuffer(signature!);
|
|
1111
|
+
return ed.verifySync(signatureBuffer, dataBuffer, rawKey);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
const signVerify = (
|
|
1116
|
+
algorithm: SubtleAlgorithm,
|
|
1117
|
+
key: CryptoKey,
|
|
1118
|
+
data: BufferLike,
|
|
1119
|
+
signature?: BufferLike,
|
|
1120
|
+
): ArrayBuffer | boolean => {
|
|
1121
|
+
const usage: Operation = signature === undefined ? 'sign' : 'verify';
|
|
1122
|
+
algorithm = normalizeAlgorithm(algorithm, usage);
|
|
1123
|
+
|
|
1124
|
+
if (!key.usages.includes(usage) || algorithm.name !== key.algorithm.name) {
|
|
1125
|
+
throw lazyDOMException(
|
|
1126
|
+
`Unable to use this key to ${usage}`,
|
|
1127
|
+
'InvalidAccessError',
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
switch (algorithm.name) {
|
|
1132
|
+
case 'ECDSA':
|
|
1133
|
+
return ecdsaSignVerify(key, data, algorithm, signature);
|
|
1134
|
+
case 'HMAC':
|
|
1135
|
+
return hmacSignVerify(key, data, signature);
|
|
1136
|
+
case 'RSASSA-PKCS1-v1_5':
|
|
1137
|
+
return rsaSignVerify(key, data, 'pkcs1', signature);
|
|
1138
|
+
case 'RSA-PSS':
|
|
1139
|
+
return rsaSignVerify(key, data, 'pss', signature, algorithm.saltLength);
|
|
1140
|
+
case 'Ed25519':
|
|
1141
|
+
case 'Ed448':
|
|
1142
|
+
return edSignVerify(key, data, signature);
|
|
1143
|
+
}
|
|
1144
|
+
throw lazyDOMException(
|
|
1145
|
+
`Unrecognized algorithm name '${algorithm.name}' for '${usage}'`,
|
|
1146
|
+
'NotSupportedError',
|
|
1147
|
+
);
|
|
1148
|
+
};
|
|
1149
|
+
|
|
1150
|
+
const cipherOrWrap = async (
|
|
1151
|
+
mode: CipherOrWrapMode,
|
|
1152
|
+
algorithm: EncryptDecryptParams,
|
|
1153
|
+
key: CryptoKey,
|
|
1154
|
+
data: ArrayBuffer,
|
|
1155
|
+
op: Operation,
|
|
1156
|
+
): Promise<ArrayBuffer> => {
|
|
1157
|
+
if (
|
|
1158
|
+
key.algorithm.name !== algorithm.name ||
|
|
1159
|
+
!key.usages.includes(op as KeyUsage)
|
|
1160
|
+
) {
|
|
1161
|
+
throw lazyDOMException(
|
|
1162
|
+
'The requested operation is not valid for the provided key',
|
|
1163
|
+
'InvalidAccessError',
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
validateMaxBufferLength(data, 'data');
|
|
1168
|
+
|
|
1169
|
+
switch (algorithm.name) {
|
|
1170
|
+
case 'RSA-OAEP':
|
|
1171
|
+
return rsaCipher(mode, key, data, algorithm);
|
|
1172
|
+
case 'AES-CTR':
|
|
1173
|
+
// Fall through
|
|
1174
|
+
case 'AES-CBC':
|
|
1175
|
+
// Fall through
|
|
1176
|
+
case 'AES-GCM':
|
|
1177
|
+
return aesCipher(mode, key, data, algorithm);
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
|
|
1181
|
+
export class Subtle {
|
|
1182
|
+
async decrypt(
|
|
1183
|
+
algorithm: EncryptDecryptParams,
|
|
1184
|
+
key: CryptoKey,
|
|
1185
|
+
data: BufferLike,
|
|
1186
|
+
): Promise<ArrayBuffer> {
|
|
1187
|
+
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'decrypt');
|
|
1188
|
+
return cipherOrWrap(
|
|
1189
|
+
CipherOrWrapMode.kWebCryptoCipherDecrypt,
|
|
1190
|
+
normalizedAlgorithm as EncryptDecryptParams,
|
|
1191
|
+
key,
|
|
1192
|
+
bufferLikeToArrayBuffer(data),
|
|
1193
|
+
'decrypt',
|
|
1194
|
+
);
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
async digest(
|
|
1198
|
+
algorithm: SubtleAlgorithm | AnyAlgorithm,
|
|
1199
|
+
data: BufferLike,
|
|
1200
|
+
): Promise<ArrayBuffer> {
|
|
1201
|
+
const normalizedAlgorithm = normalizeAlgorithm(
|
|
1202
|
+
algorithm,
|
|
1203
|
+
'digest' as Operation,
|
|
1204
|
+
);
|
|
1205
|
+
return asyncDigest(normalizedAlgorithm, data);
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
async deriveBits(
|
|
1209
|
+
algorithm: SubtleAlgorithm,
|
|
1210
|
+
baseKey: CryptoKey,
|
|
1211
|
+
length: number,
|
|
1212
|
+
): Promise<ArrayBuffer> {
|
|
1213
|
+
if (!baseKey.keyUsages.includes('deriveBits')) {
|
|
1214
|
+
throw new Error('baseKey does not have deriveBits usage');
|
|
1215
|
+
}
|
|
1216
|
+
if (baseKey.algorithm.name !== algorithm.name)
|
|
1217
|
+
throw new Error('Key algorithm mismatch');
|
|
1218
|
+
switch (algorithm.name) {
|
|
1219
|
+
case 'PBKDF2':
|
|
1220
|
+
return pbkdf2DeriveBits(algorithm, baseKey, length);
|
|
1221
|
+
}
|
|
1222
|
+
throw new Error(
|
|
1223
|
+
`'subtle.deriveBits()' for ${algorithm.name} is not implemented.`,
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
async encrypt(
|
|
1228
|
+
algorithm: EncryptDecryptParams,
|
|
1229
|
+
key: CryptoKey,
|
|
1230
|
+
data: BufferLike,
|
|
1231
|
+
): Promise<ArrayBuffer> {
|
|
1232
|
+
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'encrypt');
|
|
1233
|
+
return cipherOrWrap(
|
|
1234
|
+
CipherOrWrapMode.kWebCryptoCipherEncrypt,
|
|
1235
|
+
normalizedAlgorithm as EncryptDecryptParams,
|
|
1236
|
+
key,
|
|
1237
|
+
bufferLikeToArrayBuffer(data),
|
|
1238
|
+
'encrypt',
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
async exportKey(
|
|
1243
|
+
format: ImportFormat,
|
|
1244
|
+
key: CryptoKey,
|
|
1245
|
+
): Promise<ArrayBuffer | JWK> {
|
|
1246
|
+
if (!key.extractable) throw new Error('key is not extractable');
|
|
1247
|
+
|
|
1248
|
+
switch (format) {
|
|
1249
|
+
case 'spki':
|
|
1250
|
+
return (await exportKeySpki(key)) as ArrayBuffer;
|
|
1251
|
+
case 'pkcs8':
|
|
1252
|
+
return (await exportKeyPkcs8(key)) as ArrayBuffer;
|
|
1253
|
+
case 'jwk':
|
|
1254
|
+
return exportKeyJWK(key) as JWK;
|
|
1255
|
+
case 'raw':
|
|
1256
|
+
return exportKeyRaw(key) as ArrayBuffer;
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
async generateKey(
|
|
1261
|
+
algorithm: SubtleAlgorithm,
|
|
1262
|
+
extractable: boolean,
|
|
1263
|
+
keyUsages: KeyUsage[],
|
|
1264
|
+
): Promise<CryptoKey | CryptoKeyPair> {
|
|
1265
|
+
algorithm = normalizeAlgorithm(algorithm, 'generateKey');
|
|
1266
|
+
let result: CryptoKey | CryptoKeyPair;
|
|
1267
|
+
switch (algorithm.name) {
|
|
1268
|
+
case 'RSASSA-PKCS1-v1_5':
|
|
1269
|
+
// Fall through
|
|
1270
|
+
case 'RSA-PSS':
|
|
1271
|
+
// Fall through
|
|
1272
|
+
case 'RSA-OAEP':
|
|
1273
|
+
result = await rsa_generateKeyPair(algorithm, extractable, keyUsages);
|
|
1274
|
+
break;
|
|
1275
|
+
case 'ECDSA':
|
|
1276
|
+
// Fall through
|
|
1277
|
+
case 'ECDH':
|
|
1278
|
+
result = await ec_generateKeyPair(
|
|
1279
|
+
algorithm.name,
|
|
1280
|
+
algorithm.namedCurve!,
|
|
1281
|
+
extractable,
|
|
1282
|
+
keyUsages,
|
|
1283
|
+
);
|
|
1284
|
+
checkCryptoKeyPairUsages(result as CryptoKeyPair);
|
|
1285
|
+
break;
|
|
1286
|
+
case 'AES-CTR':
|
|
1287
|
+
// Fall through
|
|
1288
|
+
case 'AES-CBC':
|
|
1289
|
+
// Fall through
|
|
1290
|
+
case 'AES-GCM':
|
|
1291
|
+
// Fall through
|
|
1292
|
+
case 'AES-KW':
|
|
1293
|
+
result = await aesGenerateKey(
|
|
1294
|
+
algorithm as AesKeyGenParams,
|
|
1295
|
+
extractable,
|
|
1296
|
+
keyUsages,
|
|
1297
|
+
);
|
|
1298
|
+
break;
|
|
1299
|
+
case 'HMAC':
|
|
1300
|
+
result = await hmacGenerateKey(algorithm, extractable, keyUsages);
|
|
1301
|
+
break;
|
|
1302
|
+
case 'Ed25519':
|
|
1303
|
+
// Fall through
|
|
1304
|
+
case 'Ed448':
|
|
1305
|
+
result = await ed_generateKeyPairWebCrypto(
|
|
1306
|
+
algorithm.name.toLowerCase() as 'ed25519' | 'ed448',
|
|
1307
|
+
extractable,
|
|
1308
|
+
keyUsages,
|
|
1309
|
+
);
|
|
1310
|
+
checkCryptoKeyPairUsages(result as CryptoKeyPair);
|
|
1311
|
+
break;
|
|
1312
|
+
default:
|
|
1313
|
+
throw new Error(
|
|
1314
|
+
`'subtle.generateKey()' is not implemented for ${algorithm.name}.
|
|
1315
|
+
Unrecognized algorithm name`,
|
|
1316
|
+
);
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
return result;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
async importKey(
|
|
1323
|
+
format: ImportFormat,
|
|
1324
|
+
data: BufferLike | BinaryLike | JWK,
|
|
1325
|
+
algorithm: SubtleAlgorithm | AnyAlgorithm,
|
|
1326
|
+
extractable: boolean,
|
|
1327
|
+
keyUsages: KeyUsage[],
|
|
1328
|
+
): Promise<CryptoKey> {
|
|
1329
|
+
const normalizedAlgorithm = normalizeAlgorithm(algorithm, 'importKey');
|
|
1330
|
+
let result: CryptoKey;
|
|
1331
|
+
switch (normalizedAlgorithm.name) {
|
|
1332
|
+
case 'RSASSA-PKCS1-v1_5':
|
|
1333
|
+
// Fall through
|
|
1334
|
+
case 'RSA-PSS':
|
|
1335
|
+
// Fall through
|
|
1336
|
+
case 'RSA-OAEP':
|
|
1337
|
+
result = rsaImportKey(
|
|
1338
|
+
format,
|
|
1339
|
+
data as BufferLike | JWK,
|
|
1340
|
+
normalizedAlgorithm,
|
|
1341
|
+
extractable,
|
|
1342
|
+
keyUsages,
|
|
1343
|
+
);
|
|
1344
|
+
break;
|
|
1345
|
+
case 'ECDSA':
|
|
1346
|
+
// Fall through
|
|
1347
|
+
case 'ECDH':
|
|
1348
|
+
result = ecImportKey(
|
|
1349
|
+
format,
|
|
1350
|
+
data,
|
|
1351
|
+
normalizedAlgorithm,
|
|
1352
|
+
extractable,
|
|
1353
|
+
keyUsages,
|
|
1354
|
+
);
|
|
1355
|
+
break;
|
|
1356
|
+
case 'HMAC':
|
|
1357
|
+
result = await hmacImportKey(
|
|
1358
|
+
normalizedAlgorithm,
|
|
1359
|
+
format,
|
|
1360
|
+
data as BufferLike | JWK,
|
|
1361
|
+
extractable,
|
|
1362
|
+
keyUsages,
|
|
1363
|
+
);
|
|
1364
|
+
break;
|
|
1365
|
+
case 'AES-CTR':
|
|
1366
|
+
// Fall through
|
|
1367
|
+
case 'AES-CBC':
|
|
1368
|
+
// Fall through
|
|
1369
|
+
case 'AES-GCM':
|
|
1370
|
+
// Fall through
|
|
1371
|
+
case 'AES-KW':
|
|
1372
|
+
result = await aesImportKey(
|
|
1373
|
+
normalizedAlgorithm,
|
|
1374
|
+
format,
|
|
1375
|
+
data as BufferLike | JWK,
|
|
1376
|
+
extractable,
|
|
1377
|
+
keyUsages,
|
|
1378
|
+
);
|
|
1379
|
+
break;
|
|
1380
|
+
case 'PBKDF2':
|
|
1381
|
+
result = await importGenericSecretKey(
|
|
1382
|
+
normalizedAlgorithm,
|
|
1383
|
+
format,
|
|
1384
|
+
data as BufferLike | BinaryLike,
|
|
1385
|
+
extractable,
|
|
1386
|
+
keyUsages,
|
|
1387
|
+
);
|
|
1388
|
+
break;
|
|
1389
|
+
case 'Ed25519':
|
|
1390
|
+
// Fall through
|
|
1391
|
+
case 'Ed448':
|
|
1392
|
+
result = edImportKey(
|
|
1393
|
+
format,
|
|
1394
|
+
data as BufferLike,
|
|
1395
|
+
normalizedAlgorithm,
|
|
1396
|
+
extractable,
|
|
1397
|
+
keyUsages,
|
|
1398
|
+
);
|
|
1399
|
+
break;
|
|
1400
|
+
default:
|
|
1401
|
+
throw new Error(
|
|
1402
|
+
`"subtle.importKey()" is not implemented for ${normalizedAlgorithm.name}`,
|
|
1403
|
+
);
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
if (
|
|
1407
|
+
(result.type === 'secret' || result.type === 'private') &&
|
|
1408
|
+
result.usages.length === 0
|
|
1409
|
+
) {
|
|
1410
|
+
throw new Error(
|
|
1411
|
+
`Usages cannot be empty when importing a ${result.type} key.`,
|
|
1412
|
+
);
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
return result;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
async sign(
|
|
1419
|
+
algorithm: SubtleAlgorithm,
|
|
1420
|
+
key: CryptoKey,
|
|
1421
|
+
data: BufferLike,
|
|
1422
|
+
): Promise<ArrayBuffer> {
|
|
1423
|
+
return signVerify(algorithm, key, data) as ArrayBuffer;
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
async verify(
|
|
1427
|
+
algorithm: SubtleAlgorithm,
|
|
1428
|
+
key: CryptoKey,
|
|
1429
|
+
signature: BufferLike,
|
|
1430
|
+
data: BufferLike,
|
|
1431
|
+
): Promise<ArrayBuffer> {
|
|
1432
|
+
return signVerify(algorithm, key, data, signature) as ArrayBuffer;
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
export const subtle = new Subtle();
|