Skip to content

Commit

Permalink
EaR: Update encryption methods to make 'cipherHeaderKey' optional
Browse files Browse the repository at this point in the history
Description

 diff-1: Address review comments

Major changes includes:
1. Update BlobCipher Encrypt/Decrypt classes to make 'headerCipher' optional
2. Update GetEncryptionCipherKeys actor methods to make 'headerCipherKey' optional
3. Update the usage across all encryption participant methods

Testing

BlobCipherUnitTest
EnryptedBackupCorrectness
BlobGranuleCorrectness*

devRunCorrectness - 100K
  • Loading branch information
sfc-gh-ahusain committed Feb 15, 2023
1 parent ec690fc commit 553e948
Show file tree
Hide file tree
Showing 10 changed files with 59 additions and 51 deletions.
2 changes: 1 addition & 1 deletion fdbclient/BackupAgentBase.actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ ACTOR static Future<Void> decodeBackupLogValue(Arena* arena,
state EncryptCipherDomainId domainId = logValue.encryptionHeader()->cipherTextDetails.encryptDomainId;
Reference<AsyncVar<ClientDBInfo> const> dbInfo = cx->clientInfo;
try {
TextAndHeaderCipherKeysOpt cipherKeys =
TextAndHeaderCipherKeys cipherKeys =
wait(getEncryptCipherKeys(dbInfo, *logValue.encryptionHeader(), BlobCipherMetrics::RESTORE));
logValue = logValue.decrypt(cipherKeys, tempArena, BlobCipherMetrics::BACKUP);
} catch (Error& e) {
Expand Down
6 changes: 3 additions & 3 deletions fdbclient/FileBackupAgent.actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ struct EncryptedRangeFileWriter : public IRangeFileWriter {
int64_t dataLen,
Arena* arena) {
Reference<AsyncVar<ClientDBInfo> const> dbInfo = cx->clientInfo;
TextAndHeaderCipherKeysOpt cipherKeys = wait(getEncryptCipherKeys(dbInfo, header, BlobCipherMetrics::RESTORE));
TextAndHeaderCipherKeys cipherKeys = wait(getEncryptCipherKeys(dbInfo, header, BlobCipherMetrics::RESTORE));
validateEncryptionHeader(cipherKeys.cipherHeaderKey, cipherKeys.cipherTextKey, header);
DecryptBlobCipherAes256Ctr decryptor(
cipherKeys.cipherTextKey, cipherKeys.cipherHeaderKey, header.iv, BlobCipherMetrics::BACKUP);
Expand All @@ -628,7 +628,7 @@ struct EncryptedRangeFileWriter : public IRangeFileWriter {
ACTOR static Future<Reference<BlobCipherKey>> refreshKey(EncryptedRangeFileWriter* self,
EncryptCipherDomainId domainId) {
Reference<AsyncVar<ClientDBInfo> const> dbInfo = self->cx->clientInfo;
TextAndHeaderCipherKeysOpt cipherKeys =
TextAndHeaderCipherKeys cipherKeys =
wait(getLatestEncryptCipherKeysForDomain(dbInfo, domainId, BlobCipherMetrics::BACKUP));
return cipherKeys.cipherTextKey;
}
Expand Down Expand Up @@ -670,7 +670,7 @@ struct EncryptedRangeFileWriter : public IRangeFileWriter {
state Reference<AsyncVar<ClientDBInfo> const> dbInfo = self->cx->clientInfo;

// Get text and header cipher key
TextAndHeaderCipherKeysOpt textAndHeaderCipherKeys =
TextAndHeaderCipherKeys textAndHeaderCipherKeys =
wait(getLatestEncryptCipherKeysForDomain(dbInfo, curDomainId, BlobCipherMetrics::BACKUP));
self->cipherKeys.textCipherKey = textAndHeaderCipherKeys.cipherTextKey;
self->cipherKeys.headerCipherKey = textAndHeaderCipherKeys.cipherHeaderKey;
Expand Down
18 changes: 9 additions & 9 deletions fdbclient/include/fdbclient/CommitTransaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ struct MutationRef {
return reinterpret_cast<const BlobCipherEncryptHeader*>(param1.begin());
}

MutationRef encrypt(TextAndHeaderCipherKeysOpt cipherKeys,
MutationRef encrypt(TextAndHeaderCipherKeys cipherKeys,
Arena& arena,
BlobCipherMetrics::UsageType usageType) const {
uint8_t iv[AES_256_IV_LENGTH] = { 0 };
Expand Down Expand Up @@ -203,7 +203,7 @@ struct MutationRef {
return encrypt(cipherKeys, SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_ID, arena, usageType);
}

MutationRef decrypt(TextAndHeaderCipherKeysOpt cipherKeys,
MutationRef decrypt(TextAndHeaderCipherKeys cipherKeys,
Arena& arena,
BlobCipherMetrics::UsageType usageType,
StringRef* buf = nullptr) const {
Expand All @@ -223,11 +223,11 @@ struct MutationRef {
Arena& arena,
BlobCipherMetrics::UsageType usageType,
StringRef* buf = nullptr) const {
TextAndHeaderCipherKeysOpt textAndHeaderKeys = getCipherKeys(cipherKeys);
TextAndHeaderCipherKeys textAndHeaderKeys = getCipherKeys(cipherKeys);
return decrypt(textAndHeaderKeys, arena, usageType, buf);
}

TextAndHeaderCipherKeysOpt getCipherKeys(
TextAndHeaderCipherKeys getCipherKeys(
const std::unordered_map<BlobCipherDetails, Reference<BlobCipherKey>>& cipherKeys) const {
const BlobCipherEncryptHeader* header = encryptionHeader();
auto getCipherKey = [&](const BlobCipherDetails& details) -> Reference<BlobCipherKey> {
Expand All @@ -238,7 +238,7 @@ struct MutationRef {
ASSERT(iter != cipherKeys.end() && iter->second.isValid());
return iter->second;
};
TextAndHeaderCipherKeysOpt textAndHeaderKeys;
TextAndHeaderCipherKeys textAndHeaderKeys;
textAndHeaderKeys.cipherHeaderKey = getCipherKey(header->cipherHeaderDetails);
textAndHeaderKeys.cipherTextKey = getCipherKey(header->cipherTextDetails);
return textAndHeaderKeys;
Expand Down Expand Up @@ -402,13 +402,13 @@ struct MutationsAndVersionRef {

struct MutationRefAndCipherKeys {
MutationRef mutation;
TextAndHeaderCipherKeysOpt cipherKeys;
TextAndHeaderCipherKeys cipherKeys;
};

struct EncryptedMutationsAndVersionRef {
VectorRef<MutationRef> mutations;
Optional<VectorRef<MutationRef>> encrypted;
std::vector<TextAndHeaderCipherKeysOpt> cipherKeys;
std::vector<TextAndHeaderCipherKeys> cipherKeys;
Version version = invalidVersion;
Version knownCommittedVersion = invalidVersion;

Expand All @@ -417,15 +417,15 @@ struct EncryptedMutationsAndVersionRef {
: version(version), knownCommittedVersion(knownCommittedVersion) {}
EncryptedMutationsAndVersionRef(VectorRef<MutationRef> mutations,
VectorRef<MutationRef> encrypted,
const std::vector<TextAndHeaderCipherKeysOpt>& cipherKeys,
const std::vector<TextAndHeaderCipherKeys>& cipherKeys,
Version version,
Version knownCommittedVersion)
: mutations(mutations), encrypted(encrypted), cipherKeys(cipherKeys), version(version),
knownCommittedVersion(knownCommittedVersion) {}
EncryptedMutationsAndVersionRef(Arena& to,
VectorRef<MutationRef> mutations,
Optional<VectorRef<MutationRef>> encrypt,
const std::vector<TextAndHeaderCipherKeysOpt>& cipherKeys,
const std::vector<TextAndHeaderCipherKeys>& cipherKeys,
Version version,
Version knownCommittedVersion)
: mutations(to, mutations), cipherKeys(cipherKeys), version(version),
Expand Down
31 changes: 15 additions & 16 deletions fdbclient/include/fdbclient/GetEncryptCipherKeys.actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,37 +288,37 @@ Future<std::unordered_map<BlobCipherDetails, Reference<BlobCipherKey>>> getEncry
return cipherKeys;
}

struct TextAndHeaderCipherKeysOpt {
struct TextAndHeaderCipherKeys {
Reference<BlobCipherKey> cipherTextKey;
Optional<Reference<BlobCipherKey>> cipherHeaderKey;
Reference<BlobCipherKey> cipherHeaderKey;
};

ACTOR template <class T>
Future<TextAndHeaderCipherKeysOpt> getLatestEncryptCipherKeysForDomain(Reference<AsyncVar<T> const> db,
EncryptCipherDomainId domainId,
BlobCipherMetrics::UsageType usageType) {
Future<TextAndHeaderCipherKeys> getLatestEncryptCipherKeysForDomain(Reference<AsyncVar<T> const> db,
EncryptCipherDomainId domainId,
BlobCipherMetrics::UsageType usageType) {
// TODO: Do not fetch header cipher key if authentication is diabled.
std::unordered_set<EncryptCipherDomainId> domainIds = { domainId, ENCRYPT_HEADER_DOMAIN_ID };
std::unordered_map<EncryptCipherDomainId, Reference<BlobCipherKey>> cipherKeys =
wait(getLatestEncryptCipherKeys(db, domainIds, usageType));
ASSERT(cipherKeys.count(domainId) > 0);
ASSERT(cipherKeys.count(ENCRYPT_HEADER_DOMAIN_ID) > 0);
TextAndHeaderCipherKeysOpt result{ cipherKeys.at(domainId), cipherKeys.at(ENCRYPT_HEADER_DOMAIN_ID) };
TextAndHeaderCipherKeys result{ cipherKeys.at(domainId), cipherKeys.at(ENCRYPT_HEADER_DOMAIN_ID) };
ASSERT(result.cipherTextKey.isValid());
ASSERT(result.cipherHeaderKey.present() && result.cipherHeaderKey.get().isValid());
ASSERT(result.cipherHeaderKey.isValid());
return result;
}

template <class T>
Future<TextAndHeaderCipherKeysOpt> getLatestSystemEncryptCipherKeys(const Reference<AsyncVar<T> const>& db,
BlobCipherMetrics::UsageType usageType) {
Future<TextAndHeaderCipherKeys> getLatestSystemEncryptCipherKeys(const Reference<AsyncVar<T> const>& db,
BlobCipherMetrics::UsageType usageType) {
return getLatestEncryptCipherKeysForDomain(db, SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_ID, usageType);
}

ACTOR template <class T>
Future<TextAndHeaderCipherKeysOpt> getEncryptCipherKeys(Reference<AsyncVar<T> const> db,
BlobCipherEncryptHeader header,
BlobCipherMetrics::UsageType usageType) {
Future<TextAndHeaderCipherKeys> getEncryptCipherKeys(Reference<AsyncVar<T> const> db,
BlobCipherEncryptHeader header,
BlobCipherMetrics::UsageType usageType) {
std::unordered_set<BlobCipherDetails> cipherDetails{ header.cipherTextDetails };

state bool isHeaderCipherNotPresent = header.flags.authTokenMode == ENCRYPT_HEADER_AUTH_TOKEN_MODE_NONE;
Expand All @@ -331,9 +331,9 @@ Future<TextAndHeaderCipherKeysOpt> getEncryptCipherKeys(Reference<AsyncVar<T> co
}
std::unordered_map<BlobCipherDetails, Reference<BlobCipherKey>> cipherKeys =
wait(getEncryptCipherKeys(db, cipherDetails, usageType));
TextAndHeaderCipherKeysOpt result;
TextAndHeaderCipherKeys result;

auto setCipherKey = [&](const BlobCipherDetails& details, TextAndHeaderCipherKeysOpt& result) {
auto setCipherKey = [&](const BlobCipherDetails& details, TextAndHeaderCipherKeys& result) {
if (!details.isValid()) {
return;
}
Expand All @@ -344,8 +344,7 @@ Future<TextAndHeaderCipherKeysOpt> getEncryptCipherKeys(Reference<AsyncVar<T> co
};
setCipherKey(header.cipherTextDetails, result);
setCipherKey(header.cipherHeaderDetails, result);
ASSERT(result.cipherTextKey.isValid() &&
(isHeaderCipherNotPresent || (result.cipherHeaderKey.present() && result.cipherHeaderKey.get().isValid())));
ASSERT(result.cipherTextKey.isValid() && (isHeaderCipherNotPresent || result.cipherHeaderKey.isValid()));

return result;
}
Expand Down
7 changes: 3 additions & 4 deletions fdbserver/BlobWorker.actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,11 +474,10 @@ ACTOR Future<BlobGranuleCipherKeysCtx> getLatestGranuleCipherKeys(Reference<Blob
ASSERT(domainKeyItr != domainKeyMap.end());
cipherKeysCtx.textCipherKey = BlobGranuleCipherKey::fromBlobCipherKey(domainKeyItr->second, *arena);

TextAndHeaderCipherKeysOpt systemCipherKeys =
TextAndHeaderCipherKeys systemCipherKeys =
wait(getLatestSystemEncryptCipherKeys(bwData->dbInfo, BlobCipherMetrics::BLOB_GRANULE));
ASSERT(systemCipherKeys.cipherHeaderKey.present() && systemCipherKeys.cipherHeaderKey.get().isValid());
cipherKeysCtx.headerCipherKey =
BlobGranuleCipherKey::fromBlobCipherKey(systemCipherKeys.cipherHeaderKey.get(), *arena);
ASSERT(systemCipherKeys.cipherHeaderKey.isValid());
cipherKeysCtx.headerCipherKey = BlobGranuleCipherKey::fromBlobCipherKey(systemCipherKeys.cipherHeaderKey, *arena);

cipherKeysCtx.ivRef = makeString(AES_256_IV_LENGTH, *arena);
deterministicRandom()->randomBytes(mutateString(cipherKeysCtx.ivRef), AES_256_IV_LENGTH);
Expand Down
2 changes: 1 addition & 1 deletion fdbserver/CommitProxyServer.actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1706,7 +1706,7 @@ ACTOR Future<WriteMutationRefVar> writeMutationEncryptedMutation(CommitBatchCont
ASSERT(encryptedMutation.isEncrypted());
Reference<AsyncVar<ServerDBInfo> const> dbInfo = self->pProxyCommitData->db;
header = encryptedMutation.encryptionHeader();
TextAndHeaderCipherKeysOpt cipherKeys = wait(getEncryptCipherKeys(dbInfo, *header, BlobCipherMetrics::TLOG));
TextAndHeaderCipherKeys cipherKeys = wait(getEncryptCipherKeys(dbInfo, *header, BlobCipherMetrics::TLOG));
MutationRef decryptedMutation = encryptedMutation.decrypt(cipherKeys, *arena, BlobCipherMetrics::TLOG);

ASSERT(decryptedMutation.type == mutation->type);
Expand Down
8 changes: 4 additions & 4 deletions fdbserver/KeyValueStoreMemory.actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ class KeyValueStoreMemory final : public IKeyValueStore, NonCopyable {
std::vector<std::pair<KeyValueMapPair, uint64_t>> dataSets;

bool enableEncryption;
TextAndHeaderCipherKeysOpt cipherKeys;
TextAndHeaderCipherKeys cipherKeys;
Future<Void> refreshCipherKeysActor;

int64_t commit_queue(OpQueue& ops, bool log, bool sequential = false) {
Expand Down Expand Up @@ -498,7 +498,7 @@ class KeyValueStoreMemory final : public IKeyValueStore, NonCopyable {
}

ASSERT(cipherKeys.cipherTextKey.isValid());
ASSERT(cipherKeys.cipherHeaderKey.present() && cipherKeys.cipherHeaderKey.get().isValid());
ASSERT(cipherKeys.cipherHeaderKey.isValid());
EncryptBlobCipherAes265Ctr cipher(
cipherKeys.cipherTextKey,
cipherKeys.cipherHeaderKey,
Expand Down Expand Up @@ -541,7 +541,7 @@ class KeyValueStoreMemory final : public IKeyValueStore, NonCopyable {
return data;
}
state BlobCipherEncryptHeader cipherHeader = *(BlobCipherEncryptHeader*)data.begin();
TextAndHeaderCipherKeysOpt cipherKeys =
TextAndHeaderCipherKeys cipherKeys =
wait(getEncryptCipherKeys(self->db, cipherHeader, BlobCipherMetrics::KV_MEMORY));
DecryptBlobCipherAes256Ctr cipher(
cipherKeys.cipherTextKey, cipherKeys.cipherHeaderKey, cipherHeader.iv, BlobCipherMetrics::KV_MEMORY);
Expand Down Expand Up @@ -981,7 +981,7 @@ class KeyValueStoreMemory final : public IKeyValueStore, NonCopyable {
}

ACTOR static Future<Void> updateCipherKeys(KeyValueStoreMemory* self) {
TextAndHeaderCipherKeysOpt cipherKeys =
TextAndHeaderCipherKeys cipherKeys =
wait(getLatestSystemEncryptCipherKeys(self->db, BlobCipherMetrics::KV_MEMORY));
self->cipherKeys = cipherKeys;
return Void();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ class AESEncryptionKeyProvider : public IPageEncryptionKeyProvider {

ACTOR static Future<EncryptionKey> getEncryptionKey(AESEncryptionKeyProvider* self, const void* encodingHeader) {
const BlobCipherEncryptHeader& header = reinterpret_cast<const EncodingHeader*>(encodingHeader)->encryption;
TextAndHeaderCipherKeysOpt cipherKeys =
TextAndHeaderCipherKeys cipherKeys =
wait(getEncryptCipherKeys(self->db, header, BlobCipherMetrics::KV_REDWOOD));
EncryptionKey encryptionKey;
encryptionKey.aesKey = cipherKeys;
Expand All @@ -321,7 +321,7 @@ class AESEncryptionKeyProvider : public IPageEncryptionKeyProvider {

ACTOR static Future<EncryptionKey> getLatestEncryptionKey(AESEncryptionKeyProvider* self, int64_t domainId) {
ASSERT(self->encryptionMode == EncryptionAtRestMode::DOMAIN_AWARE || domainId < 0);
TextAndHeaderCipherKeysOpt cipherKeys =
TextAndHeaderCipherKeys cipherKeys =
wait(getLatestEncryptCipherKeysForDomain(self->db, domainId, BlobCipherMetrics::KV_REDWOOD));
EncryptionKey encryptionKey;
encryptionKey.aesKey = cipherKeys;
Expand Down
26 changes: 18 additions & 8 deletions fdbserver/include/fdbserver/IPager.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ class ArenaPage : public ReferenceCounted<ArenaPage>, public FastAllocated<Arena
// Encryption key used to encrypt a page. Different encoding types may use different structs to represent
// an encryption key, and EncryptionKey is a union of these structs.
struct EncryptionKey {
TextAndHeaderCipherKeysOpt aesKey; // For AESEncryption and AESEncryptionWithAuth
TextAndHeaderCipherKeys aesKey; // For AESEncryption and AESEncryptionWithAuth
uint8_t xorKey; // For XOREncryption_TestOnly
uint8_t xorWith; // For XOREncryption_TestOnly
};
Expand Down Expand Up @@ -405,7 +405,7 @@ class ArenaPage : public ReferenceCounted<ArenaPage>, public FastAllocated<Arena
AESEncryptionWithAuthEncodingHeader>::type;

static void encode(void* header,
const TextAndHeaderCipherKeysOpt& cipherKeys,
const TextAndHeaderCipherKeys& cipherKeys,
uint8_t* payload,
int len,
PhysicalPageID seed) {
Expand All @@ -424,7 +424,7 @@ class ArenaPage : public ReferenceCounted<ArenaPage>, public FastAllocated<Arena
}

static void decode(void* header,
const TextAndHeaderCipherKeysOpt& cipherKeys,
const TextAndHeaderCipherKeys& cipherKeys,
uint8_t* payload,
int len,
PhysicalPageID seed) {
Expand Down Expand Up @@ -496,7 +496,9 @@ class ArenaPage : public ReferenceCounted<ArenaPage>, public FastAllocated<Arena
}

// Get the logical page buffer as a StringRef
Standalone<StringRef> asStringRef() const { return Standalone<StringRef>(StringRef(buffer, logicalSize)); }
Standalone<StringRef> asStringRef() const {
return Standalone<StringRef>(StringRef(buffer, logicalSize));
}

// Get a new ArenaPage that contains a copy of this page's data.
// extra is not copied to the returned page
Expand Down Expand Up @@ -624,10 +626,14 @@ class ArenaPage : public ReferenceCounted<ArenaPage>, public FastAllocated<Arena
}
}

const Arena& getArena() const { return arena; }
const Arena& getArena() const {
return arena;
}

// Returns true if the page's encoding type employs encryption
bool isEncrypted() const { return isEncodingTypeEncrypted(getEncodingType()); }
bool isEncrypted() const {
return isEncodingTypeEncrypted(getEncodingType());
}

// Return encryption domain id used. This method only use information from the encryptionKey.
// Caller should make sure encryption domain is in use.
Expand All @@ -641,7 +647,9 @@ class ArenaPage : public ReferenceCounted<ArenaPage>, public FastAllocated<Arena
}

// Return pointer to encoding header.
const void* getEncodingHeader() const { return encodingHeaderAvailable ? page->getEncodingHeader() : nullptr; }
const void* getEncodingHeader() const {
return encodingHeaderAvailable ? page->getEncodingHeader() : nullptr;
}

private:
Arena arena;
Expand All @@ -668,7 +676,9 @@ class ArenaPage : public ReferenceCounted<ArenaPage>, public FastAllocated<Arena
int payloadSize;

public:
EncodingType getEncodingType() const { return page->encodingType; }
EncodingType getEncodingType() const {
return page->encodingType;
}

PhysicalPageID getPhysicalPageID() const {
if (page->headerVersion == 1) {
Expand Down
6 changes: 3 additions & 3 deletions fdbserver/storageserver.actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3046,7 +3046,7 @@ ACTOR Future<std::pair<ChangeFeedStreamReply, bool>> getChangeFeedMutations(Stor
Version version, knownCommittedVersion;
Standalone<VectorRef<MutationRef>> mutations;
Standalone<VectorRef<MutationRef>> encryptedMutations;
std::vector<TextAndHeaderCipherKeysOpt> cipherKeys;
std::vector<TextAndHeaderCipherKeys> cipherKeys;
std::tie(id, version) = decodeChangeFeedDurableKey(res[i].key);
std::tie(encryptedMutations, knownCommittedVersion) = decodedMutations[i];
mutations = encryptedMutations;
Expand Down Expand Up @@ -6197,7 +6197,7 @@ void applyChangeFeedMutation(StorageServer* self,
it->mutations.back().cipherKeys.push_back(encryptedMutation.cipherKeys);
} else if (it->mutations.back().encrypted.present()) {
it->mutations.back().encrypted.get().push_back_deep(it->mutations.back().arena(), m);
it->mutations.back().cipherKeys.push_back(TextAndHeaderCipherKeysOpt());
it->mutations.back().cipherKeys.push_back(TextAndHeaderCipherKeys());
}
it->mutations.back().mutations.push_back_deep(it->mutations.back().arena(), m);

Expand Down Expand Up @@ -6264,7 +6264,7 @@ void applyChangeFeedMutation(StorageServer* self,
it->mutations.back().cipherKeys.push_back(encryptedMutation.cipherKeys);
} else if (it->mutations.back().encrypted.present()) {
it->mutations.back().encrypted.get().push_back_deep(it->mutations.back().arena(), m);
it->mutations.back().cipherKeys.push_back(TextAndHeaderCipherKeysOpt());
it->mutations.back().cipherKeys.push_back(TextAndHeaderCipherKeys());
}

it->mutations.back().mutations.push_back_deep(it->mutations.back().arena(), clearMutation);
Expand Down

0 comments on commit 553e948

Please sign in to comment.