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
25AWS_SUPPRESS_WARNING_PUSH(4201)
26#else
27AWS_SUPPRESS_WARNING_PUSH("-Wpedantic")
28#endif
29#endif
30
31#include <openssl/sha.h>
32
33#ifdef OPENSSL_IS_BORINGSSL
34AWS_SUPPRESS_WARNING_POP
35#endif
36
37#include <openssl/err.h>
38#include <aws/core/utils/logging/LogMacros.h>
39#include <thread>
40
41using namespace Aws::Utils;
42using namespace Aws::Utils::Crypto;
43
44namespace 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