react-native-quick-crypto 1.0.8 → 1.0.10
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 +56 -6
- package/README.md +17 -11
- package/android/CMakeLists.txt +4 -0
- package/android/build.gradle +3 -0
- package/cpp/cipher/HybridCipherFactory.hpp +15 -1
- package/cpp/cipher/OCBCipher.cpp +4 -4
- package/cpp/cipher/XChaCha20Poly1305Cipher.cpp +161 -0
- package/cpp/cipher/XChaCha20Poly1305Cipher.hpp +43 -0
- package/cpp/cipher/XSalsa20Poly1305Cipher.cpp +145 -0
- package/cpp/cipher/XSalsa20Poly1305Cipher.hpp +42 -0
- package/cpp/dh/HybridDiffieHellman.cpp +10 -0
- package/cpp/dh/HybridDiffieHellman.hpp +1 -0
- package/cpp/ec/HybridEcKeyPair.cpp +21 -0
- package/cpp/ec/HybridEcKeyPair.hpp +1 -0
- package/cpp/hash/HybridHash.cpp +1 -1
- package/cpp/hash/HybridHash.hpp +1 -1
- package/cpp/hmac/HybridHmac.cpp +1 -1
- package/cpp/hmac/HybridHmac.hpp +1 -1
- package/cpp/keys/HybridKeyObjectHandle.cpp +112 -1
- package/cpp/keys/HybridKeyObjectHandle.hpp +5 -1
- package/deps/ncrypto/.bazelrc +0 -1
- package/deps/ncrypto/.bazelversion +1 -1
- package/deps/ncrypto/.github/workflows/commitlint.yml +16 -0
- package/deps/ncrypto/.github/workflows/linter.yml +2 -2
- package/deps/ncrypto/.github/workflows/release-please.yml +16 -0
- package/deps/ncrypto/.github/workflows/ubuntu.yml +82 -0
- package/deps/ncrypto/.release-please-manifest.json +3 -0
- package/deps/ncrypto/BUILD.bazel +9 -1
- package/deps/ncrypto/CHANGELOG.md +37 -0
- package/deps/ncrypto/CMakeLists.txt +35 -11
- package/deps/ncrypto/MODULE.bazel +16 -1
- package/deps/ncrypto/MODULE.bazel.lock +299 -118
- package/deps/ncrypto/cmake/ncrypto-flags.cmake +1 -0
- package/deps/ncrypto/include/ncrypto/aead.h +137 -0
- package/deps/ncrypto/include/ncrypto/version.h +14 -0
- package/deps/ncrypto/include/ncrypto.h +85 -230
- package/deps/ncrypto/ncrypto.pc.in +10 -0
- package/deps/ncrypto/release-please-config.json +11 -0
- package/deps/ncrypto/src/CMakeLists.txt +31 -6
- package/deps/ncrypto/src/aead.cpp +302 -0
- package/deps/ncrypto/src/ncrypto.cpp +274 -556
- package/deps/ncrypto/tests/BUILD.bazel +2 -0
- package/deps/ncrypto/tests/basic.cpp +772 -2
- package/deps/ncrypto/tools/run-clang-format.sh +5 -5
- package/lib/commonjs/diffie-hellman.js +4 -1
- package/lib/commonjs/diffie-hellman.js.map +1 -1
- package/lib/commonjs/ec.js +20 -25
- package/lib/commonjs/ec.js.map +1 -1
- package/lib/commonjs/ed.js +1 -2
- package/lib/commonjs/ed.js.map +1 -1
- package/lib/commonjs/hash.js +7 -0
- package/lib/commonjs/hash.js.map +1 -1
- package/lib/commonjs/index.js +24 -2
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/keys/classes.js +9 -5
- package/lib/commonjs/keys/classes.js.map +1 -1
- package/lib/commonjs/subtle.js +82 -31
- package/lib/commonjs/subtle.js.map +1 -1
- package/lib/commonjs/utils/types.js.map +1 -1
- package/lib/module/diffie-hellman.js +4 -0
- package/lib/module/diffie-hellman.js.map +1 -1
- package/lib/module/ec.js +19 -25
- package/lib/module/ec.js.map +1 -1
- package/lib/module/ed.js +1 -2
- package/lib/module/ed.js.map +1 -1
- package/lib/module/hash.js +6 -0
- package/lib/module/hash.js.map +1 -1
- package/lib/module/index.js +10 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/keys/classes.js +9 -5
- package/lib/module/keys/classes.js.map +1 -1
- package/lib/module/subtle.js +83 -32
- package/lib/module/subtle.js.map +1 -1
- package/lib/module/utils/types.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/typescript/diffie-hellman.d.ts +2 -0
- package/lib/typescript/diffie-hellman.d.ts.map +1 -1
- package/lib/typescript/ec.d.ts +1 -0
- package/lib/typescript/ec.d.ts.map +1 -1
- package/lib/typescript/ed.d.ts.map +1 -1
- package/lib/typescript/hash.d.ts +2 -0
- package/lib/typescript/hash.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +7 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keys/classes.d.ts +2 -0
- package/lib/typescript/keys/classes.d.ts.map +1 -1
- package/lib/typescript/specs/diffie-hellman.nitro.d.ts +1 -0
- package/lib/typescript/specs/diffie-hellman.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/ecKeyPair.nitro.d.ts +1 -0
- package/lib/typescript/specs/ecKeyPair.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +2 -0
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
- package/lib/typescript/subtle.d.ts.map +1 -1
- package/lib/typescript/utils/types.d.ts +12 -5
- package/lib/typescript/utils/types.d.ts.map +1 -1
- package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +8 -5
- package/nitrogen/generated/android/QuickCrypto+autolinking.gradle +1 -1
- package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +54 -54
- package/nitrogen/generated/android/QuickCryptoOnLoad.hpp +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/crypto/QuickCryptoOnLoad.kt +1 -1
- package/nitrogen/generated/ios/QuickCrypto+autolinking.rb +2 -2
- 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 +1 -1
- package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +54 -54
- package/nitrogen/generated/ios/QuickCryptoAutolinking.swift +5 -1
- package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +1 -1
- package/nitrogen/generated/shared/c++/CipherArgs.hpp +34 -19
- package/nitrogen/generated/shared/c++/HybridBlake3Spec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridBlake3Spec.hpp +1 -3
- package/nitrogen/generated/shared/c++/HybridCipherFactorySpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridCipherFactorySpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridCipherSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridCipherSpec.hpp +1 -3
- package/nitrogen/generated/shared/c++/HybridDiffieHellmanSpec.cpp +2 -1
- package/nitrogen/generated/shared/c++/HybridDiffieHellmanSpec.hpp +3 -3
- package/nitrogen/generated/shared/c++/HybridECDHSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridECDHSpec.hpp +2 -3
- package/nitrogen/generated/shared/c++/HybridEcKeyPairSpec.cpp +2 -1
- package/nitrogen/generated/shared/c++/HybridEcKeyPairSpec.hpp +2 -3
- package/nitrogen/generated/shared/c++/HybridEdKeyPairSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridEdKeyPairSpec.hpp +2 -3
- package/nitrogen/generated/shared/c++/HybridHashSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridHashSpec.hpp +2 -4
- package/nitrogen/generated/shared/c++/HybridHkdfSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridHkdfSpec.hpp +2 -3
- package/nitrogen/generated/shared/c++/HybridHmacSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridHmacSpec.hpp +3 -4
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +3 -1
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +8 -4
- package/nitrogen/generated/shared/c++/HybridMlDsaKeyPairSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridMlDsaKeyPairSpec.hpp +2 -3
- package/nitrogen/generated/shared/c++/HybridPbkdf2Spec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridPbkdf2Spec.hpp +2 -3
- package/nitrogen/generated/shared/c++/HybridRandomSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridRandomSpec.hpp +2 -3
- package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.hpp +1 -3
- package/nitrogen/generated/shared/c++/HybridRsaKeyPairSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridRsaKeyPairSpec.hpp +1 -3
- package/nitrogen/generated/shared/c++/HybridScryptSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridScryptSpec.hpp +2 -3
- package/nitrogen/generated/shared/c++/HybridSignHandleSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridSignHandleSpec.hpp +1 -3
- package/nitrogen/generated/shared/c++/HybridUtilsSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridUtilsSpec.hpp +2 -3
- package/nitrogen/generated/shared/c++/HybridVerifyHandleSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridVerifyHandleSpec.hpp +1 -3
- package/nitrogen/generated/shared/c++/JWK.hpp +84 -68
- package/nitrogen/generated/shared/c++/JWKkty.hpp +5 -1
- package/nitrogen/generated/shared/c++/JWKuse.hpp +1 -1
- package/nitrogen/generated/shared/c++/KFormatType.hpp +1 -1
- package/nitrogen/generated/shared/c++/KeyDetail.hpp +39 -23
- package/nitrogen/generated/shared/c++/KeyEncoding.hpp +1 -1
- package/nitrogen/generated/shared/c++/KeyObject.hpp +21 -5
- package/nitrogen/generated/shared/c++/KeyType.hpp +1 -1
- package/nitrogen/generated/shared/c++/KeyUsage.hpp +1 -1
- package/nitrogen/generated/shared/c++/NamedCurve.hpp +1 -1
- package/package.json +10 -7
- package/src/diffie-hellman.ts +6 -0
- package/src/ec.ts +23 -19
- package/src/ed.ts +1 -2
- package/src/hash.ts +11 -0
- package/src/index.ts +9 -0
- package/src/keys/classes.ts +10 -3
- package/src/specs/diffie-hellman.nitro.ts +1 -0
- package/src/specs/ecKeyPair.nitro.ts +2 -0
- package/src/specs/keyObjectHandle.nitro.ts +2 -0
- package/src/subtle.ts +131 -32
- package/src/utils/types.ts +18 -3
- package/deps/ncrypto/WORKSPACE +0 -15
package/QuickCrypto.podspec
CHANGED
|
@@ -22,10 +22,50 @@ Pod::Spec.new do |s|
|
|
|
22
22
|
sodium_enabled = ENV['SODIUM_ENABLED'] == '1'
|
|
23
23
|
Pod::UI.puts("[QuickCrypto] 🧂 has libsodium #{sodium_enabled ? "enabled" : "disabled"}!")
|
|
24
24
|
|
|
25
|
+
# Ensure libsodium source is present during podspec evaluation when enabled.
|
|
26
|
+
# This is necessary because prepare_command is skipped for :path pods.
|
|
27
|
+
if sodium_enabled
|
|
28
|
+
sodium_version = "1.0.20"
|
|
29
|
+
sodium_dir = File.join(__dir__, "ios", "libsodium-stable")
|
|
30
|
+
sodium_header = File.join(sodium_dir, "src", "libsodium", "include", "sodium.h")
|
|
31
|
+
unless File.exist?(sodium_header)
|
|
32
|
+
FileUtils.mkdir_p(File.join(__dir__, "ios"))
|
|
33
|
+
FileUtils.rm_rf(sodium_dir) if File.directory?(sodium_dir)
|
|
34
|
+
|
|
35
|
+
Pod::UI.puts "[QuickCrypto] ⬇️ Downloading libsodium source..."
|
|
36
|
+
Dir.chdir(__dir__) do
|
|
37
|
+
system("curl -sSfL --connect-timeout 30 --max-time 300 -o ios/libsodium.tar.gz https://download.libsodium.org/libsodium/releases/libsodium-#{sodium_version}-stable.tar.gz") || raise("Failed to download libsodium")
|
|
38
|
+
system("tar -xzf ios/libsodium.tar.gz -C ios") || raise("Failed to extract libsodium")
|
|
39
|
+
File.delete("ios/libsodium.tar.gz") if File.exist?("ios/libsodium.tar.gz")
|
|
40
|
+
end
|
|
41
|
+
Pod::UI.puts "[QuickCrypto] ✅ libsodium source downloaded successfully"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
25
45
|
# OpenSSL 3.6+ vendored xcframework (not yet on CocoaPods trunk)
|
|
26
|
-
openssl_version = "3.6.
|
|
46
|
+
openssl_version = "3.6.0001"
|
|
27
47
|
openssl_url = "https://github.com/krzyzanowskim/OpenSSL/releases/download/#{openssl_version}/OpenSSL.xcframework.zip"
|
|
28
48
|
|
|
49
|
+
# Ensure OpenSSL.xcframework is present during podspec evaluation.
|
|
50
|
+
# This is necessary because prepare_command is skipped for :path pods,
|
|
51
|
+
# which is how React Native native modules are installed.
|
|
52
|
+
# See: https://github.com/margelo/react-native-quick-crypto/issues/882
|
|
53
|
+
openssl_dir = File.join(__dir__, "OpenSSL.xcframework")
|
|
54
|
+
openssl_plist = File.join(openssl_dir, "Info.plist")
|
|
55
|
+
unless File.exist?(openssl_plist)
|
|
56
|
+
# Clean up any partial download
|
|
57
|
+
FileUtils.rm_rf(openssl_dir) if File.directory?(openssl_dir)
|
|
58
|
+
FileUtils.rm_f(File.join(__dir__, "OpenSSL.xcframework.zip"))
|
|
59
|
+
|
|
60
|
+
Pod::UI.puts "[QuickCrypto] ⬇️ Downloading OpenSSL.xcframework..."
|
|
61
|
+
Dir.chdir(__dir__) do
|
|
62
|
+
system("curl -sSfL --connect-timeout 30 --max-time 300 -o OpenSSL.xcframework.zip #{openssl_url}") || raise("Failed to download OpenSSL")
|
|
63
|
+
system("unzip -q -o OpenSSL.xcframework.zip") || raise("Failed to unzip OpenSSL")
|
|
64
|
+
File.delete("OpenSSL.xcframework.zip") if File.exist?("OpenSSL.xcframework.zip")
|
|
65
|
+
end
|
|
66
|
+
Pod::UI.puts "[QuickCrypto] ✅ OpenSSL.xcframework downloaded successfully"
|
|
67
|
+
end
|
|
68
|
+
|
|
29
69
|
if sodium_enabled
|
|
30
70
|
# Build libsodium from source for XSalsa20 cipher support
|
|
31
71
|
# CocoaPods packages are outdated (1.0.12) and SPM causes module conflicts
|
|
@@ -72,7 +112,7 @@ Pod::Spec.new do |s|
|
|
|
72
112
|
# implementation (C++)
|
|
73
113
|
"cpp/**/*.{hpp,cpp}",
|
|
74
114
|
# dependencies (C++) - ncrypto
|
|
75
|
-
"deps/ncrypto/include
|
|
115
|
+
"deps/ncrypto/include/**/*.{h}",
|
|
76
116
|
"deps/ncrypto/src/*.{cpp}",
|
|
77
117
|
# dependencies (C) - exclude BLAKE3 x86 SIMD files (only use portable + NEON for ARM)
|
|
78
118
|
"deps/blake3/c/*.{h,c}",
|
|
@@ -103,6 +143,9 @@ Pod::Spec.new do |s|
|
|
|
103
143
|
"deps/blake3/c/example.c",
|
|
104
144
|
"deps/blake3/c/example_tbb.c",
|
|
105
145
|
"deps/blake3/c/blake3_tbb.cpp",
|
|
146
|
+
# Exclude ncrypto version.h to avoid header name collision with libsodium's version.h
|
|
147
|
+
# (ncrypto.h includes it via relative path "ncrypto/version.h" which still resolves)
|
|
148
|
+
"deps/ncrypto/include/ncrypto/version.h",
|
|
106
149
|
# Exclude non-C parts of BLAKE3 repo (Rust, benchmarks, tools, etc.)
|
|
107
150
|
"deps/blake3/src/**/*",
|
|
108
151
|
"deps/blake3/b3sum/**/*",
|
|
@@ -125,7 +168,11 @@ Pod::Spec.new do |s|
|
|
|
125
168
|
"CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
|
|
126
169
|
"CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES" => "YES",
|
|
127
170
|
# Exclude ARM NEON source when building x86_64 simulator (no NEON support).
|
|
128
|
-
"EXCLUDED_SOURCE_FILE_NAMES[sdk=iphonesimulator*][arch=x86_64]" => "deps/blake3/c/blake3_neon.c"
|
|
171
|
+
"EXCLUDED_SOURCE_FILE_NAMES[sdk=iphonesimulator*][arch=x86_64]" => "deps/blake3/c/blake3_neon.c",
|
|
172
|
+
# Disable x86 SIMD intrinsics on iOS simulator — the .c implementation files are already
|
|
173
|
+
# excluded above, but blake3_dispatch.c still references the symbols unless these macros
|
|
174
|
+
# are defined. Mirrors the Android CMakeLists.txt approach (line 18-22).
|
|
175
|
+
"GCC_PREPROCESSOR_DEFINITIONS[sdk=iphonesimulator*][arch=x86_64]" => "$(inherited) BLAKE3_NO_AVX512 BLAKE3_NO_AVX2 BLAKE3_NO_SSE41 BLAKE3_NO_SSE2"
|
|
129
176
|
}
|
|
130
177
|
|
|
131
178
|
# Add cpp subdirectories to header search paths
|
|
@@ -141,12 +188,15 @@ Pod::Spec.new do |s|
|
|
|
141
188
|
]
|
|
142
189
|
|
|
143
190
|
if sodium_enabled
|
|
191
|
+
# Use absolute path from __dir__ which resolves symlinks correctly.
|
|
192
|
+
# This is necessary in monorepo setups where the podspec is accessed via symlink
|
|
193
|
+
# but the source files are resolved to their real paths during compilation.
|
|
194
|
+
real_sodium_include = File.join(__dir__, "ios", "libsodium-stable", "src", "libsodium", "include")
|
|
144
195
|
sodium_headers = [
|
|
145
196
|
"\"$(PODS_TARGET_SRCROOT)/ios/libsodium-stable/src/libsodium/include\"",
|
|
146
197
|
"\"$(PODS_TARGET_SRCROOT)/ios/libsodium-stable/src/libsodium/include/sodium\"",
|
|
147
|
-
"\"
|
|
148
|
-
"\"
|
|
149
|
-
"\"$(PODS_ROOT)/../../packages/react-native-quick-crypto/ios/libsodium-stable/src/libsodium/include/sodium\""
|
|
198
|
+
"\"#{real_sodium_include}\"",
|
|
199
|
+
"\"#{real_sodium_include}/sodium\""
|
|
150
200
|
]
|
|
151
201
|
xcconfig["HEADER_SEARCH_PATHS"] = (cpp_headers + sodium_headers).join(' ')
|
|
152
202
|
xcconfig["GCC_PREPROCESSOR_DEFINITIONS"] = "$(inherited) FOLLY_NO_CONFIG FOLLY_CFG_NO_COROUTINES BLSALLOC_SODIUM=1"
|
package/README.md
CHANGED
|
@@ -10,19 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
A fast implementation of Node's `crypto` module.
|
|
12
12
|
|
|
13
|
-
> Note: This version `1.x` completed a major refactor, porting to OpenSSL 3.6+, New Architecture, Bridgeless, and [`Nitro Modules`](https://github.com/mrousavy/react-native-nitro). It should be at or above feature-parity compared to the `0.x` version. Status, as always, will be represented in [implementation-coverage.md](./.docs/implementation-coverage.md).
|
|
14
|
-
|
|
15
|
-
> Note: Minimum supported version of React Native is `0.75`. If you need to use earlier versions, please use `0.x` versions of this library.
|
|
16
|
-
|
|
17
13
|
## Features
|
|
18
14
|
|
|
19
15
|
Unlike any other current JS-based polyfills, react-native-quick-crypto is written in C/C++ JSI and provides much greater performance - especially on mobile devices.
|
|
20
|
-
QuickCrypto can be used as a drop-in replacement for your Web3/Crypto apps to speed up common cryptography functions.
|
|
16
|
+
QuickCrypto can be used as a drop-in replacement for your Web3/Crypto apps or CRDT-based local first databases to speed up common cryptography functions.
|
|
21
17
|
|
|
22
|
-
- 🏎️
|
|
23
|
-
- ⚡️ Lightning fast implementation with pure C++ and JSI
|
|
18
|
+
- 🏎️ Hundreds of times faster than all JS-based solutions
|
|
19
|
+
- ⚡️ Lightning fast implementation with Nitro Modules (pure C++ and JSI) instead of JS
|
|
24
20
|
- 🧪 Well tested in JS and C++ (OpenSSL)
|
|
25
|
-
- 💰 Made for crypto apps and
|
|
21
|
+
- 💰 Made for crypto apps and wallets
|
|
26
22
|
- 🔢 Secure native compiled cryptography
|
|
27
23
|
- 🔁 Easy drop-in replacement for [crypto-browserify](https://github.com/browserify/crypto-browserify) or [react-native-crypto](https://github.com/tradle/react-native-crypto)
|
|
28
24
|
|
|
@@ -33,6 +29,8 @@ QuickCrypto can be used as a drop-in replacement for your Web3/Crypto apps to sp
|
|
|
33
29
|
| `1.x` | new [->](https://github.com/reactwg/react-native-new-architecture/blob/main/docs/enable-apps.md) | Nitro Modules [->](https://github.com/mrousavy/nitro) |
|
|
34
30
|
| `0.x` | old, new 🤞 | Bridge & JSI |
|
|
35
31
|
|
|
32
|
+
> Note: Minimum supported version of React Native is `0.75`. If you need to use earlier versions, please use `0.x` versions of this library.
|
|
33
|
+
|
|
36
34
|
## Migration
|
|
37
35
|
|
|
38
36
|
Our goal in refactoring to v1.0 was to maintain API compatibility. If you are upgrading to v1.0 from v0.x, and find any discrepancies, please open an issue in this repo.
|
|
@@ -50,12 +48,18 @@ There is a benchmark suite in the Example app in this repo that has benchmarks o
|
|
|
50
48
|
</h3>
|
|
51
49
|
|
|
52
50
|
```sh
|
|
53
|
-
bun add react-native-quick-crypto react-native-nitro-modules
|
|
51
|
+
bun add react-native-quick-crypto react-native-nitro-modules react-native-quick-base64
|
|
54
52
|
cd ios && pod install
|
|
55
53
|
```
|
|
56
54
|
|
|
57
55
|
<h3>
|
|
58
|
-
Expo <a href="#"
|
|
56
|
+
Expo <a href="#">
|
|
57
|
+
<picture>
|
|
58
|
+
<source media="(prefers-color-scheme: dark)" srcset="./.docs/img/expo/dark.png" />
|
|
59
|
+
<source media="(prefers-color-scheme: light)" srcset="./.docs/img/expo/light.png" />
|
|
60
|
+
<img alt="Expo" src="./.docs/img/expo/light.png" height="12" />
|
|
61
|
+
</picture>
|
|
62
|
+
</a>
|
|
59
63
|
</h3>
|
|
60
64
|
|
|
61
65
|
```sh
|
|
@@ -114,7 +118,7 @@ module.exports = {
|
|
|
114
118
|
+ alias: {
|
|
115
119
|
+ 'crypto': 'react-native-quick-crypto',
|
|
116
120
|
+ 'stream': 'readable-stream',
|
|
117
|
-
+ 'buffer': '
|
|
121
|
+
+ 'buffer': 'react-native-quick-crypto',
|
|
118
122
|
+ },
|
|
119
123
|
+ },
|
|
120
124
|
+ ],
|
|
@@ -123,6 +127,8 @@ module.exports = {
|
|
|
123
127
|
};
|
|
124
128
|
```
|
|
125
129
|
|
|
130
|
+
> **Note:** `react-native-quick-crypto` re-exports `Buffer` from `@craftzdog/react-native-buffer`, so you can use either as the buffer alias. Using `react-native-quick-crypto` ensures a single Buffer instance across your app.
|
|
131
|
+
|
|
126
132
|
Then restart your bundler using `yarn start --reset-cache`.
|
|
127
133
|
|
|
128
134
|
## Usage
|
package/android/CMakeLists.txt
CHANGED
|
@@ -32,6 +32,8 @@ add_library(
|
|
|
32
32
|
../cpp/cipher/HybridRsaCipher.cpp
|
|
33
33
|
../cpp/cipher/OCBCipher.cpp
|
|
34
34
|
../cpp/cipher/XSalsa20Cipher.cpp
|
|
35
|
+
../cpp/cipher/XSalsa20Poly1305Cipher.cpp
|
|
36
|
+
../cpp/cipher/XChaCha20Poly1305Cipher.cpp
|
|
35
37
|
../cpp/cipher/ChaCha20Cipher.cpp
|
|
36
38
|
../cpp/cipher/ChaCha20Poly1305Cipher.cpp
|
|
37
39
|
../cpp/dh/HybridDiffieHellman.cpp
|
|
@@ -53,6 +55,8 @@ add_library(
|
|
|
53
55
|
../cpp/utils/HybridUtils.cpp
|
|
54
56
|
${BLAKE3_SOURCES}
|
|
55
57
|
../deps/fastpbkdf2/fastpbkdf2.c
|
|
58
|
+
../deps/ncrypto/src/aead.cpp
|
|
59
|
+
../deps/ncrypto/src/engine.cpp
|
|
56
60
|
../deps/ncrypto/src/ncrypto.cpp
|
|
57
61
|
)
|
|
58
62
|
|
package/android/build.gradle
CHANGED
|
@@ -79,6 +79,9 @@ android {
|
|
|
79
79
|
buildFeatures {
|
|
80
80
|
buildConfig true
|
|
81
81
|
prefab true
|
|
82
|
+
// Explicitly disable RenderScript (deprecated since Android 12, removed in AGP 9.0)
|
|
83
|
+
// to suppress 'isRenderscriptDebuggable is obsolete' warning. See #802.
|
|
84
|
+
renderScript = false
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
packagingOptions {
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
#include "HybridCipherFactorySpec.hpp"
|
|
12
12
|
#include "OCBCipher.hpp"
|
|
13
13
|
#include "QuickCryptoUtils.hpp"
|
|
14
|
+
#include "XChaCha20Poly1305Cipher.hpp"
|
|
14
15
|
#include "XSalsa20Cipher.hpp"
|
|
16
|
+
#include "XSalsa20Poly1305Cipher.hpp"
|
|
15
17
|
|
|
16
18
|
namespace margelo::nitro::crypto {
|
|
17
19
|
|
|
@@ -88,7 +90,7 @@ class HybridCipherFactory : public HybridCipherFactorySpec {
|
|
|
88
90
|
}
|
|
89
91
|
EVP_CIPHER_free(cipher);
|
|
90
92
|
|
|
91
|
-
// libsodium
|
|
93
|
+
// libsodium ciphers
|
|
92
94
|
std::string cipherName = toLower(args.cipherType);
|
|
93
95
|
if (cipherName == "xsalsa20") {
|
|
94
96
|
cipherInstance = std::make_shared<XSalsa20Cipher>();
|
|
@@ -96,6 +98,18 @@ class HybridCipherFactory : public HybridCipherFactorySpec {
|
|
|
96
98
|
cipherInstance->init(args.cipherKey, args.iv);
|
|
97
99
|
return cipherInstance;
|
|
98
100
|
}
|
|
101
|
+
if (cipherName == "xsalsa20-poly1305") {
|
|
102
|
+
cipherInstance = std::make_shared<XSalsa20Poly1305Cipher>();
|
|
103
|
+
cipherInstance->setArgs(args);
|
|
104
|
+
cipherInstance->init(args.cipherKey, args.iv);
|
|
105
|
+
return cipherInstance;
|
|
106
|
+
}
|
|
107
|
+
if (cipherName == "xchacha20-poly1305") {
|
|
108
|
+
cipherInstance = std::make_shared<XChaCha20Poly1305Cipher>();
|
|
109
|
+
cipherInstance->setArgs(args);
|
|
110
|
+
cipherInstance->init(args.cipherKey, args.iv);
|
|
111
|
+
return cipherInstance;
|
|
112
|
+
}
|
|
99
113
|
|
|
100
114
|
// Unsupported cipher type
|
|
101
115
|
throw std::runtime_error("Unsupported or unknown cipher type: " + args.cipherType);
|
package/cpp/cipher/OCBCipher.cpp
CHANGED
|
@@ -13,9 +13,9 @@ void OCBCipher::init(const std::shared_ptr<ArrayBuffer>& key, const std::shared_
|
|
|
13
13
|
HybridCipher::init(key, iv);
|
|
14
14
|
auth_tag_len = tag_len;
|
|
15
15
|
|
|
16
|
-
// Set tag length for OCB (must be
|
|
17
|
-
if (auth_tag_len <
|
|
18
|
-
throw std::runtime_error("OCB tag length must be between
|
|
16
|
+
// Set tag length for OCB (must be 8-16 bytes)
|
|
17
|
+
if (auth_tag_len < 8 || auth_tag_len > 16) {
|
|
18
|
+
throw std::runtime_error("OCB tag length must be between 8 and 16 bytes");
|
|
19
19
|
}
|
|
20
20
|
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, auth_tag_len, nullptr) != 1) {
|
|
21
21
|
throw std::runtime_error("Failed to set OCB tag length");
|
|
@@ -42,7 +42,7 @@ bool OCBCipher::setAuthTag(const std::shared_ptr<ArrayBuffer>& tag) {
|
|
|
42
42
|
}
|
|
43
43
|
auto native_tag = ToNativeArrayBuffer(tag);
|
|
44
44
|
size_t tag_len = native_tag->size();
|
|
45
|
-
if (tag_len <
|
|
45
|
+
if (tag_len < 8 || tag_len > 16) {
|
|
46
46
|
throw std::runtime_error("Invalid OCB tag length");
|
|
47
47
|
}
|
|
48
48
|
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, native_tag->data()) != 1) {
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#include "XChaCha20Poly1305Cipher.hpp"
|
|
2
|
+
|
|
3
|
+
#include <cstring>
|
|
4
|
+
#include <stdexcept>
|
|
5
|
+
|
|
6
|
+
#include "NitroModules/ArrayBuffer.hpp"
|
|
7
|
+
#include "QuickCryptoUtils.hpp"
|
|
8
|
+
|
|
9
|
+
namespace margelo::nitro::crypto {
|
|
10
|
+
|
|
11
|
+
XChaCha20Poly1305Cipher::~XChaCha20Poly1305Cipher() {
|
|
12
|
+
#ifdef BLSALLOC_SODIUM
|
|
13
|
+
sodium_memzero(key_, kKeySize);
|
|
14
|
+
sodium_memzero(nonce_, kNonceSize);
|
|
15
|
+
sodium_memzero(auth_tag_, kTagSize);
|
|
16
|
+
if (!data_buffer_.empty()) {
|
|
17
|
+
sodium_memzero(data_buffer_.data(), data_buffer_.size());
|
|
18
|
+
}
|
|
19
|
+
if (!aad_.empty()) {
|
|
20
|
+
sodium_memzero(aad_.data(), aad_.size());
|
|
21
|
+
}
|
|
22
|
+
#else
|
|
23
|
+
std::memset(key_, 0, kKeySize);
|
|
24
|
+
std::memset(nonce_, 0, kNonceSize);
|
|
25
|
+
std::memset(auth_tag_, 0, kTagSize);
|
|
26
|
+
#endif
|
|
27
|
+
data_buffer_.clear();
|
|
28
|
+
aad_.clear();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
void XChaCha20Poly1305Cipher::init(const std::shared_ptr<ArrayBuffer> cipher_key, const std::shared_ptr<ArrayBuffer> iv) {
|
|
32
|
+
auto native_key = ToNativeArrayBuffer(cipher_key);
|
|
33
|
+
auto native_iv = ToNativeArrayBuffer(iv);
|
|
34
|
+
|
|
35
|
+
if (native_key->size() != kKeySize) {
|
|
36
|
+
throw std::runtime_error("XChaCha20-Poly1305 key must be 32 bytes, got " + std::to_string(native_key->size()) + " bytes");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (native_iv->size() != kNonceSize) {
|
|
40
|
+
throw std::runtime_error("XChaCha20-Poly1305 nonce must be 24 bytes, got " + std::to_string(native_iv->size()) + " bytes");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
std::memcpy(key_, native_key->data(), kKeySize);
|
|
44
|
+
std::memcpy(nonce_, native_iv->data(), kNonceSize);
|
|
45
|
+
|
|
46
|
+
data_buffer_.clear();
|
|
47
|
+
aad_.clear();
|
|
48
|
+
final_called_ = false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
std::shared_ptr<ArrayBuffer> XChaCha20Poly1305Cipher::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
52
|
+
#ifndef BLSALLOC_SODIUM
|
|
53
|
+
throw std::runtime_error("XChaCha20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
54
|
+
#else
|
|
55
|
+
auto native_data = ToNativeArrayBuffer(data);
|
|
56
|
+
size_t data_len = native_data->size();
|
|
57
|
+
|
|
58
|
+
size_t old_size = data_buffer_.size();
|
|
59
|
+
data_buffer_.resize(old_size + data_len);
|
|
60
|
+
std::memcpy(data_buffer_.data() + old_size, native_data->data(), data_len);
|
|
61
|
+
|
|
62
|
+
return std::make_shared<NativeArrayBuffer>(nullptr, 0, nullptr);
|
|
63
|
+
#endif
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
std::shared_ptr<ArrayBuffer> XChaCha20Poly1305Cipher::final() {
|
|
67
|
+
#ifndef BLSALLOC_SODIUM
|
|
68
|
+
throw std::runtime_error("XChaCha20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
69
|
+
#else
|
|
70
|
+
if (is_cipher) {
|
|
71
|
+
uint8_t* ciphertext = new uint8_t[data_buffer_.size()];
|
|
72
|
+
|
|
73
|
+
int result =
|
|
74
|
+
crypto_aead_xchacha20poly1305_ietf_encrypt_detached(ciphertext, auth_tag_, nullptr, data_buffer_.data(), data_buffer_.size(),
|
|
75
|
+
aad_.empty() ? nullptr : aad_.data(), aad_.size(), nullptr, nonce_, key_);
|
|
76
|
+
|
|
77
|
+
if (result != 0) {
|
|
78
|
+
sodium_memzero(ciphertext, data_buffer_.size());
|
|
79
|
+
delete[] ciphertext;
|
|
80
|
+
throw std::runtime_error("XChaCha20Poly1305Cipher: encryption failed");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
final_called_ = true;
|
|
84
|
+
size_t ct_len = data_buffer_.size();
|
|
85
|
+
return std::make_shared<NativeArrayBuffer>(ciphertext, ct_len, [=]() { delete[] ciphertext; });
|
|
86
|
+
} else {
|
|
87
|
+
if (data_buffer_.empty()) {
|
|
88
|
+
final_called_ = true;
|
|
89
|
+
return std::make_shared<NativeArrayBuffer>(nullptr, 0, nullptr);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
uint8_t* plaintext = new uint8_t[data_buffer_.size()];
|
|
93
|
+
|
|
94
|
+
int result =
|
|
95
|
+
crypto_aead_xchacha20poly1305_ietf_decrypt_detached(plaintext, nullptr, data_buffer_.data(), data_buffer_.size(), auth_tag_,
|
|
96
|
+
aad_.empty() ? nullptr : aad_.data(), aad_.size(), nonce_, key_);
|
|
97
|
+
|
|
98
|
+
if (result != 0) {
|
|
99
|
+
sodium_memzero(plaintext, data_buffer_.size());
|
|
100
|
+
delete[] plaintext;
|
|
101
|
+
throw std::runtime_error("XChaCha20Poly1305Cipher: decryption failed - authentication tag mismatch");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
final_called_ = true;
|
|
105
|
+
size_t pt_len = data_buffer_.size();
|
|
106
|
+
return std::make_shared<NativeArrayBuffer>(plaintext, pt_len, [=]() { delete[] plaintext; });
|
|
107
|
+
}
|
|
108
|
+
#endif
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
bool XChaCha20Poly1305Cipher::setAAD(const std::shared_ptr<ArrayBuffer>& data, std::optional<double> plaintextLength) {
|
|
112
|
+
#ifndef BLSALLOC_SODIUM
|
|
113
|
+
throw std::runtime_error("XChaCha20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
114
|
+
#else
|
|
115
|
+
auto native_aad = ToNativeArrayBuffer(data);
|
|
116
|
+
aad_.resize(native_aad->size());
|
|
117
|
+
std::memcpy(aad_.data(), native_aad->data(), native_aad->size());
|
|
118
|
+
return true;
|
|
119
|
+
#endif
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
std::shared_ptr<ArrayBuffer> XChaCha20Poly1305Cipher::getAuthTag() {
|
|
123
|
+
#ifndef BLSALLOC_SODIUM
|
|
124
|
+
throw std::runtime_error("XChaCha20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
125
|
+
#else
|
|
126
|
+
if (!is_cipher) {
|
|
127
|
+
throw std::runtime_error("getAuthTag can only be called during encryption");
|
|
128
|
+
}
|
|
129
|
+
if (!final_called_) {
|
|
130
|
+
throw std::runtime_error("getAuthTag must be called after final()");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
uint8_t* tag_copy = new uint8_t[kTagSize];
|
|
134
|
+
std::memcpy(tag_copy, auth_tag_, kTagSize);
|
|
135
|
+
return std::make_shared<NativeArrayBuffer>(tag_copy, kTagSize, [=]() { delete[] tag_copy; });
|
|
136
|
+
#endif
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
bool XChaCha20Poly1305Cipher::setAuthTag(const std::shared_ptr<ArrayBuffer>& tag) {
|
|
140
|
+
#ifndef BLSALLOC_SODIUM
|
|
141
|
+
throw std::runtime_error("XChaCha20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
142
|
+
#else
|
|
143
|
+
if (is_cipher) {
|
|
144
|
+
throw std::runtime_error("setAuthTag can only be called during decryption");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
auto native_tag = ToNativeArrayBuffer(tag);
|
|
148
|
+
if (native_tag->size() != kTagSize) {
|
|
149
|
+
throw std::runtime_error("XChaCha20-Poly1305 tag must be 16 bytes, got " + std::to_string(native_tag->size()) + " bytes");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
std::memcpy(auth_tag_, native_tag->data(), kTagSize);
|
|
153
|
+
return true;
|
|
154
|
+
#endif
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
bool XChaCha20Poly1305Cipher::setAutoPadding(bool autoPad) {
|
|
158
|
+
throw std::runtime_error("setAutoPadding is not supported for xchacha20-poly1305");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
} // namespace margelo::nitro::crypto
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#ifdef BLSALLOC_SODIUM
|
|
4
|
+
#include "sodium.h"
|
|
5
|
+
#else
|
|
6
|
+
#define crypto_aead_xchacha20poly1305_ietf_KEYBYTES 32U
|
|
7
|
+
#define crypto_aead_xchacha20poly1305_ietf_NPUBBYTES 24U
|
|
8
|
+
#define crypto_aead_xchacha20poly1305_ietf_ABYTES 16U
|
|
9
|
+
#endif
|
|
10
|
+
|
|
11
|
+
#include <vector>
|
|
12
|
+
|
|
13
|
+
#include "HybridCipher.hpp"
|
|
14
|
+
|
|
15
|
+
namespace margelo::nitro::crypto {
|
|
16
|
+
|
|
17
|
+
class XChaCha20Poly1305Cipher : public HybridCipher {
|
|
18
|
+
public:
|
|
19
|
+
XChaCha20Poly1305Cipher() : HybridObject(TAG), final_called_(false) {}
|
|
20
|
+
~XChaCha20Poly1305Cipher();
|
|
21
|
+
|
|
22
|
+
void init(const std::shared_ptr<ArrayBuffer> cipher_key, const std::shared_ptr<ArrayBuffer> iv) override;
|
|
23
|
+
std::shared_ptr<ArrayBuffer> update(const std::shared_ptr<ArrayBuffer>& data) override;
|
|
24
|
+
std::shared_ptr<ArrayBuffer> final() override;
|
|
25
|
+
bool setAAD(const std::shared_ptr<ArrayBuffer>& data, std::optional<double> plaintextLength) override;
|
|
26
|
+
std::shared_ptr<ArrayBuffer> getAuthTag() override;
|
|
27
|
+
bool setAuthTag(const std::shared_ptr<ArrayBuffer>& tag) override;
|
|
28
|
+
bool setAutoPadding(bool autoPad) override;
|
|
29
|
+
|
|
30
|
+
private:
|
|
31
|
+
static constexpr size_t kKeySize = crypto_aead_xchacha20poly1305_ietf_KEYBYTES;
|
|
32
|
+
static constexpr size_t kNonceSize = crypto_aead_xchacha20poly1305_ietf_NPUBBYTES;
|
|
33
|
+
static constexpr size_t kTagSize = crypto_aead_xchacha20poly1305_ietf_ABYTES;
|
|
34
|
+
|
|
35
|
+
uint8_t key_[kKeySize];
|
|
36
|
+
uint8_t nonce_[kNonceSize];
|
|
37
|
+
std::vector<uint8_t> aad_;
|
|
38
|
+
std::vector<uint8_t> data_buffer_;
|
|
39
|
+
uint8_t auth_tag_[kTagSize];
|
|
40
|
+
bool final_called_;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
} // namespace margelo::nitro::crypto
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#include "XSalsa20Poly1305Cipher.hpp"
|
|
2
|
+
|
|
3
|
+
#include <cstring>
|
|
4
|
+
#include <stdexcept>
|
|
5
|
+
|
|
6
|
+
#include "NitroModules/ArrayBuffer.hpp"
|
|
7
|
+
#include "QuickCryptoUtils.hpp"
|
|
8
|
+
|
|
9
|
+
namespace margelo::nitro::crypto {
|
|
10
|
+
|
|
11
|
+
XSalsa20Poly1305Cipher::~XSalsa20Poly1305Cipher() {
|
|
12
|
+
#ifdef BLSALLOC_SODIUM
|
|
13
|
+
sodium_memzero(key_, kKeySize);
|
|
14
|
+
sodium_memzero(nonce_, kNonceSize);
|
|
15
|
+
sodium_memzero(auth_tag_, kTagSize);
|
|
16
|
+
if (!data_buffer_.empty()) {
|
|
17
|
+
sodium_memzero(data_buffer_.data(), data_buffer_.size());
|
|
18
|
+
}
|
|
19
|
+
#else
|
|
20
|
+
std::memset(key_, 0, kKeySize);
|
|
21
|
+
std::memset(nonce_, 0, kNonceSize);
|
|
22
|
+
std::memset(auth_tag_, 0, kTagSize);
|
|
23
|
+
#endif
|
|
24
|
+
data_buffer_.clear();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
void XSalsa20Poly1305Cipher::init(const std::shared_ptr<ArrayBuffer> cipher_key, const std::shared_ptr<ArrayBuffer> iv) {
|
|
28
|
+
auto native_key = ToNativeArrayBuffer(cipher_key);
|
|
29
|
+
auto native_iv = ToNativeArrayBuffer(iv);
|
|
30
|
+
|
|
31
|
+
if (native_key->size() != kKeySize) {
|
|
32
|
+
throw std::runtime_error("XSalsa20-Poly1305 key must be 32 bytes, got " + std::to_string(native_key->size()) + " bytes");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (native_iv->size() != kNonceSize) {
|
|
36
|
+
throw std::runtime_error("XSalsa20-Poly1305 nonce must be 24 bytes, got " + std::to_string(native_iv->size()) + " bytes");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
std::memcpy(key_, native_key->data(), kKeySize);
|
|
40
|
+
std::memcpy(nonce_, native_iv->data(), kNonceSize);
|
|
41
|
+
|
|
42
|
+
data_buffer_.clear();
|
|
43
|
+
final_called_ = false;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
std::shared_ptr<ArrayBuffer> XSalsa20Poly1305Cipher::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
47
|
+
#ifndef BLSALLOC_SODIUM
|
|
48
|
+
throw std::runtime_error("XSalsa20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
49
|
+
#else
|
|
50
|
+
auto native_data = ToNativeArrayBuffer(data);
|
|
51
|
+
size_t data_len = native_data->size();
|
|
52
|
+
|
|
53
|
+
size_t old_size = data_buffer_.size();
|
|
54
|
+
data_buffer_.resize(old_size + data_len);
|
|
55
|
+
std::memcpy(data_buffer_.data() + old_size, native_data->data(), data_len);
|
|
56
|
+
|
|
57
|
+
return std::make_shared<NativeArrayBuffer>(nullptr, 0, nullptr);
|
|
58
|
+
#endif
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
std::shared_ptr<ArrayBuffer> XSalsa20Poly1305Cipher::final() {
|
|
62
|
+
#ifndef BLSALLOC_SODIUM
|
|
63
|
+
throw std::runtime_error("XSalsa20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
64
|
+
#else
|
|
65
|
+
if (is_cipher) {
|
|
66
|
+
uint8_t* ciphertext = new uint8_t[data_buffer_.size()];
|
|
67
|
+
|
|
68
|
+
int result = crypto_secretbox_detached(ciphertext, auth_tag_, data_buffer_.data(), data_buffer_.size(), nonce_, key_);
|
|
69
|
+
|
|
70
|
+
if (result != 0) {
|
|
71
|
+
sodium_memzero(ciphertext, data_buffer_.size());
|
|
72
|
+
delete[] ciphertext;
|
|
73
|
+
throw std::runtime_error("XSalsa20Poly1305Cipher: encryption failed");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
final_called_ = true;
|
|
77
|
+
size_t ct_len = data_buffer_.size();
|
|
78
|
+
return std::make_shared<NativeArrayBuffer>(ciphertext, ct_len, [=]() { delete[] ciphertext; });
|
|
79
|
+
} else {
|
|
80
|
+
if (data_buffer_.empty()) {
|
|
81
|
+
final_called_ = true;
|
|
82
|
+
return std::make_shared<NativeArrayBuffer>(nullptr, 0, nullptr);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
uint8_t* plaintext = new uint8_t[data_buffer_.size()];
|
|
86
|
+
|
|
87
|
+
int result = crypto_secretbox_open_detached(plaintext, data_buffer_.data(), auth_tag_, data_buffer_.size(), nonce_, key_);
|
|
88
|
+
|
|
89
|
+
if (result != 0) {
|
|
90
|
+
sodium_memzero(plaintext, data_buffer_.size());
|
|
91
|
+
delete[] plaintext;
|
|
92
|
+
throw std::runtime_error("XSalsa20Poly1305Cipher: decryption failed - authentication tag mismatch");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
final_called_ = true;
|
|
96
|
+
size_t pt_len = data_buffer_.size();
|
|
97
|
+
return std::make_shared<NativeArrayBuffer>(plaintext, pt_len, [=]() { delete[] plaintext; });
|
|
98
|
+
}
|
|
99
|
+
#endif
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
bool XSalsa20Poly1305Cipher::setAAD(const std::shared_ptr<ArrayBuffer>& data, std::optional<double> plaintextLength) {
|
|
103
|
+
throw std::runtime_error("AAD is not supported for xsalsa20-poly1305 (use xchacha20-poly1305 instead)");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
std::shared_ptr<ArrayBuffer> XSalsa20Poly1305Cipher::getAuthTag() {
|
|
107
|
+
#ifndef BLSALLOC_SODIUM
|
|
108
|
+
throw std::runtime_error("XSalsa20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
109
|
+
#else
|
|
110
|
+
if (!is_cipher) {
|
|
111
|
+
throw std::runtime_error("getAuthTag can only be called during encryption");
|
|
112
|
+
}
|
|
113
|
+
if (!final_called_) {
|
|
114
|
+
throw std::runtime_error("getAuthTag must be called after final()");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
uint8_t* tag_copy = new uint8_t[kTagSize];
|
|
118
|
+
std::memcpy(tag_copy, auth_tag_, kTagSize);
|
|
119
|
+
return std::make_shared<NativeArrayBuffer>(tag_copy, kTagSize, [=]() { delete[] tag_copy; });
|
|
120
|
+
#endif
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
bool XSalsa20Poly1305Cipher::setAuthTag(const std::shared_ptr<ArrayBuffer>& tag) {
|
|
124
|
+
#ifndef BLSALLOC_SODIUM
|
|
125
|
+
throw std::runtime_error("XSalsa20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
126
|
+
#else
|
|
127
|
+
if (is_cipher) {
|
|
128
|
+
throw std::runtime_error("setAuthTag can only be called during decryption");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
auto native_tag = ToNativeArrayBuffer(tag);
|
|
132
|
+
if (native_tag->size() != kTagSize) {
|
|
133
|
+
throw std::runtime_error("XSalsa20-Poly1305 tag must be 16 bytes, got " + std::to_string(native_tag->size()) + " bytes");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
std::memcpy(auth_tag_, native_tag->data(), kTagSize);
|
|
137
|
+
return true;
|
|
138
|
+
#endif
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
bool XSalsa20Poly1305Cipher::setAutoPadding(bool autoPad) {
|
|
142
|
+
throw std::runtime_error("setAutoPadding is not supported for xsalsa20-poly1305");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
} // namespace margelo::nitro::crypto
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#ifdef BLSALLOC_SODIUM
|
|
4
|
+
#include "sodium.h"
|
|
5
|
+
#else
|
|
6
|
+
#define crypto_secretbox_xsalsa20poly1305_KEYBYTES 32U
|
|
7
|
+
#define crypto_secretbox_xsalsa20poly1305_NONCEBYTES 24U
|
|
8
|
+
#define crypto_secretbox_xsalsa20poly1305_MACBYTES 16U
|
|
9
|
+
#endif
|
|
10
|
+
|
|
11
|
+
#include <vector>
|
|
12
|
+
|
|
13
|
+
#include "HybridCipher.hpp"
|
|
14
|
+
|
|
15
|
+
namespace margelo::nitro::crypto {
|
|
16
|
+
|
|
17
|
+
class XSalsa20Poly1305Cipher : public HybridCipher {
|
|
18
|
+
public:
|
|
19
|
+
XSalsa20Poly1305Cipher() : HybridObject(TAG), final_called_(false) {}
|
|
20
|
+
~XSalsa20Poly1305Cipher();
|
|
21
|
+
|
|
22
|
+
void init(const std::shared_ptr<ArrayBuffer> cipher_key, const std::shared_ptr<ArrayBuffer> iv) override;
|
|
23
|
+
std::shared_ptr<ArrayBuffer> update(const std::shared_ptr<ArrayBuffer>& data) override;
|
|
24
|
+
std::shared_ptr<ArrayBuffer> final() override;
|
|
25
|
+
bool setAAD(const std::shared_ptr<ArrayBuffer>& data, std::optional<double> plaintextLength) override;
|
|
26
|
+
std::shared_ptr<ArrayBuffer> getAuthTag() override;
|
|
27
|
+
bool setAuthTag(const std::shared_ptr<ArrayBuffer>& tag) override;
|
|
28
|
+
bool setAutoPadding(bool autoPad) override;
|
|
29
|
+
|
|
30
|
+
private:
|
|
31
|
+
static constexpr size_t kKeySize = crypto_secretbox_xsalsa20poly1305_KEYBYTES;
|
|
32
|
+
static constexpr size_t kNonceSize = crypto_secretbox_xsalsa20poly1305_NONCEBYTES;
|
|
33
|
+
static constexpr size_t kTagSize = crypto_secretbox_xsalsa20poly1305_MACBYTES;
|
|
34
|
+
|
|
35
|
+
uint8_t key_[kKeySize];
|
|
36
|
+
uint8_t nonce_[kNonceSize];
|
|
37
|
+
std::vector<uint8_t> data_buffer_;
|
|
38
|
+
uint8_t auth_tag_[kTagSize];
|
|
39
|
+
bool final_called_;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
} // namespace margelo::nitro::crypto
|
|
@@ -433,6 +433,16 @@ const DH* HybridDiffieHellman::getDH() const {
|
|
|
433
433
|
return dh;
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
+
double HybridDiffieHellman::getVerifyError() {
|
|
437
|
+
ensureInitialized();
|
|
438
|
+
const DH* dh = getDH();
|
|
439
|
+
int codes = 0;
|
|
440
|
+
if (DH_check(const_cast<DH*>(dh), &codes) != 1) {
|
|
441
|
+
return 0;
|
|
442
|
+
}
|
|
443
|
+
return static_cast<double>(codes);
|
|
444
|
+
}
|
|
445
|
+
|
|
436
446
|
#pragma clang diagnostic pop
|
|
437
447
|
|
|
438
448
|
} // namespace margelo::nitro::crypto
|