Skip to content

Commit 8bab2be

Browse files
authored
fix: preserve existing keys in DH generateKeys() (#954)
1 parent 424c9ae commit 8bab2be

4 files changed

Lines changed: 44 additions & 13 deletions

File tree

example/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2811,7 +2811,7 @@ SPEC CHECKSUMS:
28112811
MMKVCore: f2dd4c9befea04277a55e84e7812f930537993df
28122812
NitroMmkv: afbc5b2fbf963be567c6c545aa1efcf6a9cec68e
28132813
NitroModules: 11bba9d065af151eae51e38a6425e04c3b223ff3
2814-
QuickCrypto: e284e5357d96346ce473c754f840dcdb79443b1f
2814+
QuickCrypto: 34cbc0a0deada5ffccae96aae6622a4efafd3969
28152815
RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669
28162816
RCTDeprecation: c4b9e2fd0ab200e3af72b013ed6113187c607077
28172817
RCTRequired: e97dd5dafc1db8094e63bc5031e0371f092ae92a

example/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"react-native-mmkv": "4.0.1",
4141
"react-native-nitro-modules": "0.33.2",
4242
"react-native-quick-base64": "2.2.2",
43-
"react-native-quick-crypto": "1.0.13",
43+
"react-native-quick-crypto": "workspace:*",
4444
"react-native-safe-area-context": "5.6.2",
4545
"react-native-screens": "4.18.0",
4646
"react-native-vector-icons": "10.3.0",

example/src/tests/dh/dh_tests.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,31 @@ test(SUITE, 'should set keys', () => {
7474
assert.strictEqual(bob.getPrivateKey('hex'), alice.getPrivateKey('hex'));
7575
});
7676

77+
test(SUITE, 'generateKeys should preserve a previously set private key', () => {
78+
const dh1 = crypto.getDiffieHellman('modp14');
79+
dh1.generateKeys();
80+
81+
const dh2 = crypto.createDiffieHellman(dh1.getPrime(), dh1.getGenerator());
82+
dh2.setPrivateKey(dh1.getPrivateKey());
83+
dh2.generateKeys();
84+
85+
assert.strictEqual(dh2.getPrivateKey('hex'), dh1.getPrivateKey('hex'));
86+
assert.strictEqual(dh2.getPublicKey('hex'), dh1.getPublicKey('hex'));
87+
});
88+
89+
test(SUITE, 'generateKeys should not regenerate keys on second call', () => {
90+
const dh = crypto.getDiffieHellman('modp14');
91+
dh.generateKeys();
92+
93+
const privKey = dh.getPrivateKey('hex');
94+
const pubKey = dh.getPublicKey('hex');
95+
96+
dh.generateKeys();
97+
98+
assert.strictEqual(dh.getPrivateKey('hex'), privKey);
99+
assert.strictEqual(dh.getPublicKey('hex'), pubKey);
100+
});
101+
77102
test(SUITE, 'should create DiffieHellman from standard group', () => {
78103
const dh = crypto.getDiffieHellman('modp14');
79104
assert.isOk(dh);

packages/react-native-quick-crypto/cpp/dh/HybridDiffieHellman.cpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -101,23 +101,29 @@ void HybridDiffieHellman::initWithSize(double primeLength, double generator) {
101101
std::shared_ptr<ArrayBuffer> HybridDiffieHellman::generateKeys() {
102102
ensureInitialized();
103103

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");
104+
// EVP_PKEY_get0_DH may return a provider-cached copy in OpenSSL 3.x,
105+
// so we must detach the DH, generate keys on it directly (like ncrypto),
106+
// then re-wrap in a fresh EVP_PKEY.
107+
DH* dh = EVP_PKEY_get1_DH(_pkey.get());
108+
if (!dh) {
109+
throw std::runtime_error("DiffieHellman: failed to get DH key");
111110
}
112111

113-
EVP_PKEY* newKey = nullptr;
114-
if (EVP_PKEY_keygen(kctx.get(), &newKey) <= 0) {
112+
// DH_generate_key preserves an existing private key and only computes the
113+
// public key. When no private key is set it generates both.
114+
if (!DH_generate_key(dh)) {
115+
DH_free(dh);
115116
throw std::runtime_error("DiffieHellman: failed to generate key pair");
116117
}
117118

118-
// Replace parameters-only key with full key (which includes parameters)
119-
_pkey.reset(newKey);
119+
EVP_PKEY_ptr newPkey(EVP_PKEY_new(), EVP_PKEY_free);
120+
if (!newPkey || EVP_PKEY_assign_DH(newPkey.get(), dh) != 1) {
121+
DH_free(dh);
122+
throw std::runtime_error("DiffieHellman: failed to assign DH to EVP_PKEY");
123+
}
124+
// EVP_PKEY_assign_DH took ownership of dh
120125

126+
_pkey = std::move(newPkey);
121127
return getPublicKey();
122128
}
123129

0 commit comments

Comments
 (0)