react-native-quick-crypto 1.0.11 → 1.0.13
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/android/CMakeLists.txt +7 -0
- package/cpp/cipher/CCMCipher.cpp +4 -1
- package/cpp/cipher/ChaCha20Cipher.cpp +3 -1
- package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +5 -5
- package/cpp/cipher/ChaCha20Poly1305Cipher.hpp +1 -2
- package/cpp/cipher/HybridCipher.cpp +10 -1
- package/cpp/cipher/HybridCipher.hpp +2 -0
- package/cpp/cipher/HybridRsaCipher.cpp +0 -13
- package/cpp/cipher/XChaCha20Poly1305Cipher.cpp +7 -5
- package/cpp/cipher/XChaCha20Poly1305Cipher.hpp +1 -2
- package/cpp/cipher/XSalsa20Cipher.cpp +4 -0
- package/cpp/cipher/XSalsa20Poly1305Cipher.cpp +7 -5
- package/cpp/cipher/XSalsa20Poly1305Cipher.hpp +1 -2
- package/cpp/ecdh/HybridECDH.cpp +20 -133
- package/cpp/keys/HybridKeyObjectHandle.cpp +144 -141
- package/cpp/keys/HybridKeyObjectHandle.hpp +6 -3
- package/cpp/keys/KeyObjectData.hpp +2 -0
- package/cpp/kmac/HybridKmac.cpp +83 -0
- package/cpp/kmac/HybridKmac.hpp +31 -0
- package/cpp/mldsa/HybridMlDsaKeyPair.cpp +11 -20
- package/cpp/mldsa/HybridMlDsaKeyPair.hpp +4 -2
- package/cpp/mlkem/HybridMlKemKeyPair.cpp +319 -0
- package/cpp/mlkem/HybridMlKemKeyPair.hpp +48 -0
- package/cpp/sign/SignUtils.hpp +9 -26
- package/cpp/utils/QuickCryptoUtils.cpp +44 -0
- package/cpp/utils/QuickCryptoUtils.hpp +39 -0
- package/cpp/x509/HybridX509Certificate.cpp +174 -0
- package/cpp/x509/HybridX509Certificate.hpp +51 -0
- package/lib/commonjs/cipher.js +15 -2
- package/lib/commonjs/cipher.js.map +1 -1
- package/lib/commonjs/dhKeyPair.js +3 -3
- package/lib/commonjs/dhKeyPair.js.map +1 -1
- package/lib/commonjs/dsa.js +3 -3
- package/lib/commonjs/dsa.js.map +1 -1
- package/lib/commonjs/ec.js +18 -18
- package/lib/commonjs/ec.js.map +1 -1
- package/lib/commonjs/ed.js +9 -9
- package/lib/commonjs/ed.js.map +1 -1
- package/lib/commonjs/hash.js +17 -12
- package/lib/commonjs/hash.js.map +1 -1
- package/lib/commonjs/hkdf.js.map +1 -1
- package/lib/commonjs/index.js +22 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/keys/classes.js +2 -2
- package/lib/commonjs/keys/classes.js.map +1 -1
- package/lib/commonjs/keys/index.js +24 -0
- package/lib/commonjs/keys/index.js.map +1 -1
- package/lib/commonjs/keys/publicCipher.js +2 -2
- package/lib/commonjs/keys/publicCipher.js.map +1 -1
- package/lib/commonjs/keys/signVerify.js +0 -2
- package/lib/commonjs/keys/signVerify.js.map +1 -1
- package/lib/commonjs/mlkem.js +219 -0
- package/lib/commonjs/mlkem.js.map +1 -0
- package/lib/commonjs/pbkdf2.js +18 -1
- package/lib/commonjs/pbkdf2.js.map +1 -1
- package/lib/commonjs/rsa.js +7 -7
- package/lib/commonjs/rsa.js.map +1 -1
- package/lib/commonjs/specs/kmac.nitro.js +6 -0
- package/lib/commonjs/specs/kmac.nitro.js.map +1 -0
- package/lib/commonjs/specs/mlKemKeyPair.nitro.js +6 -0
- package/lib/commonjs/specs/mlKemKeyPair.nitro.js.map +1 -0
- package/lib/commonjs/specs/x509certificate.nitro.js +6 -0
- package/lib/commonjs/specs/x509certificate.nitro.js.map +1 -0
- package/lib/commonjs/subtle.js +292 -112
- package/lib/commonjs/subtle.js.map +1 -1
- package/lib/commonjs/utils/conversion.js +3 -3
- package/lib/commonjs/utils/conversion.js.map +1 -1
- package/lib/commonjs/utils/hashnames.js +31 -0
- package/lib/commonjs/utils/hashnames.js.map +1 -1
- package/lib/commonjs/utils/types.js.map +1 -1
- package/lib/commonjs/x509certificate.js +189 -0
- package/lib/commonjs/x509certificate.js.map +1 -0
- package/lib/module/cipher.js +16 -3
- package/lib/module/cipher.js.map +1 -1
- package/lib/module/dhKeyPair.js +1 -1
- package/lib/module/dhKeyPair.js.map +1 -1
- package/lib/module/dsa.js +1 -1
- package/lib/module/dsa.js.map +1 -1
- package/lib/module/ec.js +6 -6
- package/lib/module/ec.js.map +1 -1
- package/lib/module/ed.js +1 -1
- package/lib/module/ed.js.map +1 -1
- package/lib/module/hash.js +17 -12
- package/lib/module/hash.js.map +1 -1
- package/lib/module/hkdf.js.map +1 -1
- package/lib/module/index.js +6 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/keys/classes.js +2 -2
- package/lib/module/keys/classes.js.map +1 -1
- package/lib/module/keys/index.js +25 -1
- package/lib/module/keys/index.js.map +1 -1
- package/lib/module/keys/publicCipher.js +2 -2
- package/lib/module/keys/publicCipher.js.map +1 -1
- package/lib/module/keys/signVerify.js +0 -2
- package/lib/module/keys/signVerify.js.map +1 -1
- package/lib/module/mlkem.js +211 -0
- package/lib/module/mlkem.js.map +1 -0
- package/lib/module/pbkdf2.js +18 -1
- package/lib/module/pbkdf2.js.map +1 -1
- package/lib/module/rsa.js +1 -1
- package/lib/module/rsa.js.map +1 -1
- package/lib/module/specs/kmac.nitro.js +4 -0
- package/lib/module/specs/kmac.nitro.js.map +1 -0
- package/lib/module/specs/mlKemKeyPair.nitro.js +4 -0
- package/lib/module/specs/mlKemKeyPair.nitro.js.map +1 -0
- package/lib/module/specs/x509certificate.nitro.js +4 -0
- package/lib/module/specs/x509certificate.nitro.js.map +1 -0
- package/lib/module/subtle.js +292 -112
- package/lib/module/subtle.js.map +1 -1
- package/lib/module/utils/conversion.js +3 -4
- package/lib/module/utils/conversion.js.map +1 -1
- package/lib/module/utils/hashnames.js +31 -0
- package/lib/module/utils/hashnames.js.map +1 -1
- package/lib/module/utils/types.js.map +1 -1
- package/lib/module/x509certificate.js +184 -0
- package/lib/module/x509certificate.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/typescript/cipher.d.ts +3 -0
- package/lib/typescript/cipher.d.ts.map +1 -1
- package/lib/typescript/dhKeyPair.d.ts +1 -1
- package/lib/typescript/dhKeyPair.d.ts.map +1 -1
- package/lib/typescript/dsa.d.ts +1 -1
- package/lib/typescript/dsa.d.ts.map +1 -1
- package/lib/typescript/ec.d.ts +1 -1
- package/lib/typescript/ec.d.ts.map +1 -1
- package/lib/typescript/ed.d.ts +1 -1
- package/lib/typescript/ed.d.ts.map +1 -1
- package/lib/typescript/hash.d.ts.map +1 -1
- package/lib/typescript/hkdf.d.ts +2 -6
- package/lib/typescript/hkdf.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +15 -4
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keys/classes.d.ts +5 -5
- package/lib/typescript/keys/classes.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.map +1 -1
- package/lib/typescript/mlkem.d.ts +30 -0
- package/lib/typescript/mlkem.d.ts.map +1 -0
- package/lib/typescript/pbkdf2.d.ts +2 -2
- package/lib/typescript/pbkdf2.d.ts.map +1 -1
- package/lib/typescript/rsa.d.ts +1 -1
- package/lib/typescript/rsa.d.ts.map +1 -1
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +1 -0
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/kmac.nitro.d.ts +10 -0
- package/lib/typescript/specs/kmac.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts +18 -0
- package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/x509certificate.nitro.d.ts +34 -0
- package/lib/typescript/specs/x509certificate.nitro.d.ts.map +1 -0
- package/lib/typescript/subtle.d.ts +10 -0
- package/lib/typescript/subtle.d.ts.map +1 -1
- package/lib/typescript/utils/conversion.d.ts.map +1 -1
- package/lib/typescript/utils/hashnames.d.ts +1 -1
- package/lib/typescript/utils/hashnames.d.ts.map +1 -1
- package/lib/typescript/utils/types.d.ts +13 -7
- package/lib/typescript/utils/types.d.ts.map +1 -1
- package/lib/typescript/x509certificate.d.ts +64 -0
- package/lib/typescript/x509certificate.d.ts.map +1 -0
- package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +3 -0
- package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +30 -0
- package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +30 -0
- package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +12 -0
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +1 -0
- package/nitrogen/generated/shared/c++/HybridKmacSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridKmacSpec.hpp +66 -0
- package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.cpp +31 -0
- package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.hpp +74 -0
- package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.cpp +46 -0
- package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.hpp +96 -0
- package/package.json +4 -1
- package/src/cipher.ts +17 -3
- package/src/dhKeyPair.ts +1 -1
- package/src/dsa.ts +1 -1
- package/src/ec.ts +9 -9
- package/src/ed.ts +2 -2
- package/src/hash.ts +34 -11
- package/src/hkdf.ts +2 -7
- package/src/index.ts +7 -0
- package/src/keys/classes.ts +10 -9
- package/src/keys/index.ts +37 -2
- package/src/keys/publicCipher.ts +2 -2
- package/src/keys/signVerify.ts +0 -5
- package/src/mlkem.ts +350 -0
- package/src/pbkdf2.ts +34 -5
- package/src/rsa.ts +1 -1
- package/src/specs/keyObjectHandle.nitro.ts +5 -0
- package/src/specs/kmac.nitro.ts +12 -0
- package/src/specs/mlKemKeyPair.nitro.ts +32 -0
- package/src/specs/x509certificate.nitro.ts +38 -0
- package/src/subtle.ts +551 -125
- package/src/utils/conversion.ts +10 -4
- package/src/utils/hashnames.ts +33 -2
- package/src/utils/types.ts +42 -5
- package/src/x509certificate.ts +277 -0
package/android/CMakeLists.txt
CHANGED
|
@@ -47,9 +47,11 @@ add_library(
|
|
|
47
47
|
../cpp/hash/HybridHash.cpp
|
|
48
48
|
../cpp/hmac/HybridHmac.cpp
|
|
49
49
|
../cpp/hkdf/HybridHkdf.cpp
|
|
50
|
+
../cpp/kmac/HybridKmac.cpp
|
|
50
51
|
../cpp/keys/HybridKeyObjectHandle.cpp
|
|
51
52
|
../cpp/keys/KeyObjectData.cpp
|
|
52
53
|
../cpp/mldsa/HybridMlDsaKeyPair.cpp
|
|
54
|
+
../cpp/mlkem/HybridMlKemKeyPair.cpp
|
|
53
55
|
../cpp/pbkdf2/HybridPbkdf2.cpp
|
|
54
56
|
../cpp/prime/HybridPrime.cpp
|
|
55
57
|
../cpp/random/HybridRandom.cpp
|
|
@@ -57,7 +59,9 @@ add_library(
|
|
|
57
59
|
../cpp/scrypt/HybridScrypt.cpp
|
|
58
60
|
../cpp/sign/HybridSignHandle.cpp
|
|
59
61
|
../cpp/sign/HybridVerifyHandle.cpp
|
|
62
|
+
../cpp/x509/HybridX509Certificate.cpp
|
|
60
63
|
../cpp/utils/HybridUtils.cpp
|
|
64
|
+
../cpp/utils/QuickCryptoUtils.cpp
|
|
61
65
|
${BLAKE3_SOURCES}
|
|
62
66
|
../deps/fastpbkdf2/fastpbkdf2.c
|
|
63
67
|
../deps/ncrypto/src/aead.cpp
|
|
@@ -83,8 +87,10 @@ include_directories(
|
|
|
83
87
|
"../cpp/hash"
|
|
84
88
|
"../cpp/hkdf"
|
|
85
89
|
"../cpp/hmac"
|
|
90
|
+
"../cpp/kmac"
|
|
86
91
|
"../cpp/keys"
|
|
87
92
|
"../cpp/mldsa"
|
|
93
|
+
"../cpp/mlkem"
|
|
88
94
|
"../cpp/pbkdf2"
|
|
89
95
|
"../cpp/prime"
|
|
90
96
|
"../cpp/random"
|
|
@@ -92,6 +98,7 @@ include_directories(
|
|
|
92
98
|
"../cpp/sign"
|
|
93
99
|
"../cpp/scrypt"
|
|
94
100
|
"../cpp/utils"
|
|
101
|
+
"../cpp/x509"
|
|
95
102
|
"../deps/blake3/c"
|
|
96
103
|
"../deps/fastpbkdf2"
|
|
97
104
|
"../deps/ncrypto/include"
|
package/cpp/cipher/CCMCipher.cpp
CHANGED
|
@@ -54,6 +54,7 @@ void CCMCipher::init(const std::shared_ptr<ArrayBuffer> cipher_key, const std::s
|
|
|
54
54
|
|
|
55
55
|
std::shared_ptr<ArrayBuffer> CCMCipher::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
56
56
|
checkCtx();
|
|
57
|
+
checkNotFinalized();
|
|
57
58
|
auto native_data = ToNativeArrayBuffer(data);
|
|
58
59
|
size_t in_len = native_data->size();
|
|
59
60
|
if (in_len < 0 || in_len > INT_MAX) {
|
|
@@ -104,10 +105,11 @@ std::shared_ptr<ArrayBuffer> CCMCipher::update(const std::shared_ptr<ArrayBuffer
|
|
|
104
105
|
|
|
105
106
|
std::shared_ptr<ArrayBuffer> CCMCipher::final() {
|
|
106
107
|
checkCtx();
|
|
108
|
+
checkNotFinalized();
|
|
107
109
|
|
|
108
110
|
// CCM decryption does not use final. Verification happens in the last update call.
|
|
109
111
|
if (!is_cipher) {
|
|
110
|
-
|
|
112
|
+
is_finalized = true;
|
|
111
113
|
unsigned char* empty_output = new unsigned char[0];
|
|
112
114
|
return std::make_shared<NativeArrayBuffer>(empty_output, 0, [=]() { delete[] empty_output; });
|
|
113
115
|
}
|
|
@@ -138,6 +140,7 @@ std::shared_ptr<ArrayBuffer> CCMCipher::final() {
|
|
|
138
140
|
throw std::runtime_error("Failed to get auth tag after finalization: " + std::string(err_buf));
|
|
139
141
|
}
|
|
140
142
|
auth_tag_state = kAuthTagKnown;
|
|
143
|
+
is_finalized = true;
|
|
141
144
|
|
|
142
145
|
unsigned char* final_output = out_buf.release();
|
|
143
146
|
return std::make_shared<NativeArrayBuffer>(final_output, out_len, [=]() { delete[] final_output; });
|
|
@@ -64,6 +64,7 @@ void ChaCha20Cipher::init(const std::shared_ptr<ArrayBuffer> cipher_key, const s
|
|
|
64
64
|
|
|
65
65
|
std::shared_ptr<ArrayBuffer> ChaCha20Cipher::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
66
66
|
checkCtx();
|
|
67
|
+
checkNotFinalized();
|
|
67
68
|
auto native_data = ToNativeArrayBuffer(data);
|
|
68
69
|
size_t in_len = native_data->size();
|
|
69
70
|
if (in_len > INT_MAX) {
|
|
@@ -89,7 +90,8 @@ std::shared_ptr<ArrayBuffer> ChaCha20Cipher::update(const std::shared_ptr<ArrayB
|
|
|
89
90
|
|
|
90
91
|
std::shared_ptr<ArrayBuffer> ChaCha20Cipher::final() {
|
|
91
92
|
checkCtx();
|
|
92
|
-
|
|
93
|
+
checkNotFinalized();
|
|
94
|
+
is_finalized = true;
|
|
93
95
|
unsigned char* empty_output = new unsigned char[0];
|
|
94
96
|
return std::make_shared<NativeArrayBuffer>(empty_output, 0, [=]() { delete[] empty_output; });
|
|
95
97
|
}
|
|
@@ -60,13 +60,12 @@ void ChaCha20Poly1305Cipher::init(const std::shared_ptr<ArrayBuffer> cipher_key,
|
|
|
60
60
|
ctx = nullptr;
|
|
61
61
|
throw std::runtime_error("ChaCha20Poly1305Cipher: Failed to set key/IV: " + std::string(err_buf));
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
// Reset final_called flag
|
|
65
|
-
final_called = false;
|
|
63
|
+
is_finalized = false;
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
std::shared_ptr<ArrayBuffer> ChaCha20Poly1305Cipher::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
69
67
|
checkCtx();
|
|
68
|
+
checkNotFinalized();
|
|
70
69
|
auto native_data = ToNativeArrayBuffer(data);
|
|
71
70
|
size_t in_len = native_data->size();
|
|
72
71
|
if (in_len > INT_MAX) {
|
|
@@ -92,6 +91,7 @@ std::shared_ptr<ArrayBuffer> ChaCha20Poly1305Cipher::update(const std::shared_pt
|
|
|
92
91
|
|
|
93
92
|
std::shared_ptr<ArrayBuffer> ChaCha20Poly1305Cipher::final() {
|
|
94
93
|
checkCtx();
|
|
94
|
+
checkNotFinalized();
|
|
95
95
|
|
|
96
96
|
// For ChaCha20-Poly1305, we need to call final to generate the tag
|
|
97
97
|
int out_len = 0;
|
|
@@ -105,7 +105,7 @@ std::shared_ptr<ArrayBuffer> ChaCha20Poly1305Cipher::final() {
|
|
|
105
105
|
throw std::runtime_error("ChaCha20Poly1305Cipher: Failed to finalize: " + std::string(err_buf));
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
is_finalized = true;
|
|
109
109
|
return std::make_shared<NativeArrayBuffer>(out, out_len, [=]() { delete[] out; });
|
|
110
110
|
}
|
|
111
111
|
|
|
@@ -130,7 +130,7 @@ std::shared_ptr<ArrayBuffer> ChaCha20Poly1305Cipher::getAuthTag() {
|
|
|
130
130
|
if (!is_cipher) {
|
|
131
131
|
throw std::runtime_error("getAuthTag can only be called during encryption");
|
|
132
132
|
}
|
|
133
|
-
if (!
|
|
133
|
+
if (!is_finalized) {
|
|
134
134
|
throw std::runtime_error("getAuthTag must be called after final()");
|
|
135
135
|
}
|
|
136
136
|
|
|
@@ -6,7 +6,7 @@ namespace margelo::nitro::crypto {
|
|
|
6
6
|
|
|
7
7
|
class ChaCha20Poly1305Cipher : public HybridCipher {
|
|
8
8
|
public:
|
|
9
|
-
ChaCha20Poly1305Cipher() : HybridObject(TAG)
|
|
9
|
+
ChaCha20Poly1305Cipher() : HybridObject(TAG) {}
|
|
10
10
|
~ChaCha20Poly1305Cipher() {
|
|
11
11
|
// Let parent destructor free the context
|
|
12
12
|
ctx = nullptr;
|
|
@@ -24,7 +24,6 @@ class ChaCha20Poly1305Cipher : public HybridCipher {
|
|
|
24
24
|
static constexpr int kKeySize = 32;
|
|
25
25
|
static constexpr int kNonceSize = 12;
|
|
26
26
|
static constexpr int kTagSize = 16; // Poly1305 tag is always 16 bytes
|
|
27
|
-
bool final_called;
|
|
28
27
|
};
|
|
29
28
|
|
|
30
29
|
} // namespace margelo::nitro::crypto
|
|
@@ -27,6 +27,12 @@ void HybridCipher::checkCtx() const {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
void HybridCipher::checkNotFinalized() const {
|
|
31
|
+
if (is_finalized) {
|
|
32
|
+
throw std::runtime_error("Unsupported state or unable to authenticate data");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
30
36
|
bool HybridCipher::maybePassAuthTagToOpenSSL() {
|
|
31
37
|
if (auth_tag_state == kAuthTagKnown) {
|
|
32
38
|
OSSL_PARAM params[] = {OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, auth_tag, auth_tag_len),
|
|
@@ -48,6 +54,7 @@ void HybridCipher::init(const std::shared_ptr<ArrayBuffer> cipher_key, const std
|
|
|
48
54
|
EVP_CIPHER_CTX_free(ctx);
|
|
49
55
|
ctx = nullptr;
|
|
50
56
|
}
|
|
57
|
+
is_finalized = false;
|
|
51
58
|
|
|
52
59
|
// 1. Get cipher implementation by name
|
|
53
60
|
const EVP_CIPHER* cipher = EVP_get_cipherbyname(cipher_type.c_str());
|
|
@@ -100,6 +107,7 @@ void HybridCipher::init(const std::shared_ptr<ArrayBuffer> cipher_key, const std
|
|
|
100
107
|
std::shared_ptr<ArrayBuffer> HybridCipher::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
101
108
|
auto native_data = ToNativeArrayBuffer(data);
|
|
102
109
|
checkCtx();
|
|
110
|
+
checkNotFinalized();
|
|
103
111
|
size_t in_len = native_data->size();
|
|
104
112
|
if (in_len > INT_MAX) {
|
|
105
113
|
throw std::runtime_error("Message too long");
|
|
@@ -125,6 +133,7 @@ std::shared_ptr<ArrayBuffer> HybridCipher::update(const std::shared_ptr<ArrayBuf
|
|
|
125
133
|
|
|
126
134
|
std::shared_ptr<ArrayBuffer> HybridCipher::final() {
|
|
127
135
|
checkCtx();
|
|
136
|
+
checkNotFinalized();
|
|
128
137
|
// Block size is max output size for final, unless EVP_CIPH_NO_PADDING is set
|
|
129
138
|
int block_size = EVP_CIPHER_CTX_block_size(ctx);
|
|
130
139
|
if (block_size <= 0)
|
|
@@ -149,8 +158,8 @@ std::shared_ptr<ArrayBuffer> HybridCipher::final() {
|
|
|
149
158
|
|
|
150
159
|
// Context should NOT be freed here. It might be needed for getAuthTag() for GCM/OCB.
|
|
151
160
|
// The context will be freed by the destructor (~HybridCipher) when the object goes out of scope.
|
|
161
|
+
is_finalized = true;
|
|
152
162
|
|
|
153
|
-
// Return the shared_ptr<NativeArrayBuffer> (implicit upcast to shared_ptr<ArrayBuffer>)
|
|
154
163
|
return native_final_chunk;
|
|
155
164
|
}
|
|
156
165
|
|
|
@@ -53,6 +53,7 @@ class HybridCipher : public HybridCipherSpec {
|
|
|
53
53
|
protected:
|
|
54
54
|
// Properties
|
|
55
55
|
bool is_cipher = true;
|
|
56
|
+
bool is_finalized = false;
|
|
56
57
|
std::string cipher_type;
|
|
57
58
|
EVP_CIPHER_CTX* ctx = nullptr;
|
|
58
59
|
bool pending_auth_failed = false;
|
|
@@ -66,6 +67,7 @@ class HybridCipher : public HybridCipherSpec {
|
|
|
66
67
|
// Methods
|
|
67
68
|
int getMode();
|
|
68
69
|
void checkCtx() const;
|
|
70
|
+
void checkNotFinalized() const;
|
|
69
71
|
bool maybePassAuthTagToOpenSSL();
|
|
70
72
|
};
|
|
71
73
|
|
|
@@ -14,19 +14,6 @@ using margelo::nitro::NativeArrayBuffer;
|
|
|
14
14
|
constexpr int kRsaPkcs1Padding = 1;
|
|
15
15
|
constexpr int kRsaOaepPadding = 4;
|
|
16
16
|
|
|
17
|
-
const EVP_MD* getDigestByName(const std::string& hashAlgorithm) {
|
|
18
|
-
if (hashAlgorithm == "SHA-1" || hashAlgorithm == "SHA1" || hashAlgorithm == "sha1" || hashAlgorithm == "sha-1") {
|
|
19
|
-
return EVP_sha1();
|
|
20
|
-
} else if (hashAlgorithm == "SHA-256" || hashAlgorithm == "SHA256" || hashAlgorithm == "sha256" || hashAlgorithm == "sha-256") {
|
|
21
|
-
return EVP_sha256();
|
|
22
|
-
} else if (hashAlgorithm == "SHA-384" || hashAlgorithm == "SHA384" || hashAlgorithm == "sha384" || hashAlgorithm == "sha-384") {
|
|
23
|
-
return EVP_sha384();
|
|
24
|
-
} else if (hashAlgorithm == "SHA-512" || hashAlgorithm == "SHA512" || hashAlgorithm == "sha512" || hashAlgorithm == "sha-512") {
|
|
25
|
-
return EVP_sha512();
|
|
26
|
-
}
|
|
27
|
-
throw std::runtime_error("Unsupported hash algorithm: " + hashAlgorithm);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
17
|
int toOpenSSLPadding(int padding) {
|
|
31
18
|
switch (padding) {
|
|
32
19
|
case kRsaPkcs1Padding:
|
|
@@ -45,10 +45,11 @@ void XChaCha20Poly1305Cipher::init(const std::shared_ptr<ArrayBuffer> cipher_key
|
|
|
45
45
|
|
|
46
46
|
data_buffer_.clear();
|
|
47
47
|
aad_.clear();
|
|
48
|
-
|
|
48
|
+
is_finalized = false;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
std::shared_ptr<ArrayBuffer> XChaCha20Poly1305Cipher::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
52
|
+
checkNotFinalized();
|
|
52
53
|
#ifndef BLSALLOC_SODIUM
|
|
53
54
|
throw std::runtime_error("XChaCha20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
54
55
|
#else
|
|
@@ -64,6 +65,7 @@ std::shared_ptr<ArrayBuffer> XChaCha20Poly1305Cipher::update(const std::shared_p
|
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
std::shared_ptr<ArrayBuffer> XChaCha20Poly1305Cipher::final() {
|
|
68
|
+
checkNotFinalized();
|
|
67
69
|
#ifndef BLSALLOC_SODIUM
|
|
68
70
|
throw std::runtime_error("XChaCha20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
69
71
|
#else
|
|
@@ -80,12 +82,12 @@ std::shared_ptr<ArrayBuffer> XChaCha20Poly1305Cipher::final() {
|
|
|
80
82
|
throw std::runtime_error("XChaCha20Poly1305Cipher: encryption failed");
|
|
81
83
|
}
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
is_finalized = true;
|
|
84
86
|
size_t ct_len = data_buffer_.size();
|
|
85
87
|
return std::make_shared<NativeArrayBuffer>(ciphertext, ct_len, [=]() { delete[] ciphertext; });
|
|
86
88
|
} else {
|
|
87
89
|
if (data_buffer_.empty()) {
|
|
88
|
-
|
|
90
|
+
is_finalized = true;
|
|
89
91
|
return std::make_shared<NativeArrayBuffer>(nullptr, 0, nullptr);
|
|
90
92
|
}
|
|
91
93
|
|
|
@@ -101,7 +103,7 @@ std::shared_ptr<ArrayBuffer> XChaCha20Poly1305Cipher::final() {
|
|
|
101
103
|
throw std::runtime_error("XChaCha20Poly1305Cipher: decryption failed - authentication tag mismatch");
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
|
|
106
|
+
is_finalized = true;
|
|
105
107
|
size_t pt_len = data_buffer_.size();
|
|
106
108
|
return std::make_shared<NativeArrayBuffer>(plaintext, pt_len, [=]() { delete[] plaintext; });
|
|
107
109
|
}
|
|
@@ -126,7 +128,7 @@ std::shared_ptr<ArrayBuffer> XChaCha20Poly1305Cipher::getAuthTag() {
|
|
|
126
128
|
if (!is_cipher) {
|
|
127
129
|
throw std::runtime_error("getAuthTag can only be called during encryption");
|
|
128
130
|
}
|
|
129
|
-
if (!
|
|
131
|
+
if (!is_finalized) {
|
|
130
132
|
throw std::runtime_error("getAuthTag must be called after final()");
|
|
131
133
|
}
|
|
132
134
|
|
|
@@ -16,7 +16,7 @@ namespace margelo::nitro::crypto {
|
|
|
16
16
|
|
|
17
17
|
class XChaCha20Poly1305Cipher : public HybridCipher {
|
|
18
18
|
public:
|
|
19
|
-
XChaCha20Poly1305Cipher() : HybridObject(TAG)
|
|
19
|
+
XChaCha20Poly1305Cipher() : HybridObject(TAG) {}
|
|
20
20
|
~XChaCha20Poly1305Cipher();
|
|
21
21
|
|
|
22
22
|
void init(const std::shared_ptr<ArrayBuffer> cipher_key, const std::shared_ptr<ArrayBuffer> iv) override;
|
|
@@ -37,7 +37,6 @@ class XChaCha20Poly1305Cipher : public HybridCipher {
|
|
|
37
37
|
std::vector<uint8_t> aad_;
|
|
38
38
|
std::vector<uint8_t> data_buffer_;
|
|
39
39
|
uint8_t auth_tag_[kTagSize];
|
|
40
|
-
bool final_called_;
|
|
41
40
|
};
|
|
42
41
|
|
|
43
42
|
} // namespace margelo::nitro::crypto
|
|
@@ -28,12 +28,14 @@ void XSalsa20Cipher::init(const std::shared_ptr<ArrayBuffer> cipher_key, const s
|
|
|
28
28
|
// Copy key and nonce data
|
|
29
29
|
std::memcpy(key, native_key->data(), crypto_stream_KEYBYTES);
|
|
30
30
|
std::memcpy(nonce, native_iv->data(), crypto_stream_NONCEBYTES);
|
|
31
|
+
is_finalized = false;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* xsalsa20 call to sodium implementation
|
|
35
36
|
*/
|
|
36
37
|
std::shared_ptr<ArrayBuffer> XSalsa20Cipher::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
38
|
+
checkNotFinalized();
|
|
37
39
|
#ifndef BLSALLOC_SODIUM
|
|
38
40
|
throw std::runtime_error("XSalsa20Cipher: libsodium must be enabled to use this cipher (BLSALLOC_SODIUM is not defined).");
|
|
39
41
|
#else
|
|
@@ -51,9 +53,11 @@ std::shared_ptr<ArrayBuffer> XSalsa20Cipher::update(const std::shared_ptr<ArrayB
|
|
|
51
53
|
* xsalsa20 does not have a final step, returns empty buffer
|
|
52
54
|
*/
|
|
53
55
|
std::shared_ptr<ArrayBuffer> XSalsa20Cipher::final() {
|
|
56
|
+
checkNotFinalized();
|
|
54
57
|
#ifndef BLSALLOC_SODIUM
|
|
55
58
|
throw std::runtime_error("XSalsa20Cipher: libsodium must be enabled to use this cipher (BLSALLOC_SODIUM is not defined).");
|
|
56
59
|
#else
|
|
60
|
+
is_finalized = true;
|
|
57
61
|
return std::make_shared<NativeArrayBuffer>(nullptr, 0, nullptr);
|
|
58
62
|
#endif
|
|
59
63
|
}
|
|
@@ -40,10 +40,11 @@ void XSalsa20Poly1305Cipher::init(const std::shared_ptr<ArrayBuffer> cipher_key,
|
|
|
40
40
|
std::memcpy(nonce_, native_iv->data(), kNonceSize);
|
|
41
41
|
|
|
42
42
|
data_buffer_.clear();
|
|
43
|
-
|
|
43
|
+
is_finalized = false;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
std::shared_ptr<ArrayBuffer> XSalsa20Poly1305Cipher::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
47
|
+
checkNotFinalized();
|
|
47
48
|
#ifndef BLSALLOC_SODIUM
|
|
48
49
|
throw std::runtime_error("XSalsa20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
49
50
|
#else
|
|
@@ -59,6 +60,7 @@ std::shared_ptr<ArrayBuffer> XSalsa20Poly1305Cipher::update(const std::shared_pt
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
std::shared_ptr<ArrayBuffer> XSalsa20Poly1305Cipher::final() {
|
|
63
|
+
checkNotFinalized();
|
|
62
64
|
#ifndef BLSALLOC_SODIUM
|
|
63
65
|
throw std::runtime_error("XSalsa20Poly1305Cipher: libsodium must be enabled (BLSALLOC_SODIUM)");
|
|
64
66
|
#else
|
|
@@ -73,12 +75,12 @@ std::shared_ptr<ArrayBuffer> XSalsa20Poly1305Cipher::final() {
|
|
|
73
75
|
throw std::runtime_error("XSalsa20Poly1305Cipher: encryption failed");
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
|
|
78
|
+
is_finalized = true;
|
|
77
79
|
size_t ct_len = data_buffer_.size();
|
|
78
80
|
return std::make_shared<NativeArrayBuffer>(ciphertext, ct_len, [=]() { delete[] ciphertext; });
|
|
79
81
|
} else {
|
|
80
82
|
if (data_buffer_.empty()) {
|
|
81
|
-
|
|
83
|
+
is_finalized = true;
|
|
82
84
|
return std::make_shared<NativeArrayBuffer>(nullptr, 0, nullptr);
|
|
83
85
|
}
|
|
84
86
|
|
|
@@ -92,7 +94,7 @@ std::shared_ptr<ArrayBuffer> XSalsa20Poly1305Cipher::final() {
|
|
|
92
94
|
throw std::runtime_error("XSalsa20Poly1305Cipher: decryption failed - authentication tag mismatch");
|
|
93
95
|
}
|
|
94
96
|
|
|
95
|
-
|
|
97
|
+
is_finalized = true;
|
|
96
98
|
size_t pt_len = data_buffer_.size();
|
|
97
99
|
return std::make_shared<NativeArrayBuffer>(plaintext, pt_len, [=]() { delete[] plaintext; });
|
|
98
100
|
}
|
|
@@ -110,7 +112,7 @@ std::shared_ptr<ArrayBuffer> XSalsa20Poly1305Cipher::getAuthTag() {
|
|
|
110
112
|
if (!is_cipher) {
|
|
111
113
|
throw std::runtime_error("getAuthTag can only be called during encryption");
|
|
112
114
|
}
|
|
113
|
-
if (!
|
|
115
|
+
if (!is_finalized) {
|
|
114
116
|
throw std::runtime_error("getAuthTag must be called after final()");
|
|
115
117
|
}
|
|
116
118
|
|
|
@@ -16,7 +16,7 @@ namespace margelo::nitro::crypto {
|
|
|
16
16
|
|
|
17
17
|
class XSalsa20Poly1305Cipher : public HybridCipher {
|
|
18
18
|
public:
|
|
19
|
-
XSalsa20Poly1305Cipher() : HybridObject(TAG)
|
|
19
|
+
XSalsa20Poly1305Cipher() : HybridObject(TAG) {}
|
|
20
20
|
~XSalsa20Poly1305Cipher();
|
|
21
21
|
|
|
22
22
|
void init(const std::shared_ptr<ArrayBuffer> cipher_key, const std::shared_ptr<ArrayBuffer> iv) override;
|
|
@@ -36,7 +36,6 @@ class XSalsa20Poly1305Cipher : public HybridCipher {
|
|
|
36
36
|
uint8_t nonce_[kNonceSize];
|
|
37
37
|
std::vector<uint8_t> data_buffer_;
|
|
38
38
|
uint8_t auth_tag_[kTagSize];
|
|
39
|
-
bool final_called_;
|
|
40
39
|
};
|
|
41
40
|
|
|
42
41
|
} // namespace margelo::nitro::crypto
|
package/cpp/ecdh/HybridECDH.cpp
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#include "QuickCryptoUtils.hpp"
|
|
3
3
|
#include <NitroModules/ArrayBuffer.hpp>
|
|
4
4
|
#include <openssl/bn.h>
|
|
5
|
+
#include <openssl/core_names.h>
|
|
5
6
|
#include <openssl/ec.h>
|
|
6
7
|
#include <openssl/err.h>
|
|
7
8
|
#include <openssl/evp.h>
|
|
@@ -12,15 +13,9 @@ namespace margelo::nitro::crypto {
|
|
|
12
13
|
|
|
13
14
|
// Smart pointer type aliases for RAII
|
|
14
15
|
using EVP_PKEY_CTX_ptr = std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)>;
|
|
15
|
-
using EC_KEY_ptr = std::unique_ptr<EC_KEY, decltype(&EC_KEY_free)>;
|
|
16
16
|
using EC_POINT_ptr = std::unique_ptr<EC_POINT, decltype(&EC_POINT_free)>;
|
|
17
17
|
using BN_ptr = std::unique_ptr<BIGNUM, decltype(&BN_free)>;
|
|
18
18
|
|
|
19
|
-
// Suppress deprecation warnings for EC_KEY_* functions
|
|
20
|
-
// These APIs work but are deprecated in OpenSSL 3.x
|
|
21
|
-
#pragma clang diagnostic push
|
|
22
|
-
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
|
23
|
-
|
|
24
19
|
void HybridECDH::init(const std::string& curveName) {
|
|
25
20
|
int nid = getCurveNid(curveName);
|
|
26
21
|
if (nid == NID_undef) {
|
|
@@ -70,41 +65,8 @@ std::shared_ptr<ArrayBuffer> HybridECDH::computeSecret(const std::shared_ptr<Arr
|
|
|
70
65
|
throw std::runtime_error("ECDH: private key not set");
|
|
71
66
|
}
|
|
72
67
|
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
if (!point) {
|
|
76
|
-
throw std::runtime_error("ECDH: failed to create EC point");
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (EC_POINT_oct2point(_group.get(), point.get(), otherPublicKey->data(), otherPublicKey->size(), nullptr) != 1) {
|
|
80
|
-
throw std::runtime_error("ECDH: failed to decode peer public key");
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Create EC_KEY for the peer
|
|
84
|
-
EC_KEY_ptr ecKey(EC_KEY_new(), EC_KEY_free);
|
|
85
|
-
if (!ecKey) {
|
|
86
|
-
throw std::runtime_error("ECDH: failed to create EC_KEY");
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (EC_KEY_set_group(ecKey.get(), _group.get()) != 1) {
|
|
90
|
-
throw std::runtime_error("ECDH: failed to set EC group");
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
|
|
94
|
-
throw std::runtime_error("ECDH: failed to set peer public key");
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Create EVP_PKEY for the peer
|
|
98
|
-
EVP_PKEY_ptr peerPkey(EVP_PKEY_new(), EVP_PKEY_free);
|
|
99
|
-
if (!peerPkey) {
|
|
100
|
-
throw std::runtime_error("ECDH: failed to create peer EVP_PKEY");
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// EVP_PKEY_assign_EC_KEY takes ownership of ecKey on success
|
|
104
|
-
if (EVP_PKEY_assign_EC_KEY(peerPkey.get(), ecKey.get()) != 1) {
|
|
105
|
-
throw std::runtime_error("ECDH: failed to assign EC_KEY to EVP_PKEY");
|
|
106
|
-
}
|
|
107
|
-
ecKey.release(); // EVP_PKEY now owns the EC_KEY
|
|
68
|
+
// Build peer EVP_PKEY from raw public key octets
|
|
69
|
+
EVP_PKEY_ptr peerPkey(createEcEvpPkey(_curveName.c_str(), otherPublicKey->data(), otherPublicKey->size()), EVP_PKEY_free);
|
|
108
70
|
|
|
109
71
|
// Derive shared secret using EVP API
|
|
110
72
|
EVP_PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new(_pkey.get(), nullptr), EVP_PKEY_CTX_free);
|
|
@@ -142,19 +104,15 @@ std::shared_ptr<ArrayBuffer> HybridECDH::getPrivateKey() {
|
|
|
142
104
|
throw std::runtime_error("ECDH: no key set");
|
|
143
105
|
}
|
|
144
106
|
|
|
145
|
-
|
|
146
|
-
if (!
|
|
147
|
-
throw std::runtime_error("ECDH: key is not an EC key");
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const BIGNUM* priv = EC_KEY_get0_private_key(ec);
|
|
151
|
-
if (!priv) {
|
|
107
|
+
BIGNUM* priv = nullptr;
|
|
108
|
+
if (EVP_PKEY_get_bn_param(_pkey.get(), OSSL_PKEY_PARAM_PRIV_KEY, &priv) != 1 || !priv) {
|
|
152
109
|
throw std::runtime_error("ECDH: no private key available");
|
|
153
110
|
}
|
|
154
111
|
|
|
155
112
|
int len = BN_num_bytes(priv);
|
|
156
113
|
std::vector<uint8_t> buf(len);
|
|
157
114
|
BN_bn2bin(priv, buf.data());
|
|
115
|
+
BN_free(priv);
|
|
158
116
|
|
|
159
117
|
return ToNativeArrayBuffer(buf);
|
|
160
118
|
}
|
|
@@ -162,23 +120,12 @@ std::shared_ptr<ArrayBuffer> HybridECDH::getPrivateKey() {
|
|
|
162
120
|
void HybridECDH::setPrivateKey(const std::shared_ptr<ArrayBuffer>& privateKey) {
|
|
163
121
|
ensureInitialized();
|
|
164
122
|
|
|
165
|
-
// Create new EC_KEY
|
|
166
|
-
EC_KEY_ptr ecKey(EC_KEY_new(), EC_KEY_free);
|
|
167
|
-
if (!ecKey) {
|
|
168
|
-
throw std::runtime_error("ECDH: failed to create EC_KEY");
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (EC_KEY_set_group(ecKey.get(), _group.get()) != 1) {
|
|
172
|
-
throw std::runtime_error("ECDH: failed to set EC group");
|
|
173
|
-
}
|
|
174
|
-
|
|
175
123
|
// Convert private key bytes to BIGNUM
|
|
176
124
|
BN_ptr privBn(BN_bin2bn(privateKey->data(), static_cast<int>(privateKey->size()), nullptr), BN_free);
|
|
177
125
|
if (!privBn) {
|
|
178
126
|
throw std::runtime_error("ECDH: failed to convert private key");
|
|
179
127
|
}
|
|
180
128
|
|
|
181
|
-
// Calculate public key from private key
|
|
182
129
|
EC_POINT_ptr pubPoint(EC_POINT_new(_group.get()), EC_POINT_free);
|
|
183
130
|
if (!pubPoint) {
|
|
184
131
|
throw std::runtime_error("ECDH: failed to create EC point");
|
|
@@ -188,28 +135,17 @@ void HybridECDH::setPrivateKey(const std::shared_ptr<ArrayBuffer>& privateKey) {
|
|
|
188
135
|
throw std::runtime_error("ECDH: failed to compute public key from private key");
|
|
189
136
|
}
|
|
190
137
|
|
|
191
|
-
|
|
192
|
-
if (
|
|
193
|
-
throw std::runtime_error("ECDH: failed to
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (EC_KEY_set_public_key(ecKey.get(), pubPoint.get()) != 1) {
|
|
197
|
-
throw std::runtime_error("ECDH: failed to set public key");
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Create new EVP_PKEY
|
|
201
|
-
EVP_PKEY_ptr pkey(EVP_PKEY_new(), EVP_PKEY_free);
|
|
202
|
-
if (!pkey) {
|
|
203
|
-
throw std::runtime_error("ECDH: failed to create EVP_PKEY");
|
|
138
|
+
size_t pubLen = EC_POINT_point2oct(_group.get(), pubPoint.get(), POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
|
|
139
|
+
if (pubLen == 0) {
|
|
140
|
+
throw std::runtime_error("ECDH: failed to get public key length");
|
|
204
141
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
throw std::runtime_error("ECDH: failed to assign EC_KEY to EVP_PKEY");
|
|
142
|
+
std::vector<uint8_t> pubOct(pubLen);
|
|
143
|
+
if (EC_POINT_point2oct(_group.get(), pubPoint.get(), POINT_CONVERSION_UNCOMPRESSED, pubOct.data(), pubLen, nullptr) == 0) {
|
|
144
|
+
throw std::runtime_error("ECDH: failed to serialize public key");
|
|
209
145
|
}
|
|
210
|
-
ecKey.release(); // EVP_PKEY now owns the EC_KEY
|
|
211
146
|
|
|
212
|
-
|
|
147
|
+
// Build EVP_PKEY via OSSL_PARAM_BLD
|
|
148
|
+
_pkey.reset(createEcEvpPkey(_curveName.c_str(), pubOct.data(), pubOct.size(), privBn.get()));
|
|
213
149
|
}
|
|
214
150
|
|
|
215
151
|
std::shared_ptr<ArrayBuffer> HybridECDH::getPublicKey() {
|
|
@@ -217,26 +153,14 @@ std::shared_ptr<ArrayBuffer> HybridECDH::getPublicKey() {
|
|
|
217
153
|
throw std::runtime_error("ECDH: no key set");
|
|
218
154
|
}
|
|
219
155
|
|
|
220
|
-
|
|
221
|
-
if (
|
|
222
|
-
throw std::runtime_error("ECDH: key is not an EC key");
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const EC_POINT* point = EC_KEY_get0_public_key(ec);
|
|
226
|
-
const EC_GROUP* group = EC_KEY_get0_group(ec);
|
|
227
|
-
if (!point || !group) {
|
|
228
|
-
throw std::runtime_error("ECDH: incomplete key");
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Get uncompressed public key size
|
|
232
|
-
size_t len = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
|
|
233
|
-
if (len == 0) {
|
|
156
|
+
size_t len = 0;
|
|
157
|
+
if (EVP_PKEY_get_octet_string_param(_pkey.get(), OSSL_PKEY_PARAM_PUB_KEY, nullptr, 0, &len) != 1 || len == 0) {
|
|
234
158
|
throw std::runtime_error("ECDH: failed to get public key length");
|
|
235
159
|
}
|
|
236
160
|
|
|
237
161
|
std::vector<uint8_t> buf(len);
|
|
238
|
-
if (
|
|
239
|
-
throw std::runtime_error("ECDH: failed to
|
|
162
|
+
if (EVP_PKEY_get_octet_string_param(_pkey.get(), OSSL_PKEY_PARAM_PUB_KEY, buf.data(), buf.size(), &len) != 1) {
|
|
163
|
+
throw std::runtime_error("ECDH: failed to get public key");
|
|
240
164
|
}
|
|
241
165
|
|
|
242
166
|
return ToNativeArrayBuffer(buf);
|
|
@@ -245,43 +169,8 @@ std::shared_ptr<ArrayBuffer> HybridECDH::getPublicKey() {
|
|
|
245
169
|
void HybridECDH::setPublicKey(const std::shared_ptr<ArrayBuffer>& publicKey) {
|
|
246
170
|
ensureInitialized();
|
|
247
171
|
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
if (!point) {
|
|
251
|
-
throw std::runtime_error("ECDH: failed to create EC point");
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
if (EC_POINT_oct2point(_group.get(), point.get(), publicKey->data(), publicKey->size(), nullptr) != 1) {
|
|
255
|
-
throw std::runtime_error("ECDH: invalid public key");
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Create new EC_KEY
|
|
259
|
-
EC_KEY_ptr ecKey(EC_KEY_new(), EC_KEY_free);
|
|
260
|
-
if (!ecKey) {
|
|
261
|
-
throw std::runtime_error("ECDH: failed to create EC_KEY");
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (EC_KEY_set_group(ecKey.get(), _group.get()) != 1) {
|
|
265
|
-
throw std::runtime_error("ECDH: failed to set EC group");
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
|
|
269
|
-
throw std::runtime_error("ECDH: failed to set public key");
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// Create new EVP_PKEY
|
|
273
|
-
EVP_PKEY_ptr pkey(EVP_PKEY_new(), EVP_PKEY_free);
|
|
274
|
-
if (!pkey) {
|
|
275
|
-
throw std::runtime_error("ECDH: failed to create EVP_PKEY");
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// EVP_PKEY_assign_EC_KEY takes ownership of ecKey on success
|
|
279
|
-
if (EVP_PKEY_assign_EC_KEY(pkey.get(), ecKey.get()) != 1) {
|
|
280
|
-
throw std::runtime_error("ECDH: failed to assign EC_KEY to EVP_PKEY");
|
|
281
|
-
}
|
|
282
|
-
ecKey.release(); // EVP_PKEY now owns the EC_KEY
|
|
283
|
-
|
|
284
|
-
_pkey = std::move(pkey);
|
|
172
|
+
// Build EVP_PKEY directly from public key octets
|
|
173
|
+
_pkey.reset(createEcEvpPkey(_curveName.c_str(), publicKey->data(), publicKey->size()));
|
|
285
174
|
}
|
|
286
175
|
|
|
287
176
|
std::shared_ptr<ArrayBuffer> HybridECDH::convertKey(const std::shared_ptr<ArrayBuffer>& key, const std::string& curve, double format) {
|
|
@@ -336,6 +225,4 @@ int HybridECDH::getCurveNid(const std::string& name) {
|
|
|
336
225
|
return nid;
|
|
337
226
|
}
|
|
338
227
|
|
|
339
|
-
#pragma clang diagnostic pop
|
|
340
|
-
|
|
341
228
|
} // namespace margelo::nitro::crypto
|