|
8 | 8 | namespace margelo::nitro::crypto { |
9 | 9 |
|
10 | 10 | HybridCipher::~HybridCipher() { |
11 | | - if (this->ctx) { |
12 | | - EVP_CIPHER_CTX_free(this->ctx); |
| 11 | + if (ctx) { |
| 12 | + EVP_CIPHER_CTX_free(ctx); |
13 | 13 | } |
14 | | - if (this->cipher) { |
15 | | - EVP_CIPHER_free(this->cipher); |
| 14 | +} |
| 15 | + |
| 16 | +void |
| 17 | +HybridCipher::init() { |
| 18 | + // check if args are set |
| 19 | + if (!args.has_value()) { |
| 20 | + throw std::runtime_error("CipherArgs not set"); |
16 | 21 | } |
| 22 | + const auto& argsRef = args.value(); |
| 23 | + |
| 24 | + // fetch cipher |
| 25 | + EVP_CIPHER *cipher = EVP_CIPHER_fetch( |
| 26 | + nullptr, |
| 27 | + argsRef.cipherType.c_str(), |
| 28 | + nullptr |
| 29 | + ); |
| 30 | + if (cipher == nullptr) { |
| 31 | + throw std::runtime_error("Invalid Cipher Algorithm: " + argsRef.cipherType); |
| 32 | + } |
| 33 | + |
| 34 | + // Create cipher context |
| 35 | + ctx = EVP_CIPHER_CTX_new(); |
| 36 | + if (!ctx) { |
| 37 | + EVP_CIPHER_free(cipher); |
| 38 | + throw std::runtime_error("Failed to create cipher context"); |
| 39 | + } |
| 40 | + |
| 41 | + // Initialize cipher operation |
| 42 | + if ( |
| 43 | + EVP_CipherInit_ex2( |
| 44 | + ctx, |
| 45 | + cipher, |
| 46 | + argsRef.cipherKey->data(), |
| 47 | + argsRef.iv->data(), |
| 48 | + argsRef.isCipher ? 1 : 0, |
| 49 | + nullptr |
| 50 | + ) != 1 |
| 51 | + ) { |
| 52 | + EVP_CIPHER_CTX_free(ctx); |
| 53 | + EVP_CIPHER_free(cipher); |
| 54 | + ctx = nullptr; |
| 55 | + throw std::runtime_error("Failed to initialize encryption"); |
| 56 | + } |
| 57 | + |
| 58 | + EVP_CIPHER_free(cipher); |
17 | 59 | } |
18 | 60 |
|
19 | 61 | std::shared_ptr<ArrayBuffer> |
20 | 62 | HybridCipher::update( |
21 | 63 | const std::shared_ptr<ArrayBuffer>& data |
22 | 64 | ) { |
23 | | - return nullptr; |
| 65 | + if (!ctx) { |
| 66 | + throw std::runtime_error("Cipher not initialized. Did you call setArgs()?"); |
| 67 | + } |
| 68 | + |
| 69 | + // Calculate the maximum output length |
| 70 | + int outLen = data->size() + EVP_MAX_BLOCK_LENGTH; |
| 71 | + int updateLen = 0; |
| 72 | + |
| 73 | + // Create a temporary buffer for the operation |
| 74 | + unsigned char* tempBuf = new unsigned char[outLen]; |
| 75 | + |
| 76 | + // Perform the cipher update operation |
| 77 | + if ( |
| 78 | + EVP_CipherUpdate( |
| 79 | + ctx, |
| 80 | + tempBuf, |
| 81 | + &updateLen, |
| 82 | + reinterpret_cast<const unsigned char*>(data->data()), |
| 83 | + data->size() |
| 84 | + ) != 1 |
| 85 | + ) { |
| 86 | + delete[] tempBuf; |
| 87 | + throw std::runtime_error("Failed to update cipher"); |
| 88 | + } |
| 89 | + |
| 90 | + // Create and return a new buffer of exact size needed |
| 91 | + return std::make_shared<NativeArrayBuffer>( |
| 92 | + tempBuf, |
| 93 | + updateLen, |
| 94 | + [=]() { delete[] tempBuf; } |
| 95 | + ); |
24 | 96 | } |
25 | 97 |
|
26 | 98 | std::shared_ptr<ArrayBuffer> |
27 | 99 | HybridCipher::final() { |
28 | | - return nullptr; |
| 100 | + if (!ctx) { |
| 101 | + throw std::runtime_error("Cipher not initialized. Did you call setArgs()?"); |
| 102 | + } |
| 103 | + |
| 104 | + int finalLen = 0; |
| 105 | + unsigned char tempBuf[EVP_MAX_BLOCK_LENGTH]; |
| 106 | + |
| 107 | + // Finalize the encryption/decryption |
| 108 | + if (EVP_CipherFinal_ex( |
| 109 | + ctx, |
| 110 | + tempBuf, |
| 111 | + &finalLen) != 1) { |
| 112 | + throw std::runtime_error("Failed to finalize cipher"); |
| 113 | + } |
| 114 | + |
| 115 | + // Create and return a new buffer of exact size needed |
| 116 | + return std::make_shared<NativeArrayBuffer>( |
| 117 | + tempBuf, |
| 118 | + finalLen, |
| 119 | + nullptr |
| 120 | + ); |
29 | 121 | } |
30 | 122 |
|
31 | 123 | void |
32 | | -HybridCipher::copy() {} |
| 124 | +HybridCipher::copy() { /* TODO */ } |
33 | 125 |
|
34 | 126 | bool |
35 | 127 | HybridCipher::setAAD( |
@@ -62,49 +154,21 @@ void |
62 | 154 | HybridCipher::setArgs( |
63 | 155 | const CipherArgs& args |
64 | 156 | ) { |
65 | | - this->args = args; |
66 | | - init(); |
67 | | -} |
68 | | - |
69 | | -void |
70 | | -HybridCipher::init() { |
71 | | - // check if args are set |
72 | | - if (!args.has_value()) { |
73 | | - throw std::runtime_error("CipherArgs not set"); |
| 157 | + if (this->args.has_value()) { |
| 158 | + // Reset existing value if any |
| 159 | + this->args.reset(); |
74 | 160 | } |
75 | | - auto args = this->args.value(); |
76 | 161 |
|
77 | | - // fetch cipher |
78 | | - this->cipher = EVP_CIPHER_fetch( |
79 | | - nullptr, |
80 | | - args.cipherType.c_str(), |
81 | | - nullptr |
82 | | - ); |
83 | | - if (cipher == nullptr) { |
84 | | - throw std::runtime_error("Invalid Cipher Algorithm: " + args.cipherType); |
85 | | - } |
86 | | - |
87 | | - // Create cipher context |
88 | | - this->ctx = EVP_CIPHER_CTX_new(); |
89 | | - if (!this->ctx) { |
90 | | - throw std::runtime_error("Failed to create cipher context"); |
91 | | - } |
| 162 | + // Use std::optional::emplace with direct member initialization |
| 163 | + this->args.emplace(CipherArgs{ |
| 164 | + args.isCipher, |
| 165 | + args.cipherType, |
| 166 | + args.cipherKey, |
| 167 | + args.iv, |
| 168 | + args.authTagLen |
| 169 | + }); |
92 | 170 |
|
93 | | - // Initialize cipher operation |
94 | | - if ( |
95 | | - EVP_CipherInit_ex2( |
96 | | - this->ctx, |
97 | | - this->cipher, |
98 | | - this->args->cipherKey->data(), |
99 | | - this->args->iv->data(), |
100 | | - this->args->isCipher ? 1 : 0, |
101 | | - nullptr |
102 | | - ) != 1 |
103 | | - ) { |
104 | | - EVP_CIPHER_CTX_free(this->ctx); |
105 | | - this->ctx = nullptr; |
106 | | - throw std::runtime_error("Failed to initialize encryption"); |
107 | | - } |
| 171 | + init(); |
108 | 172 | } |
109 | 173 |
|
110 | 174 | void collect_ciphers(EVP_CIPHER *cipher, void *arg) { |
|
0 commit comments