Add transit rewrap batch method.

Closes: gh-687
Original pull request: gh-819
This commit is contained in:
Nanne Baars
2023-09-29 10:56:29 +02:00
committed by Mark Paluch
parent aa4d601e37
commit 347e3b771c
3 changed files with 91 additions and 0 deletions

View File

@@ -221,6 +221,15 @@ public interface VaultTransitOperations {
*/
String rewrap(String keyName, String ciphertext, VaultTransitContext transitContext);
/**
* Rewrap the provided batch of cipher text using the latest version of the named key.
* @param batchRequest a list of {@link Ciphertext} which includes cipher text and a
* context
* @return the rewrapped result in the order of {@code batchRequest} ciphertexts.
* @see #rewrap(String, String)
*/
List<VaultEncryptionResult> rewrap(String keyName, List<Ciphertext> batchRequest);
/**
* Create a HMAC using {@code keyName} of given {@link Plaintext} using the default
* hash algorithm. The key can be of any type supported by transit; the raw key will

View File

@@ -339,6 +339,32 @@ public class VaultTransitTemplate implements VaultTransitOperations {
.get("ciphertext");
}
@Override
public List<VaultEncryptionResult> rewrap(String keyName, List<Ciphertext> batchRequest) {
Assert.hasText(keyName, "Key name must not be empty");
Assert.notEmpty(batchRequest, "BatchRequest must not be null and must have at least one entry");
List<Map<String, String>> batch = new ArrayList<>(batchRequest.size());
for (Ciphertext request : batchRequest) {
Map<String, String> vaultRequest = new LinkedHashMap<>(2);
vaultRequest.put("ciphertext", request.getCiphertext());
if (request.getContext() != null) {
applyTransitOptions(request.getContext(), vaultRequest);
}
batch.add(vaultRequest);
}
VaultResponse vaultResponse = this.vaultOperations.write(String.format("%s/rewrap/%s", this.path, keyName),
Collections.singletonMap("batch_input", batch));
return toRewrappedEncryptionResults(vaultResponse, batchRequest);
}
@Override
public Hmac getHmac(String keyName, Plaintext plaintext) {
@@ -512,6 +538,37 @@ public class VaultTransitTemplate implements VaultTransitOperations {
return result;
}
static List<VaultEncryptionResult> toRewrappedEncryptionResults(VaultResponse vaultResponse,
List<Ciphertext> batchRequest) {
List<VaultEncryptionResult> result = new ArrayList<>(batchRequest.size());
List<Map<String, String>> batchData = getBatchData(vaultResponse);
for (int i = 0; i < batchRequest.size(); i++) {
VaultEncryptionResult encrypted;
Ciphertext ciphertext = batchRequest.get(i);
if (batchData.size() > i) {
Map<String, String> data = batchData.get(i);
if (StringUtils.hasText(data.get("error"))) {
encrypted = new VaultEncryptionResult(new VaultException(data.get("error")));
}
else {
encrypted = new VaultEncryptionResult(
toCiphertext(data.get("ciphertext"), ciphertext.getContext()));
}
}
else {
encrypted = new VaultEncryptionResult(new VaultException("No result for cipher text #" + i));
}
result.add(encrypted);
}
return result;
}
static List<VaultDecryptionResult> toDecryptionResults(VaultResponse vaultResponse, List<Ciphertext> batchRequest) {
List<VaultDecryptionResult> result = new ArrayList<>(batchRequest.size());

View File

@@ -534,6 +534,31 @@ class VaultTransitTemplateIntegrationTests extends IntegrationTestSupport {
assertThat(rewrapped).startsWith("vault:v2");
}
@Test
void encryptAndRewrapInBatchShouldCreateCiphertext() {
this.transitOperations.createKey("mykey",
VaultTransitKeyCreationRequest.builder().convergentEncryption(true).derived(true).build());
VaultTransitContext transitRequest = VaultTransitContext.builder() //
.context("blubb".getBytes()) //
.nonce("123456789012".getBytes()) //
.build();
String ciphertext1 = this.transitOperations.encrypt("mykey", "hello-world".getBytes(), transitRequest);
String ciphertext2 = this.transitOperations.encrypt("mykey", "hello-vault".getBytes(), transitRequest);
this.transitOperations.rotate("mykey");
List<Ciphertext> batchRequest = List.of(ciphertext1, ciphertext2)
.stream()
.map(ct -> Ciphertext.of(ct).with(transitRequest))
.toList();
List<VaultEncryptionResult> rewrappedResult = this.transitOperations.rewrap("mykey", batchRequest);
Assertions.assertThat(rewrappedResult)
.hasSize(2)
.allMatch(result -> result.get().getCiphertext().startsWith("vault:v2"));
}
@Test
@RequiresVaultVersion(BATCH_INTRODUCED_IN_VERSION)
void shouldBatchEncrypt() {