diff options
author | sergey.galtsev <sergey.galtsev@mongodb.com> | 2022-02-08 23:53:32 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-02-09 00:40:56 +0000 |
commit | 9357161cfc1098344d94f8e3efd38b90ce67516f (patch) | |
tree | 2810627702eca9896d82196039d416cfc79bee86 /src/mongo/crypto | |
parent | 22d69577041a96795c836988e965334305ebe9d8 (diff) | |
download | mongo-9357161cfc1098344d94f8e3efd38b90ce67516f.tar.gz |
SERVER-63186 Add AES-CTR support for OpenSSL
Diffstat (limited to 'src/mongo/crypto')
-rw-r--r-- | src/mongo/crypto/symmetric_crypto.cpp | 6 | ||||
-rw-r--r-- | src/mongo/crypto/symmetric_crypto.h | 8 | ||||
-rw-r--r-- | src/mongo/crypto/symmetric_crypto_openssl.cpp | 6 | ||||
-rw-r--r-- | src/mongo/crypto/symmetric_crypto_test.cpp | 114 |
4 files changed, 131 insertions, 3 deletions
diff --git a/src/mongo/crypto/symmetric_crypto.cpp b/src/mongo/crypto/symmetric_crypto.cpp index bb57d35e90a..375a8264f59 100644 --- a/src/mongo/crypto/symmetric_crypto.cpp +++ b/src/mongo/crypto/symmetric_crypto.cpp @@ -55,6 +55,8 @@ size_t aesGetIVSize(crypto::aesMode mode) { return crypto::aesCBCIVSize; case crypto::aesMode::gcm: return crypto::aesGCMIVSize; + case crypto::aesMode::ctr: + return crypto::aesCTRIVSize; default: fassertFailed(4053); } @@ -65,6 +67,8 @@ aesMode getCipherModeFromString(const std::string& mode) { return aesMode::cbc; } else if (mode == aes256GCMName) { return aesMode::gcm; + } else if (mode == aes256CTRName) { + return aesMode::ctr; } else { MONGO_UNREACHABLE; } @@ -75,6 +79,8 @@ std::string getStringFromCipherMode(aesMode mode) { return aes256CBCName; } else if (mode == aesMode::gcm) { return aes256GCMName; + } else if (mode == aesMode::ctr) { + return aes256CTRName; } else { MONGO_UNREACHABLE; } diff --git a/src/mongo/crypto/symmetric_crypto.h b/src/mongo/crypto/symmetric_crypto.h index 7a789577d51..d739fbe9c07 100644 --- a/src/mongo/crypto/symmetric_crypto.h +++ b/src/mongo/crypto/symmetric_crypto.h @@ -71,15 +71,21 @@ constexpr size_t aesGCMTagSize = 12; constexpr size_t aesGCMIVSize = 12; /** + * CTR tunable parameters + */ +constexpr size_t aesCTRIVSize = 16; + +/** * Encryption mode identifiers */ -enum class aesMode : uint8_t { cbc, gcm }; +enum class aesMode : uint8_t { cbc, gcm, ctr }; /** * Algorithm names which this module recognizes */ const std::string aes256CBCName = "AES256-CBC"; const std::string aes256GCMName = "AES256-GCM"; +const std::string aes256CTRName = "AES256-CTR"; aesMode getCipherModeFromString(const std::string& mode); std::string getStringFromCipherMode(aesMode); diff --git a/src/mongo/crypto/symmetric_crypto_openssl.cpp b/src/mongo/crypto/symmetric_crypto_openssl.cpp index bdf01cf5bb1..d0e843dd7d9 100644 --- a/src/mongo/crypto/symmetric_crypto_openssl.cpp +++ b/src/mongo/crypto/symmetric_crypto_openssl.cpp @@ -59,6 +59,8 @@ void initCipherContext( cipher = EVP_get_cipherbyname("aes-256-cbc"); } else if (mode == crypto::aesMode::gcm) { cipher = EVP_get_cipherbyname("aes-256-gcm"); + } else if (mode == crypto::aesMode::ctr) { + cipher = EVP_get_cipherbyname("aes-256-ctr"); } } uassert(ErrorCodes::BadValue, @@ -224,9 +226,9 @@ private: std::set<std::string> getSupportedSymmetricAlgorithms() { #if defined(EVP_CTRL_GCM_GET_TAG) && !defined(__APPLE__) - return {aes256CBCName, aes256GCMName}; + return {aes256CBCName, aes256GCMName, aes256CTRName}; #else - return {aes256CBCName}; + return {aes256CBCName, aes256CTRName}; #endif } diff --git a/src/mongo/crypto/symmetric_crypto_test.cpp b/src/mongo/crypto/symmetric_crypto_test.cpp index 14c89d12eda..704d4bf9fde 100644 --- a/src/mongo/crypto/symmetric_crypto_test.cpp +++ b/src/mongo/crypto/symmetric_crypto_test.cpp @@ -491,6 +491,21 @@ public: std::string tag; }; + class CTRTestVector { + public: + CTRTestVector(StringData key, StringData plaintext, StringData iv, StringData ciphertext) { + this->key = hexblob::decode(key); + this->plaintext = hexblob::decode(plaintext); + this->iv = hexblob::decode(iv); + this->ciphertext = hexblob::decode(ciphertext); + } + + std::string key; + std::string plaintext; + std::string iv; + std::string ciphertext; + }; + void evaluate(GCMTestVector test) { constexpr auto mode = crypto::aesMode::gcm; @@ -563,6 +578,49 @@ public: ASSERT_NOT_OK(decryptor->finalize(decryptionResultCursor)); } } + + void evaluate(CTRTestVector test) { + constexpr auto mode = crypto::aesMode::ctr; + + if (getSupportedSymmetricAlgorithms().count(getStringFromCipherMode(mode)) == 0) { + return; + } + + SymmetricKey key = aesGeneratePredictableKey256(test.key, "testID"); + + // Validate encryption + auto encryptor = uassertStatusOK(crypto::SymmetricEncryptor::create(key, mode, test.iv)); + + const size_t kBufferSize = test.plaintext.size(); + { + // Validate encryption + std::vector<uint8_t> encryptionResult(kBufferSize); + auto cipherLen = uassertStatusOK(encryptor->update(test.plaintext, encryptionResult)); + cipherLen += uassertStatusOK(encryptor->finalize( + {encryptionResult.data() + cipherLen, encryptionResult.size() - cipherLen})); + + ASSERT_EQ(test.ciphertext.size(), cipherLen); + ASSERT_EQ(hexblob::encode(test.ciphertext), + hexblob::encode( + StringData(asChar(encryptionResult.data()), encryptionResult.size()))); + } + { + // Validate decryption + auto decryptor = + uassertStatusOK(crypto::SymmetricDecryptor::create(key, mode, test.iv)); + + std::vector<uint8_t> decryptionResult(kBufferSize); + auto decipherLen = + uassertStatusOK(decryptor->update(test.ciphertext, decryptionResult)); + decipherLen += uassertStatusOK(decryptor->finalize( + {decryptionResult.data() + decipherLen, decryptionResult.size() - decipherLen})); + + ASSERT_EQ(test.plaintext.size(), decipherLen); + ASSERT_EQ(hexblob::encode(StringData(test.plaintext.data(), test.plaintext.size())), + hexblob::encode( + StringData(asChar(decryptionResult.data()), decryptionResult.size()))); + } + } }; /** Test vectors drawn from @@ -625,6 +683,62 @@ TEST_F(AESGCMTestVectors, TestCase16) { "76fc6ece0f4e1768cddf8853bb2d551b"_sd)); } +// AES-CTR test vectors are obtained here: +// https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf + +TEST_F(AESGCMTestVectors, CTRTestCase1) { + evaluate( + CTRTestVector("603deb1015ca71be2b73aef0857d7781" + "1f352c073b6108d72d9810a30914dff4", + "6bc1bee22e409f96e93d7e117393172a", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "601ec313775789a5b7a7f504bbf3d228")); +} + +TEST_F(AESGCMTestVectors, CTRTestCase2) { + evaluate( + CTRTestVector("603deb1015ca71be2b73aef0857d7781" + "1f352c073b6108d72d9810a30914dff4", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdff00", + "f443e3ca4d62b59aca84e990cacaf5c5")); +} + +TEST_F(AESGCMTestVectors, CTRTestCase3) { + evaluate( + CTRTestVector("603deb1015ca71be2b73aef0857d7781" + "1f352c073b6108d72d9810a30914dff4", + "30c81c46a35ce411e5fbc1191a0a52ef", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdff01", + "2b0930daa23de94ce87017ba2d84988d")); +} + +TEST_F(AESGCMTestVectors, CTRTestCase4) { + evaluate( + CTRTestVector("603deb1015ca71be2b73aef0857d7781" + "1f352c073b6108d72d9810a30914dff4", + "f69f2445df4f9b17ad2b417be66c3710", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdff02", + "dfc9c58db67aada613c2dd08457941a6")); +} + +TEST_F(AESGCMTestVectors, CTRTestCase1234) { + evaluate( + CTRTestVector("603deb1015ca71be2b73aef0857d7781" + "1f352c073b6108d72d9810a30914dff4", + + "6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710", + + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + + "601ec313775789a5b7a7f504bbf3d228" + "f443e3ca4d62b59aca84e990cacaf5c5" + "2b0930daa23de94ce87017ba2d84988d" + "dfc9c58db67aada613c2dd08457941a6")); +} } // namespace crypto } // namespace mongo |