summaryrefslogtreecommitdiff
path: root/src/mongo/crypto
diff options
context:
space:
mode:
authorsergey.galtsev <sergey.galtsev@mongodb.com>2022-02-08 23:53:32 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-02-09 00:40:56 +0000
commit9357161cfc1098344d94f8e3efd38b90ce67516f (patch)
tree2810627702eca9896d82196039d416cfc79bee86 /src/mongo/crypto
parent22d69577041a96795c836988e965334305ebe9d8 (diff)
downloadmongo-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.cpp6
-rw-r--r--src/mongo/crypto/symmetric_crypto.h8
-rw-r--r--src/mongo/crypto/symmetric_crypto_openssl.cpp6
-rw-r--r--src/mongo/crypto/symmetric_crypto_test.cpp114
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