1 | /* |
2 | * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"). |
5 | * You may not use this file except in compliance with the License. |
6 | * A copy of the License is located at |
7 | * |
8 | * http://aws.amazon.com/apache2.0 |
9 | * |
10 | * or in the "license" file accompanying this file. This file is distributed |
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
12 | * express or implied. See the License for the specific language governing |
13 | * permissions and limitations under the License. |
14 | */ |
15 | |
16 | #include <cstring> |
17 | |
18 | #include <aws/core/utils/memory/AWSMemory.h> |
19 | #include <aws/core/utils/crypto/openssl/CryptoImpl.h> |
20 | #include <aws/core/utils/Outcome.h> |
21 | #include <openssl/md5.h> |
22 | |
23 | #ifdef OPENSSL_IS_BORINGSSL |
24 | #ifdef _MSC_VER |
25 | AWS_SUPPRESS_WARNING_PUSH(4201) |
26 | #else |
27 | AWS_SUPPRESS_WARNING_PUSH("-Wpedantic" ) |
28 | #endif |
29 | #endif |
30 | |
31 | #include <openssl/sha.h> |
32 | |
33 | #ifdef OPENSSL_IS_BORINGSSL |
34 | AWS_SUPPRESS_WARNING_POP |
35 | #endif |
36 | |
37 | #include <openssl/err.h> |
38 | #include <aws/core/utils/logging/LogMacros.h> |
39 | #include <thread> |
40 | |
41 | using namespace Aws::Utils; |
42 | using namespace Aws::Utils::Crypto; |
43 | |
44 | namespace Aws |
45 | { |
46 | namespace Utils |
47 | { |
48 | namespace Crypto |
49 | { |
50 | namespace OpenSSL |
51 | { |
52 | /** |
53 | * openssl with OPENSSL_VERSION_NUMBER < 0x10100003L made data type details unavailable |
54 | * libressl use openssl with data type details available, but mandatorily set |
55 | * OPENSSL_VERSION_NUMBER = 0x20000000L, insane! |
56 | * https://github.com/aws/aws-sdk-cpp/pull/507/commits/2c99f1fe0c4b4683280caeb161538d4724d6a179 |
57 | */ |
58 | #if defined(LIBRESSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER == 0x20000000L) |
59 | #undef OPENSSL_VERSION_NUMBER |
60 | #define OPENSSL_VERSION_NUMBER 0x1000107fL |
61 | #endif |
62 | #define OPENSSL_VERSION_LESS_1_1 (OPENSSL_VERSION_NUMBER < 0x10100003L) |
63 | |
64 | #if OPENSSL_VERSION_LESS_1_1 |
65 | static const char* OPENSSL_INTERNALS_TAG = "OpenSSLCallbackState" ; |
66 | static std::mutex* locks(nullptr); |
67 | #endif |
68 | |
69 | GetTheLights getTheLights; |
70 | |
71 | void init_static_state() |
72 | { |
73 | #if OPENSSL_VERSION_LESS_1_1 || defined(OPENSSL_IS_BORINGSSL) |
74 | ERR_load_crypto_strings(); |
75 | #else |
76 | OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS /*options*/ ,NULL /* OpenSSL init settings*/ ); |
77 | #endif |
78 | #if !defined(OPENSSL_IS_BORINGSSL) |
79 | OPENSSL_add_all_algorithms_noconf(); |
80 | #endif |
81 | #if OPENSSL_VERSION_LESS_1_1 |
82 | if (!CRYPTO_get_locking_callback()) |
83 | { |
84 | locks = Aws::NewArray<std::mutex>(static_cast<size_t>(CRYPTO_num_locks()), |
85 | OPENSSL_INTERNALS_TAG); |
86 | CRYPTO_set_locking_callback(&locking_fn); |
87 | } |
88 | |
89 | if (!CRYPTO_get_id_callback()) |
90 | { |
91 | CRYPTO_set_id_callback(&id_fn); |
92 | } |
93 | #endif |
94 | RAND_poll(); |
95 | } |
96 | |
97 | void cleanup_static_state() |
98 | { |
99 | #if OPENSSL_VERSION_LESS_1_1 |
100 | if (CRYPTO_get_locking_callback() == &locking_fn) |
101 | { |
102 | CRYPTO_set_locking_callback(nullptr); |
103 | assert(locks); |
104 | Aws::DeleteArray(locks); |
105 | locks = nullptr; |
106 | } |
107 | |
108 | if (CRYPTO_get_id_callback() == &id_fn) |
109 | { |
110 | CRYPTO_set_id_callback(nullptr); |
111 | } |
112 | #endif |
113 | } |
114 | |
115 | #if OPENSSL_VERSION_LESS_1_1 |
116 | void locking_fn(int mode, int n, const char*, int) |
117 | { |
118 | if (mode & CRYPTO_LOCK) |
119 | { |
120 | locks[n].lock(); |
121 | } |
122 | else |
123 | { |
124 | locks[n].unlock(); |
125 | } |
126 | } |
127 | |
128 | unsigned long id_fn() |
129 | { |
130 | return static_cast<unsigned long>(std::hash<std::thread::id>()(std::this_thread::get_id())); |
131 | } |
132 | #endif |
133 | } |
134 | |
135 | void SecureRandomBytes_OpenSSLImpl::GetBytes(unsigned char* buffer, size_t bufferSize) |
136 | { |
137 | assert(buffer); |
138 | |
139 | int success = RAND_bytes(buffer, static_cast<int>(bufferSize)); |
140 | if (success != 1) |
141 | { |
142 | m_failure = true; |
143 | } |
144 | } |
145 | |
146 | class OpensslCtxRAIIGuard |
147 | { |
148 | public: |
149 | OpensslCtxRAIIGuard() |
150 | { |
151 | m_ctx = EVP_MD_CTX_create(); |
152 | assert(m_ctx != nullptr); |
153 | } |
154 | |
155 | ~OpensslCtxRAIIGuard() |
156 | { |
157 | EVP_MD_CTX_destroy(m_ctx); |
158 | m_ctx = nullptr; |
159 | } |
160 | |
161 | EVP_MD_CTX* getResource() |
162 | { |
163 | return m_ctx; |
164 | } |
165 | private: |
166 | EVP_MD_CTX *m_ctx; |
167 | }; |
168 | |
169 | HashResult MD5OpenSSLImpl::Calculate(const Aws::String& str) |
170 | { |
171 | OpensslCtxRAIIGuard guard; |
172 | auto ctx = guard.getResource(); |
173 | #if !defined(OPENSSL_IS_BORINGSSL) |
174 | EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); |
175 | #endif |
176 | EVP_DigestInit_ex(ctx, EVP_md5(), nullptr); |
177 | EVP_DigestUpdate(ctx, str.c_str(), str.size()); |
178 | |
179 | ByteBuffer hash(EVP_MD_size(EVP_md5())); |
180 | EVP_DigestFinal(ctx, hash.GetUnderlyingData(), nullptr); |
181 | |
182 | return HashResult(std::move(hash)); |
183 | } |
184 | |
185 | HashResult MD5OpenSSLImpl::Calculate(Aws::IStream& stream) |
186 | { |
187 | OpensslCtxRAIIGuard guard; |
188 | auto ctx = guard.getResource(); |
189 | #if !defined(OPENSSL_IS_BORINGSSL) |
190 | EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); |
191 | #endif |
192 | EVP_DigestInit_ex(ctx, EVP_md5(), nullptr); |
193 | |
194 | auto currentPos = stream.tellg(); |
195 | if (currentPos == -1) |
196 | { |
197 | currentPos = 0; |
198 | stream.clear(); |
199 | } |
200 | stream.seekg(0, stream.beg); |
201 | |
202 | char streamBuffer[Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE]; |
203 | while (stream.good()) |
204 | { |
205 | stream.read(streamBuffer, Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE); |
206 | auto bytesRead = stream.gcount(); |
207 | |
208 | if (bytesRead > 0) |
209 | { |
210 | EVP_DigestUpdate(ctx, streamBuffer, static_cast<size_t>(bytesRead)); |
211 | } |
212 | } |
213 | |
214 | stream.clear(); |
215 | stream.seekg(currentPos, stream.beg); |
216 | |
217 | ByteBuffer hash(EVP_MD_size(EVP_md5())); |
218 | EVP_DigestFinal(ctx, hash.GetUnderlyingData(), nullptr); |
219 | |
220 | return HashResult(std::move(hash)); |
221 | } |
222 | |
223 | HashResult Sha256OpenSSLImpl::Calculate(const Aws::String& str) |
224 | { |
225 | OpensslCtxRAIIGuard guard; |
226 | auto ctx = guard.getResource(); |
227 | EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr); |
228 | EVP_DigestUpdate(ctx, str.c_str(), str.size()); |
229 | |
230 | ByteBuffer hash(EVP_MD_size(EVP_sha256())); |
231 | EVP_DigestFinal(ctx, hash.GetUnderlyingData(), nullptr); |
232 | |
233 | return HashResult(std::move(hash)); |
234 | } |
235 | |
236 | HashResult Sha256OpenSSLImpl::Calculate(Aws::IStream& stream) |
237 | { |
238 | OpensslCtxRAIIGuard guard; |
239 | auto ctx = guard.getResource(); |
240 | |
241 | EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr); |
242 | |
243 | auto currentPos = stream.tellg(); |
244 | if (currentPos == -1) |
245 | { |
246 | currentPos = 0; |
247 | stream.clear(); |
248 | } |
249 | |
250 | stream.seekg(0, stream.beg); |
251 | |
252 | char streamBuffer[Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE]; |
253 | while (stream.good()) |
254 | { |
255 | stream.read(streamBuffer, Aws::Utils::Crypto::Hash::INTERNAL_HASH_STREAM_BUFFER_SIZE); |
256 | auto bytesRead = stream.gcount(); |
257 | |
258 | if (bytesRead > 0) |
259 | { |
260 | EVP_DigestUpdate(ctx, streamBuffer, static_cast<size_t>(bytesRead)); |
261 | } |
262 | } |
263 | |
264 | stream.clear(); |
265 | stream.seekg(currentPos, stream.beg); |
266 | |
267 | ByteBuffer hash(EVP_MD_size(EVP_sha256())); |
268 | EVP_DigestFinal(ctx, hash.GetUnderlyingData(), nullptr); |
269 | |
270 | return HashResult(std::move(hash)); |
271 | } |
272 | |
273 | class HMACRAIIGuard { |
274 | public: |
275 | HMACRAIIGuard() { |
276 | #if OPENSSL_VERSION_LESS_1_1 |
277 | m_ctx = Aws::New<HMAC_CTX>("AllocSha256HAMCOpenSSLContext" ); |
278 | #else |
279 | m_ctx = HMAC_CTX_new(); |
280 | #endif |
281 | assert(m_ctx != nullptr); |
282 | } |
283 | |
284 | ~HMACRAIIGuard() { |
285 | #if OPENSSL_VERSION_LESS_1_1 |
286 | Aws::Delete<HMAC_CTX>(m_ctx); |
287 | #else |
288 | HMAC_CTX_free(m_ctx); |
289 | #endif |
290 | m_ctx = nullptr; |
291 | } |
292 | |
293 | HMAC_CTX* getResource() { |
294 | return m_ctx; |
295 | } |
296 | private: |
297 | HMAC_CTX *m_ctx; |
298 | }; |
299 | |
300 | HashResult Sha256HMACOpenSSLImpl::Calculate(const ByteBuffer& toSign, const ByteBuffer& secret) |
301 | { |
302 | unsigned int length = SHA256_DIGEST_LENGTH; |
303 | ByteBuffer digest(length); |
304 | memset(digest.GetUnderlyingData(), 0, length); |
305 | |
306 | HMACRAIIGuard guard; |
307 | HMAC_CTX* m_ctx = guard.getResource(); |
308 | |
309 | #if OPENSSL_VERSION_LESS_1_1 |
310 | HMAC_CTX_init(m_ctx); |
311 | #endif |
312 | |
313 | HMAC_Init_ex(m_ctx, secret.GetUnderlyingData(), static_cast<int>(secret.GetLength()), EVP_sha256(), |
314 | NULL); |
315 | HMAC_Update(m_ctx, toSign.GetUnderlyingData(), toSign.GetLength()); |
316 | HMAC_Final(m_ctx, digest.GetUnderlyingData(), &length); |
317 | |
318 | #if OPENSSL_VERSION_LESS_1_1 |
319 | HMAC_CTX_cleanup(m_ctx); |
320 | #else |
321 | HMAC_CTX_reset(m_ctx); |
322 | #endif |
323 | return HashResult(std::move(digest)); |
324 | } |
325 | |
326 | static const char* OPENSSL_LOG_TAG = "OpenSSLCipher" ; |
327 | |
328 | void LogErrors(const char* logTag = OPENSSL_LOG_TAG) |
329 | { |
330 | unsigned long errorCode = ERR_get_error(); |
331 | char errStr[256]; |
332 | ERR_error_string_n(errorCode, errStr, 256); |
333 | |
334 | AWS_LOGSTREAM_ERROR(logTag, errStr); |
335 | } |
336 | |
337 | OpenSSLCipher::OpenSSLCipher(const CryptoBuffer& key, size_t blockSizeBytes, bool ctrMode) : |
338 | SymmetricCipher(key, blockSizeBytes, ctrMode), m_encryptor_ctx(nullptr), m_decryptor_ctx(nullptr) |
339 | { |
340 | Init(); |
341 | } |
342 | |
343 | OpenSSLCipher::OpenSSLCipher(OpenSSLCipher&& toMove) : SymmetricCipher(std::move(toMove)), |
344 | m_encryptor_ctx(nullptr), m_decryptor_ctx(nullptr) |
345 | { |
346 | Init(); |
347 | EVP_CIPHER_CTX_copy(m_encryptor_ctx, toMove.m_encryptor_ctx); |
348 | EVP_CIPHER_CTX_copy(m_decryptor_ctx, toMove.m_decryptor_ctx); |
349 | EVP_CIPHER_CTX_cleanup(toMove.m_encryptor_ctx); |
350 | EVP_CIPHER_CTX_cleanup(toMove.m_decryptor_ctx); |
351 | } |
352 | |
353 | OpenSSLCipher::OpenSSLCipher(CryptoBuffer&& key, CryptoBuffer&& initializationVector, CryptoBuffer&& tag) : |
354 | SymmetricCipher(std::move(key), std::move(initializationVector), std::move(tag)), |
355 | m_encryptor_ctx(nullptr), m_decryptor_ctx(nullptr) |
356 | { |
357 | Init(); |
358 | } |
359 | |
360 | OpenSSLCipher::OpenSSLCipher(const CryptoBuffer& key, const CryptoBuffer& initializationVector, |
361 | const CryptoBuffer& tag) : |
362 | SymmetricCipher(key, initializationVector, tag), m_encryptor_ctx(nullptr), m_decryptor_ctx(nullptr) |
363 | { |
364 | Init(); |
365 | } |
366 | |
367 | OpenSSLCipher::~OpenSSLCipher() |
368 | { |
369 | Cleanup(); |
370 | if (m_encryptor_ctx) |
371 | { |
372 | EVP_CIPHER_CTX_free(m_encryptor_ctx); |
373 | m_encryptor_ctx = nullptr; |
374 | } |
375 | if (m_decryptor_ctx) |
376 | { |
377 | EVP_CIPHER_CTX_free(m_decryptor_ctx); |
378 | m_decryptor_ctx = nullptr; |
379 | } |
380 | } |
381 | |
382 | void OpenSSLCipher::Init() |
383 | { |
384 | if (!m_encryptor_ctx) |
385 | { |
386 | // EVP_CIPHER_CTX_init() will be called inside EVP_CIPHER_CTX_new(). |
387 | m_encryptor_ctx = EVP_CIPHER_CTX_new(); |
388 | assert(m_encryptor_ctx != nullptr); |
389 | } |
390 | else |
391 | { // _init is the same as _reset after openssl 1.1 |
392 | EVP_CIPHER_CTX_init(m_encryptor_ctx); |
393 | } |
394 | if (!m_decryptor_ctx) |
395 | { |
396 | // EVP_CIPHER_CTX_init() will be called inside EVP_CIPHER_CTX_new(). |
397 | m_decryptor_ctx = EVP_CIPHER_CTX_new(); |
398 | assert(m_decryptor_ctx != nullptr); |
399 | } |
400 | else |
401 | { // _init is the same as _reset after openssl 1.1 |
402 | EVP_CIPHER_CTX_init(m_decryptor_ctx); |
403 | } |
404 | } |
405 | |
406 | CryptoBuffer OpenSSLCipher::EncryptBuffer(const CryptoBuffer& unEncryptedData) |
407 | { |
408 | if (m_failure) |
409 | { |
410 | AWS_LOGSTREAM_FATAL(OPENSSL_LOG_TAG, "Cipher not properly initialized for encryption. Aborting" ); |
411 | return CryptoBuffer(); |
412 | } |
413 | |
414 | int lengthWritten = static_cast<int>(unEncryptedData.GetLength() + (GetBlockSizeBytes() - 1)); |
415 | CryptoBuffer encryptedText(static_cast<size_t>( lengthWritten + (GetBlockSizeBytes() - 1))); |
416 | |
417 | if (!EVP_EncryptUpdate(m_encryptor_ctx, encryptedText.GetUnderlyingData(), &lengthWritten, |
418 | unEncryptedData.GetUnderlyingData(), |
419 | static_cast<int>(unEncryptedData.GetLength()))) |
420 | { |
421 | m_failure = true; |
422 | LogErrors(); |
423 | return CryptoBuffer(); |
424 | } |
425 | |
426 | if (static_cast<size_t>(lengthWritten) < encryptedText.GetLength()) |
427 | { |
428 | return CryptoBuffer(encryptedText.GetUnderlyingData(), static_cast<size_t>(lengthWritten)); |
429 | } |
430 | |
431 | return encryptedText; |
432 | } |
433 | |
434 | CryptoBuffer OpenSSLCipher::FinalizeEncryption() |
435 | { |
436 | if (m_failure) |
437 | { |
438 | AWS_LOGSTREAM_FATAL(OPENSSL_LOG_TAG, |
439 | "Cipher not properly initialized for encryption finalization. Aborting" ); |
440 | return CryptoBuffer(); |
441 | } |
442 | |
443 | CryptoBuffer finalBlock(GetBlockSizeBytes()); |
444 | int writtenSize = 0; |
445 | if (!EVP_EncryptFinal_ex(m_encryptor_ctx, finalBlock.GetUnderlyingData(), &writtenSize)) |
446 | { |
447 | m_failure = true; |
448 | LogErrors(); |
449 | return CryptoBuffer(); |
450 | } |
451 | return CryptoBuffer(finalBlock.GetUnderlyingData(), static_cast<size_t>(writtenSize)); |
452 | } |
453 | |
454 | CryptoBuffer OpenSSLCipher::DecryptBuffer(const CryptoBuffer& encryptedData) |
455 | { |
456 | if (m_failure) |
457 | { |
458 | AWS_LOGSTREAM_FATAL(OPENSSL_LOG_TAG, "Cipher not properly initialized for decryption. Aborting" ); |
459 | return CryptoBuffer(); |
460 | } |
461 | |
462 | int lengthWritten = static_cast<int>(encryptedData.GetLength() + (GetBlockSizeBytes() - 1)); |
463 | CryptoBuffer decryptedText(static_cast<size_t>(lengthWritten)); |
464 | |
465 | if (!EVP_DecryptUpdate(m_decryptor_ctx, decryptedText.GetUnderlyingData(), &lengthWritten, |
466 | encryptedData.GetUnderlyingData(), |
467 | static_cast<int>(encryptedData.GetLength()))) |
468 | { |
469 | m_failure = true; |
470 | LogErrors(); |
471 | return CryptoBuffer(); |
472 | } |
473 | |
474 | if (static_cast<size_t>(lengthWritten) < decryptedText.GetLength()) |
475 | { |
476 | return CryptoBuffer(decryptedText.GetUnderlyingData(), static_cast<size_t>(lengthWritten)); |
477 | } |
478 | |
479 | return decryptedText; |
480 | } |
481 | |
482 | CryptoBuffer OpenSSLCipher::FinalizeDecryption() |
483 | { |
484 | if (m_failure) |
485 | { |
486 | AWS_LOGSTREAM_FATAL(OPENSSL_LOG_TAG, |
487 | "Cipher not properly initialized for decryption finalization. Aborting" ); |
488 | return CryptoBuffer(); |
489 | } |
490 | |
491 | CryptoBuffer finalBlock(GetBlockSizeBytes()); |
492 | int writtenSize = static_cast<int>(finalBlock.GetLength()); |
493 | if (!EVP_DecryptFinal_ex(m_decryptor_ctx, finalBlock.GetUnderlyingData(), &writtenSize)) |
494 | { |
495 | m_failure = true; |
496 | LogErrors(); |
497 | return CryptoBuffer(); |
498 | } |
499 | return CryptoBuffer(finalBlock.GetUnderlyingData(), static_cast<size_t>(writtenSize)); |
500 | } |
501 | |
502 | void OpenSSLCipher::Reset() |
503 | { |
504 | Cleanup(); |
505 | Init(); |
506 | } |
507 | |
508 | void OpenSSLCipher::Cleanup() |
509 | { |
510 | m_failure = false; |
511 | |
512 | EVP_CIPHER_CTX_cleanup(m_encryptor_ctx); |
513 | EVP_CIPHER_CTX_cleanup(m_decryptor_ctx); |
514 | } |
515 | |
516 | size_t AES_CBC_Cipher_OpenSSL::BlockSizeBytes = 16; |
517 | size_t AES_CBC_Cipher_OpenSSL::KeyLengthBits = 256; |
518 | static const char* CBC_LOG_TAG = "AES_CBC_Cipher_OpenSSL" ; |
519 | |
520 | AES_CBC_Cipher_OpenSSL::AES_CBC_Cipher_OpenSSL(const CryptoBuffer& key) : OpenSSLCipher(key, BlockSizeBytes) |
521 | { |
522 | InitCipher(); |
523 | } |
524 | |
525 | AES_CBC_Cipher_OpenSSL::AES_CBC_Cipher_OpenSSL(CryptoBuffer&& key, CryptoBuffer&& initializationVector) : |
526 | OpenSSLCipher(std::move(key), std::move(initializationVector)) |
527 | { |
528 | InitCipher(); |
529 | } |
530 | |
531 | AES_CBC_Cipher_OpenSSL::AES_CBC_Cipher_OpenSSL(const CryptoBuffer& key, |
532 | const CryptoBuffer& initializationVector) : |
533 | OpenSSLCipher(key, initializationVector) |
534 | { |
535 | InitCipher(); |
536 | } |
537 | |
538 | void AES_CBC_Cipher_OpenSSL::InitCipher() |
539 | { |
540 | if (!EVP_EncryptInit_ex(m_encryptor_ctx, EVP_aes_256_cbc(), nullptr, m_key.GetUnderlyingData(), |
541 | m_initializationVector.GetUnderlyingData()) || |
542 | !EVP_DecryptInit_ex(m_decryptor_ctx, EVP_aes_256_cbc(), nullptr, m_key.GetUnderlyingData(), |
543 | m_initializationVector.GetUnderlyingData())) |
544 | { |
545 | m_failure = true; |
546 | LogErrors(CBC_LOG_TAG); |
547 | } |
548 | } |
549 | |
550 | size_t AES_CBC_Cipher_OpenSSL::GetBlockSizeBytes() const |
551 | { |
552 | return BlockSizeBytes; |
553 | } |
554 | |
555 | size_t AES_CBC_Cipher_OpenSSL::GetKeyLengthBits() const |
556 | { |
557 | return KeyLengthBits; |
558 | } |
559 | |
560 | void AES_CBC_Cipher_OpenSSL::Reset() |
561 | { |
562 | OpenSSLCipher::Reset(); |
563 | InitCipher(); |
564 | } |
565 | |
566 | size_t AES_CTR_Cipher_OpenSSL::BlockSizeBytes = 16; |
567 | size_t AES_CTR_Cipher_OpenSSL::KeyLengthBits = 256; |
568 | static const char* CTR_LOG_TAG = "AES_CTR_Cipher_OpenSSL" ; |
569 | |
570 | AES_CTR_Cipher_OpenSSL::AES_CTR_Cipher_OpenSSL(const CryptoBuffer& key) : OpenSSLCipher(key, BlockSizeBytes, |
571 | true) |
572 | { |
573 | InitCipher(); |
574 | } |
575 | |
576 | AES_CTR_Cipher_OpenSSL::AES_CTR_Cipher_OpenSSL(CryptoBuffer&& key, CryptoBuffer&& initializationVector) : |
577 | OpenSSLCipher(std::move(key), std::move(initializationVector)) |
578 | { |
579 | InitCipher(); |
580 | } |
581 | |
582 | AES_CTR_Cipher_OpenSSL::AES_CTR_Cipher_OpenSSL(const CryptoBuffer& key, |
583 | const CryptoBuffer& initializationVector) : |
584 | OpenSSLCipher(key, initializationVector) |
585 | { |
586 | InitCipher(); |
587 | } |
588 | |
589 | void AES_CTR_Cipher_OpenSSL::InitCipher() |
590 | { |
591 | if (!(EVP_EncryptInit_ex(m_encryptor_ctx, EVP_aes_256_ctr(), nullptr, m_key.GetUnderlyingData(), |
592 | m_initializationVector.GetUnderlyingData()) |
593 | && EVP_CIPHER_CTX_set_padding(m_encryptor_ctx, 0)) || |
594 | !(EVP_DecryptInit_ex(m_decryptor_ctx, EVP_aes_256_ctr(), nullptr, m_key.GetUnderlyingData(), |
595 | m_initializationVector.GetUnderlyingData()) |
596 | && EVP_CIPHER_CTX_set_padding(m_decryptor_ctx, 0))) |
597 | { |
598 | m_failure = true; |
599 | LogErrors(CTR_LOG_TAG); |
600 | } |
601 | } |
602 | |
603 | size_t AES_CTR_Cipher_OpenSSL::GetBlockSizeBytes() const |
604 | { |
605 | return BlockSizeBytes; |
606 | } |
607 | |
608 | size_t AES_CTR_Cipher_OpenSSL::GetKeyLengthBits() const |
609 | { |
610 | return KeyLengthBits; |
611 | } |
612 | |
613 | void AES_CTR_Cipher_OpenSSL::Reset() |
614 | { |
615 | OpenSSLCipher::Reset(); |
616 | InitCipher(); |
617 | } |
618 | |
619 | size_t AES_GCM_Cipher_OpenSSL::BlockSizeBytes = 16; |
620 | size_t AES_GCM_Cipher_OpenSSL::KeyLengthBits = 256; |
621 | size_t AES_GCM_Cipher_OpenSSL::IVLengthBytes = 12; |
622 | size_t AES_GCM_Cipher_OpenSSL::TagLengthBytes = 16; |
623 | |
624 | static const char* GCM_LOG_TAG = "AES_GCM_Cipher_OpenSSL" ; |
625 | |
626 | AES_GCM_Cipher_OpenSSL::AES_GCM_Cipher_OpenSSL(const CryptoBuffer& key) : OpenSSLCipher(key, IVLengthBytes) |
627 | { |
628 | InitCipher(); |
629 | } |
630 | |
631 | AES_GCM_Cipher_OpenSSL::AES_GCM_Cipher_OpenSSL(CryptoBuffer&& key, CryptoBuffer&& initializationVector, |
632 | CryptoBuffer&& tag) : |
633 | OpenSSLCipher(std::move(key), std::move(initializationVector), std::move(tag)) |
634 | { |
635 | InitCipher(); |
636 | } |
637 | |
638 | AES_GCM_Cipher_OpenSSL::AES_GCM_Cipher_OpenSSL(const CryptoBuffer& key, |
639 | const CryptoBuffer& initializationVector, |
640 | const CryptoBuffer& tag) : |
641 | OpenSSLCipher(key, initializationVector, tag) |
642 | { |
643 | InitCipher(); |
644 | } |
645 | |
646 | CryptoBuffer AES_GCM_Cipher_OpenSSL::FinalizeEncryption() |
647 | { |
648 | CryptoBuffer const& finalBuffer = OpenSSLCipher::FinalizeEncryption(); |
649 | m_tag = CryptoBuffer(TagLengthBytes); |
650 | if (!EVP_CIPHER_CTX_ctrl(m_encryptor_ctx, EVP_CTRL_GCM_GET_TAG, static_cast<int>(m_tag.GetLength()), |
651 | m_tag.GetUnderlyingData())) |
652 | { |
653 | m_failure = true; |
654 | LogErrors(GCM_LOG_TAG); |
655 | return CryptoBuffer(); |
656 | } |
657 | |
658 | return finalBuffer; |
659 | } |
660 | |
661 | void AES_GCM_Cipher_OpenSSL::InitCipher() |
662 | { |
663 | if (!(EVP_EncryptInit_ex(m_encryptor_ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr) && |
664 | EVP_EncryptInit_ex(m_encryptor_ctx, nullptr, nullptr, m_key.GetUnderlyingData(), |
665 | m_initializationVector.GetUnderlyingData()) && |
666 | EVP_CIPHER_CTX_set_padding(m_encryptor_ctx, 0)) || |
667 | !(EVP_DecryptInit_ex(m_decryptor_ctx, EVP_aes_256_gcm(), nullptr, nullptr, nullptr) && |
668 | EVP_DecryptInit_ex(m_decryptor_ctx, nullptr, nullptr, m_key.GetUnderlyingData(), |
669 | m_initializationVector.GetUnderlyingData()) && |
670 | EVP_CIPHER_CTX_set_padding(m_decryptor_ctx, 0))) |
671 | { |
672 | m_failure = true; |
673 | LogErrors(GCM_LOG_TAG); |
674 | return; |
675 | } |
676 | |
677 | //tag should always be set in GCM decrypt mode |
678 | if (m_tag.GetLength() > 0) |
679 | { |
680 | if (m_tag.GetLength() < TagLengthBytes) |
681 | { |
682 | AWS_LOGSTREAM_ERROR(GCM_LOG_TAG, |
683 | "Illegal attempt to decrypt an AES GCM payload without a valid tag set: tag length=" << |
684 | m_tag.GetLength()); |
685 | m_failure = true; |
686 | return; |
687 | } |
688 | |
689 | if (!EVP_CIPHER_CTX_ctrl(m_decryptor_ctx, EVP_CTRL_GCM_SET_TAG, static_cast<int>(m_tag.GetLength()), |
690 | m_tag.GetUnderlyingData())) |
691 | { |
692 | m_failure = true; |
693 | LogErrors(GCM_LOG_TAG); |
694 | } |
695 | } |
696 | } |
697 | |
698 | size_t AES_GCM_Cipher_OpenSSL::GetBlockSizeBytes() const |
699 | { |
700 | return BlockSizeBytes; |
701 | } |
702 | |
703 | size_t AES_GCM_Cipher_OpenSSL::GetKeyLengthBits() const |
704 | { |
705 | return KeyLengthBits; |
706 | } |
707 | |
708 | size_t AES_GCM_Cipher_OpenSSL::GetTagLengthBytes() const |
709 | { |
710 | return TagLengthBytes; |
711 | } |
712 | |
713 | void AES_GCM_Cipher_OpenSSL::Reset() |
714 | { |
715 | OpenSSLCipher::Reset(); |
716 | InitCipher(); |
717 | } |
718 | |
719 | size_t AES_KeyWrap_Cipher_OpenSSL::KeyLengthBits = 256; |
720 | size_t AES_KeyWrap_Cipher_OpenSSL::BlockSizeBytes = 8; |
721 | static const unsigned char INTEGRITY_VALUE = 0xA6; |
722 | static const size_t MIN_CEK_LENGTH_BYTES = 128 / 8; |
723 | |
724 | static const char* KEY_WRAP_TAG = "AES_KeyWrap_Cipher_OpenSSL" ; |
725 | |
726 | AES_KeyWrap_Cipher_OpenSSL::AES_KeyWrap_Cipher_OpenSSL(const CryptoBuffer& key) : OpenSSLCipher(key, 0) |
727 | { |
728 | InitCipher(); |
729 | } |
730 | |
731 | CryptoBuffer AES_KeyWrap_Cipher_OpenSSL::EncryptBuffer(const CryptoBuffer& plainText) |
732 | { |
733 | assert(!m_failure); |
734 | |
735 | m_workingKeyBuffer = CryptoBuffer({&m_workingKeyBuffer, (CryptoBuffer*) &plainText}); |
736 | return CryptoBuffer(); |
737 | } |
738 | |
739 | CryptoBuffer AES_KeyWrap_Cipher_OpenSSL::FinalizeEncryption() |
740 | { |
741 | if (m_failure) |
742 | { |
743 | AWS_LOGSTREAM_FATAL(KEY_WRAP_TAG, "Cipher not properly initialized for encryption finalization. Aborting" ); |
744 | return CryptoBuffer(); |
745 | } |
746 | |
747 | if (m_workingKeyBuffer.GetLength() < MIN_CEK_LENGTH_BYTES) |
748 | { |
749 | AWS_LOGSTREAM_ERROR(KEY_WRAP_TAG, "Incorrect input length of " << m_workingKeyBuffer.GetLength()); |
750 | m_failure = true; |
751 | return CryptoBuffer(); |
752 | } |
753 | |
754 | //the following is an in place implementation of |
755 | //RFC 3394 using the alternate in-place implementation. |
756 | //we use one in-place buffer instead of the copy at the end. |
757 | //the one letter variable names are meant to directly reflect the variables in the RFC |
758 | CryptoBuffer cipherText(m_workingKeyBuffer.GetLength() + BlockSizeBytes); |
759 | |
760 | //put the integrity check register in the first 8 bytes of the final buffer. |
761 | memset(cipherText.GetUnderlyingData(), INTEGRITY_VALUE, BlockSizeBytes); |
762 | unsigned char* a = cipherText.GetUnderlyingData(); |
763 | |
764 | //put the register buffer after the integrity check register |
765 | memcpy(cipherText.GetUnderlyingData() + BlockSizeBytes, m_workingKeyBuffer.GetUnderlyingData(), |
766 | m_workingKeyBuffer.GetLength()); |
767 | unsigned char* r = cipherText.GetUnderlyingData() + BlockSizeBytes; |
768 | |
769 | int n = static_cast<int>(m_workingKeyBuffer.GetLength() / BlockSizeBytes); |
770 | |
771 | //temporary encryption buffer |
772 | CryptoBuffer b(BlockSizeBytes * 2); |
773 | int outLen = static_cast<int>(b.GetLength()); |
774 | |
775 | //concatenation buffer |
776 | CryptoBuffer tempInput(BlockSizeBytes * 2); |
777 | |
778 | for (int j = 0; j <= 5; ++j) |
779 | { |
780 | for (int i = 1; i <= n; ++i) |
781 | { |
782 | //concat A and R[i], A should be most significant and then R[i] should be least significant. |
783 | memcpy(tempInput.GetUnderlyingData(), a, BlockSizeBytes); |
784 | memcpy(tempInput.GetUnderlyingData() + BlockSizeBytes, r, BlockSizeBytes); |
785 | |
786 | //encrypt the concatenated A and R[I] and store it in B |
787 | if (!EVP_EncryptUpdate(m_encryptor_ctx, b.GetUnderlyingData(), &outLen, |
788 | tempInput.GetUnderlyingData(), static_cast<int>(tempInput.GetLength()))) |
789 | { |
790 | LogErrors(KEY_WRAP_TAG); |
791 | m_failure = true; |
792 | return CryptoBuffer(); |
793 | } |
794 | |
795 | unsigned char t = static_cast<unsigned char>((n * j) + i); |
796 | //put the 64 MSB ^ T into A |
797 | memcpy(a, b.GetUnderlyingData(), BlockSizeBytes); |
798 | a[7] ^= t; |
799 | //put the 64 LSB into R[i] |
800 | memcpy(r, b.GetUnderlyingData() + BlockSizeBytes, BlockSizeBytes); |
801 | //increment i -> R[i] |
802 | r += BlockSizeBytes; |
803 | } |
804 | //reset R |
805 | r = cipherText.GetUnderlyingData() + BlockSizeBytes; |
806 | } |
807 | |
808 | return cipherText; |
809 | } |
810 | |
811 | CryptoBuffer AES_KeyWrap_Cipher_OpenSSL::DecryptBuffer(const CryptoBuffer& cipherText) |
812 | { |
813 | assert(!m_failure); |
814 | |
815 | m_workingKeyBuffer = CryptoBuffer({&m_workingKeyBuffer, (CryptoBuffer*)&cipherText}); |
816 | |
817 | return CryptoBuffer(); |
818 | } |
819 | |
820 | CryptoBuffer AES_KeyWrap_Cipher_OpenSSL::FinalizeDecryption() |
821 | { |
822 | if (m_failure) |
823 | { |
824 | AWS_LOGSTREAM_FATAL(KEY_WRAP_TAG, "Cipher not properly initialized for decryption finalization. Aborting" ); |
825 | return CryptoBuffer(); |
826 | } |
827 | |
828 | if (m_workingKeyBuffer.GetLength() < MIN_CEK_LENGTH_BYTES + BlockSizeBytes) |
829 | { |
830 | AWS_LOGSTREAM_ERROR(KEY_WRAP_TAG, "Incorrect input length of " << m_workingKeyBuffer.GetLength()); |
831 | m_failure = true; |
832 | return CryptoBuffer(); |
833 | } |
834 | |
835 | //the following is an in place implementation of |
836 | //RFC 3394 using the alternate in-place implementation. |
837 | //we use one in-place buffer instead of the copy at the end. |
838 | //the one letter variable names are meant to directly reflect the variables in the RFC |
839 | CryptoBuffer plainText(m_workingKeyBuffer.GetLength() - BlockSizeBytes); |
840 | memcpy(plainText.GetUnderlyingData(), m_workingKeyBuffer.GetUnderlyingData() + BlockSizeBytes, plainText.GetLength()); |
841 | |
842 | //integrity register should be the first 8 bytes of the cipher text |
843 | unsigned char* a = m_workingKeyBuffer.GetUnderlyingData(); |
844 | |
845 | //in-place register is the plaintext. For decryption, start at the last array position (8 bytes before the end); |
846 | unsigned char* r = plainText.GetUnderlyingData() + plainText.GetLength() - BlockSizeBytes; |
847 | |
848 | int n = static_cast<int>(plainText.GetLength() / BlockSizeBytes); |
849 | |
850 | //temporary encryption buffer |
851 | CryptoBuffer b(BlockSizeBytes * 10); |
852 | int outLen = static_cast<int>(b.GetLength()); |
853 | |
854 | //concatenation buffer |
855 | CryptoBuffer tempInput(BlockSizeBytes * 2); |
856 | |
857 | for(int j = 5; j >= 0; --j) |
858 | { |
859 | for(int i = n; i >= 1; --i) |
860 | { |
861 | //concat |
862 | //A ^ t |
863 | memcpy(tempInput.GetUnderlyingData(), a, BlockSizeBytes); |
864 | unsigned char t = static_cast<unsigned char>((n * j) + i); |
865 | tempInput[7] ^= t; |
866 | //R[i] |
867 | memcpy(tempInput.GetUnderlyingData() + BlockSizeBytes, r, BlockSizeBytes); |
868 | |
869 | //Decrypt the concatenated buffer |
870 | if(!EVP_DecryptUpdate(m_decryptor_ctx, b.GetUnderlyingData(), &outLen, |
871 | tempInput.GetUnderlyingData(), static_cast<int>(tempInput.GetLength()))) |
872 | { |
873 | m_failure = true; |
874 | LogErrors(KEY_WRAP_TAG); |
875 | return CryptoBuffer(); |
876 | } |
877 | |
878 | //set A to MSB 64 bits of decrypted result |
879 | memcpy(a, b.GetUnderlyingData(), BlockSizeBytes); |
880 | //set R[i] to LSB 64 bits of decrypted result |
881 | memcpy(r, b.GetUnderlyingData() + BlockSizeBytes, BlockSizeBytes); |
882 | //decrement i -> R[i] |
883 | r -= BlockSizeBytes; |
884 | } |
885 | |
886 | r = plainText.GetUnderlyingData() + plainText.GetLength() - BlockSizeBytes; |
887 | } |
888 | |
889 | //here we perform the integrity check to make sure A == 0xA6A6A6A6A6A6A6A6 |
890 | for(size_t i = 0; i < BlockSizeBytes; ++i) |
891 | { |
892 | if(a[i] != INTEGRITY_VALUE) |
893 | { |
894 | m_failure = true; |
895 | AWS_LOGSTREAM_ERROR(KEY_WRAP_TAG, "Integrity check failed for key wrap decryption." ); |
896 | return CryptoBuffer(); |
897 | } |
898 | } |
899 | |
900 | return plainText; |
901 | } |
902 | |
903 | void AES_KeyWrap_Cipher_OpenSSL::InitCipher() |
904 | { |
905 | if (!(EVP_EncryptInit_ex(m_encryptor_ctx, EVP_aes_256_ecb(), nullptr, m_key.GetUnderlyingData(), nullptr) && |
906 | EVP_CIPHER_CTX_set_padding(m_encryptor_ctx, 0)) || |
907 | !(EVP_DecryptInit_ex(m_decryptor_ctx, EVP_aes_256_ecb(), nullptr, m_key.GetUnderlyingData(), nullptr) && |
908 | EVP_CIPHER_CTX_set_padding(m_decryptor_ctx, 0))) |
909 | { |
910 | m_failure = true; |
911 | LogErrors(KEY_WRAP_TAG); |
912 | } |
913 | } |
914 | |
915 | void AES_KeyWrap_Cipher_OpenSSL::Reset() |
916 | { |
917 | m_workingKeyBuffer = CryptoBuffer(); |
918 | OpenSSLCipher::Reset(); |
919 | InitCipher(); |
920 | } |
921 | } |
922 | } |
923 | } |
924 | |