Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable mutation tracking work with encryption #11068

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
235 changes: 130 additions & 105 deletions fdbclient/BlobCipher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1114,25 +1114,29 @@ StringRef EncryptBlobCipherAes265Ctr::encrypt(const uint8_t* plaintext,
StringRef encryptBuf = makeString(plaintextLen, arena);
uint8_t* ciphertext = mutateString(encryptBuf);

int bytes{ 0 };
if (EVP_EncryptUpdate(ctx, ciphertext, &bytes, plaintext, plaintextLen) != 1) {
TraceEvent(SevWarn, "BlobCipherEncryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}
if (!g_network->isSimulated() || !ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER) {
int bytes{ 0 };
if (EVP_EncryptUpdate(ctx, ciphertext, &bytes, plaintext, plaintextLen) != 1) {
TraceEvent(SevWarn, "BlobCipherEncryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}

// Padding is not needed for AES CTR mode, so EncryptUpdate() should encrypt all the data at once.
if (bytes != plaintextLen) {
TraceEvent(SevWarn, "BlobCipherEncryptUnexpectedCipherLen")
.detail("PlaintextLen", plaintextLen)
.detail("EncryptedBufLen", bytes);
throw encrypt_ops_error();
}
// Padding is not needed for AES CTR mode, so EncryptUpdate() should encrypt all the data at once.
if (bytes != plaintextLen) {
TraceEvent(SevWarn, "BlobCipherEncryptUnexpectedCipherLen")
.detail("PlaintextLen", plaintextLen)
.detail("EncryptedBufLen", bytes);
throw encrypt_ops_error();
}

// EVP_CIPHER_CTX_reset(ctx) is called after EncryptUpdate() to make sure the same encryptor
// `EncryptBlobCipherAes265Ctr` could be reused to encrypt multiple text. Otherwise,
// ctx = EVP_CIPHER_CTX_new() is required before calling encrypt().
// EVP_CIPHER_CTX_reset(ctx) is called after EncryptUpdate() to make sure the same encryptor
// `EncryptBlobCipherAes265Ctr` could be reused to encrypt multiple text. Otherwise,
// ctx = EVP_CIPHER_CTX_new() is required before calling encrypt().
} else {
memcpy(ciphertext, plaintext, plaintextLen);
}

// Ensure encryption header authToken details sanity
ASSERT(isEncryptHeaderAuthTokenDetailsValid(authTokenMode, authTokenAlgo));
Expand Down Expand Up @@ -1160,20 +1164,22 @@ void EncryptBlobCipherAes265Ctr::encryptInplace(uint8_t* plaintext,
startTime = timer_monotonic();
}

int bytes{ 0 };
if (EVP_EncryptUpdate(ctx, plaintext, &bytes, plaintext, plaintextLen) != 1) {
TraceEvent(SevWarn, "BlobCipherInplaceEncryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}
if (!g_network->isSimulated() || !ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER) {
int bytes{ 0 };
if (EVP_EncryptUpdate(ctx, plaintext, &bytes, plaintext, plaintextLen) != 1) {
TraceEvent(SevWarn, "BlobCipherInplaceEncryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}

// Padding should be 0 for AES CTR mode, so encryptUpdate() should encrypt all the data
if (bytes != plaintextLen) {
TraceEvent(SevWarn, "BlobCipherInplaceEncryptUnexpectedCipherLen")
.detail("PlaintextLen", plaintextLen)
.detail("EncryptedBufLen", bytes);
throw encrypt_ops_error();
// Padding should be 0 for AES CTR mode, so encryptUpdate() should encrypt all the data
if (bytes != plaintextLen) {
TraceEvent(SevWarn, "BlobCipherInplaceEncryptUnexpectedCipherLen")
.detail("PlaintextLen", plaintextLen)
.detail("EncryptedBufLen", bytes);
throw encrypt_ops_error();
}
}

// Ensure encryption header authToken details sanity
Expand Down Expand Up @@ -1208,19 +1214,23 @@ Reference<EncryptBuf> EncryptBlobCipherAes265Ctr::encrypt(const uint8_t* plainte
Reference<EncryptBuf> encryptBuf = makeReference<EncryptBuf>(plaintextLen, arena);
uint8_t* ciphertext = encryptBuf->begin();

int bytes{ 0 };
if (EVP_EncryptUpdate(ctx, ciphertext, &bytes, plaintext, plaintextLen) != 1) {
TraceEvent(SevWarn, "BlobCipherEncryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}
if (!g_network->isSimulated() || !ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER) {
int bytes{ 0 };
if (EVP_EncryptUpdate(ctx, ciphertext, &bytes, plaintext, plaintextLen) != 1) {
TraceEvent(SevWarn, "BlobCipherEncryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}

if (bytes != plaintextLen) {
TraceEvent(SevWarn, "BlobCipherEncryptUnexpectedCipherLen")
.detail("PlaintextLen", plaintextLen)
.detail("EncryptedBufLen", bytes);
throw encrypt_ops_error();
if (bytes != plaintextLen) {
TraceEvent(SevWarn, "BlobCipherEncryptUnexpectedCipherLen")
.detail("PlaintextLen", plaintextLen)
.detail("EncryptedBufLen", bytes);
throw encrypt_ops_error();
}
} else {
memcpy(ciphertext, plaintext, plaintextLen);
}

updateEncryptHeader(ciphertext, plaintextLen, header);
Expand Down Expand Up @@ -1253,20 +1263,22 @@ void EncryptBlobCipherAes265Ctr::encryptInplace(uint8_t* plaintext,

memset(reinterpret_cast<uint8_t*>(header), 0, sizeof(BlobCipherEncryptHeader));

int bytes{ 0 };
if (EVP_EncryptUpdate(ctx, plaintext, &bytes, plaintext, plaintextLen) != 1) {
TraceEvent(SevWarn, "BlobCipherInplaceEncryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}
if (!g_network->isSimulated() || !ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER) {
int bytes{ 0 };
if (EVP_EncryptUpdate(ctx, plaintext, &bytes, plaintext, plaintextLen) != 1) {
TraceEvent(SevWarn, "BlobCipherInplaceEncryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}

// Padding should be 0 for AES CTR mode, so encryptUpdate() should encrypt all the data
if (bytes != plaintextLen) {
TraceEvent(SevWarn, "BlobCipherInplaceEncryptUnexpectedCipherLen")
.detail("PlaintextLen", plaintextLen)
.detail("EncryptedBufLen", bytes);
throw encrypt_ops_error();
// Padding should be 0 for AES CTR mode, so encryptUpdate() should encrypt all the data
if (bytes != plaintextLen) {
TraceEvent(SevWarn, "BlobCipherInplaceEncryptUnexpectedCipherLen")
.detail("PlaintextLen", plaintextLen)
.detail("EncryptedBufLen", bytes);
throw encrypt_ops_error();
}
}

updateEncryptHeader(plaintext, plaintextLen, header);
Expand Down Expand Up @@ -1452,19 +1464,24 @@ StringRef DecryptBlobCipherAes256Ctr::decrypt(const uint8_t* ciphertext,
StringRef decrypted = makeString(ciphertextLen, arena);

uint8_t* plaintext = mutateString(decrypted);
int bytesDecrypted{ 0 };
if (!EVP_DecryptUpdate(ctx, plaintext, &bytesDecrypted, ciphertext, ciphertextLen)) {
TraceEvent(SevWarn, "BlobCipherDecryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}

if (bytesDecrypted != ciphertextLen) {
TraceEvent(SevWarn, "BlobCipherDecryptUnexpectedPlaintextLen")
.detail("CiphertextLen", ciphertextLen)
.detail("DecryptedBufLen", bytesDecrypted);
throw encrypt_ops_error();
if (!g_network->isSimulated() || !ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER) {
int bytesDecrypted{ 0 };
if (!EVP_DecryptUpdate(ctx, plaintext, &bytesDecrypted, ciphertext, ciphertextLen)) {
TraceEvent(SevWarn, "BlobCipherDecryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}

if (bytesDecrypted != ciphertextLen) {
TraceEvent(SevWarn, "BlobCipherDecryptUnexpectedPlaintextLen")
.detail("CiphertextLen", ciphertextLen)
.detail("DecryptedBufLen", bytesDecrypted);
throw encrypt_ops_error();
}
} else {
memcpy(plaintext, ciphertext, ciphertextLen);
}

if (CLIENT_KNOBS->ENABLE_ENCRYPTION_CPU_TIME_LOGGING && decryptTime) {
Expand Down Expand Up @@ -1580,19 +1597,23 @@ Reference<EncryptBuf> DecryptBlobCipherAes256Ctr::decrypt(const uint8_t* ciphert
}

uint8_t* plaintext = decrypted->begin();
int bytesDecrypted{ 0 };
if (!EVP_DecryptUpdate(ctx, plaintext, &bytesDecrypted, ciphertext, ciphertextLen)) {
TraceEvent(SevWarn, "BlobCipherDecryptUpdateFailed")
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId)
.detail("EncryptDomainId", header.cipherTextDetails.encryptDomainId);
throw encrypt_ops_error();
}
if (!g_network->isSimulated() || !ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER) {
int bytesDecrypted{ 0 };
if (!EVP_DecryptUpdate(ctx, plaintext, &bytesDecrypted, ciphertext, ciphertextLen)) {
TraceEvent(SevWarn, "BlobCipherDecryptUpdateFailed")
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId)
.detail("EncryptDomainId", header.cipherTextDetails.encryptDomainId);
throw encrypt_ops_error();
}

if (bytesDecrypted != ciphertextLen) {
TraceEvent(SevWarn, "BlobCipherDecryptUnexpectedPlaintextLen")
.detail("CiphertextLen", ciphertextLen)
.detail("DecryptedBufLen", bytesDecrypted);
throw encrypt_ops_error();
if (bytesDecrypted != ciphertextLen) {
TraceEvent(SevWarn, "BlobCipherDecryptUnexpectedPlaintextLen")
.detail("CiphertextLen", ciphertextLen)
.detail("DecryptedBufLen", bytesDecrypted);
throw encrypt_ops_error();
}
} else {
memcpy(plaintext, ciphertext, ciphertextLen);
}

decrypted->setLogicalSize(ciphertextLen);
Expand Down Expand Up @@ -1635,20 +1656,22 @@ void DecryptBlobCipherAes256Ctr::decryptInplace(uint8_t* ciphertext,
ASSERT(authTokensValidationDone);
}

int bytesDecrypted{ 0 };
if (!EVP_DecryptUpdate(ctx, ciphertext, &bytesDecrypted, ciphertext, ciphertextLen)) {
TraceEvent(SevWarn, "BlobCipherDecryptUpdateFailed")
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId)
.detail("EncryptDomainId", header.cipherTextDetails.encryptDomainId);
throw encrypt_ops_error();
}
if (!g_network->isSimulated() || !ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER) {
int bytesDecrypted{ 0 };
if (!EVP_DecryptUpdate(ctx, ciphertext, &bytesDecrypted, ciphertext, ciphertextLen)) {
TraceEvent(SevWarn, "BlobCipherDecryptUpdateFailed")
.detail("BaseCipherId", header.cipherTextDetails.baseCipherId)
.detail("EncryptDomainId", header.cipherTextDetails.encryptDomainId);
throw encrypt_ops_error();
}

// Padding should be 0 for AES CTR mode, so DecryptUpdate() should decrypt all the data
if (bytesDecrypted != ciphertextLen) {
TraceEvent(SevWarn, "BlobCipherDecryptUnexpectedPlaintextLen")
.detail("CiphertextLen", ciphertextLen)
.detail("DecryptedBufLen", bytesDecrypted);
throw encrypt_ops_error();
// Padding should be 0 for AES CTR mode, so DecryptUpdate() should decrypt all the data
if (bytesDecrypted != ciphertextLen) {
TraceEvent(SevWarn, "BlobCipherDecryptUnexpectedPlaintextLen")
.detail("CiphertextLen", ciphertextLen)
.detail("DecryptedBufLen", bytesDecrypted);
throw encrypt_ops_error();
}
}

if (CLIENT_KNOBS->ENABLE_ENCRYPTION_CPU_TIME_LOGGING && decryptTime) {
Expand Down Expand Up @@ -1677,20 +1700,22 @@ void DecryptBlobCipherAes256Ctr::decryptInplace(uint8_t* ciphertext,
EncryptAuthTokenAlgo authTokenAlgo;
validateEncryptHeader(ciphertext, ciphertextLen, headerRef, &authTokenMode, &authTokenAlgo);

int bytesDecrypted{ 0 };
if (!EVP_DecryptUpdate(ctx, ciphertext, &bytesDecrypted, ciphertext, ciphertextLen)) {
TraceEvent(SevWarn, "BlobCipherDecryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}
if (!g_network->isSimulated() || !ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER) {
int bytesDecrypted{ 0 };
if (!EVP_DecryptUpdate(ctx, ciphertext, &bytesDecrypted, ciphertext, ciphertextLen)) {
TraceEvent(SevWarn, "BlobCipherDecryptUpdateFailed")
.detail("BaseCipherId", textCipherKey->getBaseCipherId())
.detail("EncryptDomainId", textCipherKey->getDomainId());
throw encrypt_ops_error();
}

// Padding should be 0 for AES CTR mode, so DecryptUpdate() should decrypt all the data
if (bytesDecrypted != ciphertextLen) {
TraceEvent(SevWarn, "BlobCipherDecryptUnexpectedPlaintextLen")
.detail("CiphertextLen", ciphertextLen)
.detail("DecryptedBufLen", bytesDecrypted);
throw encrypt_ops_error();
// Padding should be 0 for AES CTR mode, so DecryptUpdate() should decrypt all the data
if (bytesDecrypted != ciphertextLen) {
TraceEvent(SevWarn, "BlobCipherDecryptUnexpectedPlaintextLen")
.detail("CiphertextLen", ciphertextLen)
.detail("DecryptedBufLen", bytesDecrypted);
throw encrypt_ops_error();
}
}

if (CLIENT_KNOBS->ENABLE_ENCRYPTION_CPU_TIME_LOGGING && decryptTime) {
Expand Down
1 change: 1 addition & 0 deletions fdbclient/include/fdbclient/BlobCipher.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@

#define AES_256_KEY_LENGTH 32
#define AES_256_IV_LENGTH 16
#define ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER 0 // works when simulation

constexpr const int INVALID_ENCRYPT_HEADERS_FLAG_VERSION = 0;
constexpr const int INVALID_ENCRYPT_HEADER_ALGO_HEADER_VERSION = 0;
Expand Down
15 changes: 14 additions & 1 deletion fdbserver/MutationTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ TraceEvent debugMutationEnabled(const char* context, Version version, MutationRe
return TraceEvent();
}

TraceEvent debugEncrptedMutationEnabled(const char* context, Version version, MutationRef const& mutation, UID id) {
ASSERT(mutation.type == mutation.Encrypted);
MutationRef fmutation = Standalone(mutation);
Arena tempArena;
ArenaReader reader(tempArena, mutation.param2, AssumeVersion(ProtocolVersion::withEncryptionAtRest()));
reader >> fmutation;
return debugMutationEnabled(context, version, fmutation, id);
}

TraceEvent debugKeyRangeEnabled(const char* context, Version version, KeyRangeRef const& keys, UID id) {
return debugMutation(context, version, MutationRef(MutationRef::DebugKeyRange, keys.begin, keys.end), id);
}
Expand Down Expand Up @@ -117,7 +126,11 @@ TraceEvent debugTagsAndMessageEnabled(const char* context, Version version, Stri

#if MUTATION_TRACKING_ENABLED
TraceEvent debugMutation(const char* context, Version version, MutationRef const& mutation, UID id) {
return debugMutationEnabled(context, version, mutation, id);
if (mutation.type == mutation.Encrypted) {
return debugEncrptedMutationEnabled(context, version, mutation, id);
} else {
return debugMutationEnabled(context, version, mutation, id);
}
}
TraceEvent debugKeyRange(const char* context, Version version, KeyRangeRef const& keys, UID id) {
return debugKeyRangeEnabled(context, version, keys, id);
Expand Down
14 changes: 8 additions & 6 deletions fdbserver/tester.actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1947,12 +1947,14 @@ void encryptionAtRestPlaintextMarkerCheck() {
while (std::getline(f, buf)) {
// SOMEDAY: using 'std::boyer_moore_horspool_searcher' would significantly improve search
// time
if (buf.find(g_simulator->dataAtRestPlaintextMarker.get()) != std::string::npos) {
TraceEvent(SevError, "EncryptionAtRestPlaintextMarkerCheckPanic")
.detail("Filename", itr->path().string())
.detail("LineBuf", buf)
.detail("Marker", g_simulator->dataAtRestPlaintextMarker.get());
success = false;
if (!ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER) {
if (buf.find(g_simulator->dataAtRestPlaintextMarker.get()) != std::string::npos) {
TraceEvent(SevError, "EncryptionAtRestPlaintextMarkerCheckPanic")
.detail("Filename", itr->path().string())
.detail("LineBuf", buf)
.detail("Marker", g_simulator->dataAtRestPlaintextMarker.get());
success = false;
}
}
count++;
}
Expand Down
10 changes: 8 additions & 2 deletions fdbserver/workloads/EncryptionOps.actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,10 @@ struct EncryptionOpsWorkload : TestWorkload {

// validate encrypted buffer size and contents (not matching with plaintext)
ASSERT_EQ(encrypted->getLogicalSize(), len);
ASSERT_NE(memcmp(encrypted->begin(), payload, len), 0);
if (ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER)
ASSERT_EQ(memcmp(encrypted->begin(), payload, len), 0);
else
ASSERT_NE(memcmp(encrypted->begin(), payload, len), 0);
ASSERT_EQ(header->flags.headerVersion, EncryptBlobCipherAes265Ctr::ENCRYPT_HEADER_VERSION);

metrics->updateEncryptionTime(std::chrono::duration<double, std::nano>(end - start).count());
Expand Down Expand Up @@ -353,7 +356,10 @@ struct EncryptionOpsWorkload : TestWorkload {

ASSERT_EQ(encrypted.size(), len);
ASSERT_EQ(headerRef->flagsVersion(), CLIENT_KNOBS->ENCRYPT_HEADER_FLAGS_VERSION);
ASSERT_NE(memcmp(encrypted.begin(), payload, len), 0);
if (ENABLE_MUTATION_TRACKING_WITH_BLOB_CIPHER)
ASSERT_EQ(memcmp(encrypted.begin(), payload, len), 0);
else
ASSERT_NE(memcmp(encrypted.begin(), payload, len), 0);

metrics->updateEncryptionTime(std::chrono::duration<double, std::nano>(end - start).count());
return encrypted;
Expand Down