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.
Files changed (197) hide show
  1. package/android/CMakeLists.txt +7 -0
  2. package/cpp/cipher/CCMCipher.cpp +4 -1
  3. package/cpp/cipher/ChaCha20Cipher.cpp +3 -1
  4. package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +5 -5
  5. package/cpp/cipher/ChaCha20Poly1305Cipher.hpp +1 -2
  6. package/cpp/cipher/HybridCipher.cpp +10 -1
  7. package/cpp/cipher/HybridCipher.hpp +2 -0
  8. package/cpp/cipher/HybridRsaCipher.cpp +0 -13
  9. package/cpp/cipher/XChaCha20Poly1305Cipher.cpp +7 -5
  10. package/cpp/cipher/XChaCha20Poly1305Cipher.hpp +1 -2
  11. package/cpp/cipher/XSalsa20Cipher.cpp +4 -0
  12. package/cpp/cipher/XSalsa20Poly1305Cipher.cpp +7 -5
  13. package/cpp/cipher/XSalsa20Poly1305Cipher.hpp +1 -2
  14. package/cpp/ecdh/HybridECDH.cpp +20 -133
  15. package/cpp/keys/HybridKeyObjectHandle.cpp +144 -141
  16. package/cpp/keys/HybridKeyObjectHandle.hpp +6 -3
  17. package/cpp/keys/KeyObjectData.hpp +2 -0
  18. package/cpp/kmac/HybridKmac.cpp +83 -0
  19. package/cpp/kmac/HybridKmac.hpp +31 -0
  20. package/cpp/mldsa/HybridMlDsaKeyPair.cpp +11 -20
  21. package/cpp/mldsa/HybridMlDsaKeyPair.hpp +4 -2
  22. package/cpp/mlkem/HybridMlKemKeyPair.cpp +319 -0
  23. package/cpp/mlkem/HybridMlKemKeyPair.hpp +48 -0
  24. package/cpp/sign/SignUtils.hpp +9 -26
  25. package/cpp/utils/QuickCryptoUtils.cpp +44 -0
  26. package/cpp/utils/QuickCryptoUtils.hpp +39 -0
  27. package/cpp/x509/HybridX509Certificate.cpp +174 -0
  28. package/cpp/x509/HybridX509Certificate.hpp +51 -0
  29. package/lib/commonjs/cipher.js +15 -2
  30. package/lib/commonjs/cipher.js.map +1 -1
  31. package/lib/commonjs/dhKeyPair.js +3 -3
  32. package/lib/commonjs/dhKeyPair.js.map +1 -1
  33. package/lib/commonjs/dsa.js +3 -3
  34. package/lib/commonjs/dsa.js.map +1 -1
  35. package/lib/commonjs/ec.js +18 -18
  36. package/lib/commonjs/ec.js.map +1 -1
  37. package/lib/commonjs/ed.js +9 -9
  38. package/lib/commonjs/ed.js.map +1 -1
  39. package/lib/commonjs/hash.js +17 -12
  40. package/lib/commonjs/hash.js.map +1 -1
  41. package/lib/commonjs/hkdf.js.map +1 -1
  42. package/lib/commonjs/index.js +22 -0
  43. package/lib/commonjs/index.js.map +1 -1
  44. package/lib/commonjs/keys/classes.js +2 -2
  45. package/lib/commonjs/keys/classes.js.map +1 -1
  46. package/lib/commonjs/keys/index.js +24 -0
  47. package/lib/commonjs/keys/index.js.map +1 -1
  48. package/lib/commonjs/keys/publicCipher.js +2 -2
  49. package/lib/commonjs/keys/publicCipher.js.map +1 -1
  50. package/lib/commonjs/keys/signVerify.js +0 -2
  51. package/lib/commonjs/keys/signVerify.js.map +1 -1
  52. package/lib/commonjs/mlkem.js +219 -0
  53. package/lib/commonjs/mlkem.js.map +1 -0
  54. package/lib/commonjs/pbkdf2.js +18 -1
  55. package/lib/commonjs/pbkdf2.js.map +1 -1
  56. package/lib/commonjs/rsa.js +7 -7
  57. package/lib/commonjs/rsa.js.map +1 -1
  58. package/lib/commonjs/specs/kmac.nitro.js +6 -0
  59. package/lib/commonjs/specs/kmac.nitro.js.map +1 -0
  60. package/lib/commonjs/specs/mlKemKeyPair.nitro.js +6 -0
  61. package/lib/commonjs/specs/mlKemKeyPair.nitro.js.map +1 -0
  62. package/lib/commonjs/specs/x509certificate.nitro.js +6 -0
  63. package/lib/commonjs/specs/x509certificate.nitro.js.map +1 -0
  64. package/lib/commonjs/subtle.js +292 -112
  65. package/lib/commonjs/subtle.js.map +1 -1
  66. package/lib/commonjs/utils/conversion.js +3 -3
  67. package/lib/commonjs/utils/conversion.js.map +1 -1
  68. package/lib/commonjs/utils/hashnames.js +31 -0
  69. package/lib/commonjs/utils/hashnames.js.map +1 -1
  70. package/lib/commonjs/utils/types.js.map +1 -1
  71. package/lib/commonjs/x509certificate.js +189 -0
  72. package/lib/commonjs/x509certificate.js.map +1 -0
  73. package/lib/module/cipher.js +16 -3
  74. package/lib/module/cipher.js.map +1 -1
  75. package/lib/module/dhKeyPair.js +1 -1
  76. package/lib/module/dhKeyPair.js.map +1 -1
  77. package/lib/module/dsa.js +1 -1
  78. package/lib/module/dsa.js.map +1 -1
  79. package/lib/module/ec.js +6 -6
  80. package/lib/module/ec.js.map +1 -1
  81. package/lib/module/ed.js +1 -1
  82. package/lib/module/ed.js.map +1 -1
  83. package/lib/module/hash.js +17 -12
  84. package/lib/module/hash.js.map +1 -1
  85. package/lib/module/hkdf.js.map +1 -1
  86. package/lib/module/index.js +6 -0
  87. package/lib/module/index.js.map +1 -1
  88. package/lib/module/keys/classes.js +2 -2
  89. package/lib/module/keys/classes.js.map +1 -1
  90. package/lib/module/keys/index.js +25 -1
  91. package/lib/module/keys/index.js.map +1 -1
  92. package/lib/module/keys/publicCipher.js +2 -2
  93. package/lib/module/keys/publicCipher.js.map +1 -1
  94. package/lib/module/keys/signVerify.js +0 -2
  95. package/lib/module/keys/signVerify.js.map +1 -1
  96. package/lib/module/mlkem.js +211 -0
  97. package/lib/module/mlkem.js.map +1 -0
  98. package/lib/module/pbkdf2.js +18 -1
  99. package/lib/module/pbkdf2.js.map +1 -1
  100. package/lib/module/rsa.js +1 -1
  101. package/lib/module/rsa.js.map +1 -1
  102. package/lib/module/specs/kmac.nitro.js +4 -0
  103. package/lib/module/specs/kmac.nitro.js.map +1 -0
  104. package/lib/module/specs/mlKemKeyPair.nitro.js +4 -0
  105. package/lib/module/specs/mlKemKeyPair.nitro.js.map +1 -0
  106. package/lib/module/specs/x509certificate.nitro.js +4 -0
  107. package/lib/module/specs/x509certificate.nitro.js.map +1 -0
  108. package/lib/module/subtle.js +292 -112
  109. package/lib/module/subtle.js.map +1 -1
  110. package/lib/module/utils/conversion.js +3 -4
  111. package/lib/module/utils/conversion.js.map +1 -1
  112. package/lib/module/utils/hashnames.js +31 -0
  113. package/lib/module/utils/hashnames.js.map +1 -1
  114. package/lib/module/utils/types.js.map +1 -1
  115. package/lib/module/x509certificate.js +184 -0
  116. package/lib/module/x509certificate.js.map +1 -0
  117. package/lib/tsconfig.tsbuildinfo +1 -1
  118. package/lib/typescript/cipher.d.ts +3 -0
  119. package/lib/typescript/cipher.d.ts.map +1 -1
  120. package/lib/typescript/dhKeyPair.d.ts +1 -1
  121. package/lib/typescript/dhKeyPair.d.ts.map +1 -1
  122. package/lib/typescript/dsa.d.ts +1 -1
  123. package/lib/typescript/dsa.d.ts.map +1 -1
  124. package/lib/typescript/ec.d.ts +1 -1
  125. package/lib/typescript/ec.d.ts.map +1 -1
  126. package/lib/typescript/ed.d.ts +1 -1
  127. package/lib/typescript/ed.d.ts.map +1 -1
  128. package/lib/typescript/hash.d.ts.map +1 -1
  129. package/lib/typescript/hkdf.d.ts +2 -6
  130. package/lib/typescript/hkdf.d.ts.map +1 -1
  131. package/lib/typescript/index.d.ts +15 -4
  132. package/lib/typescript/index.d.ts.map +1 -1
  133. package/lib/typescript/keys/classes.d.ts +5 -5
  134. package/lib/typescript/keys/classes.d.ts.map +1 -1
  135. package/lib/typescript/keys/index.d.ts +2 -2
  136. package/lib/typescript/keys/index.d.ts.map +1 -1
  137. package/lib/typescript/keys/signVerify.d.ts.map +1 -1
  138. package/lib/typescript/mlkem.d.ts +30 -0
  139. package/lib/typescript/mlkem.d.ts.map +1 -0
  140. package/lib/typescript/pbkdf2.d.ts +2 -2
  141. package/lib/typescript/pbkdf2.d.ts.map +1 -1
  142. package/lib/typescript/rsa.d.ts +1 -1
  143. package/lib/typescript/rsa.d.ts.map +1 -1
  144. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +1 -0
  145. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
  146. package/lib/typescript/specs/kmac.nitro.d.ts +10 -0
  147. package/lib/typescript/specs/kmac.nitro.d.ts.map +1 -0
  148. package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts +18 -0
  149. package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts.map +1 -0
  150. package/lib/typescript/specs/x509certificate.nitro.d.ts +34 -0
  151. package/lib/typescript/specs/x509certificate.nitro.d.ts.map +1 -0
  152. package/lib/typescript/subtle.d.ts +10 -0
  153. package/lib/typescript/subtle.d.ts.map +1 -1
  154. package/lib/typescript/utils/conversion.d.ts.map +1 -1
  155. package/lib/typescript/utils/hashnames.d.ts +1 -1
  156. package/lib/typescript/utils/hashnames.d.ts.map +1 -1
  157. package/lib/typescript/utils/types.d.ts +13 -7
  158. package/lib/typescript/utils/types.d.ts.map +1 -1
  159. package/lib/typescript/x509certificate.d.ts +64 -0
  160. package/lib/typescript/x509certificate.d.ts.map +1 -0
  161. package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +3 -0
  162. package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +30 -0
  163. package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +30 -0
  164. package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +12 -0
  165. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +1 -0
  166. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +1 -0
  167. package/nitrogen/generated/shared/c++/HybridKmacSpec.cpp +23 -0
  168. package/nitrogen/generated/shared/c++/HybridKmacSpec.hpp +66 -0
  169. package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.cpp +31 -0
  170. package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.hpp +74 -0
  171. package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.cpp +46 -0
  172. package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.hpp +96 -0
  173. package/package.json +4 -1
  174. package/src/cipher.ts +17 -3
  175. package/src/dhKeyPair.ts +1 -1
  176. package/src/dsa.ts +1 -1
  177. package/src/ec.ts +9 -9
  178. package/src/ed.ts +2 -2
  179. package/src/hash.ts +34 -11
  180. package/src/hkdf.ts +2 -7
  181. package/src/index.ts +7 -0
  182. package/src/keys/classes.ts +10 -9
  183. package/src/keys/index.ts +37 -2
  184. package/src/keys/publicCipher.ts +2 -2
  185. package/src/keys/signVerify.ts +0 -5
  186. package/src/mlkem.ts +350 -0
  187. package/src/pbkdf2.ts +34 -5
  188. package/src/rsa.ts +1 -1
  189. package/src/specs/keyObjectHandle.nitro.ts +5 -0
  190. package/src/specs/kmac.nitro.ts +12 -0
  191. package/src/specs/mlKemKeyPair.nitro.ts +32 -0
  192. package/src/specs/x509certificate.nitro.ts +38 -0
  193. package/src/subtle.ts +551 -125
  194. package/src/utils/conversion.ts +10 -4
  195. package/src/utils/hashnames.ts +33 -2
  196. package/src/utils/types.ts +42 -5
  197. package/src/x509certificate.ts +277 -0
@@ -0,0 +1,319 @@
1
+ #include "HybridMlKemKeyPair.hpp"
2
+
3
+ #include <NitroModules/ArrayBuffer.hpp>
4
+ #include <openssl/bio.h>
5
+ #include <openssl/err.h>
6
+ #include <openssl/pem.h>
7
+
8
+ #include "QuickCryptoUtils.hpp"
9
+
10
+ #if OPENSSL_VERSION_NUMBER >= 0x30500000L
11
+ #define RNQC_HAS_ML_KEM 1
12
+ #else
13
+ #define RNQC_HAS_ML_KEM 0
14
+ #endif
15
+
16
+ namespace margelo::nitro::crypto {
17
+
18
+ void HybridMlKemKeyPair::setVariant(const std::string& variant) {
19
+ #if !RNQC_HAS_ML_KEM
20
+ throw std::runtime_error("ML-KEM requires OpenSSL 3.5+");
21
+ #endif
22
+ if (variant != "ML-KEM-512" && variant != "ML-KEM-768" && variant != "ML-KEM-1024") {
23
+ throw std::runtime_error("Invalid ML-KEM variant: " + variant + ". Must be ML-KEM-512, ML-KEM-768, or ML-KEM-1024");
24
+ }
25
+ variant_ = variant;
26
+ }
27
+
28
+ std::shared_ptr<Promise<void>> HybridMlKemKeyPair::generateKeyPair(double publicFormat, double publicType, double privateFormat,
29
+ double privateType) {
30
+ return Promise<void>::async([this, publicFormat, publicType, privateFormat, privateType]() {
31
+ this->generateKeyPairSync(publicFormat, publicType, privateFormat, privateType);
32
+ });
33
+ }
34
+
35
+ void HybridMlKemKeyPair::generateKeyPairSync(double publicFormat, double publicType, double privateFormat, double privateType) {
36
+ #if !RNQC_HAS_ML_KEM
37
+ throw std::runtime_error("ML-KEM requires OpenSSL 3.5+");
38
+ #else
39
+ clearOpenSSLErrors();
40
+
41
+ if (variant_.empty()) {
42
+ throw std::runtime_error("ML-KEM variant not set. Call setVariant() first.");
43
+ }
44
+
45
+ publicFormat_ = static_cast<int>(publicFormat);
46
+ publicType_ = static_cast<int>(publicType);
47
+ privateFormat_ = static_cast<int>(privateFormat);
48
+ privateType_ = static_cast<int>(privateType);
49
+
50
+ pkey_.reset();
51
+
52
+ EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_from_name(nullptr, variant_.c_str(), nullptr);
53
+ if (pctx == nullptr) {
54
+ throw std::runtime_error("Failed to create key context for " + variant_ + ": " + getOpenSSLError());
55
+ }
56
+
57
+ if (EVP_PKEY_keygen_init(pctx) <= 0) {
58
+ EVP_PKEY_CTX_free(pctx);
59
+ throw std::runtime_error("Failed to initialize keygen: " + getOpenSSLError());
60
+ }
61
+
62
+ EVP_PKEY* raw = nullptr;
63
+ if (EVP_PKEY_keygen(pctx, &raw) <= 0) {
64
+ EVP_PKEY_CTX_free(pctx);
65
+ throw std::runtime_error("Failed to generate ML-KEM key pair: " + getOpenSSLError());
66
+ }
67
+
68
+ pkey_.reset(raw);
69
+ EVP_PKEY_CTX_free(pctx);
70
+ #endif
71
+ }
72
+
73
+ std::shared_ptr<ArrayBuffer> HybridMlKemKeyPair::getPublicKey() {
74
+ #if !RNQC_HAS_ML_KEM
75
+ throw std::runtime_error("ML-KEM requires OpenSSL 3.5+");
76
+ #else
77
+ checkKeyPair();
78
+
79
+ BIO* bio = BIO_new(BIO_s_mem());
80
+ if (!bio) {
81
+ throw std::runtime_error("Failed to create BIO for public key export");
82
+ }
83
+
84
+ int result;
85
+ if (publicFormat_ == 1) {
86
+ result = PEM_write_bio_PUBKEY(bio, pkey_.get());
87
+ } else {
88
+ result = i2d_PUBKEY_bio(bio, pkey_.get());
89
+ }
90
+
91
+ if (result != 1) {
92
+ BIO_free(bio);
93
+ throw std::runtime_error("Failed to export public key: " + getOpenSSLError());
94
+ }
95
+
96
+ BUF_MEM* bptr;
97
+ BIO_get_mem_ptr(bio, &bptr);
98
+
99
+ uint8_t* data = new uint8_t[bptr->length];
100
+ memcpy(data, bptr->data, bptr->length);
101
+ size_t len = bptr->length;
102
+
103
+ BIO_free(bio);
104
+
105
+ return std::make_shared<NativeArrayBuffer>(data, len, [=]() { delete[] data; });
106
+ #endif
107
+ }
108
+
109
+ std::shared_ptr<ArrayBuffer> HybridMlKemKeyPair::getPrivateKey() {
110
+ #if !RNQC_HAS_ML_KEM
111
+ throw std::runtime_error("ML-KEM requires OpenSSL 3.5+");
112
+ #else
113
+ checkKeyPair();
114
+
115
+ BIO* bio = BIO_new(BIO_s_mem());
116
+ if (!bio) {
117
+ throw std::runtime_error("Failed to create BIO for private key export");
118
+ }
119
+
120
+ int result;
121
+ if (privateFormat_ == 1) {
122
+ result = PEM_write_bio_PrivateKey(bio, pkey_.get(), nullptr, nullptr, 0, nullptr, nullptr);
123
+ } else {
124
+ result = i2d_PKCS8PrivateKey_bio(bio, pkey_.get(), nullptr, nullptr, 0, nullptr, nullptr);
125
+ }
126
+
127
+ if (result != 1) {
128
+ BIO_free(bio);
129
+ throw std::runtime_error("Failed to export private key: " + getOpenSSLError());
130
+ }
131
+
132
+ BUF_MEM* bptr;
133
+ BIO_get_mem_ptr(bio, &bptr);
134
+
135
+ uint8_t* data = new uint8_t[bptr->length];
136
+ memcpy(data, bptr->data, bptr->length);
137
+ size_t len = bptr->length;
138
+
139
+ BIO_free(bio);
140
+
141
+ return std::make_shared<NativeArrayBuffer>(data, len, [=]() { delete[] data; });
142
+ #endif
143
+ }
144
+
145
+ void HybridMlKemKeyPair::setPublicKey(const std::shared_ptr<ArrayBuffer>& keyData, double format, double type) {
146
+ #if !RNQC_HAS_ML_KEM
147
+ throw std::runtime_error("ML-KEM requires OpenSSL 3.5+");
148
+ #else
149
+ clearOpenSSLErrors();
150
+
151
+ if (variant_.empty()) {
152
+ throw std::runtime_error("ML-KEM variant not set. Call setVariant() first.");
153
+ }
154
+
155
+ publicFormat_ = static_cast<int>(format);
156
+ publicType_ = static_cast<int>(type);
157
+
158
+ BIO* bio = BIO_new_mem_buf(keyData->data(), static_cast<int>(keyData->size()));
159
+ if (!bio) {
160
+ throw std::runtime_error("Failed to create BIO for public key import");
161
+ }
162
+
163
+ EVP_PKEY* importedKey = nullptr;
164
+ if (publicFormat_ == 1) {
165
+ importedKey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr);
166
+ } else {
167
+ importedKey = d2i_PUBKEY_bio(bio, nullptr);
168
+ }
169
+
170
+ BIO_free(bio);
171
+
172
+ if (importedKey == nullptr) {
173
+ throw std::runtime_error("Failed to import public key: " + getOpenSSLError());
174
+ }
175
+
176
+ pkey_.reset(importedKey);
177
+ #endif
178
+ }
179
+
180
+ void HybridMlKemKeyPair::setPrivateKey(const std::shared_ptr<ArrayBuffer>& keyData, double format, double type) {
181
+ #if !RNQC_HAS_ML_KEM
182
+ throw std::runtime_error("ML-KEM requires OpenSSL 3.5+");
183
+ #else
184
+ clearOpenSSLErrors();
185
+
186
+ if (variant_.empty()) {
187
+ throw std::runtime_error("ML-KEM variant not set. Call setVariant() first.");
188
+ }
189
+
190
+ privateFormat_ = static_cast<int>(format);
191
+ privateType_ = static_cast<int>(type);
192
+
193
+ BIO* bio = BIO_new_mem_buf(keyData->data(), static_cast<int>(keyData->size()));
194
+ if (!bio) {
195
+ throw std::runtime_error("Failed to create BIO for private key import");
196
+ }
197
+
198
+ EVP_PKEY* importedKey = nullptr;
199
+ if (privateFormat_ == 1) {
200
+ importedKey = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr);
201
+ } else {
202
+ importedKey = d2i_PrivateKey_bio(bio, nullptr);
203
+ }
204
+
205
+ BIO_free(bio);
206
+
207
+ if (importedKey == nullptr) {
208
+ throw std::runtime_error("Failed to import private key: " + getOpenSSLError());
209
+ }
210
+
211
+ pkey_.reset(importedKey);
212
+ #endif
213
+ }
214
+
215
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> HybridMlKemKeyPair::encapsulate() {
216
+ return Promise<std::shared_ptr<ArrayBuffer>>::async([this]() { return this->encapsulateSync(); });
217
+ }
218
+
219
+ std::shared_ptr<ArrayBuffer> HybridMlKemKeyPair::encapsulateSync() {
220
+ #if !RNQC_HAS_ML_KEM
221
+ throw std::runtime_error("ML-KEM requires OpenSSL 3.5+");
222
+ #else
223
+ clearOpenSSLErrors();
224
+ checkKeyPair();
225
+
226
+ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey_.get(), nullptr);
227
+ if (ctx == nullptr) {
228
+ throw std::runtime_error("Failed to create encapsulation context: " + getOpenSSLError());
229
+ }
230
+
231
+ if (EVP_PKEY_encapsulate_init(ctx, nullptr) <= 0) {
232
+ EVP_PKEY_CTX_free(ctx);
233
+ throw std::runtime_error("Failed to initialize encapsulation: " + getOpenSSLError());
234
+ }
235
+
236
+ size_t ct_len = 0;
237
+ size_t sk_len = 0;
238
+ if (EVP_PKEY_encapsulate(ctx, nullptr, &ct_len, nullptr, &sk_len) <= 0) {
239
+ EVP_PKEY_CTX_free(ctx);
240
+ throw std::runtime_error("Failed to determine encapsulation output sizes: " + getOpenSSLError());
241
+ }
242
+
243
+ // Pack result as: [uint32 ct_len][uint32 sk_len][ciphertext][shared_key]
244
+ size_t header_size = sizeof(uint32_t) * 2;
245
+ size_t total_size = header_size + ct_len + sk_len;
246
+ uint8_t* out = new uint8_t[total_size];
247
+
248
+ uint32_t ct_len_u32 = static_cast<uint32_t>(ct_len);
249
+ uint32_t sk_len_u32 = static_cast<uint32_t>(sk_len);
250
+ memcpy(out, &ct_len_u32, sizeof(uint32_t));
251
+ memcpy(out + sizeof(uint32_t), &sk_len_u32, sizeof(uint32_t));
252
+
253
+ uint8_t* ct_data = out + header_size;
254
+ uint8_t* sk_data = ct_data + ct_len;
255
+
256
+ if (EVP_PKEY_encapsulate(ctx, ct_data, &ct_len, sk_data, &sk_len) <= 0) {
257
+ EVP_PKEY_CTX_free(ctx);
258
+ delete[] out;
259
+ throw std::runtime_error("Failed to encapsulate: " + getOpenSSLError());
260
+ }
261
+
262
+ EVP_PKEY_CTX_free(ctx);
263
+
264
+ return std::make_shared<NativeArrayBuffer>(out, total_size, [=]() { delete[] out; });
265
+ #endif
266
+ }
267
+
268
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> HybridMlKemKeyPair::decapsulate(const std::shared_ptr<ArrayBuffer>& ciphertext) {
269
+ auto nativeCiphertext = ToNativeArrayBuffer(ciphertext);
270
+ return Promise<std::shared_ptr<ArrayBuffer>>::async([this, nativeCiphertext]() { return this->decapsulateSync(nativeCiphertext); });
271
+ }
272
+
273
+ std::shared_ptr<ArrayBuffer> HybridMlKemKeyPair::decapsulateSync(const std::shared_ptr<ArrayBuffer>& ciphertext) {
274
+ #if !RNQC_HAS_ML_KEM
275
+ throw std::runtime_error("ML-KEM requires OpenSSL 3.5+");
276
+ #else
277
+ clearOpenSSLErrors();
278
+ checkKeyPair();
279
+
280
+ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey_.get(), nullptr);
281
+ if (ctx == nullptr) {
282
+ throw std::runtime_error("Failed to create decapsulation context: " + getOpenSSLError());
283
+ }
284
+
285
+ if (EVP_PKEY_decapsulate_init(ctx, nullptr) <= 0) {
286
+ EVP_PKEY_CTX_free(ctx);
287
+ throw std::runtime_error("Failed to initialize decapsulation: " + getOpenSSLError());
288
+ }
289
+
290
+ const uint8_t* ct_data = ciphertext->data();
291
+ size_t ct_size = ciphertext->size();
292
+
293
+ size_t sk_len = 0;
294
+ if (EVP_PKEY_decapsulate(ctx, nullptr, &sk_len, ct_data, ct_size) <= 0) {
295
+ EVP_PKEY_CTX_free(ctx);
296
+ throw std::runtime_error("Failed to determine shared key size: " + getOpenSSLError());
297
+ }
298
+
299
+ uint8_t* sk_data = new uint8_t[sk_len];
300
+
301
+ if (EVP_PKEY_decapsulate(ctx, sk_data, &sk_len, ct_data, ct_size) <= 0) {
302
+ EVP_PKEY_CTX_free(ctx);
303
+ delete[] sk_data;
304
+ throw std::runtime_error("Failed to decapsulate: " + getOpenSSLError());
305
+ }
306
+
307
+ EVP_PKEY_CTX_free(ctx);
308
+
309
+ return std::make_shared<NativeArrayBuffer>(sk_data, sk_len, [=]() { delete[] sk_data; });
310
+ #endif
311
+ }
312
+
313
+ void HybridMlKemKeyPair::checkKeyPair() {
314
+ if (!pkey_) {
315
+ throw std::runtime_error("Key pair not initialized");
316
+ }
317
+ }
318
+
319
+ } // namespace margelo::nitro::crypto
@@ -0,0 +1,48 @@
1
+ #pragma once
2
+
3
+ #include <memory>
4
+ #include <openssl/evp.h>
5
+ #include <string>
6
+
7
+ #include "HybridMlKemKeyPairSpec.hpp"
8
+ #include "QuickCryptoUtils.hpp"
9
+
10
+ namespace margelo::nitro::crypto {
11
+
12
+ class HybridMlKemKeyPair : public HybridMlKemKeyPairSpec {
13
+ public:
14
+ HybridMlKemKeyPair() : HybridObject(TAG) {}
15
+ ~HybridMlKemKeyPair() override = default;
16
+
17
+ void setVariant(const std::string& variant) override;
18
+
19
+ std::shared_ptr<Promise<void>> generateKeyPair(double publicFormat, double publicType, double privateFormat, double privateType) override;
20
+ void generateKeyPairSync(double publicFormat, double publicType, double privateFormat, double privateType) override;
21
+
22
+ std::shared_ptr<ArrayBuffer> getPublicKey() override;
23
+ std::shared_ptr<ArrayBuffer> getPrivateKey() override;
24
+
25
+ void setPublicKey(const std::shared_ptr<ArrayBuffer>& keyData, double format, double type) override;
26
+ void setPrivateKey(const std::shared_ptr<ArrayBuffer>& keyData, double format, double type) override;
27
+
28
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> encapsulate() override;
29
+ std::shared_ptr<ArrayBuffer> encapsulateSync() override;
30
+
31
+ std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> decapsulate(const std::shared_ptr<ArrayBuffer>& ciphertext) override;
32
+ std::shared_ptr<ArrayBuffer> decapsulateSync(const std::shared_ptr<ArrayBuffer>& ciphertext) override;
33
+
34
+ private:
35
+ std::string variant_;
36
+
37
+ using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>;
38
+ EVP_PKEY_ptr pkey_{nullptr, EVP_PKEY_free};
39
+
40
+ int publicFormat_ = -1;
41
+ int publicType_ = -1;
42
+ int privateFormat_ = -1;
43
+ int privateType_ = -1;
44
+
45
+ void checkKeyPair();
46
+ };
47
+
48
+ } // namespace margelo::nitro::crypto
@@ -2,12 +2,16 @@
2
2
 
3
3
  #include <cstring>
4
4
  #include <memory>
5
+ #include <openssl/bn.h>
6
+ #include <openssl/core_names.h>
5
7
  #include <openssl/dsa.h>
6
8
  #include <openssl/ec.h>
7
9
  #include <openssl/ecdsa.h>
8
10
  #include <openssl/evp.h>
9
11
  #include <string>
10
12
 
13
+ #include "../utils/QuickCryptoUtils.hpp"
14
+
11
15
  namespace margelo::nitro::crypto {
12
16
 
13
17
  enum DSASigEnc {
@@ -15,29 +19,6 @@ enum DSASigEnc {
15
19
  kSigEncP1363 = 1,
16
20
  };
17
21
 
18
- inline const EVP_MD* getDigestByName(const std::string& algorithm) {
19
- if (algorithm == "SHA1" || algorithm == "sha1" || algorithm == "SHA-1" || algorithm == "sha-1") {
20
- return EVP_sha1();
21
- } else if (algorithm == "SHA224" || algorithm == "sha224" || algorithm == "SHA-224" || algorithm == "sha-224") {
22
- return EVP_sha224();
23
- } else if (algorithm == "SHA256" || algorithm == "sha256" || algorithm == "SHA-256" || algorithm == "sha-256") {
24
- return EVP_sha256();
25
- } else if (algorithm == "SHA384" || algorithm == "sha384" || algorithm == "SHA-384" || algorithm == "sha-384") {
26
- return EVP_sha384();
27
- } else if (algorithm == "SHA512" || algorithm == "sha512" || algorithm == "SHA-512" || algorithm == "sha-512") {
28
- return EVP_sha512();
29
- } else if (algorithm == "SHA3-224" || algorithm == "sha3-224") {
30
- return EVP_sha3_224();
31
- } else if (algorithm == "SHA3-256" || algorithm == "sha3-256") {
32
- return EVP_sha3_256();
33
- } else if (algorithm == "SHA3-384" || algorithm == "sha3-384") {
34
- return EVP_sha3_384();
35
- } else if (algorithm == "SHA3-512" || algorithm == "sha3-512") {
36
- return EVP_sha3_512();
37
- }
38
- throw std::runtime_error("Unsupported hash algorithm: " + algorithm);
39
- }
40
-
41
22
  inline unsigned int getBytesOfRS(EVP_PKEY* pkey) {
42
23
  int bits;
43
24
  int base_id = EVP_PKEY_base_id(pkey);
@@ -46,9 +27,11 @@ inline unsigned int getBytesOfRS(EVP_PKEY* pkey) {
46
27
  const DSA* dsa_key = EVP_PKEY_get0_DSA(pkey);
47
28
  bits = BN_num_bits(DSA_get0_q(dsa_key));
48
29
  } else if (base_id == EVP_PKEY_EC) {
49
- const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey);
50
- const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key);
51
- bits = EC_GROUP_order_bits(ec_group);
30
+ BIGNUM* order = nullptr;
31
+ if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_ORDER, &order) != 1 || !order)
32
+ return 0;
33
+ bits = BN_num_bits(order);
34
+ BN_free(order);
52
35
  } else {
53
36
  return 0;
54
37
  }
@@ -0,0 +1,44 @@
1
+ #include "QuickCryptoUtils.hpp"
2
+ #include <openssl/bn.h>
3
+ #include <openssl/core_names.h>
4
+ #include <openssl/evp.h>
5
+ #include <openssl/param_build.h>
6
+ #include <stdexcept>
7
+
8
+ namespace margelo::nitro::crypto {
9
+
10
+ EVP_PKEY* createEcEvpPkey(const char* group_name, const uint8_t* pub_oct, size_t pub_len, const BIGNUM* priv_bn) {
11
+ OSSL_PARAM_BLD* bld = OSSL_PARAM_BLD_new();
12
+ if (!bld)
13
+ throw std::runtime_error("Failed to create OSSL_PARAM_BLD");
14
+
15
+ OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0);
16
+ OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pub_oct, pub_len);
17
+ if (priv_bn)
18
+ OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, priv_bn);
19
+
20
+ OSSL_PARAM* params = OSSL_PARAM_BLD_to_param(bld);
21
+ OSSL_PARAM_BLD_free(bld);
22
+ if (!params)
23
+ throw std::runtime_error("Failed to build EC parameters");
24
+
25
+ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr);
26
+ if (!ctx) {
27
+ OSSL_PARAM_free(params);
28
+ throw std::runtime_error("Failed to create EVP_PKEY_CTX for EC");
29
+ }
30
+
31
+ int selection = priv_bn ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY;
32
+ EVP_PKEY* pkey = nullptr;
33
+ if (EVP_PKEY_fromdata_init(ctx) <= 0 || EVP_PKEY_fromdata(ctx, &pkey, selection, params) <= 0) {
34
+ EVP_PKEY_CTX_free(ctx);
35
+ OSSL_PARAM_free(params);
36
+ throw std::runtime_error("Failed to create EVP_PKEY from EC parameters");
37
+ }
38
+
39
+ EVP_PKEY_CTX_free(ctx);
40
+ OSSL_PARAM_free(params);
41
+ return pkey;
42
+ }
43
+
44
+ } // namespace margelo::nitro::crypto
@@ -3,7 +3,9 @@
3
3
  #include <algorithm>
4
4
  #include <cctype>
5
5
  #include <limits>
6
+ #include <openssl/bn.h>
6
7
  #include <openssl/err.h>
8
+ #include <openssl/evp.h>
7
9
  #include <string>
8
10
  #include <vector>
9
11
 
@@ -72,4 +74,41 @@ inline std::string toLower(std::string s) {
72
74
  return s;
73
75
  }
74
76
 
77
+ inline const EVP_MD* getDigestByName(const std::string& algorithm) {
78
+ std::string algo = toLower(algorithm);
79
+
80
+ // Strip legacy RSA- prefix (e.g. rsa-sha256 -> sha256) for Node.js compat
81
+ if (algo.size() > 4 && algo.compare(0, 4, "rsa-") == 0) {
82
+ algo = algo.substr(4);
83
+ }
84
+
85
+ if (algo == "sha1" || algo == "sha-1") {
86
+ return EVP_sha1();
87
+ } else if (algo == "sha224" || algo == "sha-224") {
88
+ return EVP_sha224();
89
+ } else if (algo == "sha256" || algo == "sha-256") {
90
+ return EVP_sha256();
91
+ } else if (algo == "sha384" || algo == "sha-384") {
92
+ return EVP_sha384();
93
+ } else if (algo == "sha512" || algo == "sha-512") {
94
+ return EVP_sha512();
95
+ } else if (algo == "sha3-224") {
96
+ return EVP_sha3_224();
97
+ } else if (algo == "sha3-256") {
98
+ return EVP_sha3_256();
99
+ } else if (algo == "sha3-384") {
100
+ return EVP_sha3_384();
101
+ } else if (algo == "sha3-512") {
102
+ return EVP_sha3_512();
103
+ } else if (algo == "ripemd160" || algo == "ripemd-160") {
104
+ return EVP_ripemd160();
105
+ }
106
+ throw std::runtime_error("Unsupported hash algorithm: " + algorithm);
107
+ }
108
+
109
+ // Build an EVP_PKEY from EC curve name + public key octets + optional private key BIGNUM.
110
+ // Uses OSSL_PARAM_BLD + EVP_PKEY_fromdata (OpenSSL 3.x, no deprecated EC_KEY APIs).
111
+ // Caller owns the returned EVP_PKEY*.
112
+ EVP_PKEY* createEcEvpPkey(const char* group_name, const uint8_t* pub_oct, size_t pub_len, const BIGNUM* priv_bn = nullptr);
113
+
75
114
  } // namespace margelo::nitro::crypto
@@ -0,0 +1,174 @@
1
+ #include "HybridX509Certificate.hpp"
2
+ #include "../keys/HybridKeyObjectHandle.hpp"
3
+ #include "../keys/KeyObjectData.hpp"
4
+ #include "QuickCryptoUtils.hpp"
5
+ #include <ncrypto.h>
6
+
7
+ namespace margelo::nitro::crypto {
8
+
9
+ std::string HybridX509Certificate::bioToString(ncrypto::BIOPointer bio) const {
10
+ if (!bio)
11
+ return "";
12
+ BUF_MEM* mem = bio;
13
+ if (!mem || mem->length == 0)
14
+ return "";
15
+ return std::string(mem->data, mem->length);
16
+ }
17
+
18
+ void HybridX509Certificate::init(const std::shared_ptr<ArrayBuffer>& buffer) {
19
+ ncrypto::Buffer<const unsigned char> buf{.data = reinterpret_cast<const unsigned char*>(buffer->data()), .len = buffer->size()};
20
+ auto result = ncrypto::X509Pointer::Parse(buf);
21
+ if (!result) {
22
+ throw std::runtime_error("Failed to parse X509 certificate");
23
+ }
24
+ cert_ = std::move(result.value);
25
+ }
26
+
27
+ std::string HybridX509Certificate::subject() {
28
+ return bioToString(cert_.view().getSubject());
29
+ }
30
+
31
+ std::string HybridX509Certificate::subjectAltName() {
32
+ return bioToString(cert_.view().getSubjectAltName());
33
+ }
34
+
35
+ std::string HybridX509Certificate::issuer() {
36
+ return bioToString(cert_.view().getIssuer());
37
+ }
38
+
39
+ std::string HybridX509Certificate::infoAccess() {
40
+ return bioToString(cert_.view().getInfoAccess());
41
+ }
42
+
43
+ std::string HybridX509Certificate::validFrom() {
44
+ return bioToString(cert_.view().getValidFrom());
45
+ }
46
+
47
+ std::string HybridX509Certificate::validTo() {
48
+ return bioToString(cert_.view().getValidTo());
49
+ }
50
+
51
+ double HybridX509Certificate::validFromDate() {
52
+ return static_cast<double>(cert_.view().getValidFromTime()) * 1000.0;
53
+ }
54
+
55
+ double HybridX509Certificate::validToDate() {
56
+ return static_cast<double>(cert_.view().getValidToTime()) * 1000.0;
57
+ }
58
+
59
+ std::string HybridX509Certificate::signatureAlgorithm() {
60
+ auto algo = cert_.view().getSignatureAlgorithm();
61
+ if (!algo.has_value())
62
+ return "";
63
+ return std::string(algo.value());
64
+ }
65
+
66
+ std::string HybridX509Certificate::signatureAlgorithmOid() {
67
+ return cert_.view().getSignatureAlgorithmOID().value_or("");
68
+ }
69
+
70
+ std::string HybridX509Certificate::serialNumber() {
71
+ auto serial = cert_.view().getSerialNumber();
72
+ if (!serial)
73
+ return "";
74
+ return std::string(static_cast<const char*>(serial.get()), serial.size());
75
+ }
76
+
77
+ std::string HybridX509Certificate::fingerprint() {
78
+ return cert_.view().getFingerprint(ncrypto::Digest::SHA1).value_or("");
79
+ }
80
+
81
+ std::string HybridX509Certificate::fingerprint256() {
82
+ return cert_.view().getFingerprint(ncrypto::Digest::SHA256).value_or("");
83
+ }
84
+
85
+ std::string HybridX509Certificate::fingerprint512() {
86
+ return cert_.view().getFingerprint(ncrypto::Digest::SHA512).value_or("");
87
+ }
88
+
89
+ std::shared_ptr<ArrayBuffer> HybridX509Certificate::raw() {
90
+ auto bio = cert_.view().toDER();
91
+ if (!bio) {
92
+ throw std::runtime_error("Failed to export certificate as DER");
93
+ }
94
+ BUF_MEM* mem = bio;
95
+ return ToNativeArrayBuffer(reinterpret_cast<const uint8_t*>(mem->data), mem->length);
96
+ }
97
+
98
+ std::string HybridX509Certificate::pem() {
99
+ return bioToString(cert_.view().toPEM());
100
+ }
101
+
102
+ std::shared_ptr<HybridKeyObjectHandleSpec> HybridX509Certificate::publicKey() {
103
+ auto result = cert_.view().getPublicKey();
104
+ if (!result) {
105
+ throw std::runtime_error("Failed to extract public key from certificate");
106
+ }
107
+ auto handle = std::make_shared<HybridKeyObjectHandle>();
108
+ handle->setKeyObjectData(KeyObjectData::CreateAsymmetric(KeyType::PUBLIC, std::move(result.value)));
109
+ return handle;
110
+ }
111
+
112
+ std::vector<std::string> HybridX509Certificate::keyUsage() {
113
+ std::vector<std::string> usages;
114
+ cert_.view().enumUsages([&](const char* usage) { usages.emplace_back(usage); });
115
+ return usages;
116
+ }
117
+
118
+ bool HybridX509Certificate::ca() {
119
+ return cert_.view().isCA();
120
+ }
121
+
122
+ bool HybridX509Certificate::checkIssued(const std::shared_ptr<HybridX509CertificateHandleSpec>& other) {
123
+ auto otherCert = std::dynamic_pointer_cast<HybridX509Certificate>(other);
124
+ if (!otherCert) {
125
+ throw std::runtime_error("Invalid X509Certificate");
126
+ }
127
+ return cert_.view().isIssuedBy(otherCert->cert_.view());
128
+ }
129
+
130
+ bool HybridX509Certificate::checkPrivateKey(const std::shared_ptr<HybridKeyObjectHandleSpec>& key) {
131
+ auto handle = std::dynamic_pointer_cast<HybridKeyObjectHandle>(key);
132
+ if (!handle) {
133
+ throw std::runtime_error("Invalid key object");
134
+ }
135
+ return cert_.view().checkPrivateKey(handle->getKeyObjectData().GetAsymmetricKey());
136
+ }
137
+
138
+ bool HybridX509Certificate::verify(const std::shared_ptr<HybridKeyObjectHandleSpec>& key) {
139
+ auto handle = std::dynamic_pointer_cast<HybridKeyObjectHandle>(key);
140
+ if (!handle) {
141
+ throw std::runtime_error("Invalid key object");
142
+ }
143
+ return cert_.view().checkPublicKey(handle->getKeyObjectData().GetAsymmetricKey());
144
+ }
145
+
146
+ std::optional<std::string> HybridX509Certificate::checkHost(const std::string& name, double flags) {
147
+ ncrypto::DataPointer peername;
148
+ auto match = cert_.view().checkHost(name, static_cast<int>(flags), &peername);
149
+ if (match == ncrypto::X509View::CheckMatch::MATCH) {
150
+ if (peername) {
151
+ return std::string(static_cast<const char*>(peername.get()), peername.size());
152
+ }
153
+ return name;
154
+ }
155
+ return std::nullopt;
156
+ }
157
+
158
+ std::optional<std::string> HybridX509Certificate::checkEmail(const std::string& email, double flags) {
159
+ auto match = cert_.view().checkEmail(email, static_cast<int>(flags));
160
+ if (match == ncrypto::X509View::CheckMatch::MATCH) {
161
+ return email;
162
+ }
163
+ return std::nullopt;
164
+ }
165
+
166
+ std::optional<std::string> HybridX509Certificate::checkIP(const std::string& ip) {
167
+ auto match = cert_.view().checkIp(ip, 0);
168
+ if (match == ncrypto::X509View::CheckMatch::MATCH) {
169
+ return ip;
170
+ }
171
+ return std::nullopt;
172
+ }
173
+
174
+ } // namespace margelo::nitro::crypto