flags) {
+ public KeyringTraceEntry(final String keyNamespace, final String keyName, final KeyringTraceFlag... flags) {
notBlank(keyNamespace, "keyNamespace is required");
notBlank(keyName, "keyName is required");
notEmpty(flags, "At least one flag is required");
this.keyNamespace = keyNamespace;
this.keyName = keyName;
- this.flags = Collections.unmodifiableSet(flags);
+ this.flags = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(flags)));
}
/**
diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java
new file mode 100644
index 000000000..5832658a9
--- /dev/null
+++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
+ * in compliance with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.amazonaws.encryptionsdk.keyrings;
+
+import com.amazonaws.encryptionsdk.EncryptedDataKey;
+import com.amazonaws.encryptionsdk.internal.JceKeyCipher;
+import com.amazonaws.encryptionsdk.internal.Utils;
+
+import javax.crypto.SecretKey;
+
+/**
+ * A {@code Keyring} which does local AES-GCM encryption
+ * decryption of data keys using the provided wrapping key.
+ *
+ * Instantiate by using the {@code StandardKeyrings.rawAes(...)} factory method.
+ */
+class RawAesKeyring extends RawKeyring {
+
+ RawAesKeyring(String keyNamespace, String keyName, SecretKey wrappingKey) {
+ super(keyNamespace, keyName, JceKeyCipher.aesGcm(wrappingKey));
+ }
+
+ @Override
+ boolean validToDecrypt(EncryptedDataKey encryptedDataKey) {
+
+ // the key provider ID of the encrypted data key must
+ // have a value equal to this keyring's key namespace.
+ if (!keyNamespace.equals(encryptedDataKey.getProviderId())) {
+ return false;
+ }
+
+ // the key name obtained from the encrypted data key's key provider
+ // information must have a value equal to this keyring's key name.
+ if (!Utils.arrayPrefixEquals(encryptedDataKey.getProviderInformation(), keyNameBytes, keyNameBytes.length)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ KeyringTraceEntry traceOnEncrypt() {
+ return new KeyringTraceEntry(keyNamespace, keyName,
+ KeyringTraceFlag.ENCRYPTED_DATA_KEY,
+ KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT);
+ }
+
+ @Override
+ KeyringTraceEntry traceOnDecrypt() {
+ return new KeyringTraceEntry(keyNamespace, keyName,
+ KeyringTraceFlag.DECRYPTED_DATA_KEY,
+ KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT);
+ }
+}
diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java
new file mode 100644
index 000000000..8daa567f8
--- /dev/null
+++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
+ * in compliance with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.amazonaws.encryptionsdk.keyrings;
+
+import com.amazonaws.encryptionsdk.EncryptedDataKey;
+import com.amazonaws.encryptionsdk.internal.JceKeyCipher;
+import com.amazonaws.encryptionsdk.internal.Utils;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import static com.amazonaws.encryptionsdk.EncryptedDataKey.PROVIDER_ENCODING;
+import static java.util.Objects.requireNonNull;
+import static org.apache.commons.lang3.Validate.notBlank;
+
+/**
+ * A keyring supporting local encryption and decryption using either RSA or AES-GCM.
+ */
+abstract class RawKeyring implements Keyring {
+
+ final String keyNamespace;
+ final String keyName;
+ final byte[] keyNameBytes;
+ private final JceKeyCipher jceKeyCipher;
+ private static final Logger LOGGER = Logger.getLogger(RawKeyring.class.getName());
+
+ RawKeyring(final String keyNamespace, final String keyName, JceKeyCipher jceKeyCipher) {
+ notBlank(keyNamespace, "keyNamespace is required");
+ notBlank(keyName, "keyName is required");
+ requireNonNull(jceKeyCipher, "jceKeyCipher is required");
+
+ this.keyNamespace = keyNamespace;
+ this.keyName = keyName;
+ this.keyNameBytes = keyName.getBytes(PROVIDER_ENCODING);
+ this.jceKeyCipher = jceKeyCipher;
+ }
+
+ /**
+ * Returns true if the given encrypted data key may be decrypted with this keyring.
+ *
+ * @param encryptedDataKey The encrypted data key.
+ * @return True if the key may be decrypted, false otherwise.
+ */
+ abstract boolean validToDecrypt(EncryptedDataKey encryptedDataKey);
+
+ /**
+ * Gets the trace entry to add the the keyring trace upon successful encryption.
+ *
+ * @return The keyring trace entry.
+ */
+ abstract KeyringTraceEntry traceOnEncrypt();
+
+ /**
+ * Gets the trace entry to add to the keyring trace upon successful decryption.
+ *
+ * @return The keyring trace entry.
+ */
+ abstract KeyringTraceEntry traceOnDecrypt();
+
+ @Override
+ public void onEncrypt(EncryptionMaterials encryptionMaterials) {
+ requireNonNull(encryptionMaterials, "encryptionMaterials are required");
+
+ if (!encryptionMaterials.hasPlaintextDataKey()) {
+ generateDataKey(encryptionMaterials);
+ }
+
+ final EncryptedDataKey encryptedDataKey = jceKeyCipher.encryptKey(
+ encryptionMaterials.getPlaintextDataKey().getEncoded(),
+ keyName, keyNamespace, encryptionMaterials.getEncryptionContext());
+ encryptionMaterials.addEncryptedDataKey(encryptedDataKey, traceOnEncrypt());
+ }
+
+ @Override
+ public void onDecrypt(DecryptionMaterials decryptionMaterials, List extends EncryptedDataKey> encryptedDataKeys) {
+ requireNonNull(decryptionMaterials, "decryptionMaterials are required");
+ requireNonNull(encryptedDataKeys, "encryptedDataKeys are required");
+
+ if (decryptionMaterials.hasPlaintextDataKey() || encryptedDataKeys.isEmpty()) {
+ return;
+ }
+
+ for (EncryptedDataKey encryptedDataKey : encryptedDataKeys) {
+ if (validToDecrypt(encryptedDataKey)) {
+ try {
+ final byte[] decryptedKey = jceKeyCipher.decryptKey(
+ encryptedDataKey, keyName, decryptionMaterials.getEncryptionContext());
+ decryptionMaterials.setPlaintextDataKey(
+ new SecretKeySpec(decryptedKey, decryptionMaterials.getAlgorithmSuite().getDataKeyAlgo()),
+ traceOnDecrypt());
+ return;
+ } catch (Exception e) {
+ LOGGER.info("Could not decrypt key due to: " + e.getMessage());
+ }
+ }
+ }
+
+ LOGGER.warning("Could not decrypt any data keys");
+ }
+
+ private void generateDataKey(EncryptionMaterials encryptionMaterials) {
+ final byte[] rawKey = new byte[encryptionMaterials.getAlgorithmSuite().getDataKeyLength()];
+ Utils.getSecureRandom().nextBytes(rawKey);
+ final SecretKey key = new SecretKeySpec(rawKey, encryptionMaterials.getAlgorithmSuite().getDataKeyAlgo());
+
+ encryptionMaterials.setPlaintextDataKey(key, new KeyringTraceEntry(keyNamespace, keyName, KeyringTraceFlag.GENERATED_DATA_KEY));
+ }
+}
diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java
new file mode 100644
index 000000000..486cd26e6
--- /dev/null
+++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
+ * in compliance with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.amazonaws.encryptionsdk.keyrings;
+
+import com.amazonaws.encryptionsdk.EncryptedDataKey;
+import com.amazonaws.encryptionsdk.internal.JceKeyCipher;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Arrays;
+
+/**
+ * A {@link Keyring} which does local RSA encryption and decryption of data keys using the
+ * provided public and private keys.
+ *
+ * Instantiate by using the {@code StandardKeyrings.rawRsa(...)} factory method.
+ */
+class RawRsaKeyring extends RawKeyring {
+
+ RawRsaKeyring(String keyNamespace, String keyName, PublicKey publicKey, PrivateKey privateKey, String transformation) {
+ super(keyNamespace, keyName, JceKeyCipher.rsa(publicKey, privateKey, transformation));
+ }
+
+ @Override
+ boolean validToDecrypt(EncryptedDataKey encryptedDataKey) {
+
+ // the key provider ID of the encrypted data key must
+ // have a value equal to this keyring's key namespace.
+ if (!keyNamespace.equals(encryptedDataKey.getProviderId())) {
+ return false;
+ }
+
+ // the encrypted data key's key provider information
+ // must have a value equal to this keyring's key name.
+ if (!Arrays.equals(encryptedDataKey.getProviderInformation(), keyNameBytes)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ KeyringTraceEntry traceOnEncrypt() {
+ return new KeyringTraceEntry(keyNamespace, keyName, KeyringTraceFlag.ENCRYPTED_DATA_KEY);
+ }
+
+ @Override
+ KeyringTraceEntry traceOnDecrypt() {
+ return new KeyringTraceEntry(keyNamespace, keyName, KeyringTraceFlag.DECRYPTED_DATA_KEY);
+ }
+}
diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/StandardKeyrings.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/StandardKeyrings.java
new file mode 100644
index 000000000..d36dae07e
--- /dev/null
+++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/StandardKeyrings.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
+ * in compliance with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.amazonaws.encryptionsdk.keyrings;
+
+import javax.crypto.SecretKey;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * Factory methods for instantiating the standard {@code Keyring}s provided by the AWS Encryption SDK.
+ */
+public class StandardKeyrings {
+
+ private StandardKeyrings() {
+ }
+
+ /**
+ * Constructs a {@code Keyring} which does local AES-GCM encryption
+ * decryption of data keys using the provided wrapping key.
+ *
+ * @param keyNamespace A value that, together with the key name, identifies the wrapping key.
+ * @param keyName A value that, together with the key namespace, identifies the wrapping key.
+ * @param wrappingKey The AES key input to AES-GCM to encrypt plaintext data keys.
+ * @return The {@link Keyring}
+ */
+ public static Keyring rawAes(String keyNamespace, String keyName, SecretKey wrappingKey) {
+ return new RawAesKeyring(keyNamespace, keyName, wrappingKey);
+ }
+
+ /**
+ * Constructs a {@code Keyring} which does local RSA encryption and decryption of data keys using the
+ * provided public and private keys. If {@code privateKey} is {@code null} then the returned {@code Keyring}
+ * can only be used for encryption.
+ *
+ * @param keyNamespace A value that, together with the key name, identifies the wrapping key.
+ * @param keyName A value that, together with the key namespace, identifies the wrapping key.
+ * @param publicKey The RSA public key used by this keyring to encrypt data keys.
+ * @param privateKey The RSA private key used by this keyring to decrypt data keys.
+ * @param wrappingAlgorithm The RSA algorithm to use with this keyring.
+ * @return The {@link Keyring}
+ */
+ public static Keyring rawRsa(String keyNamespace, String keyName, PublicKey publicKey, PrivateKey privateKey, String wrappingAlgorithm) {
+ return new RawRsaKeyring(keyNamespace, keyName, publicKey, privateKey, wrappingAlgorithm);
+ }
+}
diff --git a/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java
index 0c0ba52c7..94423b884 100644
--- a/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java
+++ b/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java
@@ -3,17 +3,14 @@
import java.security.PublicKey;
import com.amazonaws.encryptionsdk.DataKey;
-import com.amazonaws.encryptionsdk.keyrings.KeyringTrace;
public final class DecryptionMaterials {
private final DataKey> dataKey;
private final PublicKey trailingSignatureKey;
- private final KeyringTrace keyringTrace;
private DecryptionMaterials(Builder b) {
dataKey = b.getDataKey();
trailingSignatureKey = b.getTrailingSignatureKey();
- keyringTrace = b.getKeyringTrace();
}
public DataKey> getDataKey() {
@@ -24,10 +21,6 @@ public PublicKey getTrailingSignatureKey() {
return trailingSignatureKey;
}
- public KeyringTrace getKeyringTrace() {
- return keyringTrace;
- }
-
public static Builder newBuilder() {
return new Builder();
}
@@ -39,12 +32,10 @@ public Builder toBuilder() {
public static final class Builder {
private DataKey> dataKey;
private PublicKey trailingSignatureKey;
- private KeyringTrace keyringTrace;
private Builder(DecryptionMaterials result) {
this.dataKey = result.getDataKey();
this.trailingSignatureKey = result.getTrailingSignatureKey();
- this.keyringTrace = result.getKeyringTrace();
}
private Builder() {}
@@ -67,15 +58,6 @@ public Builder setTrailingSignatureKey(PublicKey trailingSignatureKey) {
return this;
}
- public KeyringTrace getKeyringTrace() {
- return keyringTrace;
- }
-
- public Builder setKeyringTrace(KeyringTrace keyringTrace) {
- this.keyringTrace = keyringTrace;
- return this;
- }
-
public DecryptionMaterials build() {
return new DecryptionMaterials(this);
}
diff --git a/src/main/java/com/amazonaws/encryptionsdk/model/EncryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/model/EncryptionMaterials.java
index f9b05a153..1a40d7c36 100644
--- a/src/main/java/com/amazonaws/encryptionsdk/model/EncryptionMaterials.java
+++ b/src/main/java/com/amazonaws/encryptionsdk/model/EncryptionMaterials.java
@@ -11,7 +11,6 @@
import com.amazonaws.encryptionsdk.CryptoAlgorithm;
import com.amazonaws.encryptionsdk.MasterKey;
-import com.amazonaws.encryptionsdk.keyrings.KeyringTrace;
/**
* Contains the cryptographic materials needed for an encryption operation.
@@ -25,7 +24,6 @@ public final class EncryptionMaterials {
private final SecretKey cleartextDataKey;
private final PrivateKey trailingSignatureKey;
private final List masterKeys;
- private final KeyringTrace keyringTrace;
private EncryptionMaterials(Builder b) {
this.algorithm = b.algorithm;
@@ -34,7 +32,6 @@ private EncryptionMaterials(Builder b) {
this.cleartextDataKey = b.cleartextDataKey;
this.trailingSignatureKey = b.trailingSignatureKey;
this.masterKeys = b.getMasterKeys();
- this.keyringTrace = b.keyringTrace;
}
public Builder toBuilder() {
@@ -103,13 +100,12 @@ public List getMasterKeys() {
Objects.equals(encryptedDataKeys, that.encryptedDataKeys) &&
Objects.equals(cleartextDataKey, that.cleartextDataKey) &&
Objects.equals(trailingSignatureKey, that.trailingSignatureKey) &&
- Objects.equals(masterKeys, that.masterKeys) &&
- Objects.equals(keyringTrace, that.keyringTrace);
+ Objects.equals(masterKeys, that.masterKeys);
}
@Override public int hashCode() {
return Objects.hash(algorithm, encryptionContext, encryptedDataKeys, cleartextDataKey, trailingSignatureKey,
- masterKeys, keyringTrace);
+ masterKeys);
}
public static class Builder {
@@ -119,7 +115,6 @@ public static class Builder {
private SecretKey cleartextDataKey;
private PrivateKey trailingSignatureKey;
private List masterKeys = Collections.emptyList();
- private KeyringTrace keyringTrace;
private Builder() {}
@@ -130,7 +125,6 @@ private Builder(EncryptionMaterials r) {
cleartextDataKey = r.cleartextDataKey;
trailingSignatureKey = r.trailingSignatureKey;
setMasterKeys(r.masterKeys);
- keyringTrace = r.keyringTrace;
}
public EncryptionMaterials build() {
@@ -190,14 +184,5 @@ public Builder setMasterKeys(List masterKeys) {
this.masterKeys = Collections.unmodifiableList(new ArrayList<>(masterKeys));
return this;
}
-
- public KeyringTrace getKeyringTrace() {
- return keyringTrace;
- }
-
- public Builder setKeyringTrace(KeyringTrace keyringTrace) {
- this.keyringTrace = keyringTrace;
- return this;
- }
}
}
diff --git a/src/main/java/com/amazonaws/encryptionsdk/model/KeyBlob.java b/src/main/java/com/amazonaws/encryptionsdk/model/KeyBlob.java
index c44fd2f8f..dbea9f6b4 100644
--- a/src/main/java/com/amazonaws/encryptionsdk/model/KeyBlob.java
+++ b/src/main/java/com/amazonaws/encryptionsdk/model/KeyBlob.java
@@ -542,7 +542,7 @@ public int getKeyProviderIdLen() {
*/
@Override
public String getProviderId() {
- String s = new String(keyProviderId_, StandardCharsets.UTF_8);
+ String s = new String(keyProviderId_, PROVIDER_ENCODING);
// The following assume statement essentially says that different
// calls to the String constructor above, with the same parameters,
// result in strings with the same contents. The assumption is
@@ -627,7 +627,7 @@ public byte[] getEncryptedDataKey() {
//@ assignable \nothing;
//@ signals_only AwsCryptoException;
public void setKeyProviderId(final String keyProviderId) {
- final byte[] keyProviderIdBytes = keyProviderId.getBytes(StandardCharsets.UTF_8);
+ final byte[] keyProviderIdBytes = keyProviderId.getBytes(PROVIDER_ENCODING);
//@ assume Arrays.equalArrays(keyProviderIdBytes, EncryptedDataKey.s2ba(keyProviderId));
if (keyProviderIdBytes.length > Constants.UNSIGNED_SHORT_MAX_VAL) {
throw new AwsCryptoException(
diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterialsTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterialsTest.java
new file mode 100644
index 000000000..68687d4ad
--- /dev/null
+++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterialsTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
+ * in compliance with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.amazonaws.encryptionsdk.keyrings;
+
+import com.amazonaws.encryptionsdk.CryptoAlgorithm;
+import com.amazonaws.encryptionsdk.internal.TrailingSignatureAlgorithm;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.util.Collections;
+import java.util.Map;
+
+import static com.amazonaws.encryptionsdk.internal.RandomBytesGenerator.generate;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class DecryptionMaterialsTest {
+
+ private static final CryptoAlgorithm ALGORITHM_SUITE = CryptoAlgorithm.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384;
+ private static final Map ENCRYPTION_CONTEXT = Collections.singletonMap("testKey", "testValue");
+ private static final KeyringTrace KEYRING_TRACE = new KeyringTrace();
+ private static final KeyringTraceEntry KEYRING_TRACE_ENTRY = new KeyringTraceEntry("Namespace", "Name", KeyringTraceFlag.ENCRYPTED_DATA_KEY);
+ private static final SecretKey PLAINTEXT_DATA_KEY = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength()), ALGORITHM_SUITE.getDataKeyAlgo());
+ private static PublicKey VERIFICATION_KEY;
+
+ @BeforeAll
+ static void setup() throws Exception {
+
+ final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(2048);
+ final KeyPair keyPair = TrailingSignatureAlgorithm.forCryptoAlgorithm(ALGORITHM_SUITE).generateKey();
+ VERIFICATION_KEY = keyPair.getPublic();
+ }
+
+ @Test
+ void testBuilderNullCryptoAlgorithm() {
+ assertThrows(NullPointerException.class, () -> DecryptionMaterials.newBuilder(null).build());
+ }
+
+ @Test
+ void testBuilder() {
+ DecryptionMaterials result = DecryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(KEYRING_TRACE)
+ .plaintextDataKey(PLAINTEXT_DATA_KEY)
+ .verificationKey(VERIFICATION_KEY)
+ .build();
+
+ assertEquals(ALGORITHM_SUITE, result.getAlgorithmSuite());
+ assertEquals(ENCRYPTION_CONTEXT, result.getEncryptionContext());
+ assertEquals(KEYRING_TRACE, result.getKeyringTrace());
+ assertEquals(PLAINTEXT_DATA_KEY, result.getPlaintextDataKey());
+ assertEquals(VERIFICATION_KEY, result.getVerificationKey());
+ }
+
+ @Test
+ void testInvalidPlaintextDataKey() {
+ SecretKey wrongLength = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength() + 1), ALGORITHM_SUITE.getDataKeyAlgo());
+ assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .plaintextDataKey(wrongLength)
+ .verificationKey(VERIFICATION_KEY)
+ .build());
+
+ SecretKey wrongAlgorithm = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength()), "InvalidAlgorithm");
+ assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .plaintextDataKey(wrongAlgorithm)
+ .verificationKey(VERIFICATION_KEY)
+ .build());
+
+ DecryptionMaterials materials = DecryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .verificationKey(VERIFICATION_KEY)
+ .build();
+ assertThrows(IllegalArgumentException.class, () -> materials
+ .setPlaintextDataKey(wrongAlgorithm, KEYRING_TRACE_ENTRY));
+ assertThrows(IllegalArgumentException.class, () -> materials
+ .setPlaintextDataKey(wrongLength, KEYRING_TRACE_ENTRY));
+ }
+
+ @Test
+ void testInvalidVerificationKey() {
+ assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .verificationKey(null)
+ .build());
+ assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256)
+ .verificationKey(VERIFICATION_KEY)
+ .build());
+
+ }
+
+ @Test
+ void testToBuilder() {
+ DecryptionMaterials expected = DecryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(KEYRING_TRACE)
+ .plaintextDataKey(PLAINTEXT_DATA_KEY)
+ .verificationKey(VERIFICATION_KEY)
+ .build();
+
+ DecryptionMaterials actual = expected.toBuilder().build();
+
+ assertEquals(expected, actual);
+ assertNotSame(expected, actual);
+ }
+
+ @Test
+ void testSetPlaintextDataKey() {
+ DecryptionMaterials materials = DecryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .verificationKey(VERIFICATION_KEY)
+ .build();
+
+ assertThrows(NullPointerException.class, () -> materials.setPlaintextDataKey(null, KEYRING_TRACE_ENTRY));
+ assertThrows(NullPointerException.class, () -> materials.setPlaintextDataKey(PLAINTEXT_DATA_KEY, null));
+
+ materials.setPlaintextDataKey(PLAINTEXT_DATA_KEY, KEYRING_TRACE_ENTRY);
+ assertEquals(PLAINTEXT_DATA_KEY, materials.getPlaintextDataKey());
+ assertEquals(1, materials.getKeyringTrace().getEntries().size());
+ assertEquals(KEYRING_TRACE_ENTRY, materials.getKeyringTrace().getEntries().get(0));
+
+ assertThrows(IllegalStateException.class, () -> materials.setPlaintextDataKey(PLAINTEXT_DATA_KEY, KEYRING_TRACE_ENTRY));
+ }
+
+ @Test
+ void testGetOptionalProperties() {
+ DecryptionMaterials materials = DecryptionMaterials.newBuilder(CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256)
+ .build();
+
+ assertThrows(IllegalStateException.class, materials::getPlaintextDataKey);
+ assertThrows(IllegalStateException.class, materials::getVerificationKey);
+ }
+
+}
diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java
new file mode 100644
index 000000000..d1c207dbd
--- /dev/null
+++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
+ * in compliance with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.amazonaws.encryptionsdk.keyrings;
+
+import com.amazonaws.encryptionsdk.CryptoAlgorithm;
+import com.amazonaws.encryptionsdk.EncryptedDataKey;
+import com.amazonaws.encryptionsdk.internal.TrailingSignatureAlgorithm;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.util.Collections;
+import java.util.Map;
+
+import static com.amazonaws.encryptionsdk.internal.RandomBytesGenerator.generate;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@ExtendWith(MockitoExtension.class)
+class EncryptionMaterialsTest {
+
+ private static final CryptoAlgorithm ALGORITHM_SUITE = CryptoAlgorithm.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384;
+ private static final Map ENCRYPTION_CONTEXT = Collections.singletonMap("testKey", "testValue");
+ private static final KeyringTrace KEYRING_TRACE = new KeyringTrace();
+ private static final KeyringTraceEntry KEYRING_TRACE_ENTRY = new KeyringTraceEntry("Namespace", "Name", KeyringTraceFlag.ENCRYPTED_DATA_KEY);
+ private static final SecretKey PLAINTEXT_DATA_KEY = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength()), ALGORITHM_SUITE.getDataKeyAlgo());
+ @Mock
+ private static EncryptedDataKey ENCRYPTED_DATA_KEY;
+ private static PrivateKey SIGNING_KEY;
+
+ @BeforeAll
+ static void setup() throws Exception {
+
+ final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(2048);
+ final KeyPair keyPair = TrailingSignatureAlgorithm.forCryptoAlgorithm(ALGORITHM_SUITE).generateKey();
+ SIGNING_KEY = keyPair.getPrivate();
+ }
+
+ @Test
+ void testBuilderNullCryptoAlgorithm() {
+ assertThrows(NullPointerException.class, () -> EncryptionMaterials.newBuilder(null).build());
+ }
+
+ @Test
+ void testBuilder() {
+ EncryptionMaterials result = EncryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(KEYRING_TRACE)
+ .plaintextDataKey(PLAINTEXT_DATA_KEY)
+ .encryptedDataKeys(Collections.singletonList(ENCRYPTED_DATA_KEY))
+ .signingKey(SIGNING_KEY)
+ .build();
+
+ assertEquals(ALGORITHM_SUITE, result.getAlgorithmSuite());
+ assertEquals(ENCRYPTION_CONTEXT, result.getEncryptionContext());
+ assertEquals(KEYRING_TRACE, result.getKeyringTrace());
+ assertEquals(PLAINTEXT_DATA_KEY, result.getPlaintextDataKey());
+ assertEquals(1, result.getEncryptedDataKeys().size());
+ assertEquals(ENCRYPTED_DATA_KEY, result.getEncryptedDataKeys().get(0));
+ assertEquals(SIGNING_KEY, result.getSigningKey());
+ }
+
+ @Test
+ void testInvalidPlaintextDataKey() {
+ SecretKey wrongLength = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength() + 1), ALGORITHM_SUITE.getDataKeyAlgo());
+ assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .plaintextDataKey(wrongLength)
+ .signingKey(SIGNING_KEY)
+ .build());
+
+ SecretKey wrongAlgorithm = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength()), "InvalidAlgorithm");
+ assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .plaintextDataKey(wrongAlgorithm)
+ .signingKey(SIGNING_KEY)
+ .build());
+
+ EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .signingKey(SIGNING_KEY)
+ .build();
+ assertThrows(IllegalArgumentException.class, () -> materials
+ .setPlaintextDataKey(wrongAlgorithm, KEYRING_TRACE_ENTRY));
+ assertThrows(IllegalArgumentException.class, () -> materials
+ .setPlaintextDataKey(wrongLength, KEYRING_TRACE_ENTRY));
+ }
+
+ @Test
+ void testInvalidSigningKey() {
+ assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .signingKey(null)
+ .build());
+ assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256)
+ .signingKey(SIGNING_KEY)
+ .build());
+
+ }
+
+ @Test
+ void testToBuilder() {
+ EncryptionMaterials expected = EncryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(KEYRING_TRACE)
+ .plaintextDataKey(PLAINTEXT_DATA_KEY)
+ .encryptedDataKeys(Collections.singletonList(ENCRYPTED_DATA_KEY))
+ .signingKey(SIGNING_KEY)
+ .build();
+
+ EncryptionMaterials actual = expected.toBuilder().build();
+
+ assertEquals(expected, actual);
+ assertNotSame(expected, actual);
+ }
+
+ @Test
+ void testAddEncryptedDataKey() {
+ EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .signingKey(SIGNING_KEY)
+ .build();
+
+ assertThrows(NullPointerException.class, () -> materials.addEncryptedDataKey(null, KEYRING_TRACE_ENTRY));
+ assertThrows(NullPointerException.class, () -> materials.addEncryptedDataKey(ENCRYPTED_DATA_KEY, null));
+
+ materials.addEncryptedDataKey(ENCRYPTED_DATA_KEY, KEYRING_TRACE_ENTRY);
+ assertEquals(1, materials.getEncryptedDataKeys().size());
+ assertEquals(ENCRYPTED_DATA_KEY, materials.getEncryptedDataKeys().get(0));
+ assertEquals(1, materials.getKeyringTrace().getEntries().size());
+ assertEquals(KEYRING_TRACE_ENTRY, materials.getKeyringTrace().getEntries().get(0));
+ }
+
+ @Test
+ void testSetPlaintextDataKey() {
+ EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM_SUITE)
+ .signingKey(SIGNING_KEY)
+ .build();
+
+ assertThrows(NullPointerException.class, () -> materials.setPlaintextDataKey(null, KEYRING_TRACE_ENTRY));
+ assertThrows(NullPointerException.class, () -> materials.setPlaintextDataKey(PLAINTEXT_DATA_KEY, null));
+
+ materials.setPlaintextDataKey(PLAINTEXT_DATA_KEY, KEYRING_TRACE_ENTRY);
+ assertEquals(PLAINTEXT_DATA_KEY, materials.getPlaintextDataKey());
+ assertEquals(1, materials.getKeyringTrace().getEntries().size());
+ assertEquals(KEYRING_TRACE_ENTRY, materials.getKeyringTrace().getEntries().get(0));
+
+ assertThrows(IllegalStateException.class, () -> materials.setPlaintextDataKey(PLAINTEXT_DATA_KEY, KEYRING_TRACE_ENTRY));
+ }
+
+ @Test
+ void testGetOptionalProperties() {
+ EncryptionMaterials materials = EncryptionMaterials.newBuilder(CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256)
+ .build();
+
+ assertThrows(IllegalStateException.class, materials::getPlaintextDataKey);
+ assertThrows(IllegalStateException.class, materials::getSigningKey);
+ }
+
+}
diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java
index c67fcbe77..5b6105070 100644
--- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java
+++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java
@@ -13,22 +13,19 @@
package com.amazonaws.encryptionsdk.keyrings;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
-import static java.util.Collections.singleton;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
-public class KeyringTraceTest {
+class KeyringTraceTest {
@Test
- public void testOrderMaintained() {
- KeyringTraceEntry entry1 = new KeyringTraceEntry("ns1", "name1",
- singleton(KeyringTraceFlag.GENERATED_DATA_KEY));
- KeyringTraceEntry entry2 = new KeyringTraceEntry("ns2", "name2",
- singleton(KeyringTraceFlag.DECRYPTED_DATA_KEY));
- KeyringTraceEntry entry3 = new KeyringTraceEntry("ns3", "name3",
- singleton(KeyringTraceFlag.ENCRYPTED_DATA_KEY));
+ void testOrderMaintained() {
+ KeyringTraceEntry entry1 = new KeyringTraceEntry("ns1", "name1", KeyringTraceFlag.GENERATED_DATA_KEY);
+ KeyringTraceEntry entry2 = new KeyringTraceEntry("ns2", "name2", KeyringTraceFlag.DECRYPTED_DATA_KEY);
+ KeyringTraceEntry entry3 = new KeyringTraceEntry("ns3", "name3", KeyringTraceFlag.ENCRYPTED_DATA_KEY);
KeyringTrace trace = new KeyringTrace();
trace.add(entry1.getKeyNamespace(), entry1.getKeyName(), entry1.getFlags().iterator().next());
@@ -40,23 +37,20 @@ public void testOrderMaintained() {
assertEquals(entry3, trace.getEntries().get(2));
}
- @Test(expected = UnsupportedOperationException.class)
- public void testImmutable() {
+ @Test
+ void testImmutable() {
KeyringTrace trace = new KeyringTrace();
trace.add("namespace", "name", KeyringTraceFlag.GENERATED_DATA_KEY);
- trace.getEntries().add(new KeyringTraceEntry("ns1", "name1",
- singleton(KeyringTraceFlag.GENERATED_DATA_KEY)));
+ assertThrows(UnsupportedOperationException.class, () ->
+ trace.getEntries().add(new KeyringTraceEntry("ns1", "name1", KeyringTraceFlag.GENERATED_DATA_KEY)));
}
@Test
- public void testKeyringTraceEntryEquals() {
- KeyringTraceEntry entry1 = new KeyringTraceEntry("namespace", "name",
- singleton(KeyringTraceFlag.GENERATED_DATA_KEY));
- KeyringTraceEntry entry2 = new KeyringTraceEntry(entry1.getKeyNamespace(), entry1.getKeyName(),
- entry1.getFlags());
- KeyringTraceEntry entry3 = new KeyringTraceEntry("othernamespace", "name",
- singleton(KeyringTraceFlag.GENERATED_DATA_KEY));
+ void testKeyringTraceEntryEquals() {
+ KeyringTraceEntry entry1 = new KeyringTraceEntry("namespace", "name", KeyringTraceFlag.GENERATED_DATA_KEY);
+ KeyringTraceEntry entry2 = new KeyringTraceEntry(entry1.getKeyNamespace(), entry1.getKeyName(), entry1.getFlags().toArray(new KeyringTraceFlag[]{}));
+ KeyringTraceEntry entry3 = new KeyringTraceEntry("othernamespace", "name", KeyringTraceFlag.GENERATED_DATA_KEY);
assertEquals(entry1, entry1);
assertEquals(entry1, entry2);
diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java
new file mode 100644
index 000000000..4183e9a06
--- /dev/null
+++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
+ * in compliance with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.amazonaws.encryptionsdk.keyrings;
+
+import com.amazonaws.encryptionsdk.EncryptedDataKey;
+import com.amazonaws.encryptionsdk.internal.Utils;
+import com.amazonaws.encryptionsdk.model.KeyBlob;
+import org.apache.commons.lang3.ArrayUtils;
+import org.junit.jupiter.api.Test;
+
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+
+import static com.amazonaws.encryptionsdk.internal.RandomBytesGenerator.generate;
+import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.ALGORITHM;
+import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.DATA_KEY;
+import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.ENCRYPTION_CONTEXT;
+import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.KEYNAME;
+import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.KEYNAMESPACE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class RawAesKeyringTest {
+
+ private final RawAesKeyring keyring = new RawAesKeyring(KEYNAMESPACE, KEYNAME, new SecretKeySpec(generate(32), "AES"));
+
+ @Test
+ void testValidToDecrypt() {
+ assertTrue(keyring.validToDecrypt(new KeyBlob(
+ KEYNAMESPACE, KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{})));
+ assertTrue(keyring.validToDecrypt(new KeyBlob(
+ KEYNAMESPACE, ArrayUtils.add(KEYNAME.getBytes(StandardCharsets.UTF_8), (byte) 5), new byte[]{})));
+ //Bad namespace
+ assertFalse(keyring.validToDecrypt(new KeyBlob(
+ "WrongNamespace", KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{})));
+ //Bad provider info
+ assertFalse(keyring.validToDecrypt(new KeyBlob(
+ KEYNAMESPACE, new byte[]{1,2,3}, new byte[]{})));
+ }
+
+ @Test
+ void testEncryptDecryptExistingDataKey() {
+ EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM)
+ .plaintextDataKey(DATA_KEY)
+ .keyringTrace(new KeyringTrace())
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .build();
+
+ keyring.onEncrypt(encryptionMaterials);
+
+ assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size());
+
+ final EncryptedDataKey actualEncryptedDataKey = encryptionMaterials.getEncryptedDataKeys().get(0);
+ assertEquals(KEYNAMESPACE, actualEncryptedDataKey.getProviderId());
+ assertTrue(Utils.arrayPrefixEquals(keyring.keyNameBytes, actualEncryptedDataKey.getProviderInformation(), keyring.keyNameBytes.length));
+ assertTrue(actualEncryptedDataKey.getProviderInformation().length > keyring.keyNameBytes.length);
+
+ assertEquals(1, encryptionMaterials.getKeyringTrace().getEntries().size());
+ assertEquals(KEYNAME, encryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyName());
+ assertEquals(KEYNAMESPACE, encryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyNamespace());
+ assertEquals(2, encryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().size());
+ assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.ENCRYPTED_DATA_KEY));
+ assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT));
+
+ DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(new KeyringTrace())
+ .build();
+
+ keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys());
+
+ assertEquals(DATA_KEY, decryptionMaterials.getPlaintextDataKey());
+ assertEquals(KEYNAME, decryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyName());
+ assertEquals(KEYNAMESPACE, decryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyNamespace());
+ assertEquals(2, decryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().size());
+ assertTrue(decryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.DECRYPTED_DATA_KEY));
+ assertTrue(decryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT));
+ }
+
+ @Test
+ void testEncryptDecryptGenerateDataKey() {
+ EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM)
+ .keyringTrace(new KeyringTrace())
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .build();
+
+ keyring.onEncrypt(encryptionMaterials);
+
+ assertNotNull(encryptionMaterials.getPlaintextDataKey());
+ assertEquals(encryptionMaterials.getPlaintextDataKey().getAlgorithm(), ALGORITHM.getDataKeyAlgo());
+ assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size());
+
+ final EncryptedDataKey actualEncryptedDataKey = encryptionMaterials.getEncryptedDataKeys().get(0);
+ assertEquals(KEYNAMESPACE, actualEncryptedDataKey.getProviderId());
+ assertTrue(Utils.arrayPrefixEquals(keyring.keyNameBytes, actualEncryptedDataKey.getProviderInformation(), keyring.keyNameBytes.length));
+ assertTrue(actualEncryptedDataKey.getProviderInformation().length > keyring.keyNameBytes.length);
+
+ assertEquals(2, encryptionMaterials.getKeyringTrace().getEntries().size());
+ assertEquals(1, encryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().size());
+ assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.GENERATED_DATA_KEY));
+ assertEquals(2, encryptionMaterials.getKeyringTrace().getEntries().get(1).getFlags().size());
+ assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(1).getFlags().contains(KeyringTraceFlag.ENCRYPTED_DATA_KEY));
+ assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(1).getFlags().contains(KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT));
+
+ DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(new KeyringTrace())
+ .build();
+
+ keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys());
+
+ assertEquals(encryptionMaterials.getPlaintextDataKey(), decryptionMaterials.getPlaintextDataKey());
+ assertEquals(KEYNAME, decryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyName());
+ assertEquals(KEYNAMESPACE, decryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyNamespace());
+ assertEquals(2, decryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().size());
+ assertTrue(decryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.DECRYPTED_DATA_KEY));
+ assertTrue(decryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT));
+ }
+
+}
diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java
new file mode 100644
index 000000000..945aa17bc
--- /dev/null
+++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
+ * in compliance with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.amazonaws.encryptionsdk.keyrings;
+
+import com.amazonaws.encryptionsdk.CryptoAlgorithm;
+import com.amazonaws.encryptionsdk.EncryptedDataKey;
+import com.amazonaws.encryptionsdk.internal.JceKeyCipher;
+import com.amazonaws.encryptionsdk.model.KeyBlob;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static com.amazonaws.encryptionsdk.internal.RandomBytesGenerator.generate;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class RawKeyringTest {
+
+ static final String KEYNAME = "testKeyname";
+ static final String KEYNAMESPACE = "testKeynamespace";
+ static final CryptoAlgorithm ALGORITHM = CryptoAlgorithm.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA256;
+ static final SecretKey DATA_KEY = new SecretKeySpec(generate(ALGORITHM.getDataKeyLength()), ALGORITHM.getDataKeyAlgo());
+ static final Map ENCRYPTION_CONTEXT = Collections.singletonMap("myKey", "myValue");
+ private static final EncryptedDataKey ENCRYPTED_DATA_KEY = new KeyBlob("keyProviderId", new byte[]{1, 2, 3}, generate(ALGORITHM.getDataKeyLength()));
+ private static final EncryptedDataKey INVALID_DATA_KEY = new KeyBlob("invalidProviderId", new byte[]{1, 2, 3}, generate(ALGORITHM.getDataKeyLength()));
+ private static final KeyringTraceEntry ENCRYPTED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, KeyringTraceFlag.ENCRYPTED_DATA_KEY);
+ private static final KeyringTraceEntry DECRYPTED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, KeyringTraceFlag.DECRYPTED_DATA_KEY);
+ private static final KeyringTraceEntry GENERATED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, KeyringTraceFlag.GENERATED_DATA_KEY);
+ @Mock(lenient = true) private JceKeyCipher jceKeyCipher;
+ private Keyring keyring;
+
+ @BeforeEach
+ void setup() throws Exception {
+ when(jceKeyCipher.encryptKey(DATA_KEY.getEncoded(), KEYNAME, KEYNAMESPACE, ENCRYPTION_CONTEXT)).thenReturn(ENCRYPTED_DATA_KEY);
+ when(jceKeyCipher.decryptKey(ENCRYPTED_DATA_KEY, KEYNAME, ENCRYPTION_CONTEXT)).thenReturn(DATA_KEY.getEncoded());
+
+ keyring = new RawKeyring(KEYNAMESPACE, KEYNAME, jceKeyCipher) {
+ @Override
+ boolean validToDecrypt(EncryptedDataKey encryptedDataKey) {
+ return !encryptedDataKey.getProviderId().equals(INVALID_DATA_KEY.getProviderId());
+ }
+
+ @Override
+ KeyringTraceEntry traceOnEncrypt() {
+ return ENCRYPTED_DATA_KEY_TRACE;
+ }
+
+ @Override
+ KeyringTraceEntry traceOnDecrypt() {
+ return DECRYPTED_DATA_KEY_TRACE;
+ }
+ };
+ }
+
+ @Test
+ void testEncryptDecryptExistingDataKey() {
+ EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM)
+ .plaintextDataKey(DATA_KEY)
+ .keyringTrace(new KeyringTrace())
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .build();
+
+ keyring.onEncrypt(encryptionMaterials);
+
+ assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size());
+ assertEncryptedDataKeyEquals(ENCRYPTED_DATA_KEY, encryptionMaterials.getEncryptedDataKeys().get(0));
+ assertEquals(1, encryptionMaterials.getKeyringTrace().getEntries().size());
+ assertEquals(ENCRYPTED_DATA_KEY_TRACE, encryptionMaterials.getKeyringTrace().getEntries().get(0));
+
+ DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(new KeyringTrace())
+ .build();
+
+ keyring.onDecrypt(decryptionMaterials, Collections.singletonList(ENCRYPTED_DATA_KEY));
+
+ assertEquals(DATA_KEY, decryptionMaterials.getPlaintextDataKey());
+ assertEquals(DECRYPTED_DATA_KEY_TRACE, decryptionMaterials.getKeyringTrace().getEntries().get(0));
+ }
+
+ @Test
+ void testEncryptNullDataKey() {
+ EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM)
+ .keyringTrace(new KeyringTrace())
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .build();
+
+ ArgumentCaptor dataKeyCaptor = ArgumentCaptor.forClass(byte[].class);
+ when(jceKeyCipher.encryptKey(dataKeyCaptor.capture(), eq(KEYNAME), eq(KEYNAMESPACE), eq(ENCRYPTION_CONTEXT))).thenReturn(ENCRYPTED_DATA_KEY);
+ keyring.onEncrypt(encryptionMaterials);
+
+ assertEquals(encryptionMaterials.getPlaintextDataKey().getAlgorithm(), ALGORITHM.getDataKeyAlgo());
+ assertArrayEquals(encryptionMaterials.getPlaintextDataKey().getEncoded(), dataKeyCaptor.getValue());
+ assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size());
+ assertNotNull(encryptionMaterials.getPlaintextDataKey());
+ assertEncryptedDataKeyEquals(ENCRYPTED_DATA_KEY, encryptionMaterials.getEncryptedDataKeys().get(0));
+ assertEquals(2, encryptionMaterials.getKeyringTrace().getEntries().size());
+ assertEquals(GENERATED_DATA_KEY_TRACE, encryptionMaterials.getKeyringTrace().getEntries().get(0));
+ assertEquals(ENCRYPTED_DATA_KEY_TRACE, encryptionMaterials.getKeyringTrace().getEntries().get(1));
+ }
+
+ @Test
+ void testDecryptAlreadyDecryptedDataKey() {
+ DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM)
+ .plaintextDataKey(DATA_KEY)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(new KeyringTrace())
+ .build();
+
+ keyring.onDecrypt(decryptionMaterials, Collections.singletonList(ENCRYPTED_DATA_KEY));
+
+ assertEquals(DATA_KEY, decryptionMaterials.getPlaintextDataKey());
+ assertEquals(0, decryptionMaterials.getKeyringTrace().getEntries().size());
+ }
+
+ @Test
+ void testDecryptNoValidDataKey() {
+ DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(new KeyringTrace())
+ .build();
+
+ keyring.onDecrypt(decryptionMaterials, Collections.singletonList(INVALID_DATA_KEY));
+
+ assertFalse(decryptionMaterials.hasPlaintextDataKey());
+ assertEquals(0, decryptionMaterials.getKeyringTrace().getEntries().size());
+ }
+
+ @Test
+ void testDecryptNoDataKey() {
+ DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(new KeyringTrace())
+ .build();
+
+ keyring.onDecrypt(decryptionMaterials, Collections.emptyList());
+
+ assertFalse(decryptionMaterials.hasPlaintextDataKey());
+ assertEquals(0, decryptionMaterials.getKeyringTrace().getEntries().size());
+ }
+
+
+ @Test
+ void testDecryptMultipleKeysOneInvalid() {
+ DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(new KeyringTrace())
+ .build();
+
+ final List edks = new ArrayList<>();
+ edks.add(INVALID_DATA_KEY);
+ edks.add(ENCRYPTED_DATA_KEY);
+
+ keyring.onDecrypt(decryptionMaterials, edks);
+
+ assertEquals(DATA_KEY, decryptionMaterials.getPlaintextDataKey());
+ assertEquals(DECRYPTED_DATA_KEY_TRACE, decryptionMaterials.getKeyringTrace().getEntries().get(0));
+ }
+
+ @Test
+ void testDecryptMultipleKeysOneException() throws GeneralSecurityException {
+ final EncryptedDataKey BAD_DATA_KEY = new KeyBlob("exceptionProvider", new byte[]{1, 2, 3}, new byte[]{4, 5, 6});
+
+ DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(new KeyringTrace())
+ .build();
+
+ when(jceKeyCipher.decryptKey(BAD_DATA_KEY, KEYNAME, ENCRYPTION_CONTEXT))
+ .thenThrow(new GeneralSecurityException("could not decrypt key"));
+
+ final List edks = new ArrayList<>();
+ edks.add(BAD_DATA_KEY);
+ edks.add(ENCRYPTED_DATA_KEY);
+
+ keyring.onDecrypt(decryptionMaterials, edks);
+
+ assertEquals(DATA_KEY, decryptionMaterials.getPlaintextDataKey());
+ assertEquals(DECRYPTED_DATA_KEY_TRACE, decryptionMaterials.getKeyringTrace().getEntries().get(0));
+ }
+
+ private void assertEncryptedDataKeyEquals(EncryptedDataKey expected, EncryptedDataKey actual) {
+ assertEquals(expected.getProviderId(), actual.getProviderId());
+ assertArrayEquals(expected.getProviderInformation(), actual.getProviderInformation());
+ assertArrayEquals(expected.getEncryptedDataKey(), actual.getEncryptedDataKey());
+ }
+}
diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java
new file mode 100644
index 000000000..6e43d5d37
--- /dev/null
+++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
+ * in compliance with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.amazonaws.encryptionsdk.keyrings;
+
+import com.amazonaws.encryptionsdk.EncryptedDataKey;
+import com.amazonaws.encryptionsdk.model.KeyBlob;
+import org.apache.commons.lang3.ArrayUtils;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+
+import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.ALGORITHM;
+import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.DATA_KEY;
+import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.ENCRYPTION_CONTEXT;
+import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.KEYNAME;
+import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.KEYNAMESPACE;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class RawRsaKeyringTest {
+
+ private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding";
+ private static RawRsaKeyring keyring;
+
+ @BeforeAll
+ static void setup() throws Exception {
+ final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
+ keyPairGenerator.initialize(2048);
+ final KeyPair keyPair = keyPairGenerator.generateKeyPair();
+ keyring = new RawRsaKeyring(KEYNAMESPACE, KEYNAME, keyPair.getPublic(), keyPair.getPrivate(), TRANSFORMATION);
+ }
+
+ @Test
+ void testValidToDecrypt() {
+ assertTrue(keyring.validToDecrypt(new KeyBlob(
+ KEYNAMESPACE, KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{})));
+ //Provider info has extra data
+ assertFalse(keyring.validToDecrypt(new KeyBlob(
+ KEYNAMESPACE, ArrayUtils.add(KEYNAME.getBytes(StandardCharsets.UTF_8), (byte)5), new byte[]{})));
+ //Bad namespace
+ assertFalse(keyring.validToDecrypt(new KeyBlob(
+ "WrongNamespace", KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{})));
+ }
+
+ @Test
+ void testEncryptDecryptExistingDataKey() {
+ EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM)
+ .plaintextDataKey(DATA_KEY)
+ .keyringTrace(new KeyringTrace())
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .build();
+
+ keyring.onEncrypt(encryptionMaterials);
+
+ assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size());
+
+ final EncryptedDataKey actualEncryptedDataKey = encryptionMaterials.getEncryptedDataKeys().get(0);
+ assertEquals(KEYNAMESPACE, actualEncryptedDataKey.getProviderId());
+ assertArrayEquals(keyring.keyNameBytes, actualEncryptedDataKey.getProviderInformation());
+
+ assertEquals(1, encryptionMaterials.getKeyringTrace().getEntries().size());
+ assertEquals(KEYNAME, encryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyName());
+ assertEquals(KEYNAMESPACE, encryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyNamespace());
+ assertEquals(1, encryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().size());
+ assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.ENCRYPTED_DATA_KEY));
+
+ DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(new KeyringTrace())
+ .build();
+
+ keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys());
+
+ assertEquals(DATA_KEY, decryptionMaterials.getPlaintextDataKey());
+ assertEquals(KEYNAME, decryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyName());
+ assertEquals(KEYNAMESPACE, decryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyNamespace());
+ assertEquals(1, decryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().size());
+ assertTrue(decryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.DECRYPTED_DATA_KEY));
+ }
+
+ @Test
+ void testEncryptDecryptGenerateDataKey() {
+ EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM)
+ .keyringTrace(new KeyringTrace())
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .build();
+
+ keyring.onEncrypt(encryptionMaterials);
+
+ assertNotNull(encryptionMaterials.getPlaintextDataKey());
+ assertEquals(encryptionMaterials.getPlaintextDataKey().getAlgorithm(), ALGORITHM.getDataKeyAlgo());
+ assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size());
+
+ final EncryptedDataKey actualEncryptedDataKey = encryptionMaterials.getEncryptedDataKeys().get(0);
+ assertEquals(KEYNAMESPACE, actualEncryptedDataKey.getProviderId());
+ assertArrayEquals(keyring.keyNameBytes, actualEncryptedDataKey.getProviderInformation());
+
+ assertEquals(2, encryptionMaterials.getKeyringTrace().getEntries().size());
+ assertEquals(1, encryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().size());
+ assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.GENERATED_DATA_KEY));
+ assertEquals(1, encryptionMaterials.getKeyringTrace().getEntries().get(1).getFlags().size());
+ assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(1).getFlags().contains(KeyringTraceFlag.ENCRYPTED_DATA_KEY));
+
+ DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM)
+ .encryptionContext(ENCRYPTION_CONTEXT)
+ .keyringTrace(new KeyringTrace())
+ .build();
+
+ keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys());
+
+ assertEquals(encryptionMaterials.getPlaintextDataKey(), decryptionMaterials.getPlaintextDataKey());
+ assertEquals(KEYNAME, decryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyName());
+ assertEquals(KEYNAMESPACE, decryptionMaterials.getKeyringTrace().getEntries().get(0).getKeyNamespace());
+ assertEquals(1, decryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().size());
+ assertTrue(decryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.DECRYPTED_DATA_KEY));
+ }
+
+}