Skip to content

Initial add of cached key decryptor#157

Open
coltfred wants to merge 3 commits intomainfrom
cached-key-ops
Open

Initial add of cached key decryptor#157
coltfred wants to merge 3 commits intomainfrom
cached-key-ops

Conversation

@coltfred
Copy link
Member

This is a strawman implementation of the idea of caching a DEK for reuse for a short period of time.

TODO:

  • Add the encryptor counterpart.
  • Decide if we should zero the DEK the caller sends in to the decryptor to ensure proper disposal
  • Add reporting of DEK usage on close

Comment on lines +190 to +200
private CompletableFuture<PlaintextDocument> decryptFields(Map<String, byte[]> document,
String documentEdek) {
// Check closed/expired state again before starting decryption
if (closed.get()) {
return CompletableFuture.failedFuture(new TscException(
TenantSecurityErrorCodes.DOCUMENT_DECRYPT_FAILED, "CachedKeyDecryptor has been closed"));
}
if (isExpired()) {
return CompletableFuture.failedFuture(new TscException(
TenantSecurityErrorCodes.DOCUMENT_DECRYPT_FAILED, "CachedKeyDecryptor has expired"));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-checking these feels really unnecessary to me. If you're following the calls from decrypt, there's not really any code between the check and the re-check, right? Or we could remove the checks from decrypt and only have them here

Comment on lines +202 to +215
// Parallel decrypt each field
Map<String, CompletableFuture<byte[]>> decryptOps = document.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
entry -> CompletableFuture.supplyAsync(
() -> CryptoUtils.decryptDocument(entry.getValue(), dek).join(),
encryptionExecutor)));

// Join all futures and build result
return CompletableFutures.tryCatchNonFatal(() -> {
Map<String, byte[]> decryptedBytes = decryptOps.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().join()));
return new PlaintextDocument(decryptedBytes, documentEdek);
});
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bummer that this has to just be duplicated code

Comment on lines +165 to +180
if (closed.get()) {
return CompletableFuture.failedFuture(new TscException(
TenantSecurityErrorCodes.DOCUMENT_DECRYPT_FAILED, "CachedKeyDecryptor has been closed"));
}
if (isExpired()) {
return CompletableFuture.failedFuture(new TscException(
TenantSecurityErrorCodes.DOCUMENT_DECRYPT_FAILED, "CachedKeyDecryptor has expired"));
}

// Validate EDEK matches
if (!this.edek.equals(edek)) {
return CompletableFuture
.failedFuture(new TscException(TenantSecurityErrorCodes.DOCUMENT_DECRYPT_FAILED,
"Provided EDEK does not match the cached EDEK. "
+ "This decryptor can only decrypt documents with matching EDEKs."));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These checks should probably move to a function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants