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.
- package/QuickCrypto.podspec +24 -8
- package/README.md +11 -7
- package/android/CMakeLists.txt +1 -0
- package/cpp/blake3/HybridBlake3.cpp +1 -1
- package/cpp/cipher/CCMCipher.cpp +1 -1
- package/cpp/cipher/ChaCha20Cipher.cpp +1 -1
- package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +1 -1
- package/cpp/cipher/GCMCipher.cpp +1 -1
- package/cpp/cipher/HybridCipher.cpp +1 -1
- package/cpp/cipher/HybridCipherFactory.hpp +1 -1
- package/cpp/cipher/HybridRsaCipher.cpp +112 -26
- package/cpp/cipher/HybridRsaCipher.hpp +5 -1
- package/cpp/cipher/OCBCipher.cpp +1 -1
- package/cpp/cipher/XSalsa20Cipher.cpp +1 -1
- package/cpp/ec/HybridEcKeyPair.cpp +1 -1
- package/cpp/ec/HybridEcKeyPair.hpp +1 -1
- package/cpp/ed25519/HybridEdKeyPair.hpp +1 -1
- package/cpp/hash/HybridHash.cpp +12 -5
- package/cpp/hash/HybridHash.hpp +1 -1
- package/cpp/hkdf/HybridHkdf.cpp +1 -1
- package/cpp/hmac/HybridHmac.cpp +13 -4
- package/cpp/hmac/HybridHmac.hpp +2 -1
- package/cpp/keys/HybridKeyObjectHandle.cpp +1 -1
- package/cpp/keys/KeyObjectData.cpp +1 -1
- package/cpp/keys/KeyObjectData.hpp +1 -1
- package/cpp/mldsa/HybridMlDsaKeyPair.cpp +1 -1
- package/cpp/pbkdf2/HybridPbkdf2.cpp +1 -1
- package/cpp/random/HybridRandom.cpp +1 -1
- package/cpp/rsa/HybridRsaKeyPair.cpp +1 -1
- package/cpp/scrypt/HybridScrypt.cpp +1 -1
- package/cpp/sign/HybridSignHandle.cpp +1 -1
- package/cpp/sign/HybridVerifyHandle.cpp +1 -1
- package/cpp/utils/HybridUtils.cpp +19 -0
- package/cpp/utils/HybridUtils.hpp +15 -0
- package/lib/commonjs/hash.js +7 -1
- package/lib/commonjs/hash.js.map +1 -1
- package/lib/commonjs/hmac.js +7 -1
- package/lib/commonjs/hmac.js.map +1 -1
- package/lib/commonjs/keys/publicCipher.js +30 -18
- package/lib/commonjs/keys/publicCipher.js.map +1 -1
- package/lib/commonjs/specs/utils.nitro.js +6 -0
- package/lib/commonjs/specs/utils.nitro.js.map +1 -0
- package/lib/commonjs/utils/index.js +11 -0
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/commonjs/utils/timingSafeEqual.js +24 -0
- package/lib/commonjs/utils/timingSafeEqual.js.map +1 -0
- package/lib/module/hash.js +7 -1
- package/lib/module/hash.js.map +1 -1
- package/lib/module/hmac.js +7 -1
- package/lib/module/hmac.js.map +1 -1
- package/lib/module/keys/publicCipher.js +30 -18
- package/lib/module/keys/publicCipher.js.map +1 -1
- package/lib/module/specs/utils.nitro.js +4 -0
- package/lib/module/specs/utils.nitro.js.map +1 -0
- package/lib/module/utils/index.js +1 -0
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/utils/timingSafeEqual.js +20 -0
- package/lib/module/utils/timingSafeEqual.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/typescript/hash.d.ts.map +1 -1
- package/lib/typescript/hmac.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keys/publicCipher.d.ts +2 -0
- package/lib/typescript/keys/publicCipher.d.ts.map +1 -1
- package/lib/typescript/specs/hash.nitro.d.ts +1 -1
- package/lib/typescript/specs/hash.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/hmac.nitro.d.ts +1 -1
- package/lib/typescript/specs/hmac.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/rsaCipher.nitro.d.ts +14 -4
- package/lib/typescript/specs/rsaCipher.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/utils.nitro.d.ts +8 -0
- package/lib/typescript/specs/utils.nitro.d.ts.map +1 -0
- package/lib/typescript/utils/index.d.ts +1 -0
- package/lib/typescript/utils/index.d.ts.map +1 -1
- package/lib/typescript/utils/timingSafeEqual.d.ts +3 -0
- package/lib/typescript/utils/timingSafeEqual.d.ts.map +1 -0
- package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +1 -0
- package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +10 -0
- package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +10 -0
- package/nitrogen/generated/shared/c++/HybridHashSpec.hpp +2 -1
- package/nitrogen/generated/shared/c++/HybridHmacSpec.hpp +2 -1
- package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridRsaCipherSpec.hpp +2 -1
- package/nitrogen/generated/shared/c++/HybridUtilsSpec.cpp +21 -0
- package/nitrogen/generated/shared/c++/HybridUtilsSpec.hpp +63 -0
- package/package.json +2 -2
- package/src/hash.ts +6 -1
- package/src/hmac.ts +6 -1
- package/src/keys/publicCipher.ts +46 -26
- package/src/specs/hash.nitro.ts +1 -1
- package/src/specs/hmac.nitro.ts +1 -1
- package/src/specs/rsaCipher.nitro.ts +20 -3
- package/src/specs/utils.nitro.ts +5 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/timingSafeEqual.ts +23 -0
- package/react-native.config.js +0 -19
- package/scripts/embed_openssl_framework.sh +0 -18
- /package/cpp/utils/{Utils.hpp → QuickCryptoUtils.hpp} +0 -0
package/QuickCrypto.podspec
CHANGED
|
@@ -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="
|
|
4
|
-
<source media="(prefers-color-scheme: light)" srcset="
|
|
5
|
-
<img alt="react-native-quick-crypto" src="
|
|
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](
|
|
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="
|
|
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="
|
|
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](
|
|
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.
|
package/android/CMakeLists.txt
CHANGED
package/cpp/cipher/CCMCipher.cpp
CHANGED
package/cpp/cipher/GCMCipher.cpp
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#include "HybridRsaCipher.hpp"
|
|
2
2
|
#include "../keys/HybridKeyObjectHandle.hpp"
|
|
3
|
-
#include "
|
|
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 (
|
|
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
|
|
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 (
|
|
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 (
|
|
332
|
-
|
|
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
|
|
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
|
};
|
package/cpp/cipher/OCBCipher.cpp
CHANGED
package/cpp/hash/HybridHash.cpp
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
#include <vector>
|
|
8
8
|
|
|
9
9
|
#include "HybridHash.hpp"
|
|
10
|
-
#include "
|
|
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
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
|
package/cpp/hash/HybridHash.hpp
CHANGED
|
@@ -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
|
|
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;
|
package/cpp/hkdf/HybridHkdf.cpp
CHANGED
package/cpp/hmac/HybridHmac.cpp
CHANGED
|
@@ -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
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
|
package/cpp/hmac/HybridHmac.hpp
CHANGED
|
@@ -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
|
|
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:
|