Add transit rewrap batch method.
Closes: gh-687 Original pull request: gh-819
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user