react-native-quick-crypto 1.0.11 → 1.0.12

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 (192) 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/signVerify.js +0 -2
  49. package/lib/commonjs/keys/signVerify.js.map +1 -1
  50. package/lib/commonjs/mlkem.js +219 -0
  51. package/lib/commonjs/mlkem.js.map +1 -0
  52. package/lib/commonjs/pbkdf2.js +18 -1
  53. package/lib/commonjs/pbkdf2.js.map +1 -1
  54. package/lib/commonjs/rsa.js +7 -7
  55. package/lib/commonjs/rsa.js.map +1 -1
  56. package/lib/commonjs/specs/kmac.nitro.js +6 -0
  57. package/lib/commonjs/specs/kmac.nitro.js.map +1 -0
  58. package/lib/commonjs/specs/mlKemKeyPair.nitro.js +6 -0
  59. package/lib/commonjs/specs/mlKemKeyPair.nitro.js.map +1 -0
  60. package/lib/commonjs/specs/x509certificate.nitro.js +6 -0
  61. package/lib/commonjs/specs/x509certificate.nitro.js.map +1 -0
  62. package/lib/commonjs/subtle.js +292 -112
  63. package/lib/commonjs/subtle.js.map +1 -1
  64. package/lib/commonjs/utils/conversion.js +3 -3
  65. package/lib/commonjs/utils/conversion.js.map +1 -1
  66. package/lib/commonjs/utils/hashnames.js +31 -0
  67. package/lib/commonjs/utils/hashnames.js.map +1 -1
  68. package/lib/commonjs/utils/types.js.map +1 -1
  69. package/lib/commonjs/x509certificate.js +189 -0
  70. package/lib/commonjs/x509certificate.js.map +1 -0
  71. package/lib/module/cipher.js +16 -3
  72. package/lib/module/cipher.js.map +1 -1
  73. package/lib/module/dhKeyPair.js +1 -1
  74. package/lib/module/dhKeyPair.js.map +1 -1
  75. package/lib/module/dsa.js +1 -1
  76. package/lib/module/dsa.js.map +1 -1
  77. package/lib/module/ec.js +6 -6
  78. package/lib/module/ec.js.map +1 -1
  79. package/lib/module/ed.js +1 -1
  80. package/lib/module/ed.js.map +1 -1
  81. package/lib/module/hash.js +17 -12
  82. package/lib/module/hash.js.map +1 -1
  83. package/lib/module/hkdf.js.map +1 -1
  84. package/lib/module/index.js +6 -0
  85. package/lib/module/index.js.map +1 -1
  86. package/lib/module/keys/classes.js +2 -2
  87. package/lib/module/keys/classes.js.map +1 -1
  88. package/lib/module/keys/index.js +25 -1
  89. package/lib/module/keys/index.js.map +1 -1
  90. package/lib/module/keys/signVerify.js +0 -2
  91. package/lib/module/keys/signVerify.js.map +1 -1
  92. package/lib/module/mlkem.js +211 -0
  93. package/lib/module/mlkem.js.map +1 -0
  94. package/lib/module/pbkdf2.js +18 -1
  95. package/lib/module/pbkdf2.js.map +1 -1
  96. package/lib/module/rsa.js +1 -1
  97. package/lib/module/rsa.js.map +1 -1
  98. package/lib/module/specs/kmac.nitro.js +4 -0
  99. package/lib/module/specs/kmac.nitro.js.map +1 -0
  100. package/lib/module/specs/mlKemKeyPair.nitro.js +4 -0
  101. package/lib/module/specs/mlKemKeyPair.nitro.js.map +1 -0
  102. package/lib/module/specs/x509certificate.nitro.js +4 -0
  103. package/lib/module/specs/x509certificate.nitro.js.map +1 -0
  104. package/lib/module/subtle.js +292 -112
  105. package/lib/module/subtle.js.map +1 -1
  106. package/lib/module/utils/conversion.js +3 -4
  107. package/lib/module/utils/conversion.js.map +1 -1
  108. package/lib/module/utils/hashnames.js +31 -0
  109. package/lib/module/utils/hashnames.js.map +1 -1
  110. package/lib/module/utils/types.js.map +1 -1
  111. package/lib/module/x509certificate.js +184 -0
  112. package/lib/module/x509certificate.js.map +1 -0
  113. package/lib/tsconfig.tsbuildinfo +1 -1
  114. package/lib/typescript/cipher.d.ts +3 -0
  115. package/lib/typescript/cipher.d.ts.map +1 -1
  116. package/lib/typescript/dhKeyPair.d.ts +1 -1
  117. package/lib/typescript/dhKeyPair.d.ts.map +1 -1
  118. package/lib/typescript/dsa.d.ts +1 -1
  119. package/lib/typescript/dsa.d.ts.map +1 -1
  120. package/lib/typescript/ec.d.ts +1 -1
  121. package/lib/typescript/ec.d.ts.map +1 -1
  122. package/lib/typescript/ed.d.ts +1 -1
  123. package/lib/typescript/ed.d.ts.map +1 -1
  124. package/lib/typescript/hash.d.ts.map +1 -1
  125. package/lib/typescript/hkdf.d.ts +2 -6
  126. package/lib/typescript/hkdf.d.ts.map +1 -1
  127. package/lib/typescript/index.d.ts +15 -4
  128. package/lib/typescript/index.d.ts.map +1 -1
  129. package/lib/typescript/keys/classes.d.ts +5 -5
  130. package/lib/typescript/keys/classes.d.ts.map +1 -1
  131. package/lib/typescript/keys/index.d.ts +2 -2
  132. package/lib/typescript/keys/index.d.ts.map +1 -1
  133. package/lib/typescript/keys/signVerify.d.ts.map +1 -1
  134. package/lib/typescript/mlkem.d.ts +30 -0
  135. package/lib/typescript/mlkem.d.ts.map +1 -0
  136. package/lib/typescript/pbkdf2.d.ts +2 -2
  137. package/lib/typescript/pbkdf2.d.ts.map +1 -1
  138. package/lib/typescript/rsa.d.ts +1 -1
  139. package/lib/typescript/rsa.d.ts.map +1 -1
  140. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +1 -0
  141. package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
  142. package/lib/typescript/specs/kmac.nitro.d.ts +10 -0
  143. package/lib/typescript/specs/kmac.nitro.d.ts.map +1 -0
  144. package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts +18 -0
  145. package/lib/typescript/specs/mlKemKeyPair.nitro.d.ts.map +1 -0
  146. package/lib/typescript/specs/x509certificate.nitro.d.ts +34 -0
  147. package/lib/typescript/specs/x509certificate.nitro.d.ts.map +1 -0
  148. package/lib/typescript/subtle.d.ts +10 -0
  149. package/lib/typescript/subtle.d.ts.map +1 -1
  150. package/lib/typescript/utils/conversion.d.ts.map +1 -1
  151. package/lib/typescript/utils/hashnames.d.ts +1 -1
  152. package/lib/typescript/utils/hashnames.d.ts.map +1 -1
  153. package/lib/typescript/utils/types.d.ts +13 -7
  154. package/lib/typescript/utils/types.d.ts.map +1 -1
  155. package/lib/typescript/x509certificate.d.ts +64 -0
  156. package/lib/typescript/x509certificate.d.ts.map +1 -0
  157. package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +3 -0
  158. package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +30 -0
  159. package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +30 -0
  160. package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +12 -0
  161. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +1 -0
  162. package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +1 -0
  163. package/nitrogen/generated/shared/c++/HybridKmacSpec.cpp +23 -0
  164. package/nitrogen/generated/shared/c++/HybridKmacSpec.hpp +66 -0
  165. package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.cpp +31 -0
  166. package/nitrogen/generated/shared/c++/HybridMlKemKeyPairSpec.hpp +74 -0
  167. package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.cpp +46 -0
  168. package/nitrogen/generated/shared/c++/HybridX509CertificateHandleSpec.hpp +96 -0
  169. package/package.json +4 -1
  170. package/src/cipher.ts +17 -3
  171. package/src/dhKeyPair.ts +1 -1
  172. package/src/dsa.ts +1 -1
  173. package/src/ec.ts +9 -9
  174. package/src/ed.ts +2 -2
  175. package/src/hash.ts +34 -11
  176. package/src/hkdf.ts +2 -7
  177. package/src/index.ts +7 -0
  178. package/src/keys/classes.ts +10 -9
  179. package/src/keys/index.ts +37 -2
  180. package/src/keys/signVerify.ts +0 -5
  181. package/src/mlkem.ts +350 -0
  182. package/src/pbkdf2.ts +34 -5
  183. package/src/rsa.ts +1 -1
  184. package/src/specs/keyObjectHandle.nitro.ts +5 -0
  185. package/src/specs/kmac.nitro.ts +12 -0
  186. package/src/specs/mlKemKeyPair.nitro.ts +32 -0
  187. package/src/specs/x509certificate.nitro.ts +38 -0
  188. package/src/subtle.ts +551 -125
  189. package/src/utils/conversion.ts +10 -4
  190. package/src/utils/hashnames.ts +33 -2
  191. package/src/utils/types.ts +42 -5
  192. package/src/x509certificate.ts +277 -0
@@ -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"
@@ -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
- // Return an empty buffer, matching Node.js behavior
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
- // For ChaCha20, final() should return an empty buffer since it's a stream cipher
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
- final_called = true;
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 (!final_called) {
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), final_called(false) {}
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
- final_called_ = false;
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
- final_called_ = true;
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
- final_called_ = true;
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
- final_called_ = true;
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 (!final_called_) {
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), final_called_(false) {}
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
- final_called_ = false;
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
- final_called_ = true;
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
- final_called_ = true;
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
- final_called_ = true;
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 (!final_called_) {
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), final_called_(false) {}
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
@@ -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
- // Create EC_POINT from the peer's public key bytes
74
- EC_POINT_ptr point(EC_POINT_new(_group.get()), EC_POINT_free);
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
- const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(_pkey.get());
146
- if (!ec) {
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
- // Set keys on EC_KEY (these functions copy the values, so we still own privBn and pubPoint)
192
- if (EC_KEY_set_private_key(ecKey.get(), privBn.get()) != 1) {
193
- throw std::runtime_error("ECDH: failed to set private key");
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
- // EVP_PKEY_assign_EC_KEY takes ownership of ecKey on success
207
- if (EVP_PKEY_assign_EC_KEY(pkey.get(), ecKey.get()) != 1) {
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
- _pkey = std::move(pkey);
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
- const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(_pkey.get());
221
- if (!ec) {
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 (EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, buf.data(), len, nullptr) == 0) {
239
- throw std::runtime_error("ECDH: failed to encode public key");
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
- // Create EC_POINT from the public key bytes
249
- EC_POINT_ptr point(EC_POINT_new(_group.get()), EC_POINT_free);
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