react-native-quick-crypto 1.0.9 → 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.
Files changed (170) hide show
  1. package/QuickCrypto.podspec +9 -2
  2. package/README.md +13 -9
  3. package/android/CMakeLists.txt +4 -0
  4. package/cpp/cipher/HybridCipherFactory.hpp +15 -1
  5. package/cpp/cipher/OCBCipher.cpp +4 -4
  6. package/cpp/cipher/XChaCha20Poly1305Cipher.cpp +161 -0
  7. package/cpp/cipher/XChaCha20Poly1305Cipher.hpp +43 -0
  8. package/cpp/cipher/XSalsa20Poly1305Cipher.cpp +145 -0
  9. package/cpp/cipher/XSalsa20Poly1305Cipher.hpp +42 -0
  10. package/cpp/dh/HybridDiffieHellman.cpp +10 -0
  11. package/cpp/dh/HybridDiffieHellman.hpp +1 -0
  12. package/cpp/ec/HybridEcKeyPair.cpp +21 -0
  13. package/cpp/ec/HybridEcKeyPair.hpp +1 -0
  14. package/cpp/hash/HybridHash.cpp +1 -1
  15. package/cpp/hash/HybridHash.hpp +1 -1
  16. package/cpp/hmac/HybridHmac.cpp +1 -1
  17. package/cpp/hmac/HybridHmac.hpp +1 -1
  18. package/cpp/keys/HybridKeyObjectHandle.cpp +112 -1
  19. package/cpp/keys/HybridKeyObjectHandle.hpp +5 -1
  20. package/deps/ncrypto/.bazelrc +0 -1
  21. package/deps/ncrypto/.bazelversion +1 -1
  22. package/deps/ncrypto/.github/workflows/commitlint.yml +16 -0
  23. package/deps/ncrypto/.github/workflows/linter.yml +2 -2
  24. package/deps/ncrypto/.github/workflows/release-please.yml +16 -0
  25. package/deps/ncrypto/.github/workflows/ubuntu.yml +82 -0
  26. package/deps/ncrypto/.release-please-manifest.json +3 -0
  27. package/deps/ncrypto/BUILD.bazel +9 -1
  28. package/deps/ncrypto/CHANGELOG.md +37 -0
  29. package/deps/ncrypto/CMakeLists.txt +35 -11
  30. package/deps/ncrypto/MODULE.bazel +16 -1
  31. package/deps/ncrypto/MODULE.bazel.lock +299 -118
  32. package/deps/ncrypto/cmake/ncrypto-flags.cmake +1 -0
  33. package/deps/ncrypto/include/ncrypto/aead.h +137 -0
  34. package/deps/ncrypto/include/ncrypto/version.h +14 -0
  35. package/deps/ncrypto/include/ncrypto.h +85 -230
  36. package/deps/ncrypto/ncrypto.pc.in +10 -0
  37. package/deps/ncrypto/release-please-config.json +11 -0
  38. package/deps/ncrypto/src/CMakeLists.txt +31 -6
  39. package/deps/ncrypto/src/aead.cpp +302 -0
  40. package/deps/ncrypto/src/ncrypto.cpp +274 -556
  41. package/deps/ncrypto/tests/BUILD.bazel +2 -0
  42. package/deps/ncrypto/tests/basic.cpp +772 -2
  43. package/deps/ncrypto/tools/run-clang-format.sh +5 -5
  44. package/lib/commonjs/diffie-hellman.js +4 -1
  45. package/lib/commonjs/diffie-hellman.js.map +1 -1
  46. package/lib/commonjs/ec.js +20 -25
  47. package/lib/commonjs/ec.js.map +1 -1
  48. package/lib/commonjs/ed.js +1 -2
  49. package/lib/commonjs/ed.js.map +1 -1
  50. package/lib/commonjs/hash.js +7 -0
  51. package/lib/commonjs/hash.js.map +1 -1
  52. package/lib/commonjs/index.js +11 -1
  53. package/lib/commonjs/index.js.map +1 -1
  54. package/lib/commonjs/keys/classes.js +9 -5
  55. package/lib/commonjs/keys/classes.js.map +1 -1
  56. package/lib/commonjs/subtle.js +82 -31
  57. package/lib/commonjs/subtle.js.map +1 -1
  58. package/lib/commonjs/utils/types.js.map +1 -1
  59. package/lib/module/diffie-hellman.js +4 -0
  60. package/lib/module/diffie-hellman.js.map +1 -1
  61. package/lib/module/ec.js +19 -25
  62. package/lib/module/ec.js.map +1 -1
  63. package/lib/module/ed.js +1 -2
  64. package/lib/module/ed.js.map +1 -1
  65. package/lib/module/hash.js +6 -0
  66. package/lib/module/hash.js.map +1 -1
  67. package/lib/module/index.js +3 -0
  68. package/lib/module/index.js.map +1 -1
  69. package/lib/module/keys/classes.js +9 -5
  70. package/lib/module/keys/classes.js.map +1 -1
  71. package/lib/module/subtle.js +83 -32
  72. package/lib/module/subtle.js.map +1 -1
  73. package/lib/module/utils/types.js.map +1 -1
  74. package/lib/tsconfig.tsbuildinfo +1 -1
  75. package/lib/typescript/diffie-hellman.d.ts +2 -0
  76. package/lib/typescript/diffie-hellman.d.ts.map +1 -1
  77. package/lib/typescript/ec.d.ts +1 -0
  78. package/lib/typescript/ec.d.ts.map +1 -1
  79. package/lib/typescript/ed.d.ts.map +1 -1
  80. package/lib/typescript/hash.d.ts +2 -0
  81. package/lib/typescript/hash.d.ts.map +1 -1
  82. package/lib/typescript/index.d.ts +5 -0
  83. package/lib/typescript/index.d.ts.map +1 -1
  84. package/lib/typescript/keys/classes.d.ts +2 -0
  85. package/lib/typescript/keys/classes.d.ts.map +1 -1
  86. package/lib/typescript/specs/diffie-hellman.nitro.d.ts +1 -0
  87. package/lib/typescript/specs/diffie-hellman.nitro.d.ts.map +1 -1
  88. package/lib/typescript/specs/ecKeyPair.nitro.d.ts +1 -0
  89. package/lib/typescript/specs/ecKeyPair.nitro.d.ts.map +1 -1
  90. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +2 -0
  91. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
  92. package/lib/typescript/subtle.d.ts.map +1 -1
  93. package/lib/typescript/utils/types.d.ts +12 -5
  94. package/lib/typescript/utils/types.d.ts.map +1 -1
  95. package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +8 -5
  96. package/nitrogen/generated/android/QuickCrypto+autolinking.gradle +1 -1
  97. package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +54 -54
  98. package/nitrogen/generated/android/QuickCryptoOnLoad.hpp +1 -1
  99. package/nitrogen/generated/android/kotlin/com/margelo/nitro/crypto/QuickCryptoOnLoad.kt +1 -1
  100. package/nitrogen/generated/ios/QuickCrypto+autolinking.rb +2 -2
  101. package/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.cpp +1 -1
  102. package/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Bridge.hpp +1 -1
  103. package/nitrogen/generated/ios/QuickCrypto-Swift-Cxx-Umbrella.hpp +1 -1
  104. package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +54 -54
  105. package/nitrogen/generated/ios/QuickCryptoAutolinking.swift +5 -1
  106. package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +1 -1
  107. package/nitrogen/generated/shared/c++/CipherArgs.hpp +34 -19
  108. package/nitrogen/generated/shared/c++/HybridBlake3Spec.cpp +1 -1
  109. package/nitrogen/generated/shared/c++/HybridBlake3Spec.hpp +1 -3
  110. package/nitrogen/generated/shared/c++/HybridCipherFactorySpec.cpp +1 -1
  111. package/nitrogen/generated/shared/c++/HybridCipherFactorySpec.hpp +1 -1
  112. package/nitrogen/generated/shared/c++/HybridCipherSpec.cpp +1 -1
  113. package/nitrogen/generated/shared/c++/HybridCipherSpec.hpp +1 -3
  114. package/nitrogen/generated/shared/c++/HybridDiffieHellmanSpec.cpp +2 -1
  115. package/nitrogen/generated/shared/c++/HybridDiffieHellmanSpec.hpp +3 -3
  116. package/nitrogen/generated/shared/c++/HybridECDHSpec.cpp +1 -1
  117. package/nitrogen/generated/shared/c++/HybridECDHSpec.hpp +2 -3
  118. package/nitrogen/generated/shared/c++/HybridEcKeyPairSpec.cpp +2 -1
  119. package/nitrogen/generated/shared/c++/HybridEcKeyPairSpec.hpp +2 -3
  120. package/nitrogen/generated/shared/c++/HybridEdKeyPairSpec.cpp +1 -1
  121. package/nitrogen/generated/shared/c++/HybridEdKeyPairSpec.hpp +2 -3
  122. package/nitrogen/generated/shared/c++/HybridHashSpec.cpp +1 -1
  123. package/nitrogen/generated/shared/c++/HybridHashSpec.hpp +2 -4
  124. package/nitrogen/generated/shared/c++/HybridHkdfSpec.cpp +1 -1
  125. package/nitrogen/generated/shared/c++/HybridHkdfSpec.hpp +2 -3
  126. package/nitrogen/generated/shared/c++/HybridHmacSpec.cpp +1 -1
  127. package/nitrogen/generated/shared/c++/HybridHmacSpec.hpp +3 -4
  128. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +3 -1
  129. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +8 -4
  130. package/nitrogen/generated/shared/c++/HybridMlDsaKeyPairSpec.cpp +1 -1
  131. package/nitrogen/generated/shared/c++/HybridMlDsaKeyPairSpec.hpp +2 -3
  132. package/nitrogen/generated/shared/c++/HybridPbkdf2Spec.cpp +1 -1
  133. package/nitrogen/generated/shared/c++/HybridPbkdf2Spec.hpp +2 -3
  134. package/nitrogen/generated/shared/c++/HybridRandomSpec.cpp +1 -1
  135. package/nitrogen/generated/shared/c++/HybridRandomSpec.hpp +2 -3
  136. package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.cpp +1 -1
  137. package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.hpp +1 -3
  138. package/nitrogen/generated/shared/c++/HybridRsaKeyPairSpec.cpp +1 -1
  139. package/nitrogen/generated/shared/c++/HybridRsaKeyPairSpec.hpp +1 -3
  140. package/nitrogen/generated/shared/c++/HybridScryptSpec.cpp +1 -1
  141. package/nitrogen/generated/shared/c++/HybridScryptSpec.hpp +2 -3
  142. package/nitrogen/generated/shared/c++/HybridSignHandleSpec.cpp +1 -1
  143. package/nitrogen/generated/shared/c++/HybridSignHandleSpec.hpp +1 -3
  144. package/nitrogen/generated/shared/c++/HybridUtilsSpec.cpp +1 -1
  145. package/nitrogen/generated/shared/c++/HybridUtilsSpec.hpp +2 -3
  146. package/nitrogen/generated/shared/c++/HybridVerifyHandleSpec.cpp +1 -1
  147. package/nitrogen/generated/shared/c++/HybridVerifyHandleSpec.hpp +1 -3
  148. package/nitrogen/generated/shared/c++/JWK.hpp +84 -68
  149. package/nitrogen/generated/shared/c++/JWKkty.hpp +5 -1
  150. package/nitrogen/generated/shared/c++/JWKuse.hpp +1 -1
  151. package/nitrogen/generated/shared/c++/KFormatType.hpp +1 -1
  152. package/nitrogen/generated/shared/c++/KeyDetail.hpp +39 -23
  153. package/nitrogen/generated/shared/c++/KeyEncoding.hpp +1 -1
  154. package/nitrogen/generated/shared/c++/KeyObject.hpp +21 -5
  155. package/nitrogen/generated/shared/c++/KeyType.hpp +1 -1
  156. package/nitrogen/generated/shared/c++/KeyUsage.hpp +1 -1
  157. package/nitrogen/generated/shared/c++/NamedCurve.hpp +1 -1
  158. package/package.json +1 -1
  159. package/src/diffie-hellman.ts +6 -0
  160. package/src/ec.ts +23 -19
  161. package/src/ed.ts +1 -2
  162. package/src/hash.ts +11 -0
  163. package/src/index.ts +3 -0
  164. package/src/keys/classes.ts +10 -3
  165. package/src/specs/diffie-hellman.nitro.ts +1 -0
  166. package/src/specs/ecKeyPair.nitro.ts +2 -0
  167. package/src/specs/keyObjectHandle.nitro.ts +2 -0
  168. package/src/subtle.ts +131 -32
  169. package/src/utils/types.ts +18 -3
  170. package/deps/ncrypto/WORKSPACE +0 -15
@@ -112,7 +112,7 @@ Pod::Spec.new do |s|
112
112
  # implementation (C++)
113
113
  "cpp/**/*.{hpp,cpp}",
114
114
  # dependencies (C++) - ncrypto
115
- "deps/ncrypto/include/*.{h}",
115
+ "deps/ncrypto/include/**/*.{h}",
116
116
  "deps/ncrypto/src/*.{cpp}",
117
117
  # dependencies (C) - exclude BLAKE3 x86 SIMD files (only use portable + NEON for ARM)
118
118
  "deps/blake3/c/*.{h,c}",
@@ -143,6 +143,9 @@ Pod::Spec.new do |s|
143
143
  "deps/blake3/c/example.c",
144
144
  "deps/blake3/c/example_tbb.c",
145
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",
146
149
  # Exclude non-C parts of BLAKE3 repo (Rust, benchmarks, tools, etc.)
147
150
  "deps/blake3/src/**/*",
148
151
  "deps/blake3/b3sum/**/*",
@@ -165,7 +168,11 @@ Pod::Spec.new do |s|
165
168
  "CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
166
169
  "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES" => "YES",
167
170
  # Exclude ARM NEON source when building x86_64 simulator (no NEON support).
168
- "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"
169
176
  }
170
177
 
171
178
  # Add cpp subdirectories to header search paths
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
- - 🏎️ Up to 58x faster than all other solutions
23
- - ⚡️ Lightning fast implementation with pure C++ and JSI, instead of JS
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 Wallets
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.
@@ -55,7 +53,13 @@ cd ios && pod install
55
53
  ```
56
54
 
57
55
  <h3>
58
- Expo  <a href="#"><img src="./.docs/img/expo.png" height="12" /></a>
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
@@ -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
 
@@ -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);
@@ -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 12-16 bytes)
17
- if (auth_tag_len < 12 || auth_tag_len > 16) {
18
- throw std::runtime_error("OCB tag length must be between 12 and 16 bytes");
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 < 12 || tag_len > 16) {
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
@@ -30,6 +30,7 @@ class HybridDiffieHellman : public HybridDiffieHellmanSpec {
30
30
  std::shared_ptr<ArrayBuffer> getPrivateKey() override;
31
31
  void setPublicKey(const std::shared_ptr<ArrayBuffer>& publicKey) override;
32
32
  void setPrivateKey(const std::shared_ptr<ArrayBuffer>& privateKey) override;
33
+ double getVerifyError() override;
33
34
 
34
35
  private:
35
36
  EVP_PKEY_ptr _pkey;
@@ -1,5 +1,6 @@
1
1
  #include <NitroModules/ArrayBuffer.hpp>
2
2
  #include <NitroModules/Promise.hpp>
3
+ #include <algorithm>
3
4
  #include <memory>
4
5
  #include <openssl/bio.h>
5
6
  #include <openssl/buffer.h>
@@ -425,4 +426,24 @@ void HybridEcKeyPair::checkKeyPair() {
425
426
  }
426
427
  }
427
428
 
429
+ std::vector<std::string> HybridEcKeyPair::getSupportedCurves() {
430
+ const size_t count = EC_get_builtin_curves(nullptr, 0);
431
+ std::vector<EC_builtin_curve> curves(count);
432
+ if (EC_get_builtin_curves(curves.data(), count) != count) {
433
+ throw std::runtime_error("Failed to enumerate EC curves");
434
+ }
435
+
436
+ std::vector<std::string> names;
437
+ names.reserve(count);
438
+ for (const auto& curve : curves) {
439
+ const char* sn = OBJ_nid2sn(curve.nid);
440
+ if (sn != nullptr) {
441
+ names.emplace_back(sn);
442
+ }
443
+ }
444
+
445
+ std::sort(names.begin(), names.end());
446
+ return names;
447
+ }
448
+
428
449
  } // namespace margelo::nitro::crypto
@@ -34,6 +34,7 @@ class HybridEcKeyPair : public HybridEcKeyPairSpec {
34
34
  std::shared_ptr<ArrayBuffer> sign(const std::shared_ptr<ArrayBuffer>& data, const std::string& hashAlgorithm) override;
35
35
  bool verify(const std::shared_ptr<ArrayBuffer>& data, const std::shared_ptr<ArrayBuffer>& signature,
36
36
  const std::string& hashAlgorithm) override;
37
+ std::vector<std::string> getSupportedCurves() override;
37
38
 
38
39
  protected:
39
40
  void checkKeyPair();
@@ -68,7 +68,7 @@ void HybridHash::createHash(const std::string& hashAlgorithmArg, const std::opti
68
68
  }
69
69
  }
70
70
 
71
- void HybridHash::update(const std::variant<std::string, std::shared_ptr<ArrayBuffer>>& data) {
71
+ void HybridHash::update(const std::variant<std::shared_ptr<ArrayBuffer>, std::string>& data) {
72
72
  if (!ctx) {
73
73
  throw std::runtime_error("Hash context not initialized");
74
74
  }
@@ -21,7 +21,7 @@ class HybridHash : public HybridHashSpec {
21
21
  public:
22
22
  // Methods
23
23
  void createHash(const std::string& algorithm, const std::optional<double> outputLength) override;
24
- void update(const std::variant<std::string, std::shared_ptr<ArrayBuffer>>& data) override;
24
+ void update(const std::variant<std::shared_ptr<ArrayBuffer>, std::string>& data) override;
25
25
  std::shared_ptr<ArrayBuffer> digest(const std::optional<std::string>& encoding = std::nullopt) override;
26
26
  std::shared_ptr<margelo::nitro::crypto::HybridHashSpec> copy(const std::optional<double> outputLength) override;
27
27
  std::vector<std::string> getSupportedHashAlgorithms() override;
@@ -60,7 +60,7 @@ void HybridHmac::createHmac(const std::string& hmacAlgorithm, const std::shared_
60
60
  }
61
61
  }
62
62
 
63
- void HybridHmac::update(const std::variant<std::string, std::shared_ptr<ArrayBuffer>>& data) {
63
+ void HybridHmac::update(const std::variant<std::shared_ptr<ArrayBuffer>, std::string>& data) {
64
64
  if (!ctx) {
65
65
  throw std::runtime_error("HMAC context not initialized");
66
66
  }
@@ -20,7 +20,7 @@ class HybridHmac : public HybridHmacSpec {
20
20
  public:
21
21
  // Methods
22
22
  void createHmac(const std::string& algorithm, const std::shared_ptr<ArrayBuffer>& key) override;
23
- void update(const std::variant<std::string, std::shared_ptr<ArrayBuffer>>& data) override;
23
+ void update(const std::variant<std::shared_ptr<ArrayBuffer>, std::string>& data) override;
24
24
  std::shared_ptr<ArrayBuffer> digest() override;
25
25
 
26
26
  private: