react-native-quick-crypto 1.0.0-beta.11 → 1.0.0-beta.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.
Files changed (59) hide show
  1. package/android/CMakeLists.txt +4 -0
  2. package/cpp/ed25519/HybridEdKeyPair.cpp +32 -89
  3. package/cpp/ed25519/HybridEdKeyPair.hpp +24 -54
  4. package/cpp/hash/HybridHash.cpp +151 -0
  5. package/cpp/hash/HybridHash.hpp +41 -0
  6. package/cpp/hmac/HybridHmac.cpp +95 -0
  7. package/cpp/hmac/HybridHmac.hpp +31 -0
  8. package/cpp/pbkdf2/HybridPbkdf2.cpp +34 -55
  9. package/cpp/pbkdf2/HybridPbkdf2.hpp +5 -16
  10. package/cpp/random/HybridRandom.cpp +5 -16
  11. package/cpp/random/HybridRandom.hpp +5 -6
  12. package/cpp/utils/Utils.hpp +1 -2
  13. package/lib/commonjs/hash.js +168 -0
  14. package/lib/commonjs/hash.js.map +1 -0
  15. package/lib/commonjs/hmac.js +109 -0
  16. package/lib/commonjs/hmac.js.map +1 -0
  17. package/lib/commonjs/index.js +26 -0
  18. package/lib/commonjs/index.js.map +1 -1
  19. package/lib/commonjs/specs/hash.nitro.js +6 -0
  20. package/lib/commonjs/specs/hash.nitro.js.map +1 -0
  21. package/lib/commonjs/specs/hmac.nitro.js +6 -0
  22. package/lib/commonjs/specs/hmac.nitro.js.map +1 -0
  23. package/lib/module/hash.js +162 -0
  24. package/lib/module/hash.js.map +1 -0
  25. package/lib/module/hmac.js +104 -0
  26. package/lib/module/hmac.js.map +1 -0
  27. package/lib/module/index.js +6 -0
  28. package/lib/module/index.js.map +1 -1
  29. package/lib/module/specs/hash.nitro.js +4 -0
  30. package/lib/module/specs/hash.nitro.js.map +1 -0
  31. package/lib/module/specs/hmac.nitro.js +4 -0
  32. package/lib/module/specs/hmac.nitro.js.map +1 -0
  33. package/lib/tsconfig.tsbuildinfo +1 -1
  34. package/lib/typescript/hash.d.ts +110 -0
  35. package/lib/typescript/hash.d.ts.map +1 -0
  36. package/lib/typescript/hmac.d.ts +67 -0
  37. package/lib/typescript/hmac.d.ts.map +1 -0
  38. package/lib/typescript/index.d.ts +5 -0
  39. package/lib/typescript/index.d.ts.map +1 -1
  40. package/lib/typescript/specs/hash.nitro.d.ts +12 -0
  41. package/lib/typescript/specs/hash.nitro.d.ts.map +1 -0
  42. package/lib/typescript/specs/hmac.nitro.d.ts +10 -0
  43. package/lib/typescript/specs/hmac.nitro.d.ts.map +1 -0
  44. package/lib/typescript/utils/types.d.ts +4 -0
  45. package/lib/typescript/utils/types.d.ts.map +1 -1
  46. package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +2 -0
  47. package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +20 -0
  48. package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +20 -0
  49. package/nitrogen/generated/shared/c++/HybridHashSpec.cpp +25 -0
  50. package/nitrogen/generated/shared/c++/HybridHashSpec.hpp +74 -0
  51. package/nitrogen/generated/shared/c++/HybridHmacSpec.cpp +23 -0
  52. package/nitrogen/generated/shared/c++/HybridHmacSpec.hpp +66 -0
  53. package/package.json +1 -1
  54. package/src/hash.ts +208 -0
  55. package/src/hmac.ts +135 -0
  56. package/src/index.ts +6 -0
  57. package/src/specs/hash.nitro.ts +9 -0
  58. package/src/specs/hmac.nitro.ts +7 -0
  59. package/src/utils/types.ts +9 -0
@@ -9,6 +9,8 @@ set(CMAKE_CXX_STANDARD 20)
9
9
  add_library(
10
10
  ${PACKAGE_NAME} SHARED
11
11
  src/main/cpp/cpp-adapter.cpp
12
+ ../cpp/hmac/HybridHmac.cpp
13
+ ../cpp/hash/HybridHash.cpp
12
14
  ../cpp/ed25519/HybridEdKeyPair.cpp
13
15
  ../cpp/pbkdf2/HybridPbkdf2.cpp
14
16
  ../cpp/random/HybridRandom.cpp
@@ -21,6 +23,8 @@ include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/QuickCrypto+autolinkin
21
23
  # local includes
22
24
  include_directories(
23
25
  "src/main/cpp"
26
+ "../cpp/hmac"
27
+ "../cpp/hash"
24
28
  "../cpp/ed25519"
25
29
  "../cpp/pbkdf2"
26
30
  "../cpp/random"
@@ -5,45 +5,23 @@
5
5
 
6
6
  namespace margelo::nitro::crypto {
7
7
 
8
- std::shared_ptr<Promise<void>>
9
- HybridEdKeyPair::generateKeyPair(
10
- double publicFormat,
11
- double publicType,
12
- double privateFormat,
13
- double privateType,
14
- const std::optional<std::string>& cipher,
15
- const std::optional<std::shared_ptr<ArrayBuffer>>& passphrase
16
- ) {
8
+ std::shared_ptr<Promise<void>> HybridEdKeyPair::generateKeyPair(double publicFormat, double publicType, double privateFormat,
9
+ double privateType, const std::optional<std::string>& cipher,
10
+ const std::optional<std::shared_ptr<ArrayBuffer>>& passphrase) {
17
11
  // get owned NativeArrayBuffers before passing to sync function
18
12
  std::optional<std::shared_ptr<ArrayBuffer>> nativePassphrase = std::nullopt;
19
13
  if (passphrase.has_value()) {
20
14
  nativePassphrase = ToNativeArrayBuffer(passphrase.value());
21
15
  }
22
16
 
23
- return Promise<void>::async(
24
- [this, publicFormat, publicType, privateFormat, privateType, cipher,
25
- nativePassphrase]() {
26
- this->generateKeyPairSync(
27
- publicFormat,
28
- publicType,
29
- privateFormat,
30
- privateType,
31
- cipher,
32
- nativePassphrase
33
- );
34
- }
35
- );
17
+ return Promise<void>::async([this, publicFormat, publicType, privateFormat, privateType, cipher, nativePassphrase]() {
18
+ this->generateKeyPairSync(publicFormat, publicType, privateFormat, privateType, cipher, nativePassphrase);
19
+ });
36
20
  }
37
21
 
38
- void
39
- HybridEdKeyPair::generateKeyPairSync(
40
- double publicFormat,
41
- double publicType,
42
- double privateFormat,
43
- double privateType,
44
- const std::optional<std::string>& cipher,
45
- const std::optional<std::shared_ptr<ArrayBuffer>>& passphrase
46
- ) {
22
+ void HybridEdKeyPair::generateKeyPairSync(double publicFormat, double publicType, double privateFormat, double privateType,
23
+ const std::optional<std::string>& cipher,
24
+ const std::optional<std::shared_ptr<ArrayBuffer>>& passphrase) {
47
25
  EVP_PKEY_CTX* pctx;
48
26
 
49
27
  // key context
@@ -69,12 +47,8 @@ HybridEdKeyPair::generateKeyPairSync(
69
47
  EVP_PKEY_CTX_free(pctx);
70
48
  }
71
49
 
72
-
73
- std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>>
74
- HybridEdKeyPair::sign(
75
- const std::shared_ptr<ArrayBuffer>& message,
76
- const std::optional<std::shared_ptr<ArrayBuffer>>& key
77
- ) {
50
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> HybridEdKeyPair::sign(const std::shared_ptr<ArrayBuffer>& message,
51
+ const std::optional<std::shared_ptr<ArrayBuffer>>& key) {
78
52
  // get owned NativeArrayBuffer before passing to sync function
79
53
  auto nativeMessage = ToNativeArrayBuffer(message);
80
54
  std::optional<std::shared_ptr<ArrayBuffer>> nativeKey = std::nullopt;
@@ -82,17 +56,12 @@ HybridEdKeyPair::sign(
82
56
  nativeKey = ToNativeArrayBuffer(key.value());
83
57
  }
84
58
 
85
- return Promise<std::shared_ptr<ArrayBuffer>>::async([this, nativeMessage, nativeKey]() {
86
- return this->signSync(nativeMessage, nativeKey);
87
- }
88
- );
59
+ return Promise<std::shared_ptr<ArrayBuffer>>::async(
60
+ [this, nativeMessage, nativeKey]() { return this->signSync(nativeMessage, nativeKey); });
89
61
  }
90
62
 
91
- std::shared_ptr<ArrayBuffer>
92
- HybridEdKeyPair::signSync(
93
- const std::shared_ptr<ArrayBuffer>& message,
94
- const std::optional<std::shared_ptr<ArrayBuffer>>& key
95
- ) {
63
+ std::shared_ptr<ArrayBuffer> HybridEdKeyPair::signSync(const std::shared_ptr<ArrayBuffer>& message,
64
+ const std::optional<std::shared_ptr<ArrayBuffer>>& key) {
96
65
 
97
66
  size_t sig_len = 0;
98
67
  uint8_t* sig = NULL;
@@ -135,11 +104,7 @@ HybridEdKeyPair::signSync(
135
104
  }
136
105
 
137
106
  // return value for JS
138
- std::shared_ptr<ArrayBuffer> signature = std::make_shared<NativeArrayBuffer>(
139
- sig,
140
- sig_len,
141
- [=]() { delete[] sig; }
142
- );
107
+ std::shared_ptr<ArrayBuffer> signature = std::make_shared<NativeArrayBuffer>(sig, sig_len, [=]() { delete[] sig; });
143
108
 
144
109
  // Clean up
145
110
  EVP_MD_CTX_free(md_ctx);
@@ -147,12 +112,9 @@ HybridEdKeyPair::signSync(
147
112
  return signature;
148
113
  }
149
114
 
150
- std::shared_ptr<Promise<bool>>
151
- HybridEdKeyPair::verify(
152
- const std::shared_ptr<ArrayBuffer>& signature,
153
- const std::shared_ptr<ArrayBuffer>& message,
154
- const std::optional<std::shared_ptr<ArrayBuffer>>& key
155
- ) {
115
+ std::shared_ptr<Promise<bool>> HybridEdKeyPair::verify(const std::shared_ptr<ArrayBuffer>& signature,
116
+ const std::shared_ptr<ArrayBuffer>& message,
117
+ const std::optional<std::shared_ptr<ArrayBuffer>>& key) {
156
118
  // get owned NativeArrayBuffers before passing to sync function
157
119
  auto nativeSignature = ToNativeArrayBuffer(signature);
158
120
  auto nativeMessage = ToNativeArrayBuffer(message);
@@ -161,18 +123,12 @@ HybridEdKeyPair::verify(
161
123
  nativeKey = ToNativeArrayBuffer(key.value());
162
124
  }
163
125
 
164
- return Promise<bool>::async([this, nativeSignature, nativeMessage, nativeKey]() {
165
- return this->verifySync(nativeSignature, nativeMessage, nativeKey);
166
- }
167
- );
126
+ return Promise<bool>::async(
127
+ [this, nativeSignature, nativeMessage, nativeKey]() { return this->verifySync(nativeSignature, nativeMessage, nativeKey); });
168
128
  }
169
129
 
170
- bool
171
- HybridEdKeyPair::verifySync(
172
- const std::shared_ptr<ArrayBuffer>& signature,
173
- const std::shared_ptr<ArrayBuffer>& message,
174
- const std::optional<std::shared_ptr<ArrayBuffer>>& key
175
- ) {
130
+ bool HybridEdKeyPair::verifySync(const std::shared_ptr<ArrayBuffer>& signature, const std::shared_ptr<ArrayBuffer>& message,
131
+ const std::optional<std::shared_ptr<ArrayBuffer>>& key) {
176
132
  // get key to use for verifying
177
133
  EVP_PKEY* pkey = this->importPrivateKey(key);
178
134
 
@@ -199,13 +155,9 @@ HybridEdKeyPair::verifySync(
199
155
  }
200
156
 
201
157
  // verify
202
- auto res = EVP_DigestVerify(
203
- md_ctx,
204
- signature.get()->data(), signature.get()->size(),
205
- message.get()->data(), message.get()->size()
206
- );
158
+ auto res = EVP_DigestVerify(md_ctx, signature.get()->data(), signature.get()->size(), message.get()->data(), message.get()->size());
207
159
 
208
- //return value for JS
160
+ // return value for JS
209
161
  if (res < 0) {
210
162
  EVP_MD_CTX_free(md_ctx);
211
163
  throw std::runtime_error("Failed to verify");
@@ -213,8 +165,7 @@ HybridEdKeyPair::verifySync(
213
165
  return res == 1; // true if 1, false if 0
214
166
  }
215
167
 
216
- std::shared_ptr<ArrayBuffer>
217
- HybridEdKeyPair::getPublicKey() {
168
+ std::shared_ptr<ArrayBuffer> HybridEdKeyPair::getPublicKey() {
218
169
  this->checkKeyPair();
219
170
  size_t len = 32;
220
171
  uint8_t* publ = new uint8_t[len];
@@ -223,8 +174,7 @@ HybridEdKeyPair::getPublicKey() {
223
174
  return std::make_shared<NativeArrayBuffer>(publ, len, [=]() { delete[] publ; });
224
175
  }
225
176
 
226
- std::shared_ptr<ArrayBuffer>
227
- HybridEdKeyPair::getPrivateKey() {
177
+ std::shared_ptr<ArrayBuffer> HybridEdKeyPair::getPrivateKey() {
228
178
  this->checkKeyPair();
229
179
  size_t len = 32;
230
180
  uint8_t* priv = new uint8_t[len];
@@ -233,28 +183,21 @@ HybridEdKeyPair::getPrivateKey() {
233
183
  return std::make_shared<NativeArrayBuffer>(priv, len, [=]() { delete[] priv; });
234
184
  }
235
185
 
236
- void
237
- HybridEdKeyPair::checkKeyPair() {
186
+ void HybridEdKeyPair::checkKeyPair() {
238
187
  if (this->pkey == nullptr) {
239
188
  throw std::runtime_error("Keypair not initialized");
240
189
  }
241
190
  }
242
191
 
243
- void
244
- HybridEdKeyPair::setCurve(const std::string& curve) {
192
+ void HybridEdKeyPair::setCurve(const std::string& curve) {
245
193
  this->curve = curve;
246
194
  }
247
195
 
248
- EVP_PKEY*
249
- HybridEdKeyPair::importPrivateKey(const std::optional<std::shared_ptr<ArrayBuffer>>& key) {
196
+ EVP_PKEY* HybridEdKeyPair::importPrivateKey(const std::optional<std::shared_ptr<ArrayBuffer>>& key) {
250
197
  EVP_PKEY* pkey = nullptr;
251
198
  if (key.has_value()) {
252
- pkey = EVP_PKEY_new_raw_private_key(
253
- EVP_PKEY_ED25519, // TODO: use this->curve somehow
254
- NULL,
255
- key.value()->data(),
256
- 32
257
- );
199
+ pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, // TODO: use this->curve somehow
200
+ NULL, key.value()->data(), 32);
258
201
  if (pkey == nullptr) {
259
202
  throw std::runtime_error("Failed to read private key");
260
203
  }
@@ -1,6 +1,6 @@
1
- #include <openssl/evp.h>
2
- #include <openssl/err.h>
3
1
  #include <memory>
2
+ #include <openssl/err.h>
3
+ #include <openssl/evp.h>
4
4
  #include <string>
5
5
 
6
6
  #include "HybridEdKeyPairSpec.hpp"
@@ -16,58 +16,30 @@ class HybridEdKeyPair : public HybridEdKeyPairSpec {
16
16
 
17
17
  public:
18
18
  // Methods
19
- std::shared_ptr<Promise<void>>
20
- generateKeyPair(
21
- double publicFormat,
22
- double publicType,
23
- double privateFormat,
24
- double privateType,
25
- const std::optional<std::string>& cipher,
26
- const std::optional<std::shared_ptr<ArrayBuffer>>& passphrase
27
- ) override;
28
-
29
- void
30
- generateKeyPairSync(
31
- double publicFormat,
32
- double publicType,
33
- double privateFormat,
34
- double privateType,
35
- const std::optional<std::string>& cipher,
36
- const std::optional<std::shared_ptr<ArrayBuffer>>& passphrase
37
- ) override;
38
-
39
- std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>>
40
- sign(
41
- const std::shared_ptr<ArrayBuffer>& message,
42
- const std::optional<std::shared_ptr<ArrayBuffer>>& key
43
- ) override;
44
-
45
- std::shared_ptr<ArrayBuffer>
46
- signSync(
47
- const std::shared_ptr<ArrayBuffer>& message,
48
- const std::optional<std::shared_ptr<ArrayBuffer>>& key
49
- ) override;
50
-
51
- std::shared_ptr<Promise<bool>>
52
- verify(
53
- const std::shared_ptr<ArrayBuffer>& signature,
54
- const std::shared_ptr<ArrayBuffer>& message,
55
- const std::optional<std::shared_ptr<ArrayBuffer>>& key
56
- ) override;
57
-
58
- bool
59
- verifySync(
60
- const std::shared_ptr<ArrayBuffer>& signature,
61
- const std::shared_ptr<ArrayBuffer>& message,
62
- const std::optional<std::shared_ptr<ArrayBuffer>>& key
63
- ) override;
19
+ std::shared_ptr<Promise<void>> generateKeyPair(double publicFormat, double publicType, double privateFormat, double privateType,
20
+ const std::optional<std::string>& cipher,
21
+ const std::optional<std::shared_ptr<ArrayBuffer>>& passphrase) override;
22
+
23
+ void generateKeyPairSync(double publicFormat, double publicType, double privateFormat, double privateType,
24
+ const std::optional<std::string>& cipher,
25
+ const std::optional<std::shared_ptr<ArrayBuffer>>& passphrase) override;
26
+
27
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> sign(const std::shared_ptr<ArrayBuffer>& message,
28
+ const std::optional<std::shared_ptr<ArrayBuffer>>& key) override;
29
+
30
+ std::shared_ptr<ArrayBuffer> signSync(const std::shared_ptr<ArrayBuffer>& message,
31
+ const std::optional<std::shared_ptr<ArrayBuffer>>& key) override;
32
+
33
+ std::shared_ptr<Promise<bool>> verify(const std::shared_ptr<ArrayBuffer>& signature, const std::shared_ptr<ArrayBuffer>& message,
34
+ const std::optional<std::shared_ptr<ArrayBuffer>>& key) override;
35
+
36
+ bool verifySync(const std::shared_ptr<ArrayBuffer>& signature, const std::shared_ptr<ArrayBuffer>& message,
37
+ const std::optional<std::shared_ptr<ArrayBuffer>>& key) override;
64
38
 
65
39
  protected:
66
- std::shared_ptr<ArrayBuffer>
67
- getPublicKey() override;
40
+ std::shared_ptr<ArrayBuffer> getPublicKey() override;
68
41
 
69
- std::shared_ptr<ArrayBuffer>
70
- getPrivateKey() override;
42
+ std::shared_ptr<ArrayBuffer> getPrivateKey() override;
71
43
 
72
44
  void checkKeyPair();
73
45
 
@@ -77,9 +49,7 @@ class HybridEdKeyPair : public HybridEdKeyPairSpec {
77
49
  std::string curve;
78
50
  EVP_PKEY* pkey = nullptr;
79
51
 
80
- EVP_PKEY* importPrivateKey(
81
- const std::optional<std::shared_ptr<ArrayBuffer>>& key
82
- );
52
+ EVP_PKEY* importPrivateKey(const std::optional<std::shared_ptr<ArrayBuffer>>& key);
83
53
  };
84
54
 
85
55
  } // namespace margelo::nitro::crypto
@@ -0,0 +1,151 @@
1
+ #include <NitroModules/ArrayBuffer.hpp>
2
+ #include <memory>
3
+ #include <openssl/err.h>
4
+ #include <openssl/evp.h>
5
+ #include <optional>
6
+ #include <string>
7
+ #include <vector>
8
+
9
+ #include "HybridHash.hpp"
10
+
11
+ namespace margelo::nitro::crypto {
12
+
13
+ HybridHash::~HybridHash() {
14
+ if (ctx) {
15
+ EVP_MD_CTX_free(ctx);
16
+ ctx = nullptr;
17
+ }
18
+ }
19
+
20
+ void HybridHash::createHash(const std::string& hashAlgorithmArg, const std::optional<double> outputLengthArg) {
21
+ algorithm = hashAlgorithmArg;
22
+ outputLength = outputLengthArg;
23
+
24
+ // Create hash context
25
+ ctx = EVP_MD_CTX_new();
26
+ if (!ctx) {
27
+ throw std::runtime_error("Failed to create hash context: " + std::to_string(ERR_get_error()));
28
+ }
29
+
30
+ // Get the message digest by name
31
+ md = EVP_get_digestbyname(algorithm.c_str());
32
+ if (!md) {
33
+ EVP_MD_CTX_free(ctx);
34
+ ctx = nullptr;
35
+ throw std::runtime_error("Unknown hash algorithm: " + algorithm);
36
+ }
37
+
38
+ // Initialize the digest
39
+ if (EVP_DigestInit_ex(ctx, md, nullptr) != 1) {
40
+ EVP_MD_CTX_free(ctx);
41
+ ctx = nullptr;
42
+ throw std::runtime_error("Failed to initialize hash digest: " + std::to_string(ERR_get_error()));
43
+ }
44
+ }
45
+
46
+ void HybridHash::update(const std::shared_ptr<ArrayBuffer>& data) {
47
+ if (!ctx) {
48
+ throw std::runtime_error("Hash context not initialized");
49
+ }
50
+
51
+ // Update the digest with the data
52
+ if (EVP_DigestUpdate(ctx, reinterpret_cast<const uint8_t*>(data->data()), data->size()) != 1) {
53
+ throw std::runtime_error("Failed to update hash digest: " + std::to_string(ERR_get_error()));
54
+ }
55
+ }
56
+
57
+ std::shared_ptr<ArrayBuffer> HybridHash::digest(const std::optional<std::string>& encoding) {
58
+ if (!ctx) {
59
+ throw std::runtime_error("Hash context not initialized");
60
+ }
61
+
62
+ setParams();
63
+
64
+ // Get the default digest size
65
+ const size_t defaultLen = EVP_MD_CTX_size(ctx);
66
+ const size_t digestSize = (outputLength.has_value()) ? static_cast<int>(*outputLength) : defaultLen;
67
+
68
+ if (digestSize < 0) {
69
+ throw std::runtime_error("Invalid digest size: " + std::to_string(digestSize));
70
+ }
71
+
72
+ // Create a buffer for the hash output
73
+ uint8_t* hashBuffer = new uint8_t[digestSize];
74
+ size_t hashLength = digestSize;
75
+
76
+ // Finalize the digest
77
+ int ret;
78
+ if (digestSize == defaultLen) {
79
+ ret = EVP_DigestFinal_ex(ctx, hashBuffer, reinterpret_cast<unsigned int*>(&hashLength));
80
+ } else {
81
+ ret = EVP_DigestFinalXOF(ctx, hashBuffer, hashLength);
82
+ }
83
+
84
+ if (ret != 1) {
85
+ delete[] hashBuffer;
86
+ throw std::runtime_error("Failed to finalize hash digest: " + std::to_string(ERR_get_error()));
87
+ }
88
+
89
+ return std::make_shared<NativeArrayBuffer>(hashBuffer, hashLength, [=]() { delete[] hashBuffer; });
90
+ }
91
+
92
+ std::shared_ptr<margelo::nitro::crypto::HybridHashSpec> HybridHash::copy(const std::optional<double> outputLengthArg) {
93
+ if (!ctx) {
94
+ throw std::runtime_error("Hash context not initialized");
95
+ }
96
+
97
+ // Create a new context
98
+ EVP_MD_CTX* newCtx = EVP_MD_CTX_new();
99
+ if (!newCtx) {
100
+ throw std::runtime_error("Failed to create new hash context: " + std::to_string(ERR_get_error()));
101
+ }
102
+
103
+ // Copy the existing context to the new one
104
+ if (EVP_MD_CTX_copy(newCtx, ctx) != 1) {
105
+ EVP_MD_CTX_free(newCtx);
106
+ throw std::runtime_error("Failed to copy hash context: " + std::to_string(ERR_get_error()));
107
+ }
108
+
109
+ return std::make_shared<HybridHash>(newCtx, md, algorithm, outputLengthArg);
110
+ }
111
+
112
+ std::vector<std::string> HybridHash::getSupportedHashAlgorithms() {
113
+ std::vector<std::string> hashAlgorithms;
114
+
115
+ EVP_MD_do_all_provided(
116
+ nullptr,
117
+ [](EVP_MD* md, void* arg) {
118
+ auto* algorithms = static_cast<std::vector<std::string>*>(arg);
119
+ const char* name = EVP_MD_get0_name(md);
120
+ if (name) {
121
+ algorithms->push_back(name);
122
+ }
123
+ },
124
+ &hashAlgorithms);
125
+
126
+ return hashAlgorithms;
127
+ }
128
+
129
+ void HybridHash::setParams() {
130
+ // Handle algorithm parameters (like XOF length for SHAKE)
131
+ if (outputLength.has_value()) {
132
+ uint32_t xoflen = outputLength.value();
133
+
134
+ // Add a reasonable maximum output length
135
+ const int MAX_OUTPUT_LENGTH = 16 * 1024 * 1024; // 16MB
136
+ if (xoflen > MAX_OUTPUT_LENGTH) {
137
+ throw std::runtime_error("Output length " + std::to_string(xoflen) + " exceeds maximum allowed size of " +
138
+ std::to_string(MAX_OUTPUT_LENGTH));
139
+ }
140
+
141
+ OSSL_PARAM params[] = {OSSL_PARAM_construct_uint("xoflen", &xoflen), OSSL_PARAM_END};
142
+
143
+ if (EVP_MD_CTX_set_params(ctx, params) != 1) {
144
+ EVP_MD_CTX_free(ctx);
145
+ ctx = nullptr;
146
+ throw std::runtime_error("Failed to set XOF length (outputLength) parameter: " + std::to_string(ERR_get_error()));
147
+ }
148
+ }
149
+ }
150
+
151
+ } // namespace margelo::nitro::crypto
@@ -0,0 +1,41 @@
1
+ #include <NitroModules/ArrayBuffer.hpp>
2
+ #include <memory>
3
+ #include <openssl/evp.h>
4
+ #include <optional>
5
+ #include <string>
6
+ #include <vector>
7
+
8
+ #include "HybridHashSpec.hpp"
9
+
10
+ namespace margelo::nitro::crypto {
11
+
12
+ using namespace facebook;
13
+
14
+ class HybridHash : public HybridHashSpec {
15
+ public:
16
+ HybridHash() : HybridObject(TAG) {}
17
+ HybridHash(EVP_MD_CTX* ctx, const EVP_MD* md, const std::string& algorithm, const std::optional<double> outputLength)
18
+ : HybridObject(TAG), ctx(ctx), md(md), algorithm(algorithm), outputLength(outputLength) {}
19
+ ~HybridHash();
20
+
21
+ public:
22
+ // Methods
23
+ void createHash(const std::string& algorithm, const std::optional<double> outputLength) override;
24
+ void update(const std::shared_ptr<ArrayBuffer>& data) override;
25
+ std::shared_ptr<ArrayBuffer> digest(const std::optional<std::string>& encoding = std::nullopt) override;
26
+ std::shared_ptr<margelo::nitro::crypto::HybridHashSpec> copy(const std::optional<double> outputLength) override;
27
+ std::vector<std::string> getSupportedHashAlgorithms() override;
28
+
29
+ private:
30
+ // Methods
31
+ void setParams();
32
+
33
+ private:
34
+ // Properties
35
+ EVP_MD_CTX* ctx = nullptr;
36
+ const EVP_MD* md = nullptr;
37
+ std::string algorithm = "";
38
+ std::optional<double> outputLength = std::nullopt;
39
+ };
40
+
41
+ } // namespace margelo::nitro::crypto
@@ -0,0 +1,95 @@
1
+ #include <NitroModules/ArrayBuffer.hpp>
2
+ #include <memory>
3
+ #include <openssl/err.h>
4
+ #include <openssl/evp.h>
5
+ #include <optional>
6
+ #include <string>
7
+ #include <vector>
8
+
9
+ #include "HybridHmac.hpp"
10
+
11
+ namespace margelo::nitro::crypto {
12
+
13
+ HybridHmac::~HybridHmac() {
14
+ if (ctx) {
15
+ EVP_MAC_CTX_free(ctx);
16
+ ctx = nullptr;
17
+ }
18
+ }
19
+
20
+ void HybridHmac::createHmac(const std::string& hmacAlgorithm, const std::shared_ptr<ArrayBuffer>& secretKey) {
21
+ algorithm = hmacAlgorithm;
22
+
23
+ // Create and use EVP_MAC locally
24
+ EVP_MAC* mac = EVP_MAC_fetch(nullptr, "HMAC", nullptr);
25
+ if (!mac) {
26
+ throw std::runtime_error("Failed to fetch HMAC implementation: " + std::to_string(ERR_get_error()));
27
+ }
28
+
29
+ // Create HMAC context
30
+ ctx = EVP_MAC_CTX_new(mac);
31
+ EVP_MAC_free(mac); // Free immediately after creating the context
32
+ if (!ctx) {
33
+ throw std::runtime_error("Failed to create HMAC context: " + std::to_string(ERR_get_error()));
34
+ }
35
+
36
+ // Validate algorithm
37
+ const EVP_MD* md = EVP_get_digestbyname(algorithm.c_str());
38
+ if (!md) {
39
+ throw std::runtime_error("Unknown HMAC algorithm: " + algorithm);
40
+ }
41
+
42
+ // Set up parameters for HMAC
43
+ OSSL_PARAM params[2];
44
+ params[0] = OSSL_PARAM_construct_utf8_string("digest", const_cast<char*>(algorithm.c_str()), 0);
45
+ params[1] = OSSL_PARAM_construct_end();
46
+
47
+ const uint8_t* keyData = reinterpret_cast<const uint8_t*>(secretKey->data());
48
+ size_t keySize = secretKey->size();
49
+
50
+ // Handle empty key case by providing a dummy key
51
+ static const uint8_t dummyKey = 0;
52
+ if (keySize == 0) {
53
+ keyData = &dummyKey;
54
+ keySize = 1;
55
+ }
56
+
57
+ // Initialize HMAC
58
+ if (EVP_MAC_init(ctx, keyData, keySize, params) != 1) {
59
+ throw std::runtime_error("Failed to initialize HMAC: " + std::to_string(ERR_get_error()));
60
+ }
61
+ }
62
+
63
+ void HybridHmac::update(const std::shared_ptr<ArrayBuffer>& data) {
64
+ if (!ctx) {
65
+ throw std::runtime_error("HMAC context not initialized");
66
+ }
67
+
68
+ // Update HMAC with new data
69
+ if (EVP_MAC_update(ctx, reinterpret_cast<const uint8_t*>(data->data()), data->size()) != 1) {
70
+ throw std::runtime_error("Failed to update HMAC: " + std::to_string(ERR_get_error()));
71
+ }
72
+ }
73
+
74
+ std::shared_ptr<ArrayBuffer> HybridHmac::digest() {
75
+ if (!ctx) {
76
+ throw std::runtime_error("HMAC context not initialized");
77
+ }
78
+
79
+ // Determine the maximum possible size of the HMAC output
80
+ const EVP_MD* md = EVP_get_digestbyname(algorithm.c_str());
81
+ const size_t hmacLength = EVP_MD_get_size(md);
82
+
83
+ // Allocate buffer with the exact required size
84
+ uint8_t* hmacBuffer = new uint8_t[hmacLength];
85
+
86
+ // Finalize the HMAC computation directly into the final buffer
87
+ if (EVP_MAC_final(ctx, hmacBuffer, nullptr, hmacLength) != 1) {
88
+ delete[] hmacBuffer;
89
+ throw std::runtime_error("Failed to finalize HMAC digest: " + std::to_string(ERR_get_error()));
90
+ }
91
+
92
+ return std::make_shared<NativeArrayBuffer>(hmacBuffer, hmacLength, [=]() { delete[] hmacBuffer; });
93
+ }
94
+
95
+ } // namespace margelo::nitro::crypto
@@ -0,0 +1,31 @@
1
+ #include <NitroModules/ArrayBuffer.hpp>
2
+ #include <memory>
3
+ #include <openssl/evp.h>
4
+ #include <optional>
5
+ #include <string>
6
+ #include <vector>
7
+
8
+ #include "HybridHmacSpec.hpp"
9
+
10
+ namespace margelo::nitro::crypto {
11
+
12
+ using namespace facebook;
13
+
14
+ class HybridHmac : public HybridHmacSpec {
15
+ public:
16
+ HybridHmac() : HybridObject(TAG) {}
17
+ ~HybridHmac();
18
+
19
+ public:
20
+ // Methods
21
+ void createHmac(const std::string& algorithm, const std::shared_ptr<ArrayBuffer>& key) override;
22
+ void update(const std::shared_ptr<ArrayBuffer>& data) override;
23
+ std::shared_ptr<ArrayBuffer> digest() override;
24
+
25
+ private:
26
+ // Properties
27
+ EVP_MAC_CTX* ctx = nullptr;
28
+ std::string algorithm = "";
29
+ };
30
+
31
+ } // namespace margelo::nitro::crypto