summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSpencer Jackson <spencer.jackson@mongodb.com>2021-10-18 19:14:32 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-10-18 20:43:06 +0000
commit838a9ac7510e6169b6af748e994b315eecd94c52 (patch)
tree37a30199692eba8872d6b0e7c3d319d777278c57
parent0992b4dc9440efa979b73e88566c906459ba0f40 (diff)
downloadmongo-838a9ac7510e6169b6af748e994b315eecd94c52.tar.gz
SERVER-60568 Add tests with official GCM test vectors
-rw-r--r--src/mongo/crypto/symmetric_crypto_test.cpp147
-rw-r--r--src/mongo/crypto/symmetric_crypto_windows.cpp6
2 files changed, 153 insertions, 0 deletions
diff --git a/src/mongo/crypto/symmetric_crypto_test.cpp b/src/mongo/crypto/symmetric_crypto_test.cpp
index eb154520e84..47834b77770 100644
--- a/src/mongo/crypto/symmetric_crypto_test.cpp
+++ b/src/mongo/crypto/symmetric_crypto_test.cpp
@@ -35,6 +35,7 @@
#include "mongo/crypto/block_packer.h"
#include "mongo/unittest/unittest.h"
+#include "mongo/util/hex.h"
namespace mongo {
namespace crypto {
@@ -478,5 +479,151 @@ TEST(AES, GCMAdditionalAuthenticatedData) {
GCMAdditionalAuthenticatedDataHelper(false);
}
+class AESGCMTestVectors : public unittest::Test {
+public:
+ class GCMTestVector {
+ public:
+ GCMTestVector(StringData key,
+ StringData plaintext,
+ StringData a,
+ StringData iv,
+ StringData ciphertext,
+ StringData tag) {
+ this->key = hexblob::decode(key);
+ this->plaintext = hexblob::decode(plaintext);
+ this->a = hexblob::decode(a);
+ this->iv = hexblob::decode(iv);
+ this->ciphertext = hexblob::decode(ciphertext);
+ this->tag = hexblob::decode(tag);
+ }
+
+ std::string key;
+ std::string plaintext;
+ std::string a;
+ std::string iv;
+ std::string ciphertext;
+ std::string tag;
+ };
+
+ void evaluate(GCMTestVector test) {
+ constexpr auto mode = crypto::aesMode::gcm;
+
+ if (getSupportedSymmetricAlgorithms().count(getStringFromCipherMode(mode)) == 0) {
+ return;
+ }
+
+ SymmetricKey key = aesGeneratePredictableKey256(test.key, "testID");
+
+ // Validate encryption
+ auto encryptor = uassertStatusOK(crypto::SymmetricEncryptor::create(
+ key, mode, asUint8(test.iv.c_str()), test.iv.size()));
+
+ ASSERT_OK(encryptor->addAuthenticatedData(asUint8(test.a.c_str()), test.a.size()));
+
+ const size_t kBufferSize = test.plaintext.size();
+ {
+ std::vector<uint8_t> encryptionResult(kBufferSize);
+ auto cipherLen = uassertStatusOK(encryptor->update(asUint8(test.plaintext.c_str()),
+ test.plaintext.size(),
+ encryptionResult.data(),
+ encryptionResult.size()));
+ cipherLen += uassertStatusOK(encryptor->finalize(encryptionResult.data() + cipherLen,
+ encryptionResult.size() - cipherLen));
+
+ ASSERT_EQ(test.ciphertext.size(), cipherLen);
+ ASSERT_EQ(hexblob::encode(StringData(test.ciphertext.data(), test.ciphertext.size())),
+ hexblob::encode(
+ StringData(asChar(encryptionResult.data()), encryptionResult.size())));
+
+ std::array<std::uint8_t, 12> tag;
+ const auto taglen = uassertStatusOK(encryptor->finalizeTag(tag.data(), tag.size()));
+ ASSERT_EQ(tag.size(), taglen);
+ ASSERT_EQ(hexblob::encode(StringData(test.tag.data(), test.tag.size())).substr(0, 24),
+ hexblob::encode(StringData(asChar(tag.data()), tag.size())));
+ }
+ {
+ // Validate decryption
+ auto decryptor = uassertStatusOK(crypto::SymmetricDecryptor::create(
+ key, mode, asUint8(test.iv.c_str()), test.iv.size()));
+ uassertStatusOK(decryptor->updateTag(asUint8(test.tag.data()), 12));
+
+ ASSERT_OK(decryptor->addAuthenticatedData(asUint8(test.a.c_str()), test.a.size()));
+ std::vector<uint8_t> decryptionResult(kBufferSize);
+ auto decipherLen = uassertStatusOK(decryptor->update(asUint8(test.ciphertext.c_str()),
+ test.ciphertext.size(),
+ decryptionResult.data(),
+ decryptionResult.size()));
+ 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
+ * https://csrc.nist.rip/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf
+ */
+TEST_F(AESGCMTestVectors, TestCase13) {
+ evaluate(
+ GCMTestVector("00000000000000000000000000000000"
+ "00000000000000000000000000000000"_sd,
+ ""_sd,
+ ""_sd,
+ "000000000000000000000000"_sd,
+ ""_sd,
+ "530f8afbc74536b9a963b4f1c4cb738b"_sd));
+}
+
+TEST_F(AESGCMTestVectors, TestCase14) {
+ evaluate(
+ GCMTestVector("00000000000000000000000000000000"
+ "00000000000000000000000000000000"_sd,
+ "00000000000000000000000000000000"_sd,
+ ""_sd,
+ "000000000000000000000000"_sd,
+ "cea7403d4d606b6e074ec5d3baf39d18"_sd,
+ "d0d1c8a799996bf0265b98b5d48ab919"_sd));
+}
+
+TEST_F(AESGCMTestVectors, TestCase15) {
+ evaluate(
+ GCMTestVector("feffe9928665731c6d6a8f9467308308"
+ "feffe9928665731c6d6a8f9467308308"_sd,
+ "d9313225f88406e5a55909c5aff5269a"
+ "86a7a9531534f7da2e4c303d8a318a72"
+ "1c3c0c95956809532fcf0e2449a6b525"
+ "b16aedf5aa0de657ba637b391aafd255"_sd,
+ ""_sd,
+ "cafebabefacedbaddecaf888"_sd,
+ "522dc1f099567d07f47f37a32a84427d"
+ "643a8cdcbfe5c0c97598a2bd2555d1aa"
+ "8cb08e48590dbb3da7b08b1056828838"
+ "c5f61e6393ba7a0abcc9f662898015ad"_sd,
+ "b094dac5d93471bdec1a502270e3cc6c"_sd));
+}
+
+TEST_F(AESGCMTestVectors, TestCase16) {
+ evaluate(
+ GCMTestVector("feffe9928665731c6d6a8f9467308308"
+ "feffe9928665731c6d6a8f9467308308"_sd,
+ "d9313225f88406e5a55909c5aff5269a"
+ "86a7a9531534f7da2e4c303d8a318a72"
+ "1c3c0c95956809532fcf0e2449a6b525"
+ "b16aedf5aa0de657ba637b39"_sd,
+ "feedfacedeadbeeffeedfacedeadbeef"
+ "abaddad2"_sd,
+ "cafebabefacedbaddecaf888"_sd,
+ "522dc1f099567d07f47f37a32a84427d"
+ "643a8cdcbfe5c0c97598a2bd2555d1aa"
+ "8cb08e48590dbb3da7b08b1056828838"
+ "c5f61e6393ba7a0abcc9f662"_sd,
+ "76fc6ece0f4e1768cddf8853bb2d551b"_sd));
+}
+
+
} // namespace crypto
} // namespace mongo
diff --git a/src/mongo/crypto/symmetric_crypto_windows.cpp b/src/mongo/crypto/symmetric_crypto_windows.cpp
index e2e88cc5d23..fc621f4bcb0 100644
--- a/src/mongo/crypto/symmetric_crypto_windows.cpp
+++ b/src/mongo/crypto/symmetric_crypto_windows.cpp
@@ -338,6 +338,12 @@ public:
_paddingInfo->cbAuthData = 0;
}
+ // BCryptEncrypt may refuse to process GCM tags if no output buffer is provided.
+ uint8_t dummyOut;
+ if (!out) {
+ out = &dummyOut;
+ }
+
auto remainder = _packer.getBlock();
// if there is any data left over in the block buffer, we will encrypt it with padding
ULONG len = 0;