summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/crypto/aead_encryption.cpp70
-rw-r--r--src/mongo/crypto/aead_encryption.h21
-rw-r--r--src/mongo/crypto/aead_encryption_test.cpp115
-rw-r--r--src/mongo/crypto/fle_crypto.cpp93
-rw-r--r--src/mongo/crypto/fle_crypto.h4
-rw-r--r--src/mongo/crypto/fle_crypto_test.cpp288
-rw-r--r--src/mongo/crypto/fle_data_frames.h11
-rw-r--r--src/mongo/crypto/scripts/encryption_fle2_test_vectors.sh18
-rw-r--r--src/mongo/db/fle_crud_test.cpp38
9 files changed, 431 insertions, 227 deletions
diff --git a/src/mongo/crypto/aead_encryption.cpp b/src/mongo/crypto/aead_encryption.cpp
index b7640a1ca78..892fd4ae950 100644
--- a/src/mongo/crypto/aead_encryption.cpp
+++ b/src/mongo/crypto/aead_encryption.cpp
@@ -206,6 +206,10 @@ size_t fle2AeadCipherOutputLength(size_t plainTextLen) {
return plainTextLen + aesCTRIVSize + kHmacOutSize;
}
+size_t fle2CipherOutputLength(size_t plainTextLen) {
+ return plainTextLen + aesCTRIVSize;
+}
+
Status aeadEncryptLocalKMS(const SymmetricKey& key, ConstDataRange in, DataRange out) {
if (key.getKeySize() != kFieldLevelEncryptionKeySize) {
return Status(ErrorCodes::BadValue,
@@ -313,8 +317,8 @@ Status aeadEncryptWithIV(ConstDataRange key,
ivProvided = true;
}
- const auto* macKey = reinterpret_cast<const std::uint8_t*>(key.data());
- const auto* encKey = reinterpret_cast<const std::uint8_t*>(key.data() + sym256KeySize);
+ const auto* macKey = key.data<uint8_t>();
+ const auto* encKey = key.data<uint8_t>() + sym256KeySize;
SymmetricKey symEncKey(encKey, sym256KeySize, aesAlgorithm, "aesKey", 1);
std::size_t aesOutLen = out.length() - kHmacOutSize;
@@ -375,8 +379,8 @@ Status fle2AeadEncrypt(ConstDataRange key,
ivProvided = true;
}
- auto encKey = reinterpret_cast<const std::uint8_t*>(key.data());
- auto macKey = reinterpret_cast<const std::uint8_t*>(key.data() + sym256KeySize);
+ auto encKey = key.data<uint8_t>();
+ auto macKey = key.data<uint8_t>() + sym256KeySize;
SymmetricKey symEncKey(encKey, sym256KeySize, aesAlgorithm, "aesKey", 1);
std::size_t aesOutLen = out.length() - kHmacOutSize;
@@ -401,6 +405,41 @@ Status fle2AeadEncrypt(ConstDataRange key,
return Status::OK();
}
+Status fle2Encrypt(ConstDataRange key, ConstDataRange in, ConstDataRange iv, DataRange out) {
+ if (key.length() != sym256KeySize) {
+ return Status(ErrorCodes::BadValue, "Invalid key size.");
+ }
+
+ if (!in.length()) {
+ return Status(ErrorCodes::BadValue, "Invalid buffer length.");
+ }
+
+ if (0 != iv.length() && aesCTRIVSize != iv.length()) {
+ return Status(ErrorCodes::BadValue, "Invalid IV length.");
+ }
+
+ if (out.length() != fle2CipherOutputLength(in.length())) {
+ return Status(ErrorCodes::BadValue, "Invalid output buffer size.");
+ }
+
+ bool ivProvided = false;
+ if (iv.length() != 0) {
+ invariant(iv.length() == aesCTRIVSize);
+ out.write(iv);
+ ivProvided = true;
+ }
+
+ auto encKey = key.data<uint8_t>();
+ SymmetricKey symEncKey(encKey, sym256KeySize, aesAlgorithm, "aesKey", 1);
+
+ auto swEncrypt = _aesEncrypt(symEncKey, aesMode::ctr, in, out, ivProvided);
+ if (!swEncrypt.isOK()) {
+ return swEncrypt.getStatus();
+ }
+
+ return Status::OK();
+}
+
StatusWith<std::size_t> aeadDecrypt(const SymmetricKey& key,
ConstDataRange in,
ConstDataRange associatedData,
@@ -487,8 +526,8 @@ StatusWith<std::size_t> fle2AeadDecrypt(ConstDataRange key,
<< kMaxAssociatedDataLength << " bytes.");
}
- auto encKey = reinterpret_cast<const std::uint8_t*>(key.data());
- auto macKey = reinterpret_cast<const std::uint8_t*>(key.data() + sym256KeySize);
+ auto encKey = key.data<uint8_t>();
+ auto macKey = key.data<uint8_t>() + sym256KeySize;
auto [ivAndCipherText, hmacRange] = in.split(in.length() - kHmacOutSize);
SHA256Block hmacOutput =
@@ -503,6 +542,25 @@ StatusWith<std::size_t> fle2AeadDecrypt(ConstDataRange key,
return _aesDecrypt(symEncKey, aesMode::ctr, ivAndCipherText, out);
}
+StatusWith<std::size_t> fle2Decrypt(ConstDataRange key, ConstDataRange in, DataRange out) {
+ if (key.length() != sym256KeySize) {
+ return Status(ErrorCodes::BadValue, "Invalid key size.");
+ }
+
+ if (in.length() <= aesCTRIVSize) {
+ return Status(ErrorCodes::BadValue, "Ciphertext is not long enough.");
+ }
+
+ size_t expectedPlainTextSize = uassertStatusOK(fle2GetPlainTextLength(in.length()));
+ if (out.length() != expectedPlainTextSize) {
+ return Status(ErrorCodes::BadValue, "Output buffer must be as long as the cipherText.");
+ }
+
+ auto encKey = key.data<uint8_t>();
+ SymmetricKey symEncKey(encKey, sym256KeySize, aesAlgorithm, "aesKey", 1);
+ return _aesDecrypt(symEncKey, aesMode::ctr, in, out);
+}
+
Status aeadDecryptDataFrame(FLEDecryptionFrame& dataframe) {
auto ciphertext = dataframe.getCiphertext();
auto associatedData = dataframe.getAssociatedData();
diff --git a/src/mongo/crypto/aead_encryption.h b/src/mongo/crypto/aead_encryption.h
index 0e9fe9586fc..e5c36f96e78 100644
--- a/src/mongo/crypto/aead_encryption.h
+++ b/src/mongo/crypto/aead_encryption.h
@@ -55,6 +55,16 @@ constexpr size_t kAeadAesHmacKeySize = 64;
size_t aeadCipherOutputLength(size_t plainTextLen);
/**
+ * Returns the length of the ciphertext output given the plaintext length. Only for FLE2 AEAD.
+ */
+size_t fle2AeadCipherOutputLength(size_t plainTextLen);
+
+/**
+ * Returns the length of the ciphertext output given the plaintext length. Only for FLE2.
+ */
+size_t fle2CipherOutputLength(size_t plainTextLen);
+
+/**
* Encrypts a dataframe object following the AEAD_AES_256_CBC_HMAC_SHA_512 encryption
* algorithm. Used for field level encryption.
*/
@@ -93,6 +103,12 @@ Status fle2AeadEncrypt(ConstDataRange key,
DataRange out);
/**
+ * Internal call for FLE2 encryption algorithm.
+ * Note: parameter "iv" is not required and only used for unit testing
+ */
+Status fle2Encrypt(ConstDataRange key, ConstDataRange in, ConstDataRange iv, DataRange out);
+
+/**
* Internal call for the aeadDecryption algorithm. Only used for testing.
*/
StatusWith<std::size_t> aeadDecrypt(const SymmetricKey& key,
@@ -109,6 +125,11 @@ StatusWith<std::size_t> fle2AeadDecrypt(ConstDataRange key,
DataRange out);
/**
+ * Internal call for FLE2 decryption algorithm.
+ */
+StatusWith<std::size_t> fle2Decrypt(ConstDataRange key, ConstDataRange in, DataRange out);
+
+/**
* Decrypts the cipherText using AEAD_AES_256_CBC_HMAC_SHA_512 decryption. Writes output
* to out.
*/
diff --git a/src/mongo/crypto/aead_encryption_test.cpp b/src/mongo/crypto/aead_encryption_test.cpp
index fce4f832068..7120a717c25 100644
--- a/src/mongo/crypto/aead_encryption_test.cpp
+++ b/src/mongo/crypto/aead_encryption_test.cpp
@@ -210,6 +210,32 @@ TEST(AEADFLE2, Fle2AeadDetectTampering) {
ASSERT_NOT_OK(decryptStatus2);
}
+TEST(EncryptFLE2, Fle2EncryptRandom) {
+ mongo::PseudoRandom rnd(SecureRandom().nextInt64());
+
+ std::vector<uint8_t> key(mongo::crypto::sym256KeySize);
+ rnd.fill(&key[0], key.size());
+
+ std::vector<uint8_t> plainText(static_cast<uint8_t>(rnd.nextInt32()) + 1);
+ rnd.fill(&plainText[0], plainText.size());
+ std::vector<uint8_t> encryptedBytes(plainText.size() + 16);
+ DataRange encrypted(encryptedBytes);
+
+ std::vector<uint8_t> blankIv;
+ auto encryptStatus = mongo::crypto::fle2Encrypt({key}, {plainText}, {blankIv}, encrypted);
+ ASSERT_OK(encryptStatus);
+
+ auto planTextLength = mongo::fle2GetPlainTextLength(encrypted.length());
+ ASSERT_OK(planTextLength);
+ ASSERT_EQ(plainText.size(), planTextLength.getValue());
+
+ std::vector<uint8_t> decryptedBytes(planTextLength.getValue());
+ auto decryptStatus = mongo::crypto::fle2Decrypt({key}, encrypted, DataRange(decryptedBytes));
+ ASSERT_OK(decryptStatus);
+ ASSERT_TRUE(std::equal(
+ decryptedBytes.begin(), decryptedBytes.end(), plainText.begin(), plainText.end()));
+}
+
class Fle2AeadTestVectors : public unittest::Test {
public:
struct TestVector {
@@ -376,5 +402,94 @@ TEST_F(Fle2AeadTestVectors, Fle2AeadTestCaseLonger) {
evaluate(vector);
}
+class Fle2EncryptTestVectors : public unittest::Test {
+public:
+ struct TestVector {
+ StringData d;
+ StringData k;
+ StringData iv;
+ StringData c;
+ StringData r;
+ };
+
+ void evaluate(const TestVector& vector) {
+ std::string in = hexblob::decode(vector.d);
+ std::string key = hexblob::decode(vector.k);
+ std::string iv = hexblob::decode(vector.iv);
+ std::string expect = hexblob::decode(vector.r);
+
+ std::vector<uint8_t> encryptedBytes(in.length() + 16);
+ DataRange encrypted(encryptedBytes);
+
+ auto encryptStatus = mongo::crypto::fle2Encrypt({key}, {in}, {iv}, encrypted);
+ ASSERT_OK(encryptStatus);
+
+ ASSERT_EQ(expect.size(), encrypted.length());
+ ASSERT_TRUE(std::equal(encryptedBytes.begin(),
+ encryptedBytes.end(),
+ reinterpret_cast<uint8_t*>(expect.data())));
+
+ auto planTextLength = mongo::fle2GetPlainTextLength(encrypted.length());
+ ASSERT_OK(planTextLength);
+ ASSERT_EQ(in.length(), planTextLength.getValue());
+
+ std::vector<uint8_t> decryptedBytes(planTextLength.getValue());
+ auto decryptStatus =
+ mongo::crypto::fle2Decrypt({key}, encrypted, DataRange(decryptedBytes));
+ ASSERT_OK(decryptStatus);
+ ASSERT_EQ(in.length(), decryptStatus.getValue());
+ ASSERT_TRUE(std::equal(
+ decryptedBytes.begin(), decryptedBytes.end(), reinterpret_cast<uint8_t*>(in.data())));
+ }
+};
+
+TEST_F(Fle2EncryptTestVectors, Fle2AeadTestCaseMcdonald) {
+ TestVector vector;
+ // clang-format off
+ vector.d = "4f6c64204d63446f6e616c64206861642061206661726d2c2065692d65696f"_sd;
+ vector.k = "83cf8e8646fd42318a2113e1333d515163d5c0b21ddbfec374107b71ecbec165"_sd;
+ vector.iv = "e41c6d484108219172de421a426bbe52"_sd;
+ vector.c = "6fd63feca246e26f5f9b59380e6b35f07c572c9eb6207f00fbe1bf3d4c01f4"_sd;
+ vector.r = "e41c6d484108219172de421a426bbe526fd63feca246e26f5f9b59380e6b35f07c572c9eb6207f00fbe1bf3d4c01f4"_sd;
+ // clang-format on
+ evaluate(vector);
+}
+
+TEST_F(Fle2EncryptTestVectors, Fle2AeadTestCaseOneByte) {
+ TestVector vector;
+ // clang-format off
+ vector.d = "72"_sd;
+ vector.k = "43e75cda73214f659c9b0372b3069a9c5954e07dc22ec339749def6482d40be8"_sd;
+ vector.iv = "d61217b67b49ab2259fd901ad32e9d7d"_sd;
+ vector.c = "96"_sd;
+ vector.r = "d61217b67b49ab2259fd901ad32e9d7d96"_sd;
+ // clang-format on
+ evaluate(vector);
+}
+
+TEST_F(Fle2EncryptTestVectors, Fle2AeadTestCaseMedium) {
+ TestVector vector;
+ // clang-format off
+ vector.d = "6cdfd57aa3d4fac4561a559542517e4ec5549c21531830c527d45d5ede5e5b9fe1a4fa6b54d0d7304aaf22217eac18a87a4581e0f9038a67c04c3e68639c7f0d8d1cb94487902efe8497c2bc46d70b8e61beaf1c24258ea4c2c3a8a1787bc28a869460"_sd;
+ vector.k = "f2af73a805f2e94507d43a6898cd4bfa7883f2cdeef0d9f71a3c758fdf9e19e0"_sd;
+ vector.iv = "0da1a042da8346fc46f1f1e7da0d4594"_sd;
+ vector.c = "be3fe3a2a124046bcd1c378a36b6cb12111faf90ce066b9f6dd8e4f72089d900add8bc4cf35230f80cb1bba3d720877a5ac14a0601735a2ec482760d85e9009a71c8ffae85c37ad7b4aeaf63150cfef20b2fa82c27d7d722fb7f615b86dbc183624367"_sd;
+ vector.r = "0da1a042da8346fc46f1f1e7da0d4594be3fe3a2a124046bcd1c378a36b6cb12111faf90ce066b9f6dd8e4f72089d900add8bc4cf35230f80cb1bba3d720877a5ac14a0601735a2ec482760d85e9009a71c8ffae85c37ad7b4aeaf63150cfef20b2fa82c27d7d722fb7f615b86dbc183624367"_sd;
+ // clang-format on
+ evaluate(vector);
+}
+
+TEST_F(Fle2EncryptTestVectors, Fle2AeadTestCaseLarge) {
+ TestVector vector;
+ // clang-format off
+ vector.d = "04e5f1c0e0a0bad390a61e3bfe0a6c67ab99845c8177763ef8f2086f23500e880cb83f384614ee7af7eddadbeafc6a95145462a1c599a0c192858c57bbafe2df139859cf642d3bcf57c45fc29da11d93292cccf380f8b1bd8e7beff3bb63639e24c51939cffb5865aff85f7b2b8581bb3b6b3de50f71ea1c85f5fd2e1c58c9dd9c3ab05038b7312271423d9aa15ef2c1b5e4e9b4cc96096fe6cee50699cbbde7acd105cc067b641054fc929d88226951d125a6e600bb483092fc07434c76405f9ee3c3f5c46c99af636d53dc49df25e1a058d6b0e94216f29a6b18651c01a7b8f4080df902c1954ba18b120579da8245260ea13cee5a5ca4be780b7bd3ed6214f158f116ec4d98e343b26641a4d4856e957925943832bf30cfb84a44a34fc867ff4790da1f13a5ad8d56459d47ed3546c1cb2d660e22d773482da23a9362e7ce821dc341cf5951f9ad84627a06b34adbd85359ca72cd026713d39470373843f54b58020dd006a42ce78d93ba644516e9cd43d4660c172cf5d2d5a40de761a9d22b941ed34d5e039e10acae264b8fdddfc47e4b20ce0f7a3defeb592a166c30dcf3dec8f79a754eece5da19b847ce9b2bbb3e257a34bc16bf2c1da8c1ef6028444d51e9ff1fa0ba1e7fcf0b19412d5c1b869baf5207d695e2381401034ded0ac00c4c46ab6b06def25b8dba318bc756449a83796afd8af232719e1de8bd5d4d27d31d806b3aeb1e02cdea91feec5d77a8568195ce1beea1c38af1e1e81b56a9460db6173ad74958a5c09284e8dae56f50255f15b0ce1400d650c41f437d6c8ab1d9e58b5970ff924d50c8a95a243d78d1c3910cfd5f7b3beaf097591179e9731ac031387bead4b05b82335d138c8f23c34beaddbd97f5fa7f167c3ca789efd6743489f441206b19184c0664328c27766aad389c83c3a02203e2b362a2985be574fd6f7d7e250f84dbdfeede0a75cfdf447dec726f5a47de33665f7ec68911cd38fe8ef940ea7faa831392481cbb560491708d05a68c94841d8f709300bc2fe2a2192108b97e5e37581cda3580ac3f5883429bccda045b7c0beac21d75c401004a046b1afda702"_sd;
+ vector.k = "78d4626904c0d5d76e32426a3db42c763533342884f89de5219f4e46cfab78e1"_sd;
+ vector.iv = "4feca0f2860522033cf5c9451c0673f6"_sd;
+ vector.c = "ede3594ed590195a45939f362d49475297b53cfe61d2247370c77e75b75a00ab93113c1b7b148efa6d73fbd9b4f5a19057eff8e15ff19ed3392ababcc894d172eb8fdae9c2713a7cb5e76fff1c8763655c0a16730af28498f12f4596c53499fcc25bfdb8c9fcbc90e1f5dbc717fa60c4f545c5f138347df2d9d2d3971dd8e8c0b0559587c660a7c53d21be2a640b77d46690aa9ab37f6b6ca79311bcc9a643d757dfcec74a2f5205b2f2cb1da2625a48bec3db101eee574562be0c348662461a656267be8c044ee548f2233dd6f9909d3d3d7f25403ba754e755ccc9a079054df828bebb8ba32806bdd717aa6f52f9906a58b3fe43f04f764ae2345dbd56c3afa56a29f2ecc030cd4fe4a6a27a557e67c0d854f5e2d418261d30c9ac41d71baf59e3dbcfebd3a72adbec9c44a99fd37a846bec1bf02555bd54482693b39a260f4e64a89c5a1e53f18cf20bc3c94d5a802b906f61c6c68a8577523c57f3edf64174472db1b165c09d95c787d234c12e5711bbadd56fbb0547a33d1f4f08e258855c0b57b52d2377820b8e4d5642da44730c64c7ac7a9de3c3923774504761dabf716db3b5ebeb4522fdd337361c309944539efb78699b589df015e922dc9a1501e90ab6535fbb1428e581f988502528fb447e3774cc4fc0ea1118bb7f4fb6fc8378f711e9c94a19ec3a9fd649fc0938aabf4fe7efc04f247e23d688b8b866cfbaffa5ae84fd29ba0338a341139c11aa317b9951e2071c706cbd63cf6f2d1096e3352d6662a8df510c746831b55c0b65d992fec1fe19eefbca960305ff2e52d1939bf57a5c4c8b17a01ed6a07df5d56db9abdf464b465d726f53714529a08ad132a0da043aefa837f2706b81fd02e8d969fb67940662da28f3337d49967986bd4947bb773fa245752aa8bf2a986d26e1476f73230e6e78d162d82e6393e1f0392d3157ec0a3f26545a51bf74b8fa05bbe67070fddb70473be84f95e0bcf64f66c091885f2291db4d9a52db461f110953a963573dec698a66d1a54003d9aa96937027740c14df2e32dd9ae40a486e3807e826e038be11d36a4a7d899875f7d6e75311f4826c1dde"_sd;
+ vector.r = "4feca0f2860522033cf5c9451c0673f6ede3594ed590195a45939f362d49475297b53cfe61d2247370c77e75b75a00ab93113c1b7b148efa6d73fbd9b4f5a19057eff8e15ff19ed3392ababcc894d172eb8fdae9c2713a7cb5e76fff1c8763655c0a16730af28498f12f4596c53499fcc25bfdb8c9fcbc90e1f5dbc717fa60c4f545c5f138347df2d9d2d3971dd8e8c0b0559587c660a7c53d21be2a640b77d46690aa9ab37f6b6ca79311bcc9a643d757dfcec74a2f5205b2f2cb1da2625a48bec3db101eee574562be0c348662461a656267be8c044ee548f2233dd6f9909d3d3d7f25403ba754e755ccc9a079054df828bebb8ba32806bdd717aa6f52f9906a58b3fe43f04f764ae2345dbd56c3afa56a29f2ecc030cd4fe4a6a27a557e67c0d854f5e2d418261d30c9ac41d71baf59e3dbcfebd3a72adbec9c44a99fd37a846bec1bf02555bd54482693b39a260f4e64a89c5a1e53f18cf20bc3c94d5a802b906f61c6c68a8577523c57f3edf64174472db1b165c09d95c787d234c12e5711bbadd56fbb0547a33d1f4f08e258855c0b57b52d2377820b8e4d5642da44730c64c7ac7a9de3c3923774504761dabf716db3b5ebeb4522fdd337361c309944539efb78699b589df015e922dc9a1501e90ab6535fbb1428e581f988502528fb447e3774cc4fc0ea1118bb7f4fb6fc8378f711e9c94a19ec3a9fd649fc0938aabf4fe7efc04f247e23d688b8b866cfbaffa5ae84fd29ba0338a341139c11aa317b9951e2071c706cbd63cf6f2d1096e3352d6662a8df510c746831b55c0b65d992fec1fe19eefbca960305ff2e52d1939bf57a5c4c8b17a01ed6a07df5d56db9abdf464b465d726f53714529a08ad132a0da043aefa837f2706b81fd02e8d969fb67940662da28f3337d49967986bd4947bb773fa245752aa8bf2a986d26e1476f73230e6e78d162d82e6393e1f0392d3157ec0a3f26545a51bf74b8fa05bbe67070fddb70473be84f95e0bcf64f66c091885f2291db4d9a52db461f110953a963573dec698a66d1a54003d9aa96937027740c14df2e32dd9ae40a486e3807e826e038be11d36a4a7d899875f7d6e75311f4826c1dde"_sd;
+ // clang-format on
+ evaluate(vector);
+}
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/crypto/fle_crypto.cpp b/src/mongo/crypto/fle_crypto.cpp
index bc21ae56310..7b4fdfa851d 100644
--- a/src/mongo/crypto/fle_crypto.cpp
+++ b/src/mongo/crypto/fle_crypto.cpp
@@ -132,6 +132,8 @@ constexpr auto kDollarIn = "$in";
constexpr auto kEncryptedFields = "encryptedFields";
+constexpr size_t kHmacKeyOffset = 64;
+
#ifdef FLE2_DEBUG_STATE_COLLECTIONS
constexpr auto kDebugId = "_debug_id";
constexpr auto kDebugValuePosition = "_debug_value_position";
@@ -145,7 +147,7 @@ using UUIDBuf = std::array<uint8_t, UUID::kNumBytes>;
static_assert(sizeof(PrfBlock) == SHA256Block::kHashLength);
-PrfBlock blockToArray(SHA256Block& block) {
+PrfBlock blockToArray(const SHA256Block& block) {
PrfBlock data;
memcpy(data.data(), block.data(), sizeof(PrfBlock));
return data;
@@ -159,7 +161,15 @@ PrfBlock PrfBlockfromCDR(ConstDataRange block) {
return ret;
}
+ConstDataRange hmacKey(const KeyMaterial& keyMaterial) {
+ static_assert(kHmacKeyOffset + crypto::sym256KeySize <= crypto::kFieldLevelEncryptionKeySize);
+ invariant(crypto::kFieldLevelEncryptionKeySize == keyMaterial->size());
+ return {keyMaterial->data() + kHmacKeyOffset, crypto::sym256KeySize};
+}
+
PrfBlock prf(ConstDataRange key, ConstDataRange cdr) {
+ uassert(6378002, "Invalid key length", key.length() == crypto::sym256KeySize);
+
SHA256Block block;
SHA256Block::computeHmac(key.data<uint8_t>(), key.length(), {cdr}, &block);
return blockToArray(block);
@@ -173,6 +183,8 @@ PrfBlock prf(ConstDataRange key, uint64_t value) {
}
PrfBlock prf(ConstDataRange key, uint64_t value, int64_t value2) {
+ uassert(6378003, "Invalid key length", key.length() == crypto::sym256KeySize);
+
SHA256Block block;
std::array<char, sizeof(uint64_t)> bufValue;
@@ -287,43 +299,31 @@ FLEToken<TokenT> FLETokenFromCDR(ConstDataRange cdr) {
* Block size = 16 bytes
* SHA-256 - block size = 256 bits = 32 bytes
*/
-// TODO (SERVER-63780) - replace with call to CTR AEAD algorithm
StatusWith<std::vector<uint8_t>> encryptDataWithAssociatedData(ConstDataRange key,
ConstDataRange associatedData,
ConstDataRange plainText) {
+ std::vector<uint8_t> out(crypto::fle2AeadCipherOutputLength(plainText.length()));
- std::array<uint8_t, sizeof(uint64_t)> dataLenBitsEncodedStorage;
- DataRange dataLenBitsEncoded(dataLenBitsEncodedStorage);
- dataLenBitsEncoded.write<BigEndian<uint64_t>>(
- static_cast<uint64_t>(associatedData.length() * 8));
-
- std::vector<uint8_t> out;
- out.resize(crypto::aeadCipherOutputLength(plainText.length()));
-
- if (key.length() == 96) {
- key = ConstDataRange(key.data(), key.data() + 64);
- }
-
- auto s = crypto::aeadEncryptWithIV(
- key, plainText, ConstDataRange(0, 0), associatedData, dataLenBitsEncoded, out);
- if (!s.isOK()) {
- return s;
+ auto k = key.slice(crypto::kFieldLevelEncryption2KeySize);
+ auto status = crypto::fle2AeadEncrypt(k, plainText, ConstDataRange(0, 0), associatedData, out);
+ if (!status.isOK()) {
+ return status;
}
return {out};
}
-// TODO (SERVER-63780) - replace with call to CTR algorithm, NOT CTR AEAD
StatusWith<std::vector<uint8_t>> encryptData(ConstDataRange key, ConstDataRange plainText) {
+ std::vector<uint8_t> out(crypto::fle2CipherOutputLength(plainText.length()));
- std::array<uint8_t, 64> bigToken;
- std::copy(key.data(), key.data() + key.length(), bigToken.data());
- std::copy(key.data(), key.data() + key.length(), bigToken.data() + key.length());
+ auto status = crypto::fle2Encrypt(key, plainText, ConstDataRange(0, 0), out);
+ if (!status.isOK()) {
+ return status;
+ }
- return encryptDataWithAssociatedData(bigToken, ConstDataRange(0, 0), plainText);
+ return {out};
}
-// TODO (SERVER-63780) - replace with call to CTR algorithm, NOT CTR AEAD
StatusWith<std::vector<uint8_t>> encryptData(ConstDataRange key, uint64_t value) {
std::array<char, sizeof(uint64_t)> bufValue;
@@ -332,43 +332,44 @@ StatusWith<std::vector<uint8_t>> encryptData(ConstDataRange key, uint64_t value)
return encryptData(key, bufValue);
}
-// TODO (SERVER-63780) - replace with call to CTR AEAD algorithm
StatusWith<std::vector<uint8_t>> decryptDataWithAssociatedData(ConstDataRange key,
ConstDataRange associatedData,
ConstDataRange cipherText) {
- // TODO - key is too short, we have 32, need 64. The new API should only 32 bytes and this can
- // be removed
- if (key.length() == 96) {
- key = ConstDataRange(key.data(), key.data() + 64);
- }
-
- SymmetricKey sk(key.data<uint8_t>(), key.length(), 0, SymmetricKeyId("ignore"), 0);
-
- auto swLen = aeadGetMaximumPlainTextLength(cipherText.length());
+ auto swLen = fle2AeadGetPlainTextLength(cipherText.length());
if (!swLen.isOK()) {
return swLen.getStatus();
}
- std::vector<uint8_t> out;
- out.resize(swLen.getValue());
+ std::vector<uint8_t> out(static_cast<size_t>(swLen.getValue()));
- auto swOutLen = crypto::aeadDecrypt(sk, cipherText, associatedData, out);
+ auto k = key.slice(crypto::kFieldLevelEncryption2KeySize);
+ auto swOutLen = crypto::fle2AeadDecrypt(k, cipherText, associatedData, out);
if (!swOutLen.isOK()) {
return swOutLen.getStatus();
}
- out.resize(swOutLen.getValue());
+
+ if (out.size() != swOutLen.getValue()) {
+ return {ErrorCodes::InternalError, "Data length mismatch for AES-CTR-HMAC256-AEAD."};
+ }
+
return out;
}
-// TODO (SERVER-63780) - replace with call to CTR algorithm, NOT CTR AEAD
StatusWith<std::vector<uint8_t>> decryptData(ConstDataRange key, ConstDataRange cipherText) {
- std::array<uint8_t, 64> bigToken;
- std::copy(key.data(), key.data() + key.length(), bigToken.data());
- std::copy(key.data(), key.data() + key.length(), bigToken.data() + key.length());
+ auto plainTextLength = fle2GetPlainTextLength(cipherText.length());
+ if (!plainTextLength.isOK()) {
+ return plainTextLength.getStatus();
+ }
- return decryptDataWithAssociatedData(bigToken, ConstDataRange(0, 0), cipherText);
+ std::vector<uint8_t> out(static_cast<size_t>(plainTextLength.getValue()));
+
+ auto status = crypto::fle2Decrypt(key, cipherText, out);
+ if (!status.isOK()) {
+ return status.getStatus();
+ }
+
+ return {out};
}
-// TODO (SERVER-63780) - replace with call to CTR algorithm, NOT CTR AEAD
StatusWith<uint64_t> decryptUInt64(ConstDataRange key, ConstDataRange cipherText) {
auto swPlainText = decryptData(key, cipherText);
if (!swPlainText.isOK()) {
@@ -1100,12 +1101,12 @@ stdx::unordered_map<std::string, EncryptedField> toFieldMap(const EncryptedField
CollectionsLevel1Token FLELevel1TokenGenerator::generateCollectionsLevel1Token(
FLEIndexKey indexKey) {
- return prf(indexKey.toCDR(), kLevel1Collection);
+ return prf(hmacKey(indexKey.data), kLevel1Collection);
}
ServerDataEncryptionLevel1Token FLELevel1TokenGenerator::generateServerDataEncryptionLevel1Token(
FLEIndexKey indexKey) {
- return prf(indexKey.toCDR(), kLevelServerDataEncryption);
+ return prf(hmacKey(indexKey.data), kLevelServerDataEncryption);
}
diff --git a/src/mongo/crypto/fle_crypto.h b/src/mongo/crypto/fle_crypto.h
index 5e3261e924c..2460e0b1436 100644
--- a/src/mongo/crypto/fle_crypto.h
+++ b/src/mongo/crypto/fle_crypto.h
@@ -81,8 +81,10 @@ struct FLEKey {
FLEKey() = default;
FLEKey(KeyMaterial dataIn) : data(std::move(dataIn)) {
+ // This is not a mistake; same keys will be used in FLE2 as in FLE1
uassert(6364500,
- str::stream() << "Length of KeyMaterial is expected to be 32 bytes, found "
+ str::stream() << "Length of KeyMaterial is expected to be "
+ << crypto::kFieldLevelEncryptionKeySize << " bytes, found "
<< data->size(),
data->size() == crypto::kFieldLevelEncryptionKeySize);
}
diff --git a/src/mongo/crypto/fle_crypto_test.cpp b/src/mongo/crypto/fle_crypto_test.cpp
index bdefa073aab..4b91c4e6bde 100644
--- a/src/mongo/crypto/fle_crypto_test.cpp
+++ b/src/mongo/crypto/fle_crypto_test.cpp
@@ -60,10 +60,6 @@
#include "mongo/util/time_support.h"
-// TODO (SERVER-63780) - remove once we stop using AEAD for ECC crypto with empty associated data
-// Tomcrypt SHA implementation cannot accept it so we skip these tests for now
-#ifdef MONGO_CONFIG_SSL
-
namespace mongo {
template <FLETokenType tt>
@@ -113,22 +109,6 @@ std::basic_ostream<char>& operator<<(std::basic_ostream<char>& os, const FLEToke
return os << "{" << static_cast<int>(right.type) << "," << hexdump(right.data) << "}";
}
-std::array<uint8_t, 96> indexVec = {
- 0x44, 0xba, 0xd4, 0x1d, 0x6a, 0x9b, 0xdd, 0x38, 0x60, 0xc8, 0xfa, 0x9d, 0xf1, 0x1b, 0x8a, 0x75,
- 0x30, 0x61, 0x91, 0xb4, 0xd0, 0x17, 0x2e, 0xa7, 0x15, 0x18, 0xf1, 0x36, 0xc4, 0xef, 0x71, 0x68,
- 0x7e, 0xad, 0x69, 0xb7, 0x64, 0xcf, 0x37, 0x9a, 0xaa, 0x82, 0x22, 0xf7, 0x3a, 0xf5, 0xfa, 0x7a,
- 0x6b, 0xf2, 0xbf, 0x99, 0x52, 0xa5, 0xcf, 0x51, 0xee, 0xdf, 0xa6, 0x06, 0xb5, 0x0f, 0xa3, 0x49,
- 0x4d, 0x41, 0x7f, 0x53, 0xfd, 0xa2, 0x63, 0x5d, 0xa2, 0xcd, 0x3d, 0x78, 0x18, 0x32, 0x1e, 0x35,
- 0x1c, 0x74, 0xca, 0x19, 0x92, 0x3a, 0x1d, 0xc6, 0x2a, 0x7f, 0x72, 0x52, 0x0b, 0xce, 0x59, 0x6d};
-
-std::array<uint8_t, 96> userVec = {
- 0x7c, 0xc9, 0x46, 0xd8, 0x6b, 0x19, 0x3b, 0x75, 0xfb, 0xcf, 0x0d, 0xd1, 0xf1, 0xd3, 0xb1, 0x3a,
- 0x61, 0x99, 0xaa, 0xb3, 0x1c, 0x7e, 0x6a, 0xe1, 0xe3, 0x8a, 0xd0, 0x4b, 0xd6, 0xa3, 0xcb, 0xaa,
- 0x13, 0x86, 0x15, 0xfc, 0xcf, 0x45, 0xe7, 0xd1, 0x4a, 0x69, 0x44, 0xff, 0x01, 0x85, 0xb1, 0x88,
- 0x2a, 0xa3, 0x96, 0xbb, 0xd4, 0x92, 0x0c, 0x02, 0x0f, 0xe7, 0x22, 0xf6, 0xf7, 0x68, 0x49, 0x93,
- 0x1c, 0xff, 0x62, 0x4f, 0x8e, 0xdd, 0x4c, 0x70, 0x53, 0x78, 0x0e, 0xf9, 0x20, 0x0f, 0xba, 0xa1,
- 0xe7, 0x82, 0x84, 0x36, 0x2e, 0x28, 0x0e, 0xca, 0xfd, 0x16, 0x65, 0xbd, 0xa3, 0x7e, 0xa4, 0xb0};
-
constexpr auto kIndexKeyId = "12345678-1234-9876-1234-123456789012"_sd;
constexpr auto kUserKeyId = "ABCDEFAB-1234-9876-1234-123456789012"_sd;
static UUID indexKeyId = uassertStatusOK(UUID::parse(kIndexKeyId.toString()));
@@ -137,20 +117,30 @@ static UUID userKeyId = uassertStatusOK(UUID::parse(kUserKeyId.toString()));
std::vector<char> testValue = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19};
std::vector<char> testValue2 = {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29};
+const FLEIndexKey& getIndexKey() {
+ static std::string indexVec = hexblob::decode(
+ "7dbfebc619aa68a659f64b8e23ccd21644ac326cb74a26840c3d2420176c40ae088294d00ad6cae9684237b21b754cf503f085c25cd320bf035c3417416e1e6fe3d9219f79586582112740b2add88e1030d91926ae8afc13ee575cfb8bb965b7"_sd);
+ static FLEIndexKey indexKey(KeyMaterial(indexVec.begin(), indexVec.end()));
+ return indexKey;
+}
+
+const FLEUserKey& getUserKey() {
+ static std::string userVec = hexblob::decode(
+ "e6d43e476dc400c2ce44afcaf8c6a0e589702ff5e6cd98f87fbedbc55621184fa918d65e5c5b44d73c645b7520f9683dfe601afdf03e4e7d9d6226a79e519572c9cd61e3f9b6e0a87d186fe4ad763cb673064a6072b03dffc88b744e6f024807"_sd);
+ static FLEUserKey userKey(KeyMaterial(userVec.begin(), userVec.end()));
+ return userKey;
+}
+
class TestKeyVault : public FLEKeyVault {
public:
KeyMaterial getKey(const UUID& uuid) override;
-
- FLEIndexKey indexKey{KeyMaterial(indexVec.begin(), indexVec.end())};
-
- FLEUserKey userKey{KeyMaterial(userVec.begin(), userVec.end())};
};
KeyMaterial TestKeyVault::getKey(const UUID& uuid) {
if (uuid == indexKeyId) {
- return indexKey.data;
+ return getIndexKey().data;
} else if (uuid == userKeyId) {
- return userKey.data;
+ return getUserKey().data;
} else {
FAIL("not implemented");
return KeyMaterial();
@@ -158,128 +148,125 @@ KeyMaterial TestKeyVault::getKey(const UUID& uuid) {
}
// TODO (SERVER-63594) - regenerate test vectors and reimplement test
-#if 0
-TEST(FLETokens, TestVectors) {
- TestKeyVault keyVault;
-
- // Level 1
- auto collectionToken =
- FLELevel1TokenGenerator::generateCollectionsLevel1Token(keyVault.indexKey);
-
- ASSERT_EQUALS(CollectionsLevel1Token(decodePrf(
- "ff2103ff205a36f39704f643c270c129919f008c391d9589a6d2c86a7429d0d3"_sd)),
- collectionToken);
-
- ASSERT_EQUALS(
- ServerDataEncryptionLevel1Token(
- decodePrf("d915ccc1eb81687fb5fc5b799f48c99fbe17e7a011a46a48901b9ae3d790656b"_sd)),
- FLELevel1TokenGenerator::generateServerDataEncryptionLevel1Token(keyVault.indexKey));
-
- // Level 2
- auto edcToken = FLECollectionTokenGenerator::generateEDCToken(collectionToken);
- ASSERT_EQUALS(
- EDCToken(decodePrf("167d2d2ff8e4144df37ff759db593fde0ecc7d9636f96d62dacad672eccad349"_sd)),
-
- edcToken);
- auto escToken = FLECollectionTokenGenerator::generateESCToken(collectionToken);
- ASSERT_EQUALS(
- ESCToken(decodePrf("bfd480f1658f49f48985734737bc07d0bc36b88210277605c55ff3c9c3ef50b0"_sd)),
- escToken);
- auto eccToken = FLECollectionTokenGenerator::generateECCToken(collectionToken);
- ASSERT_EQUALS(
- ECCToken(decodePrf("9d34f9c182d75a5a3347c2f903e3e647105c651d52cf9555c9420ba07ddd3aa2"_sd)),
- eccToken);
- ASSERT_EQUALS(
- ECOCToken(decodePrf("e354e3b05e81e08b970ca061cb365163fd33dec2f982ddf9440e742ed288a8f8"_sd)),
- FLECollectionTokenGenerator::generateECOCToken(collectionToken));
-
-
- // Level 3
- std::vector<uint8_t> sampleValue = {0xc0, 0x7c, 0x0d, 0xf5, 0x12, 0x57, 0x94, 0x8e,
- 0x1a, 0x0f, 0xc7, 0x0d, 0xd4, 0x56, 0x8e, 0x3a,
- 0xf9, 0x9b, 0x23, 0xb3, 0x43, 0x4c, 0x98, 0x58,
- 0x23, 0x7c, 0xa7, 0xdb, 0x62, 0xdb, 0x97, 0x66};
-
- auto edcDataToken =
- FLEDerivedFromDataTokenGenerator::generateEDCDerivedFromDataToken(edcToken, sampleValue);
- ASSERT_EQUALS(EDCDerivedFromDataToken(decodePrf(
- "53eaa4c23a3ff65e6b7c7dbc4b1389cf0a6151b1ede5383a0673ff9c67855ff9"_sd)),
- edcDataToken);
-
- auto escDataToken =
- FLEDerivedFromDataTokenGenerator::generateESCDerivedFromDataToken(escToken, sampleValue);
- ASSERT_EQUALS(ESCDerivedFromDataToken(decodePrf(
- "acb3fab332131bbeaf112814f29ae0f2b10e97dc94b62db56c594661248e7467"_sd)),
- escDataToken);
-
- auto eccDataToken =
- FLEDerivedFromDataTokenGenerator::generateECCDerivedFromDataToken(eccToken, sampleValue);
- ASSERT_EQUALS(ECCDerivedFromDataToken(decodePrf(
- "826cfd35c35dcc7d4fbe13f33a3520749853bd1ea4c47919482252fba3a70cec"_sd)),
- eccDataToken);
-
- // Level 4
- FLECounter counter = 1234567890;
-
- auto edcDataCounterToken = FLEDerivedFromDataTokenAndContentionFactorTokenGenerator::
- generateEDCDerivedFromDataTokenAndContentionFactorToken(edcDataToken, counter);
- ASSERT_EQUALS(EDCDerivedFromDataTokenAndContentionFactorToken(decodePrf(
- "70fb9a3f760996f2f1438c5bf2a4d52bcba01b0badc3596276f49ffb2f0b136e"_sd)),
- edcDataCounterToken);
-
-
- auto escDataCounterToken = FLEDerivedFromDataTokenAndContentionFactorTokenGenerator::
- generateESCDerivedFromDataTokenAndContentionFactorToken(escDataToken, counter);
- ASSERT_EQUALS(ESCDerivedFromDataTokenAndContentionFactorToken(decodePrf(
- "7076c7b05fb4be4fe585eed930b852a6d088a0c55f3c96b50069e8a26ebfb347"_sd)),
- escDataCounterToken);
-
-
- auto eccDataCounterToken = FLEDerivedFromDataTokenAndContentionFactorTokenGenerator::
- generateECCDerivedFromDataTokenAndContentionFactorToken(eccDataToken, counter);
- ASSERT_EQUALS(ECCDerivedFromDataTokenAndContentionFactorToken(decodePrf(
- "6c6a349956c19f9c5e638e612011a71fbb71921edb540310c17cd0208b7f548b"_sd)),
- eccDataCounterToken);
-
-
- // Level 5
- auto edcTwiceToken =
- FLETwiceDerivedTokenGenerator::generateEDCTwiceDerivedToken(edcDataCounterToken);
- ASSERT_EQUALS(EDCTwiceDerivedToken(decodePrf(
- "3643fd370e2719c03234cdeec787dfdc7d8fceecafa8a992e3c1f9d4d53449fe"_sd)),
- edcTwiceToken);
-
- auto escTwiceTagToken =
- FLETwiceDerivedTokenGenerator::generateESCTwiceDerivedTagToken(escDataCounterToken);
- ASSERT_EQUALS(ESCTwiceDerivedTagToken(decodePrf(
- "c73bc4ff5e70222c653140b2b4998b4d62db973f20f116f66ff811a9a907a78f"_sd)),
- escTwiceTagToken);
- auto escTwiceValueToken =
- FLETwiceDerivedTokenGenerator::generateESCTwiceDerivedValueToken(escDataCounterToken);
- ASSERT_EQUALS(ESCTwiceDerivedValueToken(decodePrf(
- "34150c6f5ab56dc39ddb935accb7f53e5276322fa937650b76a4dda9723d6fba"_sd)),
- escTwiceValueToken);
-
-
- auto eccTwiceTagToken =
- FLETwiceDerivedTokenGenerator::generateECCTwiceDerivedTagToken(eccDataCounterToken);
- ASSERT_EQUALS(ECCTwiceDerivedTagToken(decodePrf(
- "0bc36f73062f5182c2403bffd155ec06eccfde0df8de5facaca4cc1cb320a385"_sd)),
- eccTwiceTagToken);
- auto eccTwiceValueToken =
- FLETwiceDerivedTokenGenerator::generateECCTwiceDerivedValueToken(eccDataCounterToken);
- ASSERT_EQUALS(ECCTwiceDerivedValueToken(decodePrf(
- "2d7e08d58afa9f5ad215636e566d38584cbb48467d1bc9ff376eeca01fbfda6f"_sd)),
- eccTwiceValueToken);
-}
-#endif
+//
+// TEST(FLETokens, TestVectors) {
+
+// // Level 1
+// auto collectionToken =
+// FLELevel1TokenGenerator::generateCollectionsLevel1Token(getIndexKey());
+
+// ASSERT_EQUALS(CollectionsLevel1Token(decodePrf(
+// "ff2103ff205a36f39704f643c270c129919f008c391d9589a6d2c86a7429d0d3"_sd)),
+// collectionToken);
+
+// ASSERT_EQUALS(ServerDataEncryptionLevel1Token(decodePrf(
+// "d915ccc1eb81687fb5fc5b799f48c99fbe17e7a011a46a48901b9ae3d790656b"_sd)),
+// FLELevel1TokenGenerator::generateServerDataEncryptionLevel1Token(getIndexKey()));
+
+// // Level 2
+// auto edcToken = FLECollectionTokenGenerator::generateEDCToken(collectionToken);
+// ASSERT_EQUALS(
+// EDCToken(decodePrf("167d2d2ff8e4144df37ff759db593fde0ecc7d9636f96d62dacad672eccad349"_sd)),
+
+// edcToken);
+// auto escToken = FLECollectionTokenGenerator::generateESCToken(collectionToken);
+// ASSERT_EQUALS(
+// ESCToken(decodePrf("bfd480f1658f49f48985734737bc07d0bc36b88210277605c55ff3c9c3ef50b0"_sd)),
+// escToken);
+// auto eccToken = FLECollectionTokenGenerator::generateECCToken(collectionToken);
+// ASSERT_EQUALS(
+// ECCToken(decodePrf("9d34f9c182d75a5a3347c2f903e3e647105c651d52cf9555c9420ba07ddd3aa2"_sd)),
+// eccToken);
+// ASSERT_EQUALS(
+// ECOCToken(decodePrf("e354e3b05e81e08b970ca061cb365163fd33dec2f982ddf9440e742ed288a8f8"_sd)),
+// FLECollectionTokenGenerator::generateECOCToken(collectionToken));
+
+
+// // Level 3
+// std::vector<uint8_t> sampleValue = {0xc0, 0x7c, 0x0d, 0xf5, 0x12, 0x57, 0x94, 0x8e,
+// 0x1a, 0x0f, 0xc7, 0x0d, 0xd4, 0x56, 0x8e, 0x3a,
+// 0xf9, 0x9b, 0x23, 0xb3, 0x43, 0x4c, 0x98, 0x58,
+// 0x23, 0x7c, 0xa7, 0xdb, 0x62, 0xdb, 0x97, 0x66};
+
+// auto edcDataToken =
+// FLEDerivedFromDataTokenGenerator::generateEDCDerivedFromDataToken(edcToken, sampleValue);
+// ASSERT_EQUALS(EDCDerivedFromDataToken(decodePrf(
+// "53eaa4c23a3ff65e6b7c7dbc4b1389cf0a6151b1ede5383a0673ff9c67855ff9"_sd)),
+// edcDataToken);
+
+// auto escDataToken =
+// FLEDerivedFromDataTokenGenerator::generateESCDerivedFromDataToken(escToken, sampleValue);
+// ASSERT_EQUALS(ESCDerivedFromDataToken(decodePrf(
+// "acb3fab332131bbeaf112814f29ae0f2b10e97dc94b62db56c594661248e7467"_sd)),
+// escDataToken);
+
+// auto eccDataToken =
+// FLEDerivedFromDataTokenGenerator::generateECCDerivedFromDataToken(eccToken, sampleValue);
+// ASSERT_EQUALS(ECCDerivedFromDataToken(decodePrf(
+// "826cfd35c35dcc7d4fbe13f33a3520749853bd1ea4c47919482252fba3a70cec"_sd)),
+// eccDataToken);
+
+// // Level 4
+// FLECounter counter = 1234567890;
+
+// auto edcDataCounterToken = FLEDerivedFromDataTokenAndContentionFactorTokenGenerator::
+// generateEDCDerivedFromDataTokenAndContentionFactorToken(edcDataToken, counter);
+// ASSERT_EQUALS(EDCDerivedFromDataTokenAndContentionFactorToken(decodePrf(
+// "70fb9a3f760996f2f1438c5bf2a4d52bcba01b0badc3596276f49ffb2f0b136e"_sd)),
+// edcDataCounterToken);
+
+
+// auto escDataCounterToken = FLEDerivedFromDataTokenAndContentionFactorTokenGenerator::
+// generateESCDerivedFromDataTokenAndContentionFactorToken(escDataToken, counter);
+// ASSERT_EQUALS(ESCDerivedFromDataTokenAndContentionFactorToken(decodePrf(
+// "7076c7b05fb4be4fe585eed930b852a6d088a0c55f3c96b50069e8a26ebfb347"_sd)),
+// escDataCounterToken);
+
+
+// auto eccDataCounterToken = FLEDerivedFromDataTokenAndContentionFactorTokenGenerator::
+// generateECCDerivedFromDataTokenAndContentionFactorToken(eccDataToken, counter);
+// ASSERT_EQUALS(ECCDerivedFromDataTokenAndContentionFactorToken(decodePrf(
+// "6c6a349956c19f9c5e638e612011a71fbb71921edb540310c17cd0208b7f548b"_sd)),
+// eccDataCounterToken);
+
+
+// // Level 5
+// auto edcTwiceToken =
+// FLETwiceDerivedTokenGenerator::generateEDCTwiceDerivedToken(edcDataCounterToken);
+// ASSERT_EQUALS(EDCTwiceDerivedToken(decodePrf(
+// "3643fd370e2719c03234cdeec787dfdc7d8fceecafa8a992e3c1f9d4d53449fe"_sd)),
+// edcTwiceToken);
+
+// auto escTwiceTagToken =
+// FLETwiceDerivedTokenGenerator::generateESCTwiceDerivedTagToken(escDataCounterToken);
+// ASSERT_EQUALS(ESCTwiceDerivedTagToken(decodePrf(
+// "c73bc4ff5e70222c653140b2b4998b4d62db973f20f116f66ff811a9a907a78f"_sd)),
+// escTwiceTagToken);
+// auto escTwiceValueToken =
+// FLETwiceDerivedTokenGenerator::generateESCTwiceDerivedValueToken(escDataCounterToken);
+// ASSERT_EQUALS(ESCTwiceDerivedValueToken(decodePrf(
+// "34150c6f5ab56dc39ddb935accb7f53e5276322fa937650b76a4dda9723d6fba"_sd)),
+// escTwiceValueToken);
+
+
+// auto eccTwiceTagToken =
+// FLETwiceDerivedTokenGenerator::generateECCTwiceDerivedTagToken(eccDataCounterToken);
+// ASSERT_EQUALS(ECCTwiceDerivedTagToken(decodePrf(
+// "0bc36f73062f5182c2403bffd155ec06eccfde0df8de5facaca4cc1cb320a385"_sd)),
+// eccTwiceTagToken);
+// auto eccTwiceValueToken =
+// FLETwiceDerivedTokenGenerator::generateECCTwiceDerivedValueToken(eccDataCounterToken);
+// ASSERT_EQUALS(ECCTwiceDerivedValueToken(decodePrf(
+// "2d7e08d58afa9f5ad215636e566d38584cbb48467d1bc9ff376eeca01fbfda6f"_sd)),
+// eccTwiceValueToken);
+// }
TEST(FLE_ESC, RoundTrip) {
TestKeyVault keyVault;
ConstDataRange value(testValue);
- auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(keyVault.indexKey);
+ auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(getIndexKey());
auto escToken = FLECollectionTokenGenerator::generateESCToken(c1);
ESCDerivedFromDataToken escDatakey =
@@ -341,7 +328,7 @@ TEST(FLE_ECC, RoundTrip) {
ConstDataRange value(testValue);
- auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(keyVault.indexKey);
+ auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(getIndexKey());
auto token = FLECollectionTokenGenerator::generateECCToken(c1);
ECCDerivedFromDataToken datakey =
@@ -430,7 +417,7 @@ TEST(FLE_ESC, EmuBinary_Empty) {
TestDocumentCollection coll;
ConstDataRange value(testValue);
- auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(keyVault.indexKey);
+ auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(getIndexKey());
auto escToken = FLECollectionTokenGenerator::generateESCToken(c1);
ESCDerivedFromDataToken escDatakey =
@@ -458,7 +445,7 @@ TEST(FLE_ESC, EmuBinary) {
TestDocumentCollection coll;
ConstDataRange value(testValue);
- auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(keyVault.indexKey);
+ auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(getIndexKey());
auto escToken = FLECollectionTokenGenerator::generateESCToken(c1);
ESCDerivedFromDataToken escDatakey =
@@ -491,7 +478,7 @@ TEST(FLE_ESC, EmuBinary2) {
TestDocumentCollection coll;
ConstDataRange value(testValue);
- auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(keyVault.indexKey);
+ auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(getIndexKey());
auto escToken = FLECollectionTokenGenerator::generateESCToken(c1);
@@ -546,7 +533,7 @@ TEST(FLE_ESC, EmuBinary_NullRecord) {
TestDocumentCollection coll;
ConstDataRange value(testValue);
- auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(keyVault.indexKey);
+ auto c1 = FLELevel1TokenGenerator::generateCollectionsLevel1Token(getIndexKey());
auto escToken = FLECollectionTokenGenerator::generateESCToken(c1);
ESCDerivedFromDataToken escDatakey =
@@ -852,10 +839,9 @@ TEST(FLE_EDC, ServerSide_Payloads) {
auto value = ConstDataRange(element.value(), element.value() + element.valuesize());
- auto collectionToken =
- FLELevel1TokenGenerator::generateCollectionsLevel1Token(keyVault.indexKey);
+ auto collectionToken = FLELevel1TokenGenerator::generateCollectionsLevel1Token(getIndexKey());
auto serverEncryptToken =
- FLELevel1TokenGenerator::generateServerDataEncryptionLevel1Token(keyVault.indexKey);
+ FLELevel1TokenGenerator::generateServerDataEncryptionLevel1Token(getIndexKey());
auto edcToken = FLECollectionTokenGenerator::generateEDCToken(collectionToken);
auto escToken = FLECollectionTokenGenerator::generateESCToken(collectionToken);
auto eccToken = FLECollectionTokenGenerator::generateECCToken(collectionToken);
@@ -1482,5 +1468,3 @@ TEST(FLE_Update, PullTokens) {
}
} // namespace mongo
-
-#endif
diff --git a/src/mongo/crypto/fle_data_frames.h b/src/mongo/crypto/fle_data_frames.h
index 2b65069c9bb..2d71dbb50a6 100644
--- a/src/mongo/crypto/fle_data_frames.h
+++ b/src/mongo/crypto/fle_data_frames.h
@@ -62,6 +62,17 @@ inline StatusWith<size_t> fle2AeadGetPlainTextLength(size_t cipherTextLen) {
}
/**
+ * Returns the length of the plaintext output given the ciphertext length. Only for FLE2.
+ */
+inline StatusWith<size_t> fle2GetPlainTextLength(size_t cipherTextLen) {
+ if (cipherTextLen > (crypto::aesCTRIVSize)) {
+ return cipherTextLen - crypto::aesCTRIVSize;
+ }
+
+ return Status(ErrorCodes::BadValue, "Invalid cipher text length");
+}
+
+/**
* This class is a helper for encryption. It holds a ConstDataRange over the
* plaintext to be encrypted and owns a buffer where the BinData subtype 6 is
* written out to. The encrypt function can only be called after the constructor
diff --git a/src/mongo/crypto/scripts/encryption_fle2_test_vectors.sh b/src/mongo/crypto/scripts/encryption_fle2_test_vectors.sh
new file mode 100644
index 00000000000..85fef45c3e6
--- /dev/null
+++ b/src/mongo/crypto/scripts/encryption_fle2_test_vectors.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+data="$(xxd -c10000 -p)"
+key="$(xxd -c100 -p -l32 /dev/urandom)"
+iv="$(xxd -c100 -p -l16 /dev/urandom)"
+ciphertext="$(echo "$data" | xxd -r -p | openssl enc -aes-256-ctr -K "$key" -iv "$iv" | xxd -c10000 -p)"
+
+cat <<EOF
+ // clang-format off
+ vector.d = "$data"_sd;
+ vector.k = "$key"_sd;
+ vector.iv = "$iv"_sd;
+ vector.c = "$ciphertext"_sd;
+ vector.r = "$iv$ciphertext"_sd;
+ // clang-format on
+EOF \ No newline at end of file
diff --git a/src/mongo/db/fle_crud_test.cpp b/src/mongo/db/fle_crud_test.cpp
index 64495605c3d..43cc1ccdbd2 100644
--- a/src/mongo/db/fle_crud_test.cpp
+++ b/src/mongo/db/fle_crud_test.cpp
@@ -162,22 +162,6 @@ BSONObj FLEQueryTestImpl::updateWithPreimage(const NamespaceString& nss,
return preimage;
}
-std::array<uint8_t, 96> indexVec = {
- 0x44, 0xba, 0xd4, 0x1d, 0x6a, 0x9b, 0xdd, 0x38, 0x60, 0xc8, 0xfa, 0x9d, 0xf1, 0x1b, 0x8a, 0x75,
- 0x30, 0x61, 0x91, 0xb4, 0xd0, 0x17, 0x2e, 0xa7, 0x15, 0x18, 0xf1, 0x36, 0xc4, 0xef, 0x71, 0x68,
- 0x7e, 0xad, 0x69, 0xb7, 0x64, 0xcf, 0x37, 0x9a, 0xaa, 0x82, 0x22, 0xf7, 0x3a, 0xf5, 0xfa, 0x7a,
- 0x6b, 0xf2, 0xbf, 0x99, 0x52, 0xa5, 0xcf, 0x51, 0xee, 0xdf, 0xa6, 0x06, 0xb5, 0x0f, 0xa3, 0x49,
- 0x4d, 0x41, 0x7f, 0x53, 0xfd, 0xa2, 0x63, 0x5d, 0xa2, 0xcd, 0x3d, 0x78, 0x18, 0x32, 0x1e, 0x35,
- 0x1c, 0x74, 0xca, 0x19, 0x92, 0x3a, 0x1d, 0xc6, 0x2a, 0x7f, 0x72, 0x52, 0x0b, 0xce, 0x59, 0x6d};
-
-std::array<uint8_t, 96> userVec = {
- 0x7c, 0xc9, 0x46, 0xd8, 0x6b, 0x19, 0x3b, 0x75, 0xfb, 0xcf, 0x0d, 0xd1, 0xf1, 0xd3, 0xb1, 0x3a,
- 0x61, 0x99, 0xaa, 0xb3, 0x1c, 0x7e, 0x6a, 0xe1, 0xe3, 0x8a, 0xd0, 0x4b, 0xd6, 0xa3, 0xcb, 0xaa,
- 0x13, 0x86, 0x15, 0xfc, 0xcf, 0x45, 0xe7, 0xd1, 0x4a, 0x69, 0x44, 0xff, 0x01, 0x85, 0xb1, 0x88,
- 0x2a, 0xa3, 0x96, 0xbb, 0xd4, 0x92, 0x0c, 0x02, 0x0f, 0xe7, 0x22, 0xf6, 0xf7, 0x68, 0x49, 0x93,
- 0x1c, 0xff, 0x62, 0x4f, 0x8e, 0xdd, 0x4c, 0x70, 0x53, 0x78, 0x0e, 0xf9, 0x20, 0x0f, 0xba, 0xa1,
- 0xe7, 0x82, 0x84, 0x36, 0x2e, 0x28, 0x0e, 0xca, 0xfd, 0x16, 0x65, 0xbd, 0xa3, 0x7e, 0xa4, 0xb0};
-
constexpr auto kIndexKeyId = "12345678-1234-9876-1234-123456789012"_sd;
constexpr auto kUserKeyId = "ABCDEFAB-1234-9876-1234-123456789012"_sd;
static UUID indexKeyId = uassertStatusOK(UUID::parse(kIndexKeyId.toString()));
@@ -186,14 +170,24 @@ static UUID userKeyId = uassertStatusOK(UUID::parse(kUserKeyId.toString()));
std::vector<char> testValue = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19};
std::vector<char> testValue2 = {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29};
+const FLEIndexKey& getIndexKey() {
+ static std::string indexVec = hexblob::decode(
+ "f502e66502ff5d4559452ce928a0f08557a9853c4dfeacca77cff482434f0ca1251fbd60d200bc35f24309521b45ad781b2d3c4df788cacef3c0e7beca8170b6cfc514ecfcf27e217ed697ae65c08272886324def514b14369c7c60414e80f22"_sd);
+ static FLEIndexKey indexKey(KeyMaterial(indexVec.begin(), indexVec.end()));
+ return indexKey;
+}
+
+const FLEUserKey& getUserKey() {
+ static std::string userVec = hexblob::decode(
+ "cbebdf05fe16099fef502a6d045c1cbb77d29d2fe19f51aec5079a81008305d8868358845d2e3ab38e4fa9cbffcd651a0fc07201d7c9ed9ca3279bfa7cd673ec37b362a0aaa92f95062405a999afd49e4b1f7f818f766c49715407011ac37fa9"_sd);
+ static FLEUserKey userKey(KeyMaterial(userVec.begin(), userVec.end()));
+ return userKey;
+}
+
class TestKeyVault : public FLEKeyVault {
public:
TestKeyVault() : _random(123456) {}
- FLEIndexKey indexKey{KeyMaterial(indexVec.begin(), indexVec.end())};
-
- FLEUserKey userKey{KeyMaterial(userVec.begin(), userVec.end())};
-
KeyMaterial getKey(const UUID& uuid) override;
uint64_t getCount() const {
@@ -207,9 +201,9 @@ private:
KeyMaterial TestKeyVault::getKey(const UUID& uuid) {
if (uuid == indexKeyId) {
- return indexKey.data;
+ return getIndexKey().data;
} else if (uuid == userKeyId) {
- return userKey.data;
+ return getUserKey().data;
} else {
if (_dynamicKeys.find(uuid) != _dynamicKeys.end()) {
return _dynamicKeys[uuid];