diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTrace.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTrace.java new file mode 100644 index 000000000..7759d70d7 --- /dev/null +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTrace.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 org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; + +/** + * A keyring trace containing all of the actions that keyrings have taken on a set of encryption materials. + */ +public class KeyringTrace { + + private final List entries = new ArrayList<>(); + + /** + * Add a new entry to the keyring trace. + * + * @param keyNamespace The namespace for the key. + * @param keyName The name of the key. + * @param flags A set of one or more KeyringTraceFlag enums + * indicating what actions were taken by a keyring. + */ + public void add(String keyNamespace, String keyName, KeyringTraceFlag... flags) { + entries.add(new KeyringTraceEntry(keyNamespace, keyName, + new HashSet<>(Arrays.asList(flags)))); + } + + /** + * Gets an unmodifiable list of `KeyringTraceEntry`s ordered sequentially + * according to the order the actions were taken, with the earliest action + * corresponding to the first `KeyringTraceEntry` in the list. + * + * @return An unmodifiable list of `KeyringTraceEntry`s + */ + public List getEntries() { + return Collections.unmodifiableList(entries); + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append("entries", entries) + .toString(); + } +} diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceEntry.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceEntry.java new file mode 100644 index 000000000..64a14a268 --- /dev/null +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceEntry.java @@ -0,0 +1,104 @@ +/* + * 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 org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import java.util.Collections; +import java.util.Objects; +import java.util.Set; + +import static org.apache.commons.lang3.Validate.notBlank; +import static org.apache.commons.lang3.Validate.notEmpty; + +/** + * A representation of an action that a keyring has taken on a data key. + */ +public class KeyringTraceEntry { + + private final String keyNamespace; + private final String keyName; + private final Set flags; + + /** + * Constructs a new `KeyringTraceEntry`. + * + * @param keyNamespace The namespace for the key. + * @param keyName The name of the key. + * @param flags A set of one or more KeyringTraceFlag enums + * indicating what actions were taken by a keyring. + */ + KeyringTraceEntry(final String keyNamespace, final String keyName, final Set 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); + } + + /** + * Returns the key namespace. + * + * @return The key namespace. + */ + public String getKeyNamespace() { + return this.keyNamespace; + } + + /** + * Returns the key name. + * + * @return The key name. + */ + public String getKeyName() { + return this.keyName; + } + + /** + * Returns an unmodifiable set of flags that indicate + * which actions were taken by a keyring. + * + * @return The unmodifiable set of flags. + */ + public Set getFlags() { + return this.flags; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + KeyringTraceEntry that = (KeyringTraceEntry) o; + return Objects.equals(keyNamespace, that.keyNamespace) && + Objects.equals(keyName, that.keyName) && + Objects.equals(flags, that.flags); + } + + @Override + public int hashCode() { + return Objects.hash(keyNamespace, keyName, flags); + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append("keyNamespace", this.keyNamespace) + .append("keyName", this.keyName) + .append("flags", this.flags) + .toString(); + } +} diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceFlag.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceFlag.java new file mode 100644 index 000000000..94e59bc41 --- /dev/null +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceFlag.java @@ -0,0 +1,49 @@ +/* + * 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; + +/** + * Enum representing the possible actions a keyring may take on the + * different wrapping keys it manages. + */ +public enum KeyringTraceFlag { + + /** + * A flag to represent that a keyring has generated a plaintext data key. + */ + GENERATED_DATA_KEY, + + /** + * A flag to represent that a keyring has created an encrypted data key. + */ + ENCRYPTED_DATA_KEY, + + /** + * A flag to represent that a keyring has obtained the + * corresponding plaintext data key from an encrypted data key. + */ + DECRYPTED_DATA_KEY, + + /** + * A flag to represent that the keyring has cryptographically + * bound the encryption context to a newly created encrypted data key. + */ + SIGNED_ENCRYPTION_CONTEXT, + + /** + * A flag to represent that the keyring has verified that an encrypted + * data key was originally created with a particular encryption context. + */ + VERIFIED_ENCRYPTION_CONTEXT +} diff --git a/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java index 94423b884..0c0ba52c7 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java @@ -3,14 +3,17 @@ 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() { @@ -21,6 +24,10 @@ public PublicKey getTrailingSignatureKey() { return trailingSignatureKey; } + public KeyringTrace getKeyringTrace() { + return keyringTrace; + } + public static Builder newBuilder() { return new Builder(); } @@ -32,10 +39,12 @@ 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() {} @@ -58,6 +67,15 @@ 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 1a40d7c36..f9b05a153 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/model/EncryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/model/EncryptionMaterials.java @@ -11,6 +11,7 @@ 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. @@ -24,6 +25,7 @@ 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; @@ -32,6 +34,7 @@ private EncryptionMaterials(Builder b) { this.cleartextDataKey = b.cleartextDataKey; this.trailingSignatureKey = b.trailingSignatureKey; this.masterKeys = b.getMasterKeys(); + this.keyringTrace = b.keyringTrace; } public Builder toBuilder() { @@ -100,12 +103,13 @@ 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(masterKeys, that.masterKeys) && + Objects.equals(keyringTrace, that.keyringTrace); } @Override public int hashCode() { return Objects.hash(algorithm, encryptionContext, encryptedDataKeys, cleartextDataKey, trailingSignatureKey, - masterKeys); + masterKeys, keyringTrace); } public static class Builder { @@ -115,6 +119,7 @@ public static class Builder { private SecretKey cleartextDataKey; private PrivateKey trailingSignatureKey; private List masterKeys = Collections.emptyList(); + private KeyringTrace keyringTrace; private Builder() {} @@ -125,6 +130,7 @@ private Builder(EncryptionMaterials r) { cleartextDataKey = r.cleartextDataKey; trailingSignatureKey = r.trailingSignatureKey; setMasterKeys(r.masterKeys); + keyringTrace = r.keyringTrace; } public EncryptionMaterials build() { @@ -184,5 +190,14 @@ 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/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java new file mode 100644 index 000000000..c67fcbe77 --- /dev/null +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.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 org.junit.Test; + +import static java.util.Collections.singleton; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +public 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)); + + KeyringTrace trace = new KeyringTrace(); + trace.add(entry1.getKeyNamespace(), entry1.getKeyName(), entry1.getFlags().iterator().next()); + trace.add(entry2.getKeyNamespace(), entry2.getKeyName(), entry2.getFlags().iterator().next()); + trace.add(entry3.getKeyNamespace(), entry3.getKeyName(), entry3.getFlags().iterator().next()); + + assertEquals(entry1, trace.getEntries().get(0)); + assertEquals(entry2, trace.getEntries().get(1)); + assertEquals(entry3, trace.getEntries().get(2)); + } + + @Test(expected = UnsupportedOperationException.class) + public 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))); + } + + @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)); + + assertEquals(entry1, entry1); + assertEquals(entry1, entry2); + assertNotEquals(entry2, entry3); + } +}