react-native-quick-crypto 1.0.5 → 1.0.7

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 (99) hide show
  1. package/QuickCrypto.podspec +24 -8
  2. package/README.md +11 -7
  3. package/android/CMakeLists.txt +1 -0
  4. package/cpp/blake3/HybridBlake3.cpp +1 -1
  5. package/cpp/cipher/CCMCipher.cpp +1 -1
  6. package/cpp/cipher/ChaCha20Cipher.cpp +1 -1
  7. package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +1 -1
  8. package/cpp/cipher/GCMCipher.cpp +1 -1
  9. package/cpp/cipher/HybridCipher.cpp +1 -1
  10. package/cpp/cipher/HybridCipherFactory.hpp +1 -1
  11. package/cpp/cipher/HybridRsaCipher.cpp +112 -26
  12. package/cpp/cipher/HybridRsaCipher.hpp +5 -1
  13. package/cpp/cipher/OCBCipher.cpp +1 -1
  14. package/cpp/cipher/XSalsa20Cipher.cpp +1 -1
  15. package/cpp/ec/HybridEcKeyPair.cpp +1 -1
  16. package/cpp/ec/HybridEcKeyPair.hpp +1 -1
  17. package/cpp/ed25519/HybridEdKeyPair.hpp +1 -1
  18. package/cpp/hash/HybridHash.cpp +12 -5
  19. package/cpp/hash/HybridHash.hpp +1 -1
  20. package/cpp/hkdf/HybridHkdf.cpp +1 -1
  21. package/cpp/hmac/HybridHmac.cpp +13 -4
  22. package/cpp/hmac/HybridHmac.hpp +2 -1
  23. package/cpp/keys/HybridKeyObjectHandle.cpp +1 -1
  24. package/cpp/keys/KeyObjectData.cpp +1 -1
  25. package/cpp/keys/KeyObjectData.hpp +1 -1
  26. package/cpp/mldsa/HybridMlDsaKeyPair.cpp +1 -1
  27. package/cpp/pbkdf2/HybridPbkdf2.cpp +1 -1
  28. package/cpp/random/HybridRandom.cpp +1 -1
  29. package/cpp/rsa/HybridRsaKeyPair.cpp +1 -1
  30. package/cpp/scrypt/HybridScrypt.cpp +1 -1
  31. package/cpp/sign/HybridSignHandle.cpp +1 -1
  32. package/cpp/sign/HybridVerifyHandle.cpp +1 -1
  33. package/cpp/utils/HybridUtils.cpp +19 -0
  34. package/cpp/utils/HybridUtils.hpp +15 -0
  35. package/lib/commonjs/hash.js +7 -1
  36. package/lib/commonjs/hash.js.map +1 -1
  37. package/lib/commonjs/hmac.js +7 -1
  38. package/lib/commonjs/hmac.js.map +1 -1
  39. package/lib/commonjs/keys/publicCipher.js +30 -18
  40. package/lib/commonjs/keys/publicCipher.js.map +1 -1
  41. package/lib/commonjs/specs/utils.nitro.js +6 -0
  42. package/lib/commonjs/specs/utils.nitro.js.map +1 -0
  43. package/lib/commonjs/utils/index.js +11 -0
  44. package/lib/commonjs/utils/index.js.map +1 -1
  45. package/lib/commonjs/utils/timingSafeEqual.js +24 -0
  46. package/lib/commonjs/utils/timingSafeEqual.js.map +1 -0
  47. package/lib/module/hash.js +7 -1
  48. package/lib/module/hash.js.map +1 -1
  49. package/lib/module/hmac.js +7 -1
  50. package/lib/module/hmac.js.map +1 -1
  51. package/lib/module/keys/publicCipher.js +30 -18
  52. package/lib/module/keys/publicCipher.js.map +1 -1
  53. package/lib/module/specs/utils.nitro.js +4 -0
  54. package/lib/module/specs/utils.nitro.js.map +1 -0
  55. package/lib/module/utils/index.js +1 -0
  56. package/lib/module/utils/index.js.map +1 -1
  57. package/lib/module/utils/timingSafeEqual.js +20 -0
  58. package/lib/module/utils/timingSafeEqual.js.map +1 -0
  59. package/lib/tsconfig.tsbuildinfo +1 -1
  60. package/lib/typescript/hash.d.ts.map +1 -1
  61. package/lib/typescript/hmac.d.ts.map +1 -1
  62. package/lib/typescript/index.d.ts +1 -0
  63. package/lib/typescript/index.d.ts.map +1 -1
  64. package/lib/typescript/keys/publicCipher.d.ts +2 -0
  65. package/lib/typescript/keys/publicCipher.d.ts.map +1 -1
  66. package/lib/typescript/specs/hash.nitro.d.ts +1 -1
  67. package/lib/typescript/specs/hash.nitro.d.ts.map +1 -1
  68. package/lib/typescript/specs/hmac.nitro.d.ts +1 -1
  69. package/lib/typescript/specs/hmac.nitro.d.ts.map +1 -1
  70. package/lib/typescript/specs/rsaCipher.nitro.d.ts +14 -4
  71. package/lib/typescript/specs/rsaCipher.nitro.d.ts.map +1 -1
  72. package/lib/typescript/specs/utils.nitro.d.ts +8 -0
  73. package/lib/typescript/specs/utils.nitro.d.ts.map +1 -0
  74. package/lib/typescript/utils/index.d.ts +1 -0
  75. package/lib/typescript/utils/index.d.ts.map +1 -1
  76. package/lib/typescript/utils/timingSafeEqual.d.ts +3 -0
  77. package/lib/typescript/utils/timingSafeEqual.d.ts.map +1 -0
  78. package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +1 -0
  79. package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +10 -0
  80. package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +10 -0
  81. package/nitrogen/generated/shared/c++/HybridHashSpec.hpp +2 -1
  82. package/nitrogen/generated/shared/c++/HybridHmacSpec.hpp +2 -1
  83. package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.cpp +1 -0
  84. package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.hpp +2 -1
  85. package/nitrogen/generated/shared/c++/HybridUtilsSpec.cpp +21 -0
  86. package/nitrogen/generated/shared/c++/HybridUtilsSpec.hpp +63 -0
  87. package/package.json +2 -2
  88. package/src/hash.ts +6 -1
  89. package/src/hmac.ts +6 -1
  90. package/src/keys/publicCipher.ts +46 -26
  91. package/src/specs/hash.nitro.ts +1 -1
  92. package/src/specs/hmac.nitro.ts +1 -1
  93. package/src/specs/rsaCipher.nitro.ts +20 -3
  94. package/src/specs/utils.nitro.ts +5 -0
  95. package/src/utils/index.ts +1 -0
  96. package/src/utils/timingSafeEqual.ts +23 -0
  97. package/react-native.config.js +0 -19
  98. package/scripts/embed_openssl_framework.sh +0 -18
  99. /package/cpp/utils/{Utils.hpp → QuickCryptoUtils.hpp} +0 -0
@@ -22,11 +22,22 @@ 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
+ # OpenSSL 3.6+ vendored xcframework (not yet on CocoaPods trunk)
26
+ openssl_version = "3.6.0000"
27
+ openssl_url = "https://github.com/krzyzanowskim/OpenSSL/releases/download/#{openssl_version}/OpenSSL.xcframework.zip"
28
+
25
29
  if sodium_enabled
26
30
  # Build libsodium from source for XSalsa20 cipher support
27
31
  # CocoaPods packages are outdated (1.0.12) and SPM causes module conflicts
28
32
  s.prepare_command = <<-CMD
29
33
  set -e
34
+ # Download OpenSSL.xcframework
35
+ if [ ! -d "OpenSSL.xcframework" ]; then
36
+ curl -L -o OpenSSL.xcframework.zip #{openssl_url}
37
+ unzip -o OpenSSL.xcframework.zip
38
+ rm -f OpenSSL.xcframework.zip
39
+ fi
40
+ # Build libsodium
30
41
  mkdir -p ios
31
42
  curl -L -o ios/libsodium.tar.gz https://download.libsodium.org/libsodium/releases/libsodium-1.0.20-stable.tar.gz
32
43
  tar -xzf ios/libsodium.tar.gz -C ios
@@ -38,11 +49,21 @@ Pod::Spec.new do |s|
38
49
  CMD
39
50
  else
40
51
  s.prepare_command = <<-CMD
52
+ set -e
53
+ # Download OpenSSL.xcframework
54
+ if [ ! -d "OpenSSL.xcframework" ]; then
55
+ curl -L -o OpenSSL.xcframework.zip #{openssl_url}
56
+ unzip -o OpenSSL.xcframework.zip
57
+ rm -f OpenSSL.xcframework.zip
58
+ fi
59
+ # Clean up libsodium if previously built
41
60
  rm -rf ios/libsodium-stable
42
61
  rm -f ios/libsodium.tar.gz
43
62
  CMD
44
63
  end
45
64
 
65
+ s.vendored_frameworks = "OpenSSL.xcframework"
66
+
46
67
  base_source_files = [
47
68
  # implementation (Swift)
48
69
  "ios/**/*.{swift}",
@@ -102,7 +123,9 @@ Pod::Spec.new do |s|
102
123
  "GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) FOLLY_NO_CONFIG FOLLY_CFG_NO_COROUTINES",
103
124
  # Set C++ standard to C++20
104
125
  "CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
105
- "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES" => "YES"
126
+ "CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES" => "YES",
127
+ # 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"
106
129
  }
107
130
 
108
131
  # Add cpp subdirectories to header search paths
@@ -137,12 +160,5 @@ Pod::Spec.new do |s|
137
160
  s.dependency "React-jsi"
138
161
  s.dependency "React-callinvoker"
139
162
 
140
- # OpenSSL 3.6+ via SPM for ML-DSA (post-quantum cryptography) support
141
- spm_dependency(s,
142
- url: 'https://github.com/krzyzanowskim/OpenSSL.git',
143
- requirement: {kind: 'upToNextMajorVersion', minimumVersion: '3.6.0'},
144
- products: ['OpenSSL']
145
- )
146
-
147
163
  install_modules_dependencies(s)
148
164
  end
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  <a href="https://margelo.com">
2
2
  <picture>
3
- <source media="(prefers-color-scheme: dark)" srcset="./docs/img/banner-dark.png" />
4
- <source media="(prefers-color-scheme: light)" srcset="./docs/img/banner-light.png" />
5
- <img alt="react-native-quick-crypto" src="./docs/img/banner-light.png" />
3
+ <source media="(prefers-color-scheme: dark)" srcset="./.docs/img/banner-dark.png" />
4
+ <source media="(prefers-color-scheme: light)" srcset="./.docs/img/banner-light.png" />
5
+ <img alt="react-native-quick-crypto" src="./.docs/img/banner-light.png" />
6
6
  </picture>
7
7
  </a>
8
8
 
@@ -10,7 +10,7 @@
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](../main/docs/implementation-coverage.md).
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
14
 
15
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
16
 
@@ -46,7 +46,7 @@ There is a benchmark suite in the Example app in this repo that has benchmarks o
46
46
  ## Installation
47
47
 
48
48
  <h3>
49
- React Native  <a href="#"><img src="./docs/img/react-native.png" height="15" /></a>
49
+ React Native  <a href="#"><img src="./.docs/img/react-native.png" height="15" /></a>
50
50
  </h3>
51
51
 
52
52
  ```sh
@@ -55,7 +55,7 @@ cd ios && pod install
55
55
  ```
56
56
 
57
57
  <h3>
58
- Expo  <a href="#"><img src="./docs/img/expo.png" height="12" /></a>
58
+ Expo  <a href="#"><img src="./.docs/img/expo.png" height="12" /></a>
59
59
  </h3>
60
60
 
61
61
  ```sh
@@ -139,7 +139,7 @@ const hashed = QuickCrypto.createHash('sha256')
139
139
 
140
140
  ## Limitations
141
141
 
142
- Not all cryptographic algorithms are supported yet. See the [implementation coverage](./docs/implementation-coverage.md) document for more details. If you need a specific algorithm, please open a `feature request` issue and we'll see what we can do.
142
+ Not all cryptographic algorithms are supported yet. See the [implementation coverage](./.docs/implementation-coverage.md) document for more details. If you need a specific algorithm, please open a `feature request` issue and we'll see what we can do.
143
143
 
144
144
  ## Community Discord
145
145
 
@@ -153,6 +153,10 @@ Not all cryptographic algorithms are supported yet. See the [implementation cove
153
153
 
154
154
  See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
155
155
 
156
+ For more detailed guides, check out our documentation website:
157
+ - [Contributing Guide]([prod-docs]/docs/guides/contributing)
158
+ - [Writing Documentation]([prod-docs]/docs/guides/writing-documentation)
159
+
156
160
  ## License
157
161
 
158
162
  - react-native-quick-crypto is licensed under MIT.
@@ -48,6 +48,7 @@ add_library(
48
48
  ../cpp/scrypt/HybridScrypt.cpp
49
49
  ../cpp/sign/HybridSignHandle.cpp
50
50
  ../cpp/sign/HybridVerifyHandle.cpp
51
+ ../cpp/utils/HybridUtils.cpp
51
52
  ${BLAKE3_SOURCES}
52
53
  ../deps/fastpbkdf2/fastpbkdf2.c
53
54
  ../deps/ncrypto/src/ncrypto.cpp
@@ -4,7 +4,7 @@
4
4
  #include <cstring>
5
5
  #include <stdexcept>
6
6
 
7
- #include "Utils.hpp"
7
+ #include "QuickCryptoUtils.hpp"
8
8
 
9
9
  namespace margelo::nitro::crypto {
10
10
 
@@ -1,5 +1,5 @@
1
1
  #include "CCMCipher.hpp"
2
- #include "Utils.hpp"
2
+ #include "QuickCryptoUtils.hpp"
3
3
  #include <openssl/err.h>
4
4
  #include <openssl/evp.h>
5
5
  #include <stdexcept>
@@ -1,5 +1,5 @@
1
1
  #include "ChaCha20Cipher.hpp"
2
- #include "Utils.hpp"
2
+ #include "QuickCryptoUtils.hpp"
3
3
  #include <openssl/err.h>
4
4
  #include <openssl/evp.h>
5
5
  #include <stdexcept>
@@ -1,5 +1,5 @@
1
1
  #include "ChaCha20Poly1305Cipher.hpp"
2
- #include "Utils.hpp"
2
+ #include "QuickCryptoUtils.hpp"
3
3
  #include <openssl/err.h>
4
4
  #include <openssl/evp.h>
5
5
  #include <stdexcept>
@@ -1,5 +1,5 @@
1
1
  #include "GCMCipher.hpp"
2
- #include "Utils.hpp"
2
+ #include "QuickCryptoUtils.hpp"
3
3
  #include <openssl/err.h>
4
4
  #include <openssl/evp.h>
5
5
  #include <stdexcept>
@@ -6,7 +6,7 @@
6
6
  #include <vector>
7
7
 
8
8
  #include "HybridCipher.hpp"
9
- #include "Utils.hpp"
9
+ #include "QuickCryptoUtils.hpp"
10
10
 
11
11
  #include <openssl/err.h>
12
12
  #include <openssl/evp.h>
@@ -10,7 +10,7 @@
10
10
  #include "GCMCipher.hpp"
11
11
  #include "HybridCipherFactorySpec.hpp"
12
12
  #include "OCBCipher.hpp"
13
- #include "Utils.hpp"
13
+ #include "QuickCryptoUtils.hpp"
14
14
  #include "XSalsa20Cipher.hpp"
15
15
 
16
16
  namespace margelo::nitro::crypto {
@@ -1,6 +1,6 @@
1
1
  #include "HybridRsaCipher.hpp"
2
2
  #include "../keys/HybridKeyObjectHandle.hpp"
3
- #include "Utils.hpp"
3
+ #include "QuickCryptoUtils.hpp"
4
4
 
5
5
  #include <cstring>
6
6
  #include <openssl/err.h>
@@ -218,6 +218,79 @@ std::shared_ptr<ArrayBuffer> HybridRsaCipher::decrypt(const std::shared_ptr<Hybr
218
218
  return std::make_shared<NativeArrayBuffer>(out_buf.release(), outlen, [raw_ptr]() { delete[] raw_ptr; });
219
219
  }
220
220
 
221
+ std::shared_ptr<ArrayBuffer> HybridRsaCipher::publicDecrypt(const std::shared_ptr<HybridKeyObjectHandleSpec>& keyHandle,
222
+ const std::shared_ptr<ArrayBuffer>& data, double padding) {
223
+ auto keyHandleImpl = std::static_pointer_cast<HybridKeyObjectHandle>(keyHandle);
224
+ EVP_PKEY* pkey = keyHandleImpl->getKeyObjectData().GetAsymmetricKey().get();
225
+
226
+ if (!pkey) {
227
+ throw std::runtime_error("Invalid key for RSA public decryption");
228
+ }
229
+
230
+ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, nullptr);
231
+ if (!ctx) {
232
+ throw std::runtime_error("Failed to create EVP_PKEY_CTX");
233
+ }
234
+
235
+ if (EVP_PKEY_verify_recover_init(ctx) <= 0) {
236
+ EVP_PKEY_CTX_free(ctx);
237
+ unsigned long err = ERR_get_error();
238
+ char err_buf[256];
239
+ ERR_error_string_n(err, err_buf, sizeof(err_buf));
240
+ throw std::runtime_error("Failed to initialize verify recover: " + std::string(err_buf));
241
+ }
242
+
243
+ int paddingInt = static_cast<int>(padding);
244
+ int opensslPadding = toOpenSSLPadding(paddingInt);
245
+
246
+ if (EVP_PKEY_CTX_set_rsa_padding(ctx, opensslPadding) <= 0) {
247
+ EVP_PKEY_CTX_free(ctx);
248
+ throw std::runtime_error("Failed to set RSA padding");
249
+ }
250
+
251
+ auto native_data = ToNativeArrayBuffer(data);
252
+ const unsigned char* in = native_data->data();
253
+ size_t inlen = native_data->size();
254
+
255
+ size_t outlen;
256
+ if (EVP_PKEY_verify_recover(ctx, nullptr, &outlen, in, inlen) <= 0) {
257
+ EVP_PKEY_CTX_free(ctx);
258
+ unsigned long err = ERR_get_error();
259
+ char err_buf[256];
260
+ ERR_error_string_n(err, err_buf, sizeof(err_buf));
261
+ throw std::runtime_error("Failed to determine output length: " + std::string(err_buf));
262
+ }
263
+
264
+ if (outlen == 0) {
265
+ EVP_PKEY_CTX_free(ctx);
266
+ uint8_t* empty_buf = new uint8_t[1];
267
+ return std::make_shared<NativeArrayBuffer>(empty_buf, 0, [empty_buf]() { delete[] empty_buf; });
268
+ }
269
+
270
+ auto out_buf = std::make_unique<uint8_t[]>(outlen);
271
+
272
+ if (EVP_PKEY_verify_recover(ctx, out_buf.get(), &outlen, in, inlen) <= 0) {
273
+ unsigned long err = ERR_get_error();
274
+ char err_buf[256];
275
+ ERR_error_string_n(err, err_buf, sizeof(err_buf));
276
+
277
+ if ((err & 0xFFFFFFF) == 0x1C880004 || (err & 0xFF) == 0x04) {
278
+ ERR_clear_error();
279
+ EVP_PKEY_CTX_free(ctx);
280
+ uint8_t* empty_buf = new uint8_t[1];
281
+ return std::make_shared<NativeArrayBuffer>(empty_buf, 0, [empty_buf]() { delete[] empty_buf; });
282
+ }
283
+
284
+ EVP_PKEY_CTX_free(ctx);
285
+ throw std::runtime_error("Public decryption failed: " + std::string(err_buf));
286
+ }
287
+
288
+ EVP_PKEY_CTX_free(ctx);
289
+
290
+ uint8_t* raw_ptr = out_buf.get();
291
+ return std::make_shared<NativeArrayBuffer>(out_buf.release(), outlen, [raw_ptr]() { delete[] raw_ptr; });
292
+ }
293
+
221
294
  std::shared_ptr<ArrayBuffer> HybridRsaCipher::privateEncrypt(const std::shared_ptr<HybridKeyObjectHandleSpec>& keyHandle,
222
295
  const std::shared_ptr<ArrayBuffer>& data, double padding) {
223
296
  auto keyHandleImpl = std::static_pointer_cast<HybridKeyObjectHandle>(keyHandle);
@@ -278,7 +351,9 @@ std::shared_ptr<ArrayBuffer> HybridRsaCipher::privateEncrypt(const std::shared_p
278
351
  }
279
352
 
280
353
  std::shared_ptr<ArrayBuffer> HybridRsaCipher::privateDecrypt(const std::shared_ptr<HybridKeyObjectHandleSpec>& keyHandle,
281
- const std::shared_ptr<ArrayBuffer>& data, double padding) {
354
+ const std::shared_ptr<ArrayBuffer>& data, double padding,
355
+ const std::string& hashAlgorithm,
356
+ const std::optional<std::shared_ptr<ArrayBuffer>>& label) {
282
357
  auto keyHandleImpl = std::static_pointer_cast<HybridKeyObjectHandle>(keyHandle);
283
358
  EVP_PKEY* pkey = keyHandleImpl->getKeyObjectData().GetAsymmetricKey().get();
284
359
 
@@ -291,12 +366,12 @@ std::shared_ptr<ArrayBuffer> HybridRsaCipher::privateDecrypt(const std::shared_p
291
366
  throw std::runtime_error("Failed to create EVP_PKEY_CTX");
292
367
  }
293
368
 
294
- if (EVP_PKEY_verify_recover_init(ctx) <= 0) {
369
+ if (EVP_PKEY_decrypt_init(ctx) <= 0) {
295
370
  EVP_PKEY_CTX_free(ctx);
296
371
  unsigned long err = ERR_get_error();
297
372
  char err_buf[256];
298
373
  ERR_error_string_n(err, err_buf, sizeof(err_buf));
299
- throw std::runtime_error("Failed to initialize verify recover: " + std::string(err_buf));
374
+ throw std::runtime_error("Failed to initialize decryption: " + std::string(err_buf));
300
375
  }
301
376
 
302
377
  int paddingInt = static_cast<int>(padding);
@@ -307,12 +382,41 @@ std::shared_ptr<ArrayBuffer> HybridRsaCipher::privateDecrypt(const std::shared_p
307
382
  throw std::runtime_error("Failed to set RSA padding");
308
383
  }
309
384
 
385
+ if (paddingInt == kRsaOaepPadding) {
386
+ const EVP_MD* md = getDigestByName(hashAlgorithm);
387
+ if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) <= 0) {
388
+ EVP_PKEY_CTX_free(ctx);
389
+ throw std::runtime_error("Failed to set OAEP hash algorithm");
390
+ }
391
+
392
+ if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) <= 0) {
393
+ EVP_PKEY_CTX_free(ctx);
394
+ throw std::runtime_error("Failed to set MGF1 hash algorithm");
395
+ }
396
+
397
+ if (label.has_value() && label.value()->size() > 0) {
398
+ auto native_label = ToNativeArrayBuffer(label.value());
399
+ unsigned char* label_copy = (unsigned char*)OPENSSL_malloc(native_label->size());
400
+ if (!label_copy) {
401
+ EVP_PKEY_CTX_free(ctx);
402
+ throw std::runtime_error("Failed to allocate memory for label");
403
+ }
404
+ std::memcpy(label_copy, native_label->data(), native_label->size());
405
+
406
+ if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, label_copy, native_label->size()) <= 0) {
407
+ OPENSSL_free(label_copy);
408
+ EVP_PKEY_CTX_free(ctx);
409
+ throw std::runtime_error("Failed to set OAEP label");
410
+ }
411
+ }
412
+ }
413
+
310
414
  auto native_data = ToNativeArrayBuffer(data);
311
415
  const unsigned char* in = native_data->data();
312
416
  size_t inlen = native_data->size();
313
417
 
314
418
  size_t outlen;
315
- if (EVP_PKEY_verify_recover(ctx, nullptr, &outlen, in, inlen) <= 0) {
419
+ if (EVP_PKEY_decrypt(ctx, nullptr, &outlen, in, inlen) <= 0) {
316
420
  EVP_PKEY_CTX_free(ctx);
317
421
  unsigned long err = ERR_get_error();
318
422
  char err_buf[256];
@@ -320,32 +424,13 @@ std::shared_ptr<ArrayBuffer> HybridRsaCipher::privateDecrypt(const std::shared_p
320
424
  throw std::runtime_error("Failed to determine output length: " + std::string(err_buf));
321
425
  }
322
426
 
323
- if (outlen == 0) {
324
- EVP_PKEY_CTX_free(ctx);
325
- uint8_t* empty_buf = new uint8_t[1];
326
- return std::make_shared<NativeArrayBuffer>(empty_buf, 0, [empty_buf]() { delete[] empty_buf; });
327
- }
328
-
329
427
  auto out_buf = std::make_unique<uint8_t[]>(outlen);
330
428
 
331
- if (EVP_PKEY_verify_recover(ctx, out_buf.get(), &outlen, in, inlen) <= 0) {
332
- // OpenSSL 3.x may return failure when recovering empty plaintext
333
- // In this case outlen is not updated from the initial buffer size
334
- // Check the error and attempt to handle the empty data case
429
+ if (EVP_PKEY_decrypt(ctx, out_buf.get(), &outlen, in, inlen) <= 0) {
430
+ EVP_PKEY_CTX_free(ctx);
335
431
  unsigned long err = ERR_get_error();
336
432
  char err_buf[256];
337
433
  ERR_error_string_n(err, err_buf, sizeof(err_buf));
338
-
339
- // Check if this is an RSA library error that might indicate empty recovered data
340
- // Error code 0x1C880004 is "RSA lib" error from OpenSSL 3.x provider
341
- if ((err & 0xFFFFFFF) == 0x1C880004 || (err & 0xFF) == 0x04) {
342
- ERR_clear_error();
343
- EVP_PKEY_CTX_free(ctx);
344
- uint8_t* empty_buf = new uint8_t[1];
345
- return std::make_shared<NativeArrayBuffer>(empty_buf, 0, [empty_buf]() { delete[] empty_buf; });
346
- }
347
-
348
- EVP_PKEY_CTX_free(ctx);
349
434
  throw std::runtime_error("Private decryption failed: " + std::string(err_buf));
350
435
  }
351
436
 
@@ -359,6 +444,7 @@ void HybridRsaCipher::loadHybridMethods() {
359
444
  registerHybrids(this, [](Prototype& prototype) {
360
445
  prototype.registerHybridMethod("encrypt", &HybridRsaCipher::encrypt);
361
446
  prototype.registerHybridMethod("decrypt", &HybridRsaCipher::decrypt);
447
+ prototype.registerHybridMethod("publicDecrypt", &HybridRsaCipher::publicDecrypt);
362
448
  prototype.registerHybridMethod("privateEncrypt", &HybridRsaCipher::privateEncrypt);
363
449
  prototype.registerHybridMethod("privateDecrypt", &HybridRsaCipher::privateDecrypt);
364
450
  });
@@ -17,11 +17,15 @@ class HybridRsaCipher : public HybridRsaCipherSpec {
17
17
  const std::shared_ptr<ArrayBuffer>& data, double padding, const std::string& hashAlgorithm,
18
18
  const std::optional<std::shared_ptr<ArrayBuffer>>& label) override;
19
19
 
20
+ std::shared_ptr<ArrayBuffer> publicDecrypt(const std::shared_ptr<HybridKeyObjectHandleSpec>& keyHandle,
21
+ const std::shared_ptr<ArrayBuffer>& data, double padding) override;
22
+
20
23
  std::shared_ptr<ArrayBuffer> privateEncrypt(const std::shared_ptr<HybridKeyObjectHandleSpec>& keyHandle,
21
24
  const std::shared_ptr<ArrayBuffer>& data, double padding) override;
22
25
 
23
26
  std::shared_ptr<ArrayBuffer> privateDecrypt(const std::shared_ptr<HybridKeyObjectHandleSpec>& keyHandle,
24
- const std::shared_ptr<ArrayBuffer>& data, double padding) override;
27
+ const std::shared_ptr<ArrayBuffer>& data, double padding, const std::string& hashAlgorithm,
28
+ const std::optional<std::shared_ptr<ArrayBuffer>>& label) override;
25
29
 
26
30
  void loadHybridMethods() override;
27
31
  };
@@ -3,7 +3,7 @@
3
3
  #include <openssl/err.h>
4
4
  #include <openssl/evp.h>
5
5
 
6
- #include "Utils.hpp"
6
+ #include "QuickCryptoUtils.hpp"
7
7
  #include <cstdio>
8
8
  #include <iomanip>
9
9
 
@@ -2,7 +2,7 @@
2
2
  #include <stdexcept> // For std::runtime_error
3
3
 
4
4
  #include "NitroModules/ArrayBuffer.hpp"
5
- #include "Utils.hpp"
5
+ #include "QuickCryptoUtils.hpp"
6
6
  #include "XSalsa20Cipher.hpp"
7
7
 
8
8
  namespace margelo::nitro::crypto {
@@ -21,7 +21,7 @@
21
21
  #endif
22
22
 
23
23
  #include "HybridEcKeyPair.hpp"
24
- #include "Utils.hpp"
24
+ #include "QuickCryptoUtils.hpp"
25
25
 
26
26
  namespace margelo::nitro::crypto {
27
27
 
@@ -6,7 +6,7 @@
6
6
  #include <string>
7
7
 
8
8
  #include "HybridEcKeyPairSpec.hpp"
9
- #include "Utils.hpp"
9
+ #include "QuickCryptoUtils.hpp"
10
10
 
11
11
  namespace margelo::nitro::crypto {
12
12
 
@@ -4,7 +4,7 @@
4
4
  #include <string>
5
5
 
6
6
  #include "HybridEdKeyPairSpec.hpp"
7
- #include "Utils.hpp"
7
+ #include "QuickCryptoUtils.hpp"
8
8
 
9
9
  namespace margelo::nitro::crypto {
10
10
 
@@ -7,7 +7,7 @@
7
7
  #include <vector>
8
8
 
9
9
  #include "HybridHash.hpp"
10
- #include "Utils.hpp"
10
+ #include "QuickCryptoUtils.hpp"
11
11
 
12
12
  namespace margelo::nitro::crypto {
13
13
 
@@ -68,14 +68,21 @@ void HybridHash::createHash(const std::string& hashAlgorithmArg, const std::opti
68
68
  }
69
69
  }
70
70
 
71
- void HybridHash::update(const std::shared_ptr<ArrayBuffer>& data) {
71
+ void HybridHash::update(const std::variant<std::string, std::shared_ptr<ArrayBuffer>>& data) {
72
72
  if (!ctx) {
73
73
  throw std::runtime_error("Hash context not initialized");
74
74
  }
75
75
 
76
- // Update the digest with the data
77
- if (EVP_DigestUpdate(ctx, reinterpret_cast<const uint8_t*>(data->data()), data->size()) != 1) {
78
- throw std::runtime_error("Failed to update hash digest: " + std::to_string(ERR_get_error()));
76
+ if (std::holds_alternative<std::string>(data)) {
77
+ const std::string& str = std::get<std::string>(data);
78
+ if (EVP_DigestUpdate(ctx, reinterpret_cast<const uint8_t*>(str.data()), str.length()) != 1) {
79
+ throw std::runtime_error("Failed to update hash digest: " + std::to_string(ERR_get_error()));
80
+ }
81
+ } else {
82
+ const std::shared_ptr<ArrayBuffer>& buffer = std::get<std::shared_ptr<ArrayBuffer>>(data);
83
+ if (EVP_DigestUpdate(ctx, reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size()) != 1) {
84
+ throw std::runtime_error("Failed to update hash digest: " + std::to_string(ERR_get_error()));
85
+ }
79
86
  }
80
87
  }
81
88
 
@@ -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::shared_ptr<ArrayBuffer>& data) override;
24
+ void update(const std::variant<std::string, std::shared_ptr<ArrayBuffer>>& 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;
@@ -8,7 +8,7 @@
8
8
  #include <vector>
9
9
 
10
10
  #include "HybridHkdf.hpp"
11
- #include "Utils.hpp"
11
+ #include "QuickCryptoUtils.hpp"
12
12
 
13
13
  namespace margelo::nitro::crypto {
14
14
 
@@ -60,14 +60,23 @@ void HybridHmac::createHmac(const std::string& hmacAlgorithm, const std::shared_
60
60
  }
61
61
  }
62
62
 
63
- void HybridHmac::update(const std::shared_ptr<ArrayBuffer>& data) {
63
+ void HybridHmac::update(const std::variant<std::string, std::shared_ptr<ArrayBuffer>>& data) {
64
64
  if (!ctx) {
65
65
  throw std::runtime_error("HMAC context not initialized");
66
66
  }
67
67
 
68
- // Update HMAC with new data
69
- if (EVP_MAC_update(ctx, reinterpret_cast<const uint8_t*>(data->data()), data->size()) != 1) {
70
- throw std::runtime_error("Failed to update HMAC: " + std::to_string(ERR_get_error()));
68
+ if (std::holds_alternative<std::string>(data)) {
69
+ // Handle string: pass UTF-8 bytes directly to OpenSSL
70
+ const std::string& str = std::get<std::string>(data);
71
+ if (EVP_MAC_update(ctx, reinterpret_cast<const uint8_t*>(str.data()), str.length()) != 1) {
72
+ throw std::runtime_error("Failed to update HMAC: " + std::to_string(ERR_get_error()));
73
+ }
74
+ } else {
75
+ // Handle ArrayBuffer
76
+ const std::shared_ptr<ArrayBuffer>& buffer = std::get<std::shared_ptr<ArrayBuffer>>(data);
77
+ if (EVP_MAC_update(ctx, reinterpret_cast<const uint8_t*>(buffer->data()), buffer->size()) != 1) {
78
+ throw std::runtime_error("Failed to update HMAC: " + std::to_string(ERR_get_error()));
79
+ }
71
80
  }
72
81
  }
73
82
 
@@ -3,6 +3,7 @@
3
3
  #include <openssl/evp.h>
4
4
  #include <optional>
5
5
  #include <string>
6
+ #include <variant>
6
7
  #include <vector>
7
8
 
8
9
  #include "HybridHmacSpec.hpp"
@@ -19,7 +20,7 @@ class HybridHmac : public HybridHmacSpec {
19
20
  public:
20
21
  // Methods
21
22
  void createHmac(const std::string& algorithm, const std::shared_ptr<ArrayBuffer>& key) override;
22
- void update(const std::shared_ptr<ArrayBuffer>& data) override;
23
+ void update(const std::variant<std::string, std::shared_ptr<ArrayBuffer>>& data) override;
23
24
  std::shared_ptr<ArrayBuffer> digest() override;
24
25
 
25
26
  private:
@@ -3,7 +3,7 @@
3
3
 
4
4
  #include "../utils/base64.h"
5
5
  #include "HybridKeyObjectHandle.hpp"
6
- #include "Utils.hpp"
6
+ #include "QuickCryptoUtils.hpp"
7
7
  #include <openssl/bn.h>
8
8
  #include <openssl/ec.h>
9
9
  #include <openssl/evp.h>
@@ -1,5 +1,5 @@
1
1
  #include "KeyObjectData.hpp"
2
- #include "Utils.hpp"
2
+ #include "QuickCryptoUtils.hpp"
3
3
  #include <cstdio>
4
4
  #include <optional>
5
5
 
@@ -5,7 +5,7 @@
5
5
  #include "KFormatType.hpp"
6
6
  #include "KeyEncoding.hpp"
7
7
  #include "KeyType.hpp"
8
- #include "Utils.hpp"
8
+ #include "QuickCryptoUtils.hpp"
9
9
  #include <ncrypto.h>
10
10
 
11
11
  namespace margelo::nitro::crypto {
@@ -5,7 +5,7 @@
5
5
  #include <openssl/err.h>
6
6
  #include <openssl/pem.h>
7
7
 
8
- #include "Utils.hpp"
8
+ #include "QuickCryptoUtils.hpp"
9
9
 
10
10
  #if OPENSSL_VERSION_NUMBER >= 0x30500000L
11
11
  #define RNQC_HAS_ML_DSA 1
@@ -1,5 +1,5 @@
1
1
  #include "HybridPbkdf2.hpp"
2
- #include "Utils.hpp"
2
+ #include "QuickCryptoUtils.hpp"
3
3
 
4
4
  namespace margelo::nitro::crypto {
5
5
 
@@ -2,7 +2,7 @@
2
2
  #include <openssl/rand.h>
3
3
 
4
4
  #include "HybridRandom.hpp"
5
- #include "Utils.hpp"
5
+ #include "QuickCryptoUtils.hpp"
6
6
 
7
7
  namespace margelo::nitro::crypto {
8
8
 
@@ -11,7 +11,7 @@
11
11
  #include <string>
12
12
 
13
13
  #include "HybridRsaKeyPair.hpp"
14
- #include "Utils.hpp"
14
+ #include "QuickCryptoUtils.hpp"
15
15
 
16
16
  namespace margelo::nitro::crypto {
17
17
 
@@ -6,7 +6,7 @@
6
6
  #include <vector>
7
7
 
8
8
  #include "HybridScrypt.hpp"
9
- #include "Utils.hpp"
9
+ #include "QuickCryptoUtils.hpp"
10
10
 
11
11
  namespace margelo::nitro::crypto {
12
12
 
@@ -1,8 +1,8 @@
1
1
  #include "HybridSignHandle.hpp"
2
2
 
3
3
  #include "../keys/HybridKeyObjectHandle.hpp"
4
+ #include "QuickCryptoUtils.hpp"
4
5
  #include "SignUtils.hpp"
5
- #include "Utils.hpp"
6
6
 
7
7
  #include <cstring>
8
8
  #include <openssl/err.h>