react-native-quick-crypto 1.0.6 → 1.0.8
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 +6 -1
- package/README.md +11 -7
- package/android/CMakeLists.txt +4 -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 +1 -1
- package/cpp/cipher/OCBCipher.cpp +1 -1
- package/cpp/cipher/XSalsa20Cipher.cpp +1 -1
- package/cpp/dh/HybridDiffieHellman.cpp +438 -0
- package/cpp/dh/HybridDiffieHellman.hpp +41 -0
- package/cpp/ec/HybridEcKeyPair.cpp +1 -1
- package/cpp/ec/HybridEcKeyPair.hpp +1 -1
- package/cpp/ecdh/HybridECDH.cpp +306 -0
- package/cpp/ecdh/HybridECDH.hpp +42 -0
- package/cpp/ed25519/HybridEdKeyPair.hpp +1 -1
- package/cpp/hash/HybridHash.cpp +1 -1
- package/cpp/hkdf/HybridHkdf.cpp +1 -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/{Utils.hpp → QuickCryptoUtils.hpp} +14 -0
- package/lib/commonjs/dh-groups.js +29 -0
- package/lib/commonjs/dh-groups.js.map +1 -0
- package/lib/commonjs/diffie-hellman.js +147 -0
- package/lib/commonjs/diffie-hellman.js.map +1 -0
- package/lib/commonjs/ec.js +68 -180
- package/lib/commonjs/ec.js.map +1 -1
- package/lib/commonjs/ecdh.js +71 -0
- package/lib/commonjs/ecdh.js.map +1 -0
- package/lib/commonjs/index.js +26 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/keys/generateKeyPair.js.map +1 -1
- package/lib/commonjs/keys/index.js +12 -0
- package/lib/commonjs/keys/index.js.map +1 -1
- package/lib/commonjs/keys/signVerify.js +42 -0
- package/lib/commonjs/keys/signVerify.js.map +1 -1
- package/lib/commonjs/specs/diffie-hellman.nitro.js +6 -0
- package/lib/commonjs/specs/diffie-hellman.nitro.js.map +1 -0
- package/lib/commonjs/specs/ecdh.nitro.js +6 -0
- package/lib/commonjs/specs/ecdh.nitro.js.map +1 -0
- package/lib/commonjs/subtle.js +2 -0
- package/lib/commonjs/subtle.js.map +1 -1
- package/lib/module/dh-groups.js +25 -0
- package/lib/module/dh-groups.js.map +1 -0
- package/lib/module/diffie-hellman.js +140 -0
- package/lib/module/diffie-hellman.js.map +1 -0
- package/lib/module/ec.js +65 -178
- package/lib/module/ec.js.map +1 -1
- package/lib/module/ecdh.js +65 -0
- package/lib/module/ecdh.js.map +1 -0
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/keys/generateKeyPair.js.map +1 -1
- package/lib/module/keys/index.js +2 -2
- package/lib/module/keys/index.js.map +1 -1
- package/lib/module/keys/signVerify.js +40 -0
- package/lib/module/keys/signVerify.js.map +1 -1
- package/lib/module/specs/diffie-hellman.nitro.js +4 -0
- package/lib/module/specs/diffie-hellman.nitro.js.map +1 -0
- package/lib/module/specs/ecdh.nitro.js +4 -0
- package/lib/module/specs/ecdh.nitro.js.map +1 -0
- package/lib/module/subtle.js +3 -1
- package/lib/module/subtle.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/typescript/dh-groups.d.ts +5 -0
- package/lib/typescript/dh-groups.d.ts.map +1 -0
- package/lib/typescript/diffie-hellman.d.ts +16 -0
- package/lib/typescript/diffie-hellman.d.ts.map +1 -0
- package/lib/typescript/ec.d.ts +2 -1
- package/lib/typescript/ec.d.ts.map +1 -1
- package/lib/typescript/ecdh.d.ts +16 -0
- package/lib/typescript/ecdh.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +11 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keys/generateKeyPair.d.ts.map +1 -1
- package/lib/typescript/keys/index.d.ts +2 -2
- package/lib/typescript/keys/index.d.ts.map +1 -1
- package/lib/typescript/keys/signVerify.d.ts +6 -0
- package/lib/typescript/keys/signVerify.d.ts.map +1 -1
- package/lib/typescript/specs/diffie-hellman.nitro.d.ts +17 -0
- package/lib/typescript/specs/diffie-hellman.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/ecdh.nitro.d.ts +14 -0
- package/lib/typescript/specs/ecdh.nitro.d.ts.map +1 -0
- package/lib/typescript/subtle.d.ts.map +1 -1
- package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +2 -0
- package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +20 -0
- package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +20 -0
- package/nitrogen/generated/shared/c++/HybridDiffieHellmanSpec.cpp +30 -0
- package/nitrogen/generated/shared/c++/HybridDiffieHellmanSpec.hpp +72 -0
- package/nitrogen/generated/shared/c++/HybridECDHSpec.cpp +27 -0
- package/nitrogen/generated/shared/c++/HybridECDHSpec.hpp +70 -0
- package/package.json +1 -1
- package/src/dh-groups.ts +27 -0
- package/src/diffie-hellman.ts +191 -0
- package/src/ec.ts +73 -177
- package/src/ecdh.ts +76 -0
- package/src/index.ts +6 -0
- package/src/keys/generateKeyPair.ts +11 -2
- package/src/keys/index.ts +10 -1
- package/src/keys/signVerify.ts +84 -0
- package/src/specs/diffie-hellman.nitro.ts +15 -0
- package/src/specs/ecdh.nitro.ts +11 -0
- package/src/subtle.ts +8 -1
package/QuickCrypto.podspec
CHANGED
|
@@ -123,13 +123,18 @@ Pod::Spec.new do |s|
|
|
|
123
123
|
"GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) FOLLY_NO_CONFIG FOLLY_CFG_NO_COROUTINES",
|
|
124
124
|
# Set C++ standard to C++20
|
|
125
125
|
"CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
|
|
126
|
-
"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"
|
|
127
129
|
}
|
|
128
130
|
|
|
129
131
|
# Add cpp subdirectories to header search paths
|
|
130
132
|
cpp_headers = [
|
|
131
133
|
"\"$(PODS_TARGET_SRCROOT)/cpp/utils\"",
|
|
132
134
|
"\"$(PODS_TARGET_SRCROOT)/cpp/hkdf\"",
|
|
135
|
+
"\"$(PODS_TARGET_SRCROOT)/cpp/dh\"",
|
|
136
|
+
"\"$(PODS_TARGET_SRCROOT)/cpp/ecdh\"",
|
|
137
|
+
"\"$(PODS_TARGET_SRCROOT)/nitrogen/generated/shared/c++\"",
|
|
133
138
|
"\"$(PODS_TARGET_SRCROOT)/deps/ncrypto/include\"",
|
|
134
139
|
"\"$(PODS_TARGET_SRCROOT)/deps/blake3/c\"",
|
|
135
140
|
"\"$(PODS_TARGET_SRCROOT)/deps/fastpbkdf2\""
|
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
|
@@ -34,7 +34,9 @@ add_library(
|
|
|
34
34
|
../cpp/cipher/XSalsa20Cipher.cpp
|
|
35
35
|
../cpp/cipher/ChaCha20Cipher.cpp
|
|
36
36
|
../cpp/cipher/ChaCha20Poly1305Cipher.cpp
|
|
37
|
+
../cpp/dh/HybridDiffieHellman.cpp
|
|
37
38
|
../cpp/ec/HybridEcKeyPair.cpp
|
|
39
|
+
../cpp/ecdh/HybridECDH.cpp
|
|
38
40
|
../cpp/ed25519/HybridEdKeyPair.cpp
|
|
39
41
|
../cpp/hash/HybridHash.cpp
|
|
40
42
|
../cpp/hmac/HybridHmac.cpp
|
|
@@ -62,7 +64,9 @@ include_directories(
|
|
|
62
64
|
"src/main/cpp"
|
|
63
65
|
"../cpp/blake3"
|
|
64
66
|
"../cpp/cipher"
|
|
67
|
+
"../cpp/dh"
|
|
65
68
|
"../cpp/ec"
|
|
69
|
+
"../cpp/ecdh"
|
|
66
70
|
"../cpp/ed25519"
|
|
67
71
|
"../cpp/hash"
|
|
68
72
|
"../cpp/hkdf"
|
package/cpp/cipher/CCMCipher.cpp
CHANGED
package/cpp/cipher/GCMCipher.cpp
CHANGED
package/cpp/cipher/OCBCipher.cpp
CHANGED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
#include "HybridDiffieHellman.hpp"
|
|
2
|
+
#include "QuickCryptoUtils.hpp"
|
|
3
|
+
#include <NitroModules/ArrayBuffer.hpp>
|
|
4
|
+
#include <openssl/bn.h>
|
|
5
|
+
#include <openssl/dh.h>
|
|
6
|
+
#include <openssl/err.h>
|
|
7
|
+
#include <openssl/evp.h>
|
|
8
|
+
#include <stdexcept>
|
|
9
|
+
|
|
10
|
+
namespace margelo::nitro::crypto {
|
|
11
|
+
|
|
12
|
+
// Smart pointer type aliases for RAII
|
|
13
|
+
using BN_ptr = std::unique_ptr<BIGNUM, decltype(&BN_free)>;
|
|
14
|
+
using DH_ptr = std::unique_ptr<DH, decltype(&DH_free)>;
|
|
15
|
+
using EVP_PKEY_CTX_ptr = std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)>;
|
|
16
|
+
|
|
17
|
+
// Minimum DH prime size for security (2048 bits = 256 bytes)
|
|
18
|
+
static constexpr int kMinDHPrimeBits = 2048;
|
|
19
|
+
|
|
20
|
+
// Suppress deprecation warnings for DH_* functions
|
|
21
|
+
// Node.js ncrypto uses the same pattern - these APIs work but are deprecated in OpenSSL 3.x
|
|
22
|
+
#pragma clang diagnostic push
|
|
23
|
+
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
24
|
+
|
|
25
|
+
void HybridDiffieHellman::init(const std::shared_ptr<ArrayBuffer>& prime, const std::shared_ptr<ArrayBuffer>& generator) {
|
|
26
|
+
// Create DH structure
|
|
27
|
+
DH_ptr dh(DH_new(), DH_free);
|
|
28
|
+
if (!dh) {
|
|
29
|
+
throw std::runtime_error("DiffieHellman: failed to create DH structure");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Convert prime and generator to BIGNUMs
|
|
33
|
+
BIGNUM* p = BN_bin2bn(prime->data(), static_cast<int>(prime->size()), nullptr);
|
|
34
|
+
BIGNUM* g = BN_bin2bn(generator->data(), static_cast<int>(generator->size()), nullptr);
|
|
35
|
+
|
|
36
|
+
if (!p || !g) {
|
|
37
|
+
if (p)
|
|
38
|
+
BN_free(p);
|
|
39
|
+
if (g)
|
|
40
|
+
BN_free(g);
|
|
41
|
+
throw std::runtime_error("DiffieHellman: failed to convert parameters to BIGNUM");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// DH_set0_pqg takes ownership of p and g on success
|
|
45
|
+
if (DH_set0_pqg(dh.get(), p, nullptr, g) != 1) {
|
|
46
|
+
BN_free(p);
|
|
47
|
+
BN_free(g);
|
|
48
|
+
throw std::runtime_error("DiffieHellman: failed to set DH parameters");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Create EVP_PKEY and assign DH to it
|
|
52
|
+
EVP_PKEY_ptr pkey(EVP_PKEY_new(), EVP_PKEY_free);
|
|
53
|
+
if (!pkey) {
|
|
54
|
+
throw std::runtime_error("DiffieHellman: failed to create EVP_PKEY");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// EVP_PKEY_assign_DH takes ownership of dh on success
|
|
58
|
+
if (EVP_PKEY_assign_DH(pkey.get(), dh.get()) != 1) {
|
|
59
|
+
throw std::runtime_error("DiffieHellman: failed to assign DH to EVP_PKEY");
|
|
60
|
+
}
|
|
61
|
+
dh.release(); // EVP_PKEY now owns the DH
|
|
62
|
+
|
|
63
|
+
_pkey = std::move(pkey);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void HybridDiffieHellman::initWithSize(double primeLength, double generator) {
|
|
67
|
+
int primeBits = static_cast<int>(primeLength);
|
|
68
|
+
int gen = static_cast<int>(generator);
|
|
69
|
+
|
|
70
|
+
// Validate minimum key size for security
|
|
71
|
+
if (primeBits < kMinDHPrimeBits) {
|
|
72
|
+
throw std::runtime_error("DiffieHellman: prime length must be at least 2048 bits");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Create parameter generation context
|
|
76
|
+
EVP_PKEY_CTX_ptr pctx(EVP_PKEY_CTX_new_id(EVP_PKEY_DH, nullptr), EVP_PKEY_CTX_free);
|
|
77
|
+
if (!pctx) {
|
|
78
|
+
throw std::runtime_error("DiffieHellman: failed to create parameter context");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (EVP_PKEY_paramgen_init(pctx.get()) <= 0) {
|
|
82
|
+
throw std::runtime_error("DiffieHellman: failed to initialize parameter generation");
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (EVP_PKEY_CTX_set_dh_paramgen_prime_len(pctx.get(), primeBits) <= 0) {
|
|
86
|
+
throw std::runtime_error("DiffieHellman: failed to set prime length");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (EVP_PKEY_CTX_set_dh_paramgen_generator(pctx.get(), gen) <= 0) {
|
|
90
|
+
throw std::runtime_error("DiffieHellman: failed to set generator");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
EVP_PKEY* params = nullptr;
|
|
94
|
+
if (EVP_PKEY_paramgen(pctx.get(), ¶ms) <= 0) {
|
|
95
|
+
throw std::runtime_error("DiffieHellman: failed to generate parameters");
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
_pkey.reset(params);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
std::shared_ptr<ArrayBuffer> HybridDiffieHellman::generateKeys() {
|
|
102
|
+
ensureInitialized();
|
|
103
|
+
|
|
104
|
+
EVP_PKEY_CTX_ptr kctx(EVP_PKEY_CTX_new(_pkey.get(), nullptr), EVP_PKEY_CTX_free);
|
|
105
|
+
if (!kctx) {
|
|
106
|
+
throw std::runtime_error("DiffieHellman: failed to create keygen context");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (EVP_PKEY_keygen_init(kctx.get()) <= 0) {
|
|
110
|
+
throw std::runtime_error("DiffieHellman: failed to initialize key generation");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
EVP_PKEY* newKey = nullptr;
|
|
114
|
+
if (EVP_PKEY_keygen(kctx.get(), &newKey) <= 0) {
|
|
115
|
+
throw std::runtime_error("DiffieHellman: failed to generate key pair");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Replace parameters-only key with full key (which includes parameters)
|
|
119
|
+
_pkey.reset(newKey);
|
|
120
|
+
|
|
121
|
+
return getPublicKey();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
std::shared_ptr<ArrayBuffer> HybridDiffieHellman::computeSecret(const std::shared_ptr<ArrayBuffer>& otherPublicKey) {
|
|
125
|
+
ensureInitialized();
|
|
126
|
+
|
|
127
|
+
const DH* ourDh = getDH();
|
|
128
|
+
const BIGNUM *p, *q, *g;
|
|
129
|
+
DH_get0_pqg(ourDh, &p, &q, &g);
|
|
130
|
+
|
|
131
|
+
// Create peer DH with same parameters but peer's public key
|
|
132
|
+
DH_ptr peerDh(DH_new(), DH_free);
|
|
133
|
+
if (!peerDh) {
|
|
134
|
+
throw std::runtime_error("DiffieHellman: failed to create peer DH structure");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Duplicate parameters for peer
|
|
138
|
+
BIGNUM* peerP = BN_dup(p);
|
|
139
|
+
BIGNUM* peerG = BN_dup(g);
|
|
140
|
+
BIGNUM* peerPubKey = BN_bin2bn(otherPublicKey->data(), static_cast<int>(otherPublicKey->size()), nullptr);
|
|
141
|
+
|
|
142
|
+
if (!peerP || !peerG || !peerPubKey) {
|
|
143
|
+
if (peerP)
|
|
144
|
+
BN_free(peerP);
|
|
145
|
+
if (peerG)
|
|
146
|
+
BN_free(peerG);
|
|
147
|
+
if (peerPubKey)
|
|
148
|
+
BN_free(peerPubKey);
|
|
149
|
+
throw std::runtime_error("DiffieHellman: failed to create peer parameters");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Set peer DH parameters (takes ownership on success)
|
|
153
|
+
if (DH_set0_pqg(peerDh.get(), peerP, nullptr, peerG) != 1) {
|
|
154
|
+
BN_free(peerP);
|
|
155
|
+
BN_free(peerG);
|
|
156
|
+
BN_free(peerPubKey);
|
|
157
|
+
throw std::runtime_error("DiffieHellman: failed to set peer DH parameters");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Set peer public key (takes ownership on success)
|
|
161
|
+
if (DH_set0_key(peerDh.get(), peerPubKey, nullptr) != 1) {
|
|
162
|
+
BN_free(peerPubKey);
|
|
163
|
+
throw std::runtime_error("DiffieHellman: failed to set peer public key");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Create peer EVP_PKEY
|
|
167
|
+
EVP_PKEY_ptr peerPkey(EVP_PKEY_new(), EVP_PKEY_free);
|
|
168
|
+
if (!peerPkey) {
|
|
169
|
+
throw std::runtime_error("DiffieHellman: failed to create peer EVP_PKEY");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// EVP_PKEY_assign_DH takes ownership of peerDh on success
|
|
173
|
+
if (EVP_PKEY_assign_DH(peerPkey.get(), peerDh.get()) != 1) {
|
|
174
|
+
throw std::runtime_error("DiffieHellman: failed to assign peer DH to EVP_PKEY");
|
|
175
|
+
}
|
|
176
|
+
peerDh.release(); // EVP_PKEY now owns the DH
|
|
177
|
+
|
|
178
|
+
// Derive shared secret using EVP API
|
|
179
|
+
EVP_PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new(_pkey.get(), nullptr), EVP_PKEY_CTX_free);
|
|
180
|
+
if (!ctx) {
|
|
181
|
+
throw std::runtime_error("DiffieHellman: failed to create derive context");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (EVP_PKEY_derive_init(ctx.get()) <= 0) {
|
|
185
|
+
throw std::runtime_error("DiffieHellman: failed to initialize key derivation");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (EVP_PKEY_derive_set_peer(ctx.get(), peerPkey.get()) <= 0) {
|
|
189
|
+
throw std::runtime_error("DiffieHellman: failed to set peer key for derivation");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Get required buffer size
|
|
193
|
+
size_t secretLen = 0;
|
|
194
|
+
if (EVP_PKEY_derive(ctx.get(), nullptr, &secretLen) <= 0) {
|
|
195
|
+
throw std::runtime_error("DiffieHellman: failed to get shared secret length");
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Derive the shared secret
|
|
199
|
+
std::vector<uint8_t> secret(secretLen);
|
|
200
|
+
if (EVP_PKEY_derive(ctx.get(), secret.data(), &secretLen) <= 0) {
|
|
201
|
+
throw std::runtime_error("DiffieHellman: failed to derive shared secret");
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Resize to actual length (may be smaller due to leading zeros)
|
|
205
|
+
secret.resize(secretLen);
|
|
206
|
+
|
|
207
|
+
return ToNativeArrayBuffer(secret);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
std::shared_ptr<ArrayBuffer> HybridDiffieHellman::getPrime() {
|
|
211
|
+
ensureInitialized();
|
|
212
|
+
const DH* dh = getDH();
|
|
213
|
+
|
|
214
|
+
const BIGNUM *p, *q, *g;
|
|
215
|
+
DH_get0_pqg(dh, &p, &q, &g);
|
|
216
|
+
if (!p) {
|
|
217
|
+
throw std::runtime_error("DiffieHellman: no prime available");
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
int len = BN_num_bytes(p);
|
|
221
|
+
std::vector<uint8_t> buf(len);
|
|
222
|
+
BN_bn2bin(p, buf.data());
|
|
223
|
+
|
|
224
|
+
return ToNativeArrayBuffer(buf);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
std::shared_ptr<ArrayBuffer> HybridDiffieHellman::getGenerator() {
|
|
228
|
+
ensureInitialized();
|
|
229
|
+
const DH* dh = getDH();
|
|
230
|
+
|
|
231
|
+
const BIGNUM *p, *q, *g;
|
|
232
|
+
DH_get0_pqg(dh, &p, &q, &g);
|
|
233
|
+
if (!g) {
|
|
234
|
+
throw std::runtime_error("DiffieHellman: no generator available");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
int len = BN_num_bytes(g);
|
|
238
|
+
std::vector<uint8_t> buf(len);
|
|
239
|
+
BN_bn2bin(g, buf.data());
|
|
240
|
+
|
|
241
|
+
return ToNativeArrayBuffer(buf);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
std::shared_ptr<ArrayBuffer> HybridDiffieHellman::getPublicKey() {
|
|
245
|
+
ensureInitialized();
|
|
246
|
+
const DH* dh = getDH();
|
|
247
|
+
|
|
248
|
+
const BIGNUM *pub, *priv;
|
|
249
|
+
DH_get0_key(dh, &pub, &priv);
|
|
250
|
+
if (!pub) {
|
|
251
|
+
throw std::runtime_error("DiffieHellman: no public key available");
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
int len = BN_num_bytes(pub);
|
|
255
|
+
std::vector<uint8_t> buf(len);
|
|
256
|
+
BN_bn2bin(pub, buf.data());
|
|
257
|
+
|
|
258
|
+
return ToNativeArrayBuffer(buf);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
std::shared_ptr<ArrayBuffer> HybridDiffieHellman::getPrivateKey() {
|
|
262
|
+
ensureInitialized();
|
|
263
|
+
const DH* dh = getDH();
|
|
264
|
+
|
|
265
|
+
const BIGNUM *pub, *priv;
|
|
266
|
+
DH_get0_key(dh, &pub, &priv);
|
|
267
|
+
if (!priv) {
|
|
268
|
+
throw std::runtime_error("DiffieHellman: no private key available");
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
int len = BN_num_bytes(priv);
|
|
272
|
+
std::vector<uint8_t> buf(len);
|
|
273
|
+
BN_bn2bin(priv, buf.data());
|
|
274
|
+
|
|
275
|
+
return ToNativeArrayBuffer(buf);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
void HybridDiffieHellman::setPublicKey(const std::shared_ptr<ArrayBuffer>& publicKey) {
|
|
279
|
+
ensureInitialized();
|
|
280
|
+
const DH* dh = getDH();
|
|
281
|
+
|
|
282
|
+
// Get existing keys
|
|
283
|
+
const BIGNUM *oldPub, *oldPriv;
|
|
284
|
+
DH_get0_key(dh, &oldPub, &oldPriv);
|
|
285
|
+
|
|
286
|
+
// Get parameters
|
|
287
|
+
const BIGNUM *p, *q, *g;
|
|
288
|
+
DH_get0_pqg(dh, &p, &q, &g);
|
|
289
|
+
|
|
290
|
+
// Create new DH with copied parameters
|
|
291
|
+
DH_ptr newDh(DH_new(), DH_free);
|
|
292
|
+
if (!newDh) {
|
|
293
|
+
throw std::runtime_error("DiffieHellman: failed to create new DH structure");
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Duplicate parameters
|
|
297
|
+
BIGNUM* newP = BN_dup(p);
|
|
298
|
+
BIGNUM* newQ = q ? BN_dup(q) : nullptr;
|
|
299
|
+
BIGNUM* newG = BN_dup(g);
|
|
300
|
+
|
|
301
|
+
if (!newP || !newG) {
|
|
302
|
+
if (newP)
|
|
303
|
+
BN_free(newP);
|
|
304
|
+
if (newQ)
|
|
305
|
+
BN_free(newQ);
|
|
306
|
+
if (newG)
|
|
307
|
+
BN_free(newG);
|
|
308
|
+
throw std::runtime_error("DiffieHellman: failed to duplicate parameters");
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (DH_set0_pqg(newDh.get(), newP, newQ, newG) != 1) {
|
|
312
|
+
BN_free(newP);
|
|
313
|
+
if (newQ)
|
|
314
|
+
BN_free(newQ);
|
|
315
|
+
BN_free(newG);
|
|
316
|
+
throw std::runtime_error("DiffieHellman: failed to set parameters");
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Convert new public key
|
|
320
|
+
BIGNUM* newPub = BN_bin2bn(publicKey->data(), static_cast<int>(publicKey->size()), nullptr);
|
|
321
|
+
BIGNUM* newPriv = oldPriv ? BN_dup(oldPriv) : nullptr;
|
|
322
|
+
|
|
323
|
+
if (!newPub) {
|
|
324
|
+
if (newPriv)
|
|
325
|
+
BN_free(newPriv);
|
|
326
|
+
throw std::runtime_error("DiffieHellman: failed to convert public key");
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (DH_set0_key(newDh.get(), newPub, newPriv) != 1) {
|
|
330
|
+
BN_free(newPub);
|
|
331
|
+
if (newPriv)
|
|
332
|
+
BN_free(newPriv);
|
|
333
|
+
throw std::runtime_error("DiffieHellman: failed to set keys");
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Create new EVP_PKEY
|
|
337
|
+
EVP_PKEY_ptr newPkey(EVP_PKEY_new(), EVP_PKEY_free);
|
|
338
|
+
if (!newPkey) {
|
|
339
|
+
throw std::runtime_error("DiffieHellman: failed to create new EVP_PKEY");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (EVP_PKEY_assign_DH(newPkey.get(), newDh.get()) != 1) {
|
|
343
|
+
throw std::runtime_error("DiffieHellman: failed to assign DH to EVP_PKEY");
|
|
344
|
+
}
|
|
345
|
+
newDh.release();
|
|
346
|
+
|
|
347
|
+
_pkey = std::move(newPkey);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
void HybridDiffieHellman::setPrivateKey(const std::shared_ptr<ArrayBuffer>& privateKey) {
|
|
351
|
+
ensureInitialized();
|
|
352
|
+
const DH* dh = getDH();
|
|
353
|
+
|
|
354
|
+
// Get existing keys
|
|
355
|
+
const BIGNUM *oldPub, *oldPriv;
|
|
356
|
+
DH_get0_key(dh, &oldPub, &oldPriv);
|
|
357
|
+
|
|
358
|
+
// Get parameters
|
|
359
|
+
const BIGNUM *p, *q, *g;
|
|
360
|
+
DH_get0_pqg(dh, &p, &q, &g);
|
|
361
|
+
|
|
362
|
+
// Create new DH with copied parameters
|
|
363
|
+
DH_ptr newDh(DH_new(), DH_free);
|
|
364
|
+
if (!newDh) {
|
|
365
|
+
throw std::runtime_error("DiffieHellman: failed to create new DH structure");
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Duplicate parameters
|
|
369
|
+
BIGNUM* newP = BN_dup(p);
|
|
370
|
+
BIGNUM* newQ = q ? BN_dup(q) : nullptr;
|
|
371
|
+
BIGNUM* newG = BN_dup(g);
|
|
372
|
+
|
|
373
|
+
if (!newP || !newG) {
|
|
374
|
+
if (newP)
|
|
375
|
+
BN_free(newP);
|
|
376
|
+
if (newQ)
|
|
377
|
+
BN_free(newQ);
|
|
378
|
+
if (newG)
|
|
379
|
+
BN_free(newG);
|
|
380
|
+
throw std::runtime_error("DiffieHellman: failed to duplicate parameters");
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (DH_set0_pqg(newDh.get(), newP, newQ, newG) != 1) {
|
|
384
|
+
BN_free(newP);
|
|
385
|
+
if (newQ)
|
|
386
|
+
BN_free(newQ);
|
|
387
|
+
BN_free(newG);
|
|
388
|
+
throw std::runtime_error("DiffieHellman: failed to set parameters");
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Convert new private key
|
|
392
|
+
BIGNUM* newPub = oldPub ? BN_dup(oldPub) : nullptr;
|
|
393
|
+
BIGNUM* newPriv = BN_bin2bn(privateKey->data(), static_cast<int>(privateKey->size()), nullptr);
|
|
394
|
+
|
|
395
|
+
if (!newPriv) {
|
|
396
|
+
if (newPub)
|
|
397
|
+
BN_free(newPub);
|
|
398
|
+
throw std::runtime_error("DiffieHellman: failed to convert private key");
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (DH_set0_key(newDh.get(), newPub, newPriv) != 1) {
|
|
402
|
+
if (newPub)
|
|
403
|
+
BN_free(newPub);
|
|
404
|
+
BN_free(newPriv);
|
|
405
|
+
throw std::runtime_error("DiffieHellman: failed to set keys");
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Create new EVP_PKEY
|
|
409
|
+
EVP_PKEY_ptr newPkey(EVP_PKEY_new(), EVP_PKEY_free);
|
|
410
|
+
if (!newPkey) {
|
|
411
|
+
throw std::runtime_error("DiffieHellman: failed to create new EVP_PKEY");
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
if (EVP_PKEY_assign_DH(newPkey.get(), newDh.get()) != 1) {
|
|
415
|
+
throw std::runtime_error("DiffieHellman: failed to assign DH to EVP_PKEY");
|
|
416
|
+
}
|
|
417
|
+
newDh.release();
|
|
418
|
+
|
|
419
|
+
_pkey = std::move(newPkey);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
void HybridDiffieHellman::ensureInitialized() const {
|
|
423
|
+
if (!_pkey) {
|
|
424
|
+
throw std::runtime_error("DiffieHellman: not initialized");
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const DH* HybridDiffieHellman::getDH() const {
|
|
429
|
+
const DH* dh = EVP_PKEY_get0_DH(_pkey.get());
|
|
430
|
+
if (!dh) {
|
|
431
|
+
throw std::runtime_error("DiffieHellman: key is not a DH key");
|
|
432
|
+
}
|
|
433
|
+
return dh;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
#pragma clang diagnostic pop
|
|
437
|
+
|
|
438
|
+
} // namespace margelo::nitro::crypto
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <memory>
|
|
4
|
+
#include <openssl/dh.h>
|
|
5
|
+
#include <openssl/evp.h>
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <vector>
|
|
8
|
+
|
|
9
|
+
#include "HybridDiffieHellmanSpec.hpp"
|
|
10
|
+
|
|
11
|
+
namespace margelo::nitro::crypto {
|
|
12
|
+
|
|
13
|
+
using namespace facebook;
|
|
14
|
+
using margelo::nitro::ArrayBuffer;
|
|
15
|
+
|
|
16
|
+
using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>;
|
|
17
|
+
|
|
18
|
+
class HybridDiffieHellman : public HybridDiffieHellmanSpec {
|
|
19
|
+
public:
|
|
20
|
+
HybridDiffieHellman() : HybridObject("DiffieHellman"), _pkey(nullptr, EVP_PKEY_free) {}
|
|
21
|
+
virtual ~HybridDiffieHellman() = default;
|
|
22
|
+
|
|
23
|
+
void init(const std::shared_ptr<ArrayBuffer>& prime, const std::shared_ptr<ArrayBuffer>& generator) override;
|
|
24
|
+
void initWithSize(double primeLength, double generator) override;
|
|
25
|
+
std::shared_ptr<ArrayBuffer> generateKeys() override;
|
|
26
|
+
std::shared_ptr<ArrayBuffer> computeSecret(const std::shared_ptr<ArrayBuffer>& otherPublicKey) override;
|
|
27
|
+
std::shared_ptr<ArrayBuffer> getPrime() override;
|
|
28
|
+
std::shared_ptr<ArrayBuffer> getGenerator() override;
|
|
29
|
+
std::shared_ptr<ArrayBuffer> getPublicKey() override;
|
|
30
|
+
std::shared_ptr<ArrayBuffer> getPrivateKey() override;
|
|
31
|
+
void setPublicKey(const std::shared_ptr<ArrayBuffer>& publicKey) override;
|
|
32
|
+
void setPrivateKey(const std::shared_ptr<ArrayBuffer>& privateKey) override;
|
|
33
|
+
|
|
34
|
+
private:
|
|
35
|
+
EVP_PKEY_ptr _pkey;
|
|
36
|
+
|
|
37
|
+
void ensureInitialized() const;
|
|
38
|
+
const DH* getDH() const;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
} // namespace margelo::nitro::crypto
|