react-native-quick-crypto 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/QuickCrypto.podspec +1 -0
- package/android/CMakeLists.txt +4 -0
- package/cpp/cipher/CCMCipher.cpp +7 -11
- package/cpp/cipher/ChaCha20Cipher.cpp +6 -10
- package/cpp/cipher/ChaCha20Poly1305Cipher.cpp +10 -16
- package/cpp/cipher/GCMCipher.cpp +3 -5
- package/cpp/cipher/HybridCipher.cpp +7 -13
- package/cpp/cipher/HybridRsaCipher.cpp +19 -27
- package/cpp/cipher/OCBCipher.cpp +2 -3
- package/cpp/cipher/XChaCha20Poly1305Cipher.cpp +13 -19
- package/cpp/cipher/XSalsa20Cipher.cpp +8 -12
- package/cpp/cipher/XSalsa20Poly1305Cipher.cpp +11 -16
- package/cpp/keys/HybridKeyObjectHandle.cpp +630 -2
- package/cpp/keys/HybridKeyObjectHandle.hpp +21 -1
- package/cpp/sign/HybridSignHandle.cpp +26 -8
- package/cpp/sign/HybridVerifyHandle.cpp +28 -11
- package/cpp/slhdsa/HybridSlhDsaKeyPair.cpp +245 -0
- package/cpp/slhdsa/HybridSlhDsaKeyPair.hpp +48 -0
- package/cpp/turboshake/HybridTurboShake.cpp +379 -0
- package/cpp/turboshake/HybridTurboShake.hpp +28 -0
- package/cpp/utils/HybridUtils.cpp +26 -14
- package/deps/blake3/README.md +6 -7
- package/deps/blake3/c/blake3.c +3 -2
- package/deps/blake3/c/blake3.h +2 -2
- package/deps/blake3/c/blake3_dispatch.c +2 -2
- package/deps/blake3/c/blake3_impl.h +1 -1
- package/deps/blake3/c/blake3_neon.c +5 -4
- package/deps/ncrypto/include/ncrypto/version.h +2 -2
- package/deps/ncrypto/include/ncrypto.h +9 -2
- package/deps/ncrypto/src/ncrypto.cpp +130 -35
- package/lib/commonjs/dhKeyPair.js +3 -0
- package/lib/commonjs/dhKeyPair.js.map +1 -1
- package/lib/commonjs/dsa.js +3 -0
- package/lib/commonjs/dsa.js.map +1 -1
- package/lib/commonjs/ec.js +37 -30
- package/lib/commonjs/ec.js.map +1 -1
- package/lib/commonjs/ed.js +60 -6
- package/lib/commonjs/ed.js.map +1 -1
- package/lib/commonjs/hash.js +52 -5
- package/lib/commonjs/hash.js.map +1 -1
- package/lib/commonjs/keys/classes.js +33 -7
- package/lib/commonjs/keys/classes.js.map +1 -1
- package/lib/commonjs/keys/generateKeyPair.js +85 -4
- package/lib/commonjs/keys/generateKeyPair.js.map +1 -1
- package/lib/commonjs/keys/index.js +50 -2
- package/lib/commonjs/keys/index.js.map +1 -1
- package/lib/commonjs/keys/signVerify.js +9 -2
- package/lib/commonjs/keys/signVerify.js.map +1 -1
- package/lib/commonjs/keys/utils.js +59 -1
- package/lib/commonjs/keys/utils.js.map +1 -1
- package/lib/commonjs/random.js +63 -9
- package/lib/commonjs/random.js.map +1 -1
- package/lib/commonjs/rsa.js +3 -0
- package/lib/commonjs/rsa.js.map +1 -1
- package/lib/commonjs/slhdsa.js +70 -0
- package/lib/commonjs/slhdsa.js.map +1 -0
- package/lib/commonjs/specs/slhDsaKeyPair.nitro.js +6 -0
- package/lib/commonjs/specs/slhDsaKeyPair.nitro.js.map +1 -0
- package/lib/commonjs/specs/turboshake.nitro.js +6 -0
- package/lib/commonjs/specs/turboshake.nitro.js.map +1 -0
- package/lib/commonjs/subtle.js +926 -275
- package/lib/commonjs/subtle.js.map +1 -1
- package/lib/commonjs/utils/conversion.js +53 -19
- package/lib/commonjs/utils/conversion.js.map +1 -1
- package/lib/commonjs/utils/errors.js +63 -4
- package/lib/commonjs/utils/errors.js.map +1 -1
- package/lib/commonjs/utils/types.js.map +1 -1
- package/lib/commonjs/utils/validation.js +46 -0
- package/lib/commonjs/utils/validation.js.map +1 -1
- package/lib/module/dhKeyPair.js +3 -0
- package/lib/module/dhKeyPair.js.map +1 -1
- package/lib/module/dsa.js +3 -0
- package/lib/module/dsa.js.map +1 -1
- package/lib/module/ec.js +38 -31
- package/lib/module/ec.js.map +1 -1
- package/lib/module/ed.js +61 -7
- package/lib/module/ed.js.map +1 -1
- package/lib/module/hash.js +52 -5
- package/lib/module/hash.js.map +1 -1
- package/lib/module/keys/classes.js +31 -5
- package/lib/module/keys/classes.js.map +1 -1
- package/lib/module/keys/generateKeyPair.js +86 -5
- package/lib/module/keys/generateKeyPair.js.map +1 -1
- package/lib/module/keys/index.js +50 -2
- package/lib/module/keys/index.js.map +1 -1
- package/lib/module/keys/signVerify.js +9 -2
- package/lib/module/keys/signVerify.js.map +1 -1
- package/lib/module/keys/utils.js +57 -1
- package/lib/module/keys/utils.js.map +1 -1
- package/lib/module/random.js +63 -10
- package/lib/module/random.js.map +1 -1
- package/lib/module/rsa.js +3 -0
- package/lib/module/rsa.js.map +1 -1
- package/lib/module/slhdsa.js +64 -0
- package/lib/module/slhdsa.js.map +1 -0
- package/lib/module/specs/slhDsaKeyPair.nitro.js +4 -0
- package/lib/module/specs/slhDsaKeyPair.nitro.js.map +1 -0
- package/lib/module/specs/turboshake.nitro.js +4 -0
- package/lib/module/specs/turboshake.nitro.js.map +1 -0
- package/lib/module/subtle.js +927 -276
- package/lib/module/subtle.js.map +1 -1
- package/lib/module/utils/conversion.js +51 -19
- package/lib/module/utils/conversion.js.map +1 -1
- package/lib/module/utils/errors.js +61 -4
- package/lib/module/utils/errors.js.map +1 -1
- package/lib/module/utils/types.js.map +1 -1
- package/lib/module/utils/validation.js +44 -0
- package/lib/module/utils/validation.js.map +1 -1
- package/lib/typescript/dhKeyPair.d.ts.map +1 -1
- package/lib/typescript/dsa.d.ts.map +1 -1
- package/lib/typescript/ec.d.ts.map +1 -1
- package/lib/typescript/ed.d.ts.map +1 -1
- package/lib/typescript/hash.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +12 -7
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/keys/classes.d.ts +10 -1
- package/lib/typescript/keys/classes.d.ts.map +1 -1
- package/lib/typescript/keys/generateKeyPair.d.ts +12 -1
- package/lib/typescript/keys/generateKeyPair.d.ts.map +1 -1
- package/lib/typescript/keys/index.d.ts +3 -1
- package/lib/typescript/keys/index.d.ts.map +1 -1
- package/lib/typescript/keys/signVerify.d.ts.map +1 -1
- package/lib/typescript/keys/utils.d.ts +21 -4
- package/lib/typescript/keys/utils.d.ts.map +1 -1
- package/lib/typescript/random.d.ts +5 -1
- package/lib/typescript/random.d.ts.map +1 -1
- package/lib/typescript/rsa.d.ts.map +1 -1
- package/lib/typescript/slhdsa.d.ts +19 -0
- package/lib/typescript/slhdsa.d.ts.map +1 -0
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts +9 -0
- package/lib/typescript/specs/keyObjectHandle.nitro.d.ts.map +1 -1
- package/lib/typescript/specs/slhDsaKeyPair.nitro.d.ts +16 -0
- package/lib/typescript/specs/slhDsaKeyPair.nitro.d.ts.map +1 -0
- package/lib/typescript/specs/turboshake.nitro.d.ts +11 -0
- package/lib/typescript/specs/turboshake.nitro.d.ts.map +1 -0
- package/lib/typescript/subtle.d.ts +3 -2
- package/lib/typescript/subtle.d.ts.map +1 -1
- package/lib/typescript/utils/conversion.d.ts +4 -3
- package/lib/typescript/utils/conversion.d.ts.map +1 -1
- package/lib/typescript/utils/errors.d.ts +12 -0
- package/lib/typescript/utils/errors.d.ts.map +1 -1
- package/lib/typescript/utils/types.d.ts +32 -15
- package/lib/typescript/utils/types.d.ts.map +1 -1
- package/lib/typescript/utils/validation.d.ts +3 -1
- package/lib/typescript/utils/validation.d.ts.map +1 -1
- package/nitrogen/generated/android/QuickCrypto+autolinking.cmake +2 -0
- package/nitrogen/generated/android/QuickCryptoOnLoad.cpp +20 -0
- package/nitrogen/generated/ios/QuickCryptoAutolinking.mm +20 -0
- package/nitrogen/generated/shared/c++/AsymmetricKeyType.hpp +48 -0
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.cpp +9 -0
- package/nitrogen/generated/shared/c++/HybridKeyObjectHandleSpec.hpp +9 -0
- package/nitrogen/generated/shared/c++/HybridSlhDsaKeyPairSpec.cpp +29 -0
- package/nitrogen/generated/shared/c++/HybridSlhDsaKeyPairSpec.hpp +72 -0
- package/nitrogen/generated/shared/c++/HybridTurboShakeSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridTurboShakeSpec.hpp +70 -0
- package/nitrogen/generated/shared/c++/JWK.hpp +9 -1
- package/nitrogen/generated/shared/c++/JWKkty.hpp +4 -0
- package/nitrogen/generated/shared/c++/KangarooTwelveVariant.hpp +76 -0
- package/nitrogen/generated/shared/c++/TurboShakeVariant.hpp +76 -0
- package/package.json +2 -3
- package/src/dhKeyPair.ts +8 -0
- package/src/dsa.ts +8 -0
- package/src/ec.ts +52 -29
- package/src/ed.ts +95 -16
- package/src/hash.ts +108 -5
- package/src/keys/classes.ts +46 -5
- package/src/keys/generateKeyPair.ts +151 -5
- package/src/keys/index.ts +73 -3
- package/src/keys/signVerify.ts +13 -2
- package/src/keys/utils.ts +78 -5
- package/src/random.ts +93 -9
- package/src/rsa.ts +8 -0
- package/src/slhdsa.ts +146 -0
- package/src/specs/keyObjectHandle.nitro.ts +17 -0
- package/src/specs/slhDsaKeyPair.nitro.ts +29 -0
- package/src/specs/turboshake.nitro.ts +21 -0
- package/src/subtle.ts +1191 -360
- package/src/utils/conversion.ts +72 -21
- package/src/utils/errors.ts +72 -4
- package/src/utils/types.ts +80 -15
- package/src/utils/validation.ts +70 -1
|
@@ -15,7 +15,7 @@ namespace margelo::nitro::crypto {
|
|
|
15
15
|
|
|
16
16
|
class HybridKeyObjectHandle : public HybridKeyObjectHandleSpec {
|
|
17
17
|
public:
|
|
18
|
-
HybridKeyObjectHandle()
|
|
18
|
+
HybridKeyObjectHandle();
|
|
19
19
|
|
|
20
20
|
public:
|
|
21
21
|
std::shared_ptr<ArrayBuffer> exportKey(std::optional<KFormatType> format, std::optional<KeyEncoding> type,
|
|
@@ -24,6 +24,16 @@ class HybridKeyObjectHandle : public HybridKeyObjectHandleSpec {
|
|
|
24
24
|
|
|
25
25
|
JWK exportJwk(const JWK& key, bool handleRsaPss) override;
|
|
26
26
|
|
|
27
|
+
std::shared_ptr<ArrayBuffer> exportRawPublic() override;
|
|
28
|
+
|
|
29
|
+
std::shared_ptr<ArrayBuffer> exportRawPrivate() override;
|
|
30
|
+
|
|
31
|
+
std::shared_ptr<ArrayBuffer> exportRawSeed() override;
|
|
32
|
+
|
|
33
|
+
std::shared_ptr<ArrayBuffer> exportECPublicRaw(bool compressed) override;
|
|
34
|
+
|
|
35
|
+
std::shared_ptr<ArrayBuffer> exportECPrivateRaw() override;
|
|
36
|
+
|
|
27
37
|
AsymmetricKeyType getAsymmetricKeyType() override;
|
|
28
38
|
|
|
29
39
|
bool init(KeyType keyType, const std::variant<std::shared_ptr<ArrayBuffer>, std::string>& key, std::optional<KFormatType> format,
|
|
@@ -33,6 +43,14 @@ class HybridKeyObjectHandle : public HybridKeyObjectHandleSpec {
|
|
|
33
43
|
|
|
34
44
|
bool initPqcRaw(const std::string& algorithmName, const std::shared_ptr<ArrayBuffer>& keyData, bool isPublic) override;
|
|
35
45
|
|
|
46
|
+
bool initRawPublic(const std::string& asymmetricKeyType, const std::shared_ptr<ArrayBuffer>& keyData,
|
|
47
|
+
const std::optional<std::string>& namedCurve) override;
|
|
48
|
+
|
|
49
|
+
bool initRawPrivate(const std::string& asymmetricKeyType, const std::shared_ptr<ArrayBuffer>& keyData,
|
|
50
|
+
const std::optional<std::string>& namedCurve) override;
|
|
51
|
+
|
|
52
|
+
bool initRawSeed(const std::string& asymmetricKeyType, const std::shared_ptr<ArrayBuffer>& keyData) override;
|
|
53
|
+
|
|
36
54
|
std::optional<KeyType> initJwk(const JWK& keyData, std::optional<NamedCurve> namedCurve) override;
|
|
37
55
|
|
|
38
56
|
KeyDetail keyDetail() override;
|
|
@@ -41,6 +59,8 @@ class HybridKeyObjectHandle : public HybridKeyObjectHandleSpec {
|
|
|
41
59
|
|
|
42
60
|
double getSymmetricKeySize() override;
|
|
43
61
|
|
|
62
|
+
bool checkEcKeyData() override;
|
|
63
|
+
|
|
44
64
|
const KeyObjectData& getKeyObjectData() const {
|
|
45
65
|
return data_;
|
|
46
66
|
}
|
|
@@ -58,15 +58,13 @@ void HybridSignHandle::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
|
58
58
|
throw std::runtime_error("Sign not initialized");
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
auto native_data = ToNativeArrayBuffer(data);
|
|
62
|
-
|
|
63
61
|
// Accumulate raw data for potential one-shot signing (Ed25519/Ed448/ML-DSA)
|
|
64
|
-
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(
|
|
65
|
-
data_buffer.insert(data_buffer.end(), ptr, ptr +
|
|
62
|
+
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data->data());
|
|
63
|
+
data_buffer.insert(data_buffer.end(), ptr, ptr + data->size());
|
|
66
64
|
|
|
67
65
|
// Only update digest if we have one (not needed for pure signature schemes)
|
|
68
66
|
if (md != nullptr) {
|
|
69
|
-
if (EVP_DigestUpdate(md_ctx,
|
|
67
|
+
if (EVP_DigestUpdate(md_ctx, data->data(), data->size()) <= 0) {
|
|
70
68
|
unsigned long err = ERR_get_error();
|
|
71
69
|
char err_buf[256];
|
|
72
70
|
ERR_error_string_n(err, err_buf, sizeof(err_buf));
|
|
@@ -75,12 +73,32 @@ void HybridSignHandle::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
// Check if key type requires one-shot signing (Ed25519, Ed448, ML-DSA)
|
|
76
|
+
// Check if key type requires one-shot signing (Ed25519, Ed448, ML-DSA, SLH-DSA)
|
|
79
77
|
static bool isOneShotVariant(EVP_PKEY* pkey) {
|
|
80
78
|
int type = EVP_PKEY_id(pkey);
|
|
81
79
|
#if RNQC_HAS_ML_DSA
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
switch (type) {
|
|
81
|
+
case EVP_PKEY_ED25519:
|
|
82
|
+
case EVP_PKEY_ED448:
|
|
83
|
+
case EVP_PKEY_ML_DSA_44:
|
|
84
|
+
case EVP_PKEY_ML_DSA_65:
|
|
85
|
+
case EVP_PKEY_ML_DSA_87:
|
|
86
|
+
case EVP_PKEY_SLH_DSA_SHA2_128S:
|
|
87
|
+
case EVP_PKEY_SLH_DSA_SHA2_128F:
|
|
88
|
+
case EVP_PKEY_SLH_DSA_SHA2_192S:
|
|
89
|
+
case EVP_PKEY_SLH_DSA_SHA2_192F:
|
|
90
|
+
case EVP_PKEY_SLH_DSA_SHA2_256S:
|
|
91
|
+
case EVP_PKEY_SLH_DSA_SHA2_256F:
|
|
92
|
+
case EVP_PKEY_SLH_DSA_SHAKE_128S:
|
|
93
|
+
case EVP_PKEY_SLH_DSA_SHAKE_128F:
|
|
94
|
+
case EVP_PKEY_SLH_DSA_SHAKE_192S:
|
|
95
|
+
case EVP_PKEY_SLH_DSA_SHAKE_192F:
|
|
96
|
+
case EVP_PKEY_SLH_DSA_SHAKE_256S:
|
|
97
|
+
case EVP_PKEY_SLH_DSA_SHAKE_256F:
|
|
98
|
+
return true;
|
|
99
|
+
default:
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
84
102
|
#else
|
|
85
103
|
return type == EVP_PKEY_ED25519 || type == EVP_PKEY_ED448;
|
|
86
104
|
#endif
|
|
@@ -58,15 +58,13 @@ void HybridVerifyHandle::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
|
58
58
|
throw std::runtime_error("Verify not initialized");
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
auto native_data = ToNativeArrayBuffer(data);
|
|
62
|
-
|
|
63
61
|
// Accumulate raw data for potential one-shot verification (Ed25519/Ed448/ML-DSA)
|
|
64
|
-
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(
|
|
65
|
-
data_buffer.insert(data_buffer.end(), ptr, ptr +
|
|
62
|
+
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data->data());
|
|
63
|
+
data_buffer.insert(data_buffer.end(), ptr, ptr + data->size());
|
|
66
64
|
|
|
67
65
|
// Only update digest if we have one (not needed for pure signature schemes)
|
|
68
66
|
if (md != nullptr) {
|
|
69
|
-
if (EVP_DigestUpdate(md_ctx,
|
|
67
|
+
if (EVP_DigestUpdate(md_ctx, data->data(), data->size()) <= 0) {
|
|
70
68
|
unsigned long err = ERR_get_error();
|
|
71
69
|
char err_buf[256];
|
|
72
70
|
ERR_error_string_n(err, err_buf, sizeof(err_buf));
|
|
@@ -75,12 +73,32 @@ void HybridVerifyHandle::update(const std::shared_ptr<ArrayBuffer>& data) {
|
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
// Check if key type requires one-shot verification (Ed25519, Ed448, ML-DSA)
|
|
76
|
+
// Check if key type requires one-shot verification (Ed25519, Ed448, ML-DSA, SLH-DSA)
|
|
79
77
|
static bool isOneShotVariant(EVP_PKEY* pkey) {
|
|
80
78
|
int type = EVP_PKEY_id(pkey);
|
|
81
79
|
#if RNQC_HAS_ML_DSA
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
switch (type) {
|
|
81
|
+
case EVP_PKEY_ED25519:
|
|
82
|
+
case EVP_PKEY_ED448:
|
|
83
|
+
case EVP_PKEY_ML_DSA_44:
|
|
84
|
+
case EVP_PKEY_ML_DSA_65:
|
|
85
|
+
case EVP_PKEY_ML_DSA_87:
|
|
86
|
+
case EVP_PKEY_SLH_DSA_SHA2_128S:
|
|
87
|
+
case EVP_PKEY_SLH_DSA_SHA2_128F:
|
|
88
|
+
case EVP_PKEY_SLH_DSA_SHA2_192S:
|
|
89
|
+
case EVP_PKEY_SLH_DSA_SHA2_192F:
|
|
90
|
+
case EVP_PKEY_SLH_DSA_SHA2_256S:
|
|
91
|
+
case EVP_PKEY_SLH_DSA_SHA2_256F:
|
|
92
|
+
case EVP_PKEY_SLH_DSA_SHAKE_128S:
|
|
93
|
+
case EVP_PKEY_SLH_DSA_SHAKE_128F:
|
|
94
|
+
case EVP_PKEY_SLH_DSA_SHAKE_192S:
|
|
95
|
+
case EVP_PKEY_SLH_DSA_SHAKE_192F:
|
|
96
|
+
case EVP_PKEY_SLH_DSA_SHAKE_256S:
|
|
97
|
+
case EVP_PKEY_SLH_DSA_SHAKE_256F:
|
|
98
|
+
return true;
|
|
99
|
+
default:
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
84
102
|
#else
|
|
85
103
|
return type == EVP_PKEY_ED25519 || type == EVP_PKEY_ED448;
|
|
86
104
|
#endif
|
|
@@ -107,9 +125,8 @@ bool HybridVerifyHandle::verify(const std::shared_ptr<HybridKeyObjectHandleSpec>
|
|
|
107
125
|
throw std::runtime_error("Invalid public key for verification");
|
|
108
126
|
}
|
|
109
127
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
size_t sig_len = native_sig->size();
|
|
128
|
+
const unsigned char* sig_data = signature->data();
|
|
129
|
+
size_t sig_len = signature->size();
|
|
113
130
|
|
|
114
131
|
// Ed25519/Ed448/ML-DSA require one-shot verification with EVP_DigestVerify
|
|
115
132
|
// Also use one-shot path if no digest was specified (md == nullptr)
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#include "HybridSlhDsaKeyPair.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 <array>
|
|
9
|
+
|
|
10
|
+
#include "QuickCryptoUtils.hpp"
|
|
11
|
+
|
|
12
|
+
#if OPENSSL_VERSION_NUMBER >= 0x30500000L
|
|
13
|
+
#define RNQC_HAS_SLH_DSA 1
|
|
14
|
+
#else
|
|
15
|
+
#define RNQC_HAS_SLH_DSA 0
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
namespace margelo::nitro::crypto {
|
|
19
|
+
|
|
20
|
+
using EVP_MD_CTX_ptr = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>;
|
|
21
|
+
using EVP_PKEY_CTX_ptr = std::unique_ptr<EVP_PKEY_CTX, decltype(&EVP_PKEY_CTX_free)>;
|
|
22
|
+
|
|
23
|
+
#if RNQC_HAS_SLH_DSA
|
|
24
|
+
static constexpr std::array<const char*, 12> kSlhDsaVariants{
|
|
25
|
+
"SLH-DSA-SHA2-128s", "SLH-DSA-SHA2-128f", "SLH-DSA-SHA2-192s", "SLH-DSA-SHA2-192f", "SLH-DSA-SHA2-256s", "SLH-DSA-SHA2-256f",
|
|
26
|
+
"SLH-DSA-SHAKE-128s", "SLH-DSA-SHAKE-128f", "SLH-DSA-SHAKE-192s", "SLH-DSA-SHAKE-192f", "SLH-DSA-SHAKE-256s", "SLH-DSA-SHAKE-256f",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
static bool isValidSlhDsaVariant(const std::string& variant) {
|
|
30
|
+
for (const char* v : kSlhDsaVariants) {
|
|
31
|
+
if (variant == v) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
#endif
|
|
38
|
+
|
|
39
|
+
void HybridSlhDsaKeyPair::setVariant(const std::string& variant) {
|
|
40
|
+
#if !RNQC_HAS_SLH_DSA
|
|
41
|
+
throw std::runtime_error("SLH-DSA requires OpenSSL 3.5+");
|
|
42
|
+
#else
|
|
43
|
+
if (!isValidSlhDsaVariant(variant)) {
|
|
44
|
+
throw std::runtime_error("Invalid SLH-DSA variant: " + variant);
|
|
45
|
+
}
|
|
46
|
+
variant_ = variant;
|
|
47
|
+
#endif
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
std::shared_ptr<Promise<void>> HybridSlhDsaKeyPair::generateKeyPair(double publicFormat, double publicType, double privateFormat,
|
|
51
|
+
double privateType) {
|
|
52
|
+
auto self = this->shared_cast<HybridSlhDsaKeyPair>();
|
|
53
|
+
return Promise<void>::async([self, publicFormat, publicType, privateFormat, privateType]() {
|
|
54
|
+
self->generateKeyPairSync(publicFormat, publicType, privateFormat, privateType);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
void HybridSlhDsaKeyPair::generateKeyPairSync(double publicFormat, double publicType, double privateFormat, double privateType) {
|
|
59
|
+
#if !RNQC_HAS_SLH_DSA
|
|
60
|
+
throw std::runtime_error("SLH-DSA requires OpenSSL 3.5+");
|
|
61
|
+
#else
|
|
62
|
+
clearOpenSSLErrors();
|
|
63
|
+
|
|
64
|
+
if (variant_.empty()) {
|
|
65
|
+
throw std::runtime_error("SLH-DSA variant not set. Call setVariant() first.");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
publicFormat_ = static_cast<int>(publicFormat);
|
|
69
|
+
publicType_ = static_cast<int>(publicType);
|
|
70
|
+
privateFormat_ = static_cast<int>(privateFormat);
|
|
71
|
+
privateType_ = static_cast<int>(privateType);
|
|
72
|
+
|
|
73
|
+
pkey_.reset();
|
|
74
|
+
|
|
75
|
+
EVP_PKEY_CTX_ptr pctx(EVP_PKEY_CTX_new_from_name(nullptr, variant_.c_str(), nullptr), EVP_PKEY_CTX_free);
|
|
76
|
+
if (pctx == nullptr) {
|
|
77
|
+
throw std::runtime_error("Failed to create key context for " + variant_ + ": " + getOpenSSLError());
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (EVP_PKEY_keygen_init(pctx.get()) <= 0) {
|
|
81
|
+
throw std::runtime_error("Failed to initialize keygen: " + getOpenSSLError());
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
EVP_PKEY* raw = nullptr;
|
|
85
|
+
if (EVP_PKEY_keygen(pctx.get(), &raw) <= 0) {
|
|
86
|
+
throw std::runtime_error("Failed to generate SLH-DSA key pair: " + getOpenSSLError());
|
|
87
|
+
}
|
|
88
|
+
pkey_.reset(raw);
|
|
89
|
+
#endif
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
std::shared_ptr<ArrayBuffer> HybridSlhDsaKeyPair::getPublicKey() {
|
|
93
|
+
#if !RNQC_HAS_SLH_DSA
|
|
94
|
+
throw std::runtime_error("SLH-DSA requires OpenSSL 3.5+");
|
|
95
|
+
#else
|
|
96
|
+
checkKeyPair();
|
|
97
|
+
|
|
98
|
+
BIO* bio = BIO_new(BIO_s_mem());
|
|
99
|
+
if (!bio) {
|
|
100
|
+
throw std::runtime_error("Failed to create BIO for public key export");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
int result;
|
|
104
|
+
if (publicFormat_ == 1) {
|
|
105
|
+
result = PEM_write_bio_PUBKEY(bio, pkey_.get());
|
|
106
|
+
} else {
|
|
107
|
+
result = i2d_PUBKEY_bio(bio, pkey_.get());
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (result != 1) {
|
|
111
|
+
BIO_free(bio);
|
|
112
|
+
throw std::runtime_error("Failed to export public key: " + getOpenSSLError());
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
BUF_MEM* bptr;
|
|
116
|
+
BIO_get_mem_ptr(bio, &bptr);
|
|
117
|
+
|
|
118
|
+
size_t len = bptr->length;
|
|
119
|
+
auto buf = std::make_unique<uint8_t[]>(len);
|
|
120
|
+
memcpy(buf.get(), bptr->data, len);
|
|
121
|
+
|
|
122
|
+
BIO_free(bio);
|
|
123
|
+
|
|
124
|
+
uint8_t* raw_ptr = buf.get();
|
|
125
|
+
return std::make_shared<NativeArrayBuffer>(buf.release(), len, [raw_ptr]() { delete[] raw_ptr; });
|
|
126
|
+
#endif
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
std::shared_ptr<ArrayBuffer> HybridSlhDsaKeyPair::getPrivateKey() {
|
|
130
|
+
#if !RNQC_HAS_SLH_DSA
|
|
131
|
+
throw std::runtime_error("SLH-DSA requires OpenSSL 3.5+");
|
|
132
|
+
#else
|
|
133
|
+
checkKeyPair();
|
|
134
|
+
|
|
135
|
+
BIO* bio = BIO_new(BIO_s_mem());
|
|
136
|
+
if (!bio) {
|
|
137
|
+
throw std::runtime_error("Failed to create BIO for private key export");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
int result;
|
|
141
|
+
if (privateFormat_ == 1) {
|
|
142
|
+
result = PEM_write_bio_PrivateKey(bio, pkey_.get(), nullptr, nullptr, 0, nullptr, nullptr);
|
|
143
|
+
} else {
|
|
144
|
+
result = i2d_PKCS8PrivateKey_bio(bio, pkey_.get(), nullptr, nullptr, 0, nullptr, nullptr);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (result != 1) {
|
|
148
|
+
BIO_free(bio);
|
|
149
|
+
throw std::runtime_error("Failed to export private key: " + getOpenSSLError());
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
BUF_MEM* bptr;
|
|
153
|
+
BIO_get_mem_ptr(bio, &bptr);
|
|
154
|
+
|
|
155
|
+
size_t len = bptr->length;
|
|
156
|
+
auto buf = std::make_unique<uint8_t[]>(len);
|
|
157
|
+
memcpy(buf.get(), bptr->data, len);
|
|
158
|
+
|
|
159
|
+
secureZero(bptr->data, bptr->length);
|
|
160
|
+
BIO_free(bio);
|
|
161
|
+
|
|
162
|
+
uint8_t* raw_ptr = buf.get();
|
|
163
|
+
return std::make_shared<NativeArrayBuffer>(buf.release(), len, [raw_ptr]() { delete[] raw_ptr; });
|
|
164
|
+
#endif
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> HybridSlhDsaKeyPair::sign(const std::shared_ptr<ArrayBuffer>& message) {
|
|
168
|
+
auto nativeMessage = ToNativeArrayBuffer(message);
|
|
169
|
+
auto self = this->shared_cast<HybridSlhDsaKeyPair>();
|
|
170
|
+
return Promise<std::shared_ptr<ArrayBuffer>>::async([self, nativeMessage]() { return self->signSync(nativeMessage); });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
std::shared_ptr<ArrayBuffer> HybridSlhDsaKeyPair::signSync(const std::shared_ptr<ArrayBuffer>& message) {
|
|
174
|
+
#if !RNQC_HAS_SLH_DSA
|
|
175
|
+
throw std::runtime_error("SLH-DSA requires OpenSSL 3.5+");
|
|
176
|
+
#else
|
|
177
|
+
clearOpenSSLErrors();
|
|
178
|
+
checkKeyPair();
|
|
179
|
+
|
|
180
|
+
EVP_MD_CTX_ptr md_ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
|
|
181
|
+
if (md_ctx == nullptr) {
|
|
182
|
+
throw std::runtime_error("Failed to create signing context");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey_.get()) <= 0) {
|
|
186
|
+
throw std::runtime_error("Failed to initialize signing: " + getOpenSSLError());
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
size_t sig_len = 0;
|
|
190
|
+
if (EVP_DigestSign(md_ctx.get(), nullptr, &sig_len, message->data(), message->size()) <= 0) {
|
|
191
|
+
throw std::runtime_error("Failed to calculate signature size: " + getOpenSSLError());
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
auto sig = std::make_unique<uint8_t[]>(sig_len);
|
|
195
|
+
|
|
196
|
+
if (EVP_DigestSign(md_ctx.get(), sig.get(), &sig_len, message->data(), message->size()) <= 0) {
|
|
197
|
+
throw std::runtime_error("Failed to sign message: " + getOpenSSLError());
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
uint8_t* raw_ptr = sig.get();
|
|
201
|
+
return std::make_shared<NativeArrayBuffer>(sig.release(), sig_len, [raw_ptr]() { delete[] raw_ptr; });
|
|
202
|
+
#endif
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
std::shared_ptr<Promise<bool>> HybridSlhDsaKeyPair::verify(const std::shared_ptr<ArrayBuffer>& signature,
|
|
206
|
+
const std::shared_ptr<ArrayBuffer>& message) {
|
|
207
|
+
auto nativeSignature = ToNativeArrayBuffer(signature);
|
|
208
|
+
auto nativeMessage = ToNativeArrayBuffer(message);
|
|
209
|
+
auto self = this->shared_cast<HybridSlhDsaKeyPair>();
|
|
210
|
+
return Promise<bool>::async([self, nativeSignature, nativeMessage]() { return self->verifySync(nativeSignature, nativeMessage); });
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
bool HybridSlhDsaKeyPair::verifySync(const std::shared_ptr<ArrayBuffer>& signature, const std::shared_ptr<ArrayBuffer>& message) {
|
|
214
|
+
#if !RNQC_HAS_SLH_DSA
|
|
215
|
+
throw std::runtime_error("SLH-DSA requires OpenSSL 3.5+");
|
|
216
|
+
#else
|
|
217
|
+
clearOpenSSLErrors();
|
|
218
|
+
checkKeyPair();
|
|
219
|
+
|
|
220
|
+
EVP_MD_CTX_ptr md_ctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
|
|
221
|
+
if (md_ctx == nullptr) {
|
|
222
|
+
throw std::runtime_error("Failed to create verify context");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (EVP_DigestVerifyInit(md_ctx.get(), nullptr, nullptr, nullptr, pkey_.get()) <= 0) {
|
|
226
|
+
throw std::runtime_error("Failed to initialize verification: " + getOpenSSLError());
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
int result = EVP_DigestVerify(md_ctx.get(), signature->data(), signature->size(), message->data(), message->size());
|
|
230
|
+
|
|
231
|
+
if (result < 0) {
|
|
232
|
+
throw std::runtime_error("Verification error: " + getOpenSSLError());
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return result == 1;
|
|
236
|
+
#endif
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
void HybridSlhDsaKeyPair::checkKeyPair() {
|
|
240
|
+
if (!pkey_) {
|
|
241
|
+
throw std::runtime_error("Key pair not initialized");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
} // 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 "HybridSlhDsaKeyPairSpec.hpp"
|
|
8
|
+
|
|
9
|
+
namespace margelo::nitro::crypto {
|
|
10
|
+
|
|
11
|
+
class HybridSlhDsaKeyPair : public HybridSlhDsaKeyPairSpec {
|
|
12
|
+
public:
|
|
13
|
+
HybridSlhDsaKeyPair() : HybridObject(TAG) {}
|
|
14
|
+
~HybridSlhDsaKeyPair() override = default;
|
|
15
|
+
|
|
16
|
+
std::shared_ptr<Promise<void>> generateKeyPair(double publicFormat, double publicType, double privateFormat, double privateType) override;
|
|
17
|
+
|
|
18
|
+
void generateKeyPairSync(double publicFormat, double publicType, double privateFormat, double privateType) override;
|
|
19
|
+
|
|
20
|
+
std::shared_ptr<ArrayBuffer> getPublicKey() override;
|
|
21
|
+
std::shared_ptr<ArrayBuffer> getPrivateKey() override;
|
|
22
|
+
|
|
23
|
+
std::shared_ptr<Promise<std::shared_ptr<ArrayBuffer>>> sign(const std::shared_ptr<ArrayBuffer>& message) override;
|
|
24
|
+
|
|
25
|
+
std::shared_ptr<ArrayBuffer> signSync(const std::shared_ptr<ArrayBuffer>& message) override;
|
|
26
|
+
|
|
27
|
+
std::shared_ptr<Promise<bool>> verify(const std::shared_ptr<ArrayBuffer>& signature,
|
|
28
|
+
const std::shared_ptr<ArrayBuffer>& message) override;
|
|
29
|
+
|
|
30
|
+
bool verifySync(const std::shared_ptr<ArrayBuffer>& signature, const std::shared_ptr<ArrayBuffer>& message) override;
|
|
31
|
+
|
|
32
|
+
void setVariant(const std::string& variant) override;
|
|
33
|
+
|
|
34
|
+
private:
|
|
35
|
+
using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, decltype(&EVP_PKEY_free)>;
|
|
36
|
+
|
|
37
|
+
std::string variant_;
|
|
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
|