diff options
-rw-r--r-- | src/mongo/crypto/aead_encryption.cpp | 70 | ||||
-rw-r--r-- | src/mongo/crypto/aead_encryption.h | 21 | ||||
-rw-r--r-- | src/mongo/crypto/aead_encryption_test.cpp | 115 | ||||
-rw-r--r-- | src/mongo/crypto/fle_crypto.cpp | 93 | ||||
-rw-r--r-- | src/mongo/crypto/fle_crypto.h | 4 | ||||
-rw-r--r-- | src/mongo/crypto/fle_crypto_test.cpp | 288 | ||||
-rw-r--r-- | src/mongo/crypto/fle_data_frames.h | 11 | ||||
-rw-r--r-- | src/mongo/crypto/scripts/encryption_fle2_test_vectors.sh | 18 | ||||
-rw-r--r-- | src/mongo/db/fle_crud_test.cpp | 38 |
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]; |