/src/duckdb/third_party/mbedtls/mbedtls_wrapper.cpp
Line | Count | Source |
1 | | #include "mbedtls_wrapper.hpp" |
2 | | |
3 | | // otherwise we have different definitions for mbedtls_pk_context / mbedtls_sha256_context |
4 | | #define MBEDTLS_ALLOW_PRIVATE_ACCESS |
5 | | |
6 | | #include "duckdb/common/crypto/md5.hpp" |
7 | | #include "duckdb/common/helper.hpp" |
8 | | #include "mbedtls/md.h" |
9 | | #include "mbedtls/pk.h" |
10 | | #include "mbedtls/sha1.h" |
11 | | #include "mbedtls/sha256.h" |
12 | | #include "mbedtls/cipher.h" |
13 | | |
14 | | #include "duckdb/common/random_engine.hpp" |
15 | | #include "duckdb/common/types/timestamp.hpp" |
16 | | #include "duckdb/main/config.hpp" |
17 | | #include "duckdb/common/encryption_types.hpp" |
18 | | |
19 | | #include <stdexcept> |
20 | | |
21 | | using namespace duckdb_mbedtls; |
22 | | using CipherType = duckdb::EncryptionTypes::CipherType; |
23 | | using EncryptionVersion = duckdb::EncryptionTypes::EncryptionVersion; |
24 | | using MainHeader = duckdb::MainHeader; |
25 | | |
26 | | /* |
27 | | # Command line tricks to help here |
28 | | # Create a new key |
29 | | openssl genrsa -out private.pem 2048 |
30 | | |
31 | | # Export public key |
32 | | openssl rsa -in private.pem -outform PEM -pubout -out public.pem |
33 | | |
34 | | # Calculate digest and write to 'hash' file on command line |
35 | | openssl dgst -binary -sha256 dummy > hash |
36 | | |
37 | | # Calculate signature from hash |
38 | | openssl pkeyutl -sign -in hash -inkey private.pem -pkeyopt digest:sha256 -out dummy.sign |
39 | | */ |
40 | | |
41 | 0 | void MbedTlsWrapper::ComputeSha256Hash(const char *in, size_t in_len, char *out) { |
42 | |
|
43 | 0 | mbedtls_sha256_context sha_context; |
44 | 0 | mbedtls_sha256_init(&sha_context); |
45 | 0 | if (mbedtls_sha256_starts(&sha_context, false) || |
46 | 0 | mbedtls_sha256_update(&sha_context, reinterpret_cast<const unsigned char *>(in), in_len) || |
47 | 0 | mbedtls_sha256_finish(&sha_context, reinterpret_cast<unsigned char *>(out))) { |
48 | 0 | throw std::runtime_error("SHA256 Error"); |
49 | 0 | } |
50 | 0 | mbedtls_sha256_free(&sha_context); |
51 | 0 | } |
52 | | |
53 | 0 | std::string MbedTlsWrapper::ComputeSha256Hash(const std::string &file_content) { |
54 | 0 | std::string hash; |
55 | 0 | hash.resize(MbedTlsWrapper::SHA256_HASH_LENGTH_BYTES); |
56 | 0 | ComputeSha256Hash(file_content.data(), file_content.size(), (char *)hash.data()); |
57 | 0 | return hash; |
58 | 0 | } |
59 | | |
60 | | bool MbedTlsWrapper::IsValidSha256Signature(const std::string &pubkey, const std::string &signature, |
61 | 0 | const std::string &sha256_hash) { |
62 | |
|
63 | 0 | if (signature.size() != 256 || sha256_hash.size() != 32) { |
64 | 0 | throw std::runtime_error("Invalid input lengths, expected signature length 256, got " + |
65 | 0 | std::to_string(signature.size()) + ", hash length 32, got " + |
66 | 0 | std::to_string(sha256_hash.size())); |
67 | 0 | } |
68 | | |
69 | 0 | mbedtls_pk_context pk_context; |
70 | 0 | mbedtls_pk_init(&pk_context); |
71 | |
|
72 | 0 | if (mbedtls_pk_parse_public_key(&pk_context, reinterpret_cast<const unsigned char *>(pubkey.c_str()), |
73 | 0 | pubkey.size() + 1)) { |
74 | 0 | throw std::runtime_error("RSA public key import error"); |
75 | 0 | } |
76 | | |
77 | | // actually verify |
78 | 0 | bool valid = mbedtls_pk_verify(&pk_context, MBEDTLS_MD_SHA256, |
79 | 0 | reinterpret_cast<const unsigned char *>(sha256_hash.data()), sha256_hash.size(), |
80 | 0 | reinterpret_cast<const unsigned char *>(signature.data()), signature.length()) == 0; |
81 | |
|
82 | 0 | mbedtls_pk_free(&pk_context); |
83 | 0 | return valid; |
84 | 0 | } |
85 | | |
86 | | // used in s3fs |
87 | 0 | void MbedTlsWrapper::Hmac256(const char *key, size_t key_len, const char *message, size_t message_len, char *out) { |
88 | 0 | mbedtls_md_context_t hmac_ctx; |
89 | 0 | const mbedtls_md_info_t *md_type = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); |
90 | 0 | if (!md_type) { |
91 | 0 | throw std::runtime_error("failed to init hmac"); |
92 | 0 | } |
93 | | |
94 | 0 | if (mbedtls_md_setup(&hmac_ctx, md_type, 1) || |
95 | 0 | mbedtls_md_hmac_starts(&hmac_ctx, reinterpret_cast<const unsigned char *>(key), key_len) || |
96 | 0 | mbedtls_md_hmac_update(&hmac_ctx, reinterpret_cast<const unsigned char *>(message), message_len) || |
97 | 0 | mbedtls_md_hmac_finish(&hmac_ctx, reinterpret_cast<unsigned char *>(out))) { |
98 | 0 | throw std::runtime_error("HMAC256 Error"); |
99 | 0 | } |
100 | 0 | mbedtls_md_free(&hmac_ctx); |
101 | 0 | } |
102 | | |
103 | 0 | void MbedTlsWrapper::ToBase16(char *in, char *out, size_t len) { |
104 | 0 | static char const HEX_CODES[] = "0123456789abcdef"; |
105 | 0 | size_t i, j; |
106 | |
|
107 | 0 | for (j = i = 0; i < len; i++) { |
108 | 0 | int a = in[i]; |
109 | 0 | out[j++] = HEX_CODES[(a >> 4) & 0xf]; |
110 | 0 | out[j++] = HEX_CODES[a & 0xf]; |
111 | 0 | } |
112 | 0 | } |
113 | | |
114 | | class MbedTLSCryptoHashState : public duckdb::CryptoHashState { |
115 | | public: |
116 | 0 | explicit MbedTLSCryptoHashState(duckdb::CryptoHashFunction function) : duckdb::CryptoHashState(function) { |
117 | 0 | switch (function) { |
118 | 0 | case duckdb::CryptoHashFunction::MD5: |
119 | 0 | break; |
120 | 0 | case duckdb::CryptoHashFunction::SHA1: |
121 | 0 | mbedtls_sha1_init(&sha1_context); |
122 | 0 | break; |
123 | 0 | case duckdb::CryptoHashFunction::SHA256: |
124 | 0 | mbedtls_sha256_init(&sha256_context); |
125 | 0 | break; |
126 | 0 | default: |
127 | 0 | throw duckdb::InternalException("Unsupported crypto hash function"); |
128 | 0 | } |
129 | 0 | } |
130 | | |
131 | 0 | ~MbedTLSCryptoHashState() override { |
132 | 0 | switch (GetFunction()) { |
133 | 0 | case duckdb::CryptoHashFunction::MD5: |
134 | 0 | break; |
135 | 0 | case duckdb::CryptoHashFunction::SHA1: |
136 | 0 | mbedtls_sha1_free(&sha1_context); |
137 | 0 | break; |
138 | 0 | case duckdb::CryptoHashFunction::SHA256: |
139 | 0 | mbedtls_sha256_free(&sha256_context); |
140 | 0 | break; |
141 | 0 | default: |
142 | 0 | break; |
143 | 0 | } |
144 | 0 | } |
145 | | |
146 | 0 | void Hash(duckdb::const_data_ptr_t input, duckdb::idx_t input_len, duckdb::data_ptr_t output) override { |
147 | 0 | switch (GetFunction()) { |
148 | 0 | case duckdb::CryptoHashFunction::MD5: { |
149 | 0 | duckdb::MD5Context context; |
150 | 0 | context.Add(input, input_len); |
151 | 0 | context.Finish(output); |
152 | 0 | return; |
153 | 0 | } |
154 | 0 | case duckdb::CryptoHashFunction::SHA1: |
155 | 0 | if (mbedtls_sha1_starts(&sha1_context) || mbedtls_sha1_update(&sha1_context, input, input_len) || |
156 | 0 | mbedtls_sha1_finish(&sha1_context, output)) { |
157 | 0 | throw std::runtime_error("SHA1 Error"); |
158 | 0 | } |
159 | 0 | return; |
160 | 0 | case duckdb::CryptoHashFunction::SHA256: |
161 | 0 | if (mbedtls_sha256_starts(&sha256_context, false) || |
162 | 0 | mbedtls_sha256_update(&sha256_context, input, input_len) || |
163 | 0 | mbedtls_sha256_finish(&sha256_context, output)) { |
164 | 0 | throw std::runtime_error("SHA256 Error"); |
165 | 0 | } |
166 | 0 | return; |
167 | 0 | default: |
168 | 0 | throw duckdb::InternalException("Unsupported crypto hash function"); |
169 | 0 | } |
170 | 0 | } |
171 | | |
172 | | private: |
173 | | mbedtls_sha1_context sha1_context; |
174 | | mbedtls_sha256_context sha256_context; |
175 | | }; |
176 | | |
177 | | void MbedTlsWrapper::AESStateMBEDTLSFactory::Hash(duckdb::CryptoHashFunction function, duckdb::const_data_ptr_t input, |
178 | 0 | duckdb::idx_t input_len, duckdb::data_ptr_t output) const { |
179 | 0 | switch (function) { |
180 | 0 | case duckdb::CryptoHashFunction::MD5: { |
181 | 0 | duckdb::MD5Context context; |
182 | 0 | context.Add(input, input_len); |
183 | 0 | context.Finish(output); |
184 | 0 | return; |
185 | 0 | } |
186 | 0 | case duckdb::CryptoHashFunction::SHA1: |
187 | 0 | if (mbedtls_sha1(input, input_len, output)) { |
188 | 0 | throw std::runtime_error("SHA1 Error"); |
189 | 0 | } |
190 | 0 | return; |
191 | 0 | case duckdb::CryptoHashFunction::SHA256: |
192 | 0 | if (mbedtls_sha256(input, input_len, output, false)) { |
193 | 0 | throw std::runtime_error("SHA256 Error"); |
194 | 0 | } |
195 | 0 | return; |
196 | 0 | default: |
197 | 0 | throw duckdb::InternalException("Unsupported crypto hash function"); |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | | duckdb::unique_ptr<duckdb::CryptoHashState> |
202 | 0 | MbedTlsWrapper::AESStateMBEDTLSFactory::CreateHashState(duckdb::CryptoHashFunction function) const { |
203 | 0 | return duckdb::make_uniq<MbedTLSCryptoHashState>(function); |
204 | 0 | } |
205 | | |
206 | | void MbedTlsWrapper::AESStateMBEDTLSFactory::Hmac(duckdb::CryptoHashFunction function, duckdb::const_data_ptr_t key, |
207 | | duckdb::idx_t key_len, duckdb::const_data_ptr_t input, |
208 | 0 | duckdb::idx_t input_len, duckdb::data_ptr_t output) const { |
209 | 0 | if (function != duckdb::CryptoHashFunction::SHA256) { |
210 | 0 | throw duckdb::NotImplementedException("MbedTLS HMAC currently only supports SHA256"); |
211 | 0 | } |
212 | 0 | MbedTlsWrapper::Hmac256(duckdb::const_char_ptr_cast(key), key_len, duckdb::const_char_ptr_cast(input), input_len, |
213 | 0 | duckdb::char_ptr_cast(output)); |
214 | 0 | } |
215 | | |
216 | 0 | bool MbedTlsWrapper::AESStateMBEDTLSFactory::SupportsHash(duckdb::CryptoHashFunction function) const { |
217 | 0 | switch (function) { |
218 | 0 | case duckdb::CryptoHashFunction::MD5: |
219 | 0 | case duckdb::CryptoHashFunction::SHA1: |
220 | 0 | case duckdb::CryptoHashFunction::SHA256: |
221 | 0 | return true; |
222 | 0 | default: |
223 | 0 | return false; |
224 | 0 | } |
225 | 0 | } |
226 | | |
227 | 0 | bool MbedTlsWrapper::AESStateMBEDTLSFactory::SupportsHmac(duckdb::CryptoHashFunction function) const { |
228 | 0 | return function == duckdb::CryptoHashFunction::SHA256; |
229 | 0 | } |
230 | | |
231 | 0 | MbedTlsWrapper::SHA256State::SHA256State() : sha_context(new mbedtls_sha256_context()) { |
232 | 0 | auto context = reinterpret_cast<mbedtls_sha256_context *>(sha_context); |
233 | |
|
234 | 0 | mbedtls_sha256_init(context); |
235 | |
|
236 | 0 | if (mbedtls_sha256_starts(context, false)) { |
237 | 0 | throw std::runtime_error("SHA256 Error"); |
238 | 0 | } |
239 | 0 | } |
240 | | |
241 | 0 | MbedTlsWrapper::SHA256State::~SHA256State() { |
242 | 0 | auto context = reinterpret_cast<mbedtls_sha256_context *>(sha_context); |
243 | 0 | mbedtls_sha256_free(context); |
244 | 0 | delete context; |
245 | 0 | } |
246 | | |
247 | 0 | void MbedTlsWrapper::SHA256State::AddString(const std::string &str) { |
248 | 0 | auto context = reinterpret_cast<mbedtls_sha256_context *>(sha_context); |
249 | 0 | if (mbedtls_sha256_update(context, (unsigned char *)str.data(), str.size())) { |
250 | 0 | throw std::runtime_error("SHA256 Error"); |
251 | 0 | } |
252 | 0 | } |
253 | | |
254 | 0 | void MbedTlsWrapper::SHA256State::AddBytes(duckdb::const_data_ptr_t input_bytes, duckdb::idx_t len) { |
255 | 0 | auto context = reinterpret_cast<mbedtls_sha256_context *>(sha_context); |
256 | 0 | if (mbedtls_sha256_update(context, input_bytes, len)) { |
257 | 0 | throw std::runtime_error("SHA256 Error"); |
258 | 0 | } |
259 | 0 | } |
260 | | |
261 | 0 | void MbedTlsWrapper::SHA256State::AddBytes(duckdb::data_ptr_t input_bytes, duckdb::idx_t len) { |
262 | 0 | AddBytes(duckdb::const_data_ptr_t(input_bytes), len); |
263 | 0 | } |
264 | | |
265 | 0 | void MbedTlsWrapper::SHA256State::AddSalt(unsigned char *salt, size_t salt_len) { |
266 | 0 | auto context = reinterpret_cast<mbedtls_sha256_context *>(sha_context); |
267 | 0 | if (mbedtls_sha256_update(context, salt, salt_len)) { |
268 | 0 | throw std::runtime_error("SHA256 Error"); |
269 | 0 | } |
270 | 0 | } |
271 | | |
272 | 0 | void MbedTlsWrapper::SHA256State::FinalizeDerivedKey(duckdb::data_ptr_t hash) { |
273 | 0 | auto context = reinterpret_cast<mbedtls_sha256_context *>(sha_context); |
274 | |
|
275 | 0 | if (mbedtls_sha256_finish(context, (duckdb::data_ptr_t)hash)) { |
276 | 0 | throw std::runtime_error("SHA256 Error"); |
277 | 0 | } |
278 | 0 | } |
279 | | |
280 | 0 | std::string MbedTlsWrapper::SHA256State::Finalize() { |
281 | 0 | auto context = reinterpret_cast<mbedtls_sha256_context *>(sha_context); |
282 | |
|
283 | 0 | std::string hash; |
284 | 0 | hash.resize(MbedTlsWrapper::SHA256_HASH_LENGTH_BYTES); |
285 | |
|
286 | 0 | if (mbedtls_sha256_finish(context, (unsigned char *)hash.data())) { |
287 | 0 | throw std::runtime_error("SHA256 Error"); |
288 | 0 | } |
289 | | |
290 | 0 | return hash; |
291 | 0 | } |
292 | | |
293 | 0 | void MbedTlsWrapper::SHA256State::FinishHex(char *out) { |
294 | 0 | auto context = reinterpret_cast<mbedtls_sha256_context *>(sha_context); |
295 | |
|
296 | 0 | std::string hash; |
297 | 0 | hash.resize(MbedTlsWrapper::SHA256_HASH_LENGTH_BYTES); |
298 | |
|
299 | 0 | if (mbedtls_sha256_finish(context, (unsigned char *)hash.data())) { |
300 | 0 | throw std::runtime_error("SHA256 Error"); |
301 | 0 | } |
302 | | |
303 | 0 | MbedTlsWrapper::ToBase16(const_cast<char *>(hash.c_str()), out, MbedTlsWrapper::SHA256_HASH_LENGTH_BYTES); |
304 | 0 | } |
305 | | |
306 | 0 | MbedTlsWrapper::SHA1State::SHA1State() : sha_context(new mbedtls_sha1_context()) { |
307 | 0 | auto context = reinterpret_cast<mbedtls_sha1_context *>(sha_context); |
308 | |
|
309 | 0 | mbedtls_sha1_init(context); |
310 | |
|
311 | 0 | if (mbedtls_sha1_starts(context)) { |
312 | 0 | throw std::runtime_error("SHA1 Error"); |
313 | 0 | } |
314 | 0 | } |
315 | | |
316 | 0 | MbedTlsWrapper::SHA1State::~SHA1State() { |
317 | 0 | auto context = reinterpret_cast<mbedtls_sha1_context *>(sha_context); |
318 | 0 | mbedtls_sha1_free(context); |
319 | 0 | delete context; |
320 | 0 | } |
321 | | |
322 | 0 | void MbedTlsWrapper::SHA1State::AddString(const std::string &str) { |
323 | 0 | auto context = reinterpret_cast<mbedtls_sha1_context *>(sha_context); |
324 | 0 | if (mbedtls_sha1_update(context, (unsigned char *)str.data(), str.size())) { |
325 | 0 | throw std::runtime_error("SHA1 Error"); |
326 | 0 | } |
327 | 0 | } |
328 | | |
329 | 0 | std::string MbedTlsWrapper::SHA1State::Finalize() { |
330 | 0 | auto context = reinterpret_cast<mbedtls_sha1_context *>(sha_context); |
331 | |
|
332 | 0 | std::string hash; |
333 | 0 | hash.resize(MbedTlsWrapper::SHA1_HASH_LENGTH_BYTES); |
334 | |
|
335 | 0 | if (mbedtls_sha1_finish(context, (unsigned char *)hash.data())) { |
336 | 0 | throw std::runtime_error("SHA1 Error"); |
337 | 0 | } |
338 | | |
339 | 0 | return hash; |
340 | 0 | } |
341 | | |
342 | 0 | void MbedTlsWrapper::SHA1State::FinishHex(char *out) { |
343 | 0 | auto context = reinterpret_cast<mbedtls_sha1_context *>(sha_context); |
344 | |
|
345 | 0 | std::string hash; |
346 | 0 | hash.resize(MbedTlsWrapper::SHA1_HASH_LENGTH_BYTES); |
347 | |
|
348 | 0 | if (mbedtls_sha1_finish(context, (unsigned char *)hash.data())) { |
349 | 0 | throw std::runtime_error("SHA1 Error"); |
350 | 0 | } |
351 | | |
352 | 0 | MbedTlsWrapper::ToBase16(const_cast<char *>(hash.c_str()), out, MbedTlsWrapper::SHA1_HASH_LENGTH_BYTES); |
353 | 0 | } |
354 | | |
355 | 0 | const mbedtls_cipher_info_t *MbedTlsWrapper::AESStateMBEDTLS::GetCipher(){ |
356 | 0 | switch(metadata->GetCipher()) { |
357 | 0 | case CipherType::GCM: |
358 | 0 | switch (metadata->GetKeyLen()) { |
359 | 0 | case 16: |
360 | 0 | return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_GCM); |
361 | 0 | case 24: |
362 | 0 | return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_192_GCM); |
363 | 0 | case 32: |
364 | 0 | return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_GCM); |
365 | 0 | default: |
366 | 0 | throw std::runtime_error("Invalid AES key length for GCM"); |
367 | 0 | } |
368 | 0 | case CipherType::CTR: |
369 | 0 | switch (metadata->GetKeyLen()) { |
370 | 0 | case 16: |
371 | 0 | return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CTR); |
372 | 0 | case 24: |
373 | 0 | return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_192_CTR); |
374 | 0 | case 32: |
375 | 0 | return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_CTR); |
376 | 0 | default: |
377 | 0 | throw std::runtime_error("Invalid AES key length for CTR"); |
378 | 0 | } |
379 | 0 | case CipherType::CBC: |
380 | 0 | switch (metadata->GetKeyLen()) { |
381 | 0 | case 16: |
382 | 0 | return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CBC); |
383 | 0 | case 24: |
384 | 0 | return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_192_CBC); |
385 | 0 | case 32: |
386 | 0 | return mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_CBC); |
387 | 0 | default: |
388 | 0 | throw std::runtime_error("Invalid AES key length for CBC"); |
389 | 0 | } |
390 | 0 | default: |
391 | 0 | throw duckdb::InternalException("Invalid Encryption/Decryption Cipher: %s", duckdb::EncryptionTypes::CipherToString(metadata->GetCipher())); |
392 | 0 | } |
393 | 0 | } |
394 | | |
395 | 0 | void MbedTlsWrapper::AESStateMBEDTLS::SecureClearData(duckdb::data_ptr_t data, duckdb::idx_t len) { |
396 | 0 | mbedtls_platform_zeroize(data, len); |
397 | 0 | } |
398 | | |
399 | 0 | MbedTlsWrapper::AESStateMBEDTLS::AESStateMBEDTLS(duckdb::unique_ptr<duckdb::EncryptionStateMetadata> metadata_p) : EncryptionState(std::move(metadata_p)), context(duckdb::make_uniq<mbedtls_cipher_context_t>()) { |
400 | 0 | mbedtls_cipher_init(context.get()); |
401 | |
|
402 | 0 | auto cipher_info = GetCipher(); |
403 | |
|
404 | 0 | if (!cipher_info) { |
405 | 0 | throw std::runtime_error("Failed to get Cipher"); |
406 | 0 | } |
407 | | |
408 | 0 | if (mbedtls_cipher_setup(context.get(), cipher_info)) { |
409 | 0 | throw std::runtime_error("Failed to initialize cipher context"); |
410 | 0 | } |
411 | | |
412 | 0 | if (metadata->GetCipher() == duckdb::EncryptionTypes::CBC && mbedtls_cipher_set_padding_mode(context.get(), MBEDTLS_PADDING_PKCS7)) { |
413 | 0 | throw std::runtime_error("Failed to set CBC padding"); |
414 | |
|
415 | 0 | } |
416 | 0 | } |
417 | | |
418 | 0 | MbedTlsWrapper::AESStateMBEDTLS::~AESStateMBEDTLS() { |
419 | 0 | if (context) { |
420 | 0 | mbedtls_cipher_free(context.get()); |
421 | 0 | } |
422 | 0 | } |
423 | | |
424 | 0 | void MbedTlsWrapper::AESStateMBEDTLS::GenerateRandomDataInsecure(duckdb::data_ptr_t data, duckdb::idx_t len) { |
425 | 0 | if (!force_mbedtls) { |
426 | | // To use this insecure MbedTLS random number generator |
427 | | // we double check if force_mbedtls_unsafe is set |
428 | | // such that we do not accidentaly opt-in |
429 | 0 | throw duckdb::InternalException("Insecure random generation called without setting 'force_mbedtls_unsafe' = true"); |
430 | 0 | } |
431 | | |
432 | 0 | duckdb::RandomEngine random_engine; |
433 | |
|
434 | 0 | while (len != 0) { |
435 | 0 | const auto random_integer = random_engine.NextRandomInteger(); |
436 | 0 | const auto next = duckdb::MinValue<duckdb::idx_t>(len, sizeof(random_integer)); |
437 | 0 | memcpy(data, duckdb::const_data_ptr_cast(&random_integer), next); |
438 | 0 | data += next; |
439 | 0 | len -= next; |
440 | 0 | } |
441 | 0 | } |
442 | | |
443 | 0 | void MbedTlsWrapper::AESStateMBEDTLS::GenerateRandomData(duckdb::data_ptr_t data, duckdb::idx_t len) { |
444 | | // generate insecure random data |
445 | 0 | GenerateRandomDataInsecure(data, len); |
446 | 0 | } |
447 | | |
448 | 0 | void MbedTlsWrapper::AESStateMBEDTLS::InitializeInternal(duckdb::EncryptionNonce &nonce, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len){ |
449 | 0 | if (mbedtls_cipher_set_iv(context.get(), nonce.data(), nonce.total_size())) { |
450 | 0 | throw std::runtime_error("Failed to set IV for encryption"); |
451 | 0 | } |
452 | | |
453 | 0 | if (aad_len > 0) { |
454 | 0 | if (mbedtls_cipher_update_ad(context.get(), aad, aad_len)) { |
455 | 0 | throw std::runtime_error("Failed to set AAD"); |
456 | 0 | } |
457 | 0 | } |
458 | 0 | } |
459 | | |
460 | 0 | void MbedTlsWrapper::AESStateMBEDTLS::InitializeEncryption(duckdb::EncryptionNonce &nonce, duckdb::const_data_ptr_t key, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len) { |
461 | 0 | mode = duckdb::EncryptionTypes::ENCRYPT; |
462 | |
|
463 | 0 | if (mbedtls_cipher_setkey(context.get(), key, metadata->GetKeyLen() * 8, MBEDTLS_ENCRYPT) != 0) { |
464 | 0 | throw std::runtime_error("Failed to set AES key for encryption"); |
465 | 0 | } |
466 | | |
467 | 0 | InitializeInternal(nonce, aad, aad_len); |
468 | 0 | } |
469 | | |
470 | 0 | void MbedTlsWrapper::AESStateMBEDTLS::InitializeDecryption(duckdb::EncryptionNonce &nonce, duckdb::const_data_ptr_t key, duckdb::const_data_ptr_t aad, duckdb::idx_t aad_len) { |
471 | 0 | mode = duckdb::EncryptionTypes::DECRYPT; |
472 | |
|
473 | 0 | if (mbedtls_cipher_setkey(context.get(), key, metadata->GetKeyLen() * 8, MBEDTLS_DECRYPT)) { |
474 | 0 | throw std::runtime_error("Failed to set AES key for encryption"); |
475 | 0 | } |
476 | | |
477 | 0 | InitializeInternal(nonce, aad, aad_len); |
478 | 0 | } |
479 | | |
480 | | size_t MbedTlsWrapper::AESStateMBEDTLS::Process(duckdb::const_data_ptr_t in, duckdb::idx_t in_len, duckdb::data_ptr_t out, |
481 | 0 | duckdb::idx_t out_len) { |
482 | | |
483 | | // GCM works in-place, CTR and CBC don't |
484 | 0 | auto use_out_copy = in == out && metadata->GetCipher() != CipherType::GCM; |
485 | |
|
486 | 0 | auto out_ptr = out; |
487 | 0 | std::unique_ptr<duckdb::data_t[]> out_copy; |
488 | 0 | if (use_out_copy) { |
489 | 0 | out_copy.reset(new duckdb::data_t[out_len]); |
490 | 0 | out_ptr = out_copy.get(); |
491 | 0 | } |
492 | |
|
493 | 0 | size_t out_len_res = duckdb::NumericCast<size_t>(out_len); |
494 | 0 | if (mbedtls_cipher_update(context.get(), reinterpret_cast<const unsigned char *>(in), in_len, out_ptr, |
495 | 0 | &out_len_res)) { |
496 | 0 | throw std::runtime_error("Encryption or Decryption failed at Process"); |
497 | 0 | }; |
498 | |
|
499 | 0 | if (use_out_copy) { |
500 | 0 | memcpy(out, out_ptr, out_len_res); |
501 | 0 | } |
502 | 0 | return out_len_res; |
503 | 0 | } |
504 | | |
505 | 0 | void MbedTlsWrapper::AESStateMBEDTLS::FinalizeGCM(duckdb::data_ptr_t tag, duckdb::idx_t tag_len){ |
506 | |
|
507 | 0 | switch (mode) { |
508 | | |
509 | 0 | case duckdb::EncryptionTypes::ENCRYPT: { |
510 | 0 | if (mbedtls_cipher_write_tag(context.get(), tag, tag_len)) { |
511 | 0 | throw std::runtime_error("Writing tag failed"); |
512 | 0 | } |
513 | 0 | break; |
514 | 0 | } |
515 | | |
516 | 0 | case duckdb::EncryptionTypes::DECRYPT: { |
517 | 0 | if (mbedtls_cipher_check_tag(context.get(), tag, tag_len)) { |
518 | 0 | throw duckdb::InvalidInputException( |
519 | 0 | "Computed AES tag differs from read AES tag, are you using the right key?"); |
520 | 0 | } |
521 | 0 | break; |
522 | 0 | } |
523 | | |
524 | 0 | default: |
525 | 0 | throw duckdb::InternalException("Unhandled encryption mode %d", static_cast<int>(mode)); |
526 | 0 | } |
527 | 0 | } |
528 | | |
529 | | size_t MbedTlsWrapper::AESStateMBEDTLS::Finalize(duckdb::data_ptr_t out, duckdb::idx_t out_len, duckdb::data_ptr_t tag, |
530 | 0 | duckdb::idx_t tag_len) { |
531 | 0 | size_t result = out_len; |
532 | 0 | if (mbedtls_cipher_finish(context.get(), out, &result)) { |
533 | 0 | throw std::runtime_error("Encryption or Decryption failed at Finalize"); |
534 | 0 | } |
535 | 0 | if (metadata->GetCipher() == duckdb::EncryptionTypes::GCM) { |
536 | 0 | FinalizeGCM(tag, tag_len); |
537 | 0 | } |
538 | 0 | return result; |
539 | 0 | } |