From c2bcffe47632850812b87f1652fe37aefa0ec51c Mon Sep 17 00:00:00 2001 From: Wesley Rosenblum Date: Fri, 8 Nov 2019 16:49:31 -0800 Subject: [PATCH 1/9] Defining Keyring interface, RawAesKeyring and RawRsaKeyring. *Issue #, if available:* #102 *Description of changes:* This change defines the Keyring interface, RawAesKeyring and RawRsaKeyring. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. # Check any applicable: - [ ] Were any files moved? Moving files changes their URL, which breaks all hyperlinks to the files. --- .../DefaultCryptoMaterialsManager.java | 8 +- .../internal/DecryptionHandler.java | 11 +- .../encryptionsdk/keyrings/Keyring.java | 73 ++++++ .../encryptionsdk/keyrings/RawAesKeyring.java | 67 +++++ .../encryptionsdk/keyrings/RawKeyring.java | 136 ++++++++++ .../encryptionsdk/keyrings/RawRsaKeyring.java | 63 +++++ .../model/DecryptionMaterials.java | 95 ++++++- .../model/EncryptionMaterials.java | 18 +- .../DefaultCryptoMaterialsManagerTest.java | 3 +- .../caching/CacheTestFixtures.java | 9 +- ...alCryptoMaterialsCacheThreadStormTest.java | 12 +- .../keyrings/RawAesKeyringTest.java | 86 ++++++ .../keyrings/RawKeyringTest.java | 245 ++++++++++++++++++ .../keyrings/RawRsaKeyringTest.java | 84 ++++++ 14 files changed, 871 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java create mode 100644 src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java create mode 100644 src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java create mode 100644 src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java create mode 100644 src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java create mode 100644 src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java create mode 100644 src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java diff --git a/src/main/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManager.java b/src/main/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManager.java index d31c615b5..25b4d9c14 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManager.java +++ b/src/main/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManager.java @@ -131,9 +131,11 @@ public DefaultCryptoMaterialsManager(MasterKeyProvider mkp) { } return DecryptionMaterials.newBuilder() - .setDataKey(dataKey) - .setTrailingSignatureKey(pubKey) - .build(); + .setAlgorithm(request.getAlgorithm()) + .setCleartextDataKey(dataKey.getKey()) + .setMasterKey(dataKey.getMasterKey()) + .setTrailingSignatureKey(pubKey) + .build(); } private PublicKey deserializeTrailingKeyFromEc(CryptoAlgorithm algo, String pubKey) { diff --git a/src/main/java/com/amazonaws/encryptionsdk/internal/DecryptionHandler.java b/src/main/java/com/amazonaws/encryptionsdk/internal/DecryptionHandler.java index 386a4d867..5f2729155 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/internal/DecryptionHandler.java +++ b/src/main/java/com/amazonaws/encryptionsdk/internal/DecryptionHandler.java @@ -28,7 +28,6 @@ import com.amazonaws.encryptionsdk.CryptoAlgorithm; import com.amazonaws.encryptionsdk.CryptoMaterialsManager; -import com.amazonaws.encryptionsdk.DataKey; import com.amazonaws.encryptionsdk.DefaultCryptoMaterialsManager; import com.amazonaws.encryptionsdk.MasterKey; import com.amazonaws.encryptionsdk.MasterKeyProvider; @@ -61,7 +60,8 @@ public class DecryptionHandler> implements MessageCryptoH private CryptoHandler contentCryptoHandler_; - private DataKey dataKey_; + private SecretKey dataKey_; + private K masterKey_; private SecretKey decryptionKey_; private CryptoAlgorithm cryptoAlgo_; private Signature trailingSig_; @@ -454,12 +454,13 @@ private void readHeaderFields(final CiphertextHeaders ciphertextHeaders) { DecryptionMaterials result = materialsManager_.decryptMaterials(request); + dataKey_ = result.getCleartextDataKey(); //noinspection unchecked - dataKey_ = (DataKey)result.getDataKey(); + masterKey_ = (K)result.getMasterKey(); PublicKey trailingPublicKey = result.getTrailingSignatureKey(); try { - decryptionKey_ = cryptoAlgo_.getEncryptionKeyFromDataKey(dataKey_.getKey(), ciphertextHeaders); + decryptionKey_ = cryptoAlgo_.getEncryptionKeyFromDataKey(dataKey_, ciphertextHeaders); } catch (final InvalidKeyException ex) { throw new AwsCryptoException(ex); } @@ -536,7 +537,7 @@ public CiphertextHeaders getHeaders() { @Override public List getMasterKeys() { - return Collections.singletonList(dataKey_.getMasterKey()); + return Collections.singletonList(masterKey_); } @Override diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java new file mode 100644 index 000000000..cfb331ae6 --- /dev/null +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java @@ -0,0 +1,73 @@ +/* + * 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.DecryptionMaterials; +import com.amazonaws.encryptionsdk.model.EncryptionMaterials; + +import javax.crypto.SecretKey; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.List; + +/** + * Keyrings are responsible for the generation, encryption, and decryption of data keys. + */ +public interface Keyring { + + /** + * Generate a data key if not present and encrypt it using any available wrapping key + * + * @param encryptionMaterials Materials needed for encryption that the keyring may modify. + */ + void onEncrypt(EncryptionMaterials encryptionMaterials); + + /** + * Attempt to decrypt the encrypted data keys + * + * @param decryptionMaterials Materials needed for decryption that the keyring may modify. + * @param encryptedDataKeys List of encrypted data keys. + */ + void onDecrypt(DecryptionMaterials decryptionMaterials, List encryptedDataKeys); + + /** + * Constructs a {@code Keyring} which does local AES-GCM encryption + * decryption of data keys using the provided wrapping key. + * + * @param keyNamespace A UTF-8 encoded value that, together with the key name, identifies the wrapping key. + * @param keyName A UTF-8 encoded 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} + */ + 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 UTF-8 encoded value that, together with the key name, identifies the wrapping key. + * @param keyName A UTF-8 encoded 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} + */ + 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/keyrings/RawAesKeyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java new file mode 100644 index 000000000..6785e67d9 --- /dev/null +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java @@ -0,0 +1,67 @@ +/* + * 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 Keyring.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 + void traceOnEncrypt(KeyringTrace keyringTrace) { + keyringTrace.add(keyNamespace, keyName, + KeyringTraceFlag.ENCRYPTED_DATA_KEY, + KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT, + KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT); + } + + @Override + void traceOnDecrypt(KeyringTrace keyringTrace) { + keyringTrace.add(keyNamespace, keyName, + KeyringTraceFlag.DECRYPTED_DATA_KEY, + KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT, + 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..fd090e104 --- /dev/null +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java @@ -0,0 +1,136 @@ +/* + * 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 com.amazonaws.encryptionsdk.model.DecryptionMaterials; +import com.amazonaws.encryptionsdk.model.EncryptionMaterials; +import com.amazonaws.encryptionsdk.model.KeyBlob; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.logging.Logger; + +import static org.apache.commons.lang3.Validate.notBlank; +import static org.apache.commons.lang3.Validate.notNull; + +/** + * 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 Charset KEY_NAME_ENCODING = StandardCharsets.UTF_8; + 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"); + notNull(jceKeyCipher, "jceKeyCipher is required"); + + this.keyNamespace = keyNamespace; + this.keyName = keyName; + this.keyNameBytes = keyName.getBytes(KEY_NAME_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); + + /** + * Records trace entries for the given keyring upon successful encryption. + * + * @param keyringTrace The keyring trace to record to. + */ + abstract void traceOnEncrypt(KeyringTrace keyringTrace); + + /** + * Records trace entries for the given keyring upon successful decryption. + * + * @param keyringTrace The keyring trace to record to. + */ + abstract void traceOnDecrypt(KeyringTrace keyringTrace); + + @Override + public void onEncrypt(EncryptionMaterials encryptionMaterials) { + notNull(encryptionMaterials, "encryptionMaterials are required"); + + if (encryptionMaterials.getCleartextDataKey() == null) { + generateDataKey(encryptionMaterials); + } + + final SecretKey cleartextDataKey = encryptionMaterials.getCleartextDataKey(); + + if (!cleartextDataKey.getAlgorithm().equalsIgnoreCase(encryptionMaterials.getAlgorithm().getDataKeyAlgo())) { + throw new IllegalArgumentException("Incorrect key algorithm. Expected " + cleartextDataKey.getAlgorithm() + + " but got " + encryptionMaterials.getAlgorithm().getDataKeyAlgo()); + } + + final EncryptedDataKey encryptedDataKey = jceKeyCipher.encryptKey( + cleartextDataKey.getEncoded(), keyName, keyNamespace, encryptionMaterials.getEncryptionContext()); + encryptionMaterials.getEncryptedDataKeys().add(new KeyBlob(encryptedDataKey)); + + traceOnEncrypt(encryptionMaterials.getKeyringTrace()); + } + + @Override + public void onDecrypt(DecryptionMaterials decryptionMaterials, List encryptedDataKeys) { + notNull(decryptionMaterials, "decryptionMaterials are required"); + notNull(encryptedDataKeys, "encryptedDataKeys are required"); + + if (decryptionMaterials.getCleartextDataKey() != null) { + return; + } + + for (EncryptedDataKey encryptedDataKey : encryptedDataKeys) { + if (validToDecrypt(encryptedDataKey)) { + try { + final byte[] decryptedKey = jceKeyCipher.decryptKey( + encryptedDataKey, keyName, decryptionMaterials.getEncryptionContext()); + decryptionMaterials.setCleartextDataKey( + new SecretKeySpec(decryptedKey, decryptionMaterials.getAlgorithm().getDataKeyAlgo())); + traceOnDecrypt(decryptionMaterials.getKeyringTrace()); + 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.getAlgorithm().getDataKeyLength()]; + Utils.getSecureRandom().nextBytes(rawKey); + final SecretKey key = new SecretKeySpec(rawKey, encryptionMaterials.getAlgorithm().getDataKeyAlgo()); + + encryptionMaterials.setCleartextDataKey(key); + encryptionMaterials.getKeyringTrace().add(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..0ba858efd --- /dev/null +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java @@ -0,0 +1,63 @@ +/* + * 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 Keyring.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 + void traceOnEncrypt(KeyringTrace keyringTrace) { + keyringTrace.add(keyNamespace, keyName, KeyringTraceFlag.ENCRYPTED_DATA_KEY); + } + + @Override + void traceOnDecrypt(KeyringTrace keyringTrace) { + keyringTrace.add(keyNamespace, keyName, KeyringTraceFlag.DECRYPTED_DATA_KEY); + } +} diff --git a/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java index 0c0ba52c7..c72ce83c0 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/model/DecryptionMaterials.java @@ -1,29 +1,70 @@ package com.amazonaws.encryptionsdk.model; import java.security.PublicKey; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; -import com.amazonaws.encryptionsdk.DataKey; +import com.amazonaws.encryptionsdk.CryptoAlgorithm; +import com.amazonaws.encryptionsdk.MasterKey; import com.amazonaws.encryptionsdk.keyrings.KeyringTrace; +import javax.crypto.SecretKey; + public final class DecryptionMaterials { - private final DataKey dataKey; + private final CryptoAlgorithm algorithm; + private SecretKey cleartextDataKey; + private final MasterKey masterKey; private final PublicKey trailingSignatureKey; + private final Map encryptionContext; private final KeyringTrace keyringTrace; private DecryptionMaterials(Builder b) { - dataKey = b.getDataKey(); + algorithm = b.getAlgorithm(); + cleartextDataKey = b.getCleartextDataKey(); + masterKey = b.getMasterKey(); trailingSignatureKey = b.getTrailingSignatureKey(); + encryptionContext = b.getEncryptionContext(); keyringTrace = b.getKeyringTrace(); } - public DataKey getDataKey() { - return dataKey; + /** + * The algorithm to use for this decryption operation. Must match the algorithm in DecryptionMaterialsRequest, if that + * algorithm was non-null. + */ + public CryptoAlgorithm getAlgorithm() { + return algorithm; + } + + public SecretKey getCleartextDataKey() { + return cleartextDataKey; + } + + public void setCleartextDataKey(SecretKey cleartextDataKey) { + if(this.cleartextDataKey != null) { + throw new IllegalStateException("cleartextDataKey was already populated"); + } + + this.cleartextDataKey = cleartextDataKey; + } + + /** + * Gets the MasterKey (if any) used for decrypting the data key. Will be null + * if a KeyRing was used instead of a MasterKeyProvider. + * @return The MasterKey + */ + public MasterKey getMasterKey() { + return masterKey; } public PublicKey getTrailingSignatureKey() { return trailingSignatureKey; } + public Map getEncryptionContext() { + return encryptionContext; + } + public KeyringTrace getKeyringTrace() { return keyringTrace; } @@ -37,24 +78,47 @@ public Builder toBuilder() { } public static final class Builder { - private DataKey dataKey; + private CryptoAlgorithm algorithm; + private SecretKey cleartextDataKey; + private MasterKey masterKey; private PublicKey trailingSignatureKey; + private Map encryptionContext; private KeyringTrace keyringTrace; private Builder(DecryptionMaterials result) { - this.dataKey = result.getDataKey(); + this.algorithm = result.getAlgorithm(); + this.cleartextDataKey = result.getCleartextDataKey(); + this.masterKey = result.getMasterKey(); this.trailingSignatureKey = result.getTrailingSignatureKey(); this.keyringTrace = result.getKeyringTrace(); } private Builder() {} - public DataKey getDataKey() { - return dataKey; + public CryptoAlgorithm getAlgorithm() { + return algorithm; + } + + public Builder setAlgorithm(CryptoAlgorithm algorithm) { + this.algorithm = algorithm; + return this; + } + + public SecretKey getCleartextDataKey() { + return cleartextDataKey; } - public Builder setDataKey(DataKey dataKey) { - this.dataKey = dataKey; + public Builder setCleartextDataKey(SecretKey cleartextDataKey) { + this.cleartextDataKey = cleartextDataKey; + return this; + } + + public MasterKey getMasterKey() { + return masterKey; + } + + public Builder setMasterKey(MasterKey masterKey) { + this.masterKey = masterKey; return this; } @@ -67,6 +131,15 @@ public Builder setTrailingSignatureKey(PublicKey trailingSignatureKey) { return this; } + public Map getEncryptionContext() { + return encryptionContext; + } + + public Builder setEncryptionContext(Map encryptionContext) { + this.encryptionContext = Collections.unmodifiableMap(new HashMap<>(encryptionContext)); + return this; + } + public KeyringTrace getKeyringTrace() { return keyringTrace; } diff --git a/src/main/java/com/amazonaws/encryptionsdk/model/EncryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/model/EncryptionMaterials.java index f9b05a153..8c912adc1 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/model/EncryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/model/EncryptionMaterials.java @@ -22,7 +22,7 @@ public final class EncryptionMaterials { private final CryptoAlgorithm algorithm; private final Map encryptionContext; private final List encryptedDataKeys; - private final SecretKey cleartextDataKey; + private SecretKey cleartextDataKey; private final PrivateKey trailingSignatureKey; private final List masterKeys; private final KeyringTrace keyringTrace; @@ -75,6 +75,14 @@ public SecretKey getCleartextDataKey() { return cleartextDataKey; } + public void setCleartextDataKey(SecretKey cleartextDataKey) { + if(this.cleartextDataKey != null) { + throw new IllegalStateException("cleartextDataKey was already populated"); + } + + this.cleartextDataKey = cleartextDataKey; + } + /** * The private key to be used to sign the message trailer. Must be present if any only if required by the * crypto algorithm, and the key type must likewise match the algorithm in use. @@ -87,6 +95,10 @@ public PrivateKey getTrailingSignatureKey() { return trailingSignatureKey; } + public KeyringTrace getKeyringTrace() { + return keyringTrace; + } + /** * Contains a list of all MasterKeys that could decrypt this message. */ @@ -115,7 +127,7 @@ public List getMasterKeys() { public static class Builder { private CryptoAlgorithm algorithm; private Map encryptionContext = Collections.emptyMap(); - private List encryptedDataKeys = null; + private List encryptedDataKeys = new ArrayList<>(); private SecretKey cleartextDataKey; private PrivateKey trailingSignatureKey; private List masterKeys = Collections.emptyList(); @@ -160,7 +172,7 @@ public List getEncryptedDataKeys() { } public Builder setEncryptedDataKeys(List encryptedDataKeys) { - this.encryptedDataKeys = Collections.unmodifiableList(new ArrayList<>(encryptedDataKeys)); + this.encryptedDataKeys = new ArrayList<>(encryptedDataKeys); return this; } diff --git a/src/test/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManagerTest.java b/src/test/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManagerTest.java index 9f693fe28..d831e3c8b 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManagerTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManagerTest.java @@ -2,7 +2,6 @@ import static com.amazonaws.encryptionsdk.multi.MultipleProviderFactory.buildMultiProvider; import static java.util.Collections.singletonMap; -import static org.hamcrest.Matchers.hasEntry; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -250,7 +249,7 @@ public void decrypt_testSimpleRoundTrip() throws Exception { DecryptionMaterials decryptMaterials = new DefaultCryptoMaterialsManager(mk1).decryptMaterials(decryptReqFromMaterials(encryptMaterials)); - assertArrayEquals(decryptMaterials.getDataKey().getKey().getEncoded(), + assertArrayEquals(decryptMaterials.getCleartextDataKey().getEncoded(), encryptMaterials.getCleartextDataKey().getEncoded()); if (encryptMaterials.getTrailingSignatureKey() == null) { diff --git a/src/test/java/com/amazonaws/encryptionsdk/caching/CacheTestFixtures.java b/src/test/java/com/amazonaws/encryptionsdk/caching/CacheTestFixtures.java index bda4343d3..4d385ca5f 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/caching/CacheTestFixtures.java +++ b/src/test/java/com/amazonaws/encryptionsdk/caching/CacheTestFixtures.java @@ -1,12 +1,9 @@ package com.amazonaws.encryptionsdk.caching; -import static org.mockito.ArgumentMatchers.eq; - import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.util.Collections; -import com.amazonaws.encryptionsdk.DataKey; import com.amazonaws.encryptionsdk.DefaultCryptoMaterialsManager; import com.amazonaws.encryptionsdk.MasterKey; import com.amazonaws.encryptionsdk.TestUtils; @@ -56,10 +53,8 @@ public static DecryptionMaterials createDecryptResult(DecryptionMaterialsRequest DecryptionMaterials realResult = new DefaultCryptoMaterialsManager(FIXED_KEY).decryptMaterials(request); return realResult .toBuilder() - .setDataKey(new DataKey(new SentinelKey(), - realResult.getDataKey().getEncryptedDataKey(), - realResult.getDataKey().getProviderInformation(), - realResult.getDataKey().getMasterKey())) + .setCleartextDataKey(realResult.getCleartextDataKey()) + .setMasterKey(realResult.getMasterKey()) .build(); } diff --git a/src/test/java/com/amazonaws/encryptionsdk/caching/LocalCryptoMaterialsCacheThreadStormTest.java b/src/test/java/com/amazonaws/encryptionsdk/caching/LocalCryptoMaterialsCacheThreadStormTest.java index 804b148ac..e2ac53637 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/caching/LocalCryptoMaterialsCacheThreadStormTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/caching/LocalCryptoMaterialsCacheThreadStormTest.java @@ -1,9 +1,6 @@ package com.amazonaws.encryptionsdk.caching; -import static com.amazonaws.encryptionsdk.caching.CacheTestFixtures.createMaterialsResult; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.lang.reflect.Field; @@ -28,7 +25,6 @@ import org.junit.Test; -import com.amazonaws.encryptionsdk.DataKey; import com.amazonaws.encryptionsdk.caching.CryptoMaterialsCache.UsageStats; import com.amazonaws.encryptionsdk.model.DecryptionMaterials; import com.amazonaws.encryptionsdk.model.EncryptionMaterials; @@ -137,9 +133,9 @@ public void decryptAddThread() { ref[0] = 0; CacheTestFixtures.SentinelKey key = new CacheTestFixtures.SentinelKey(); - DecryptionMaterials result = BASE_DECRYPT.toBuilder().setDataKey( - new DataKey(key, new byte[0], new byte[0], BASE_DECRYPT.getDataKey().getMasterKey()) - ).build(); + DecryptionMaterials result = BASE_DECRYPT.toBuilder() + .setCleartextDataKey(key) + .setMasterKey(BASE_DECRYPT.getMasterKey()).build(); ConcurrentHashMap expectedDecryptMap = possibleDecrypts.computeIfAbsent(ByteBuffer.wrap(ref), @@ -183,7 +179,7 @@ public void decryptCheckThread() { CacheTestFixtures.SentinelKey cachedKey = null; if (result != null) { inc("decrypt: hit"); - cachedKey = (CacheTestFixtures.SentinelKey) result.getResult().getDataKey().getKey(); + cachedKey = (CacheTestFixtures.SentinelKey) result.getResult().getCleartextDataKey(); if (expectedDecryptMap.containsKey(cachedKey)) { inc("decrypt: found key in expected"); } else { 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..eb8148f55 --- /dev/null +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java @@ -0,0 +1,86 @@ +/* + * 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.model.KeyBlob; +import org.apache.commons.lang3.ArrayUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import javax.crypto.SecretKey; +import java.nio.charset.StandardCharsets; + +import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.KEYNAME; +import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.KEYNAMESPACE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@RunWith(MockitoJUnitRunner.class) +public class RawAesKeyringTest { + + @Mock + private SecretKey wrappingKey; + + @Test + public void testValidToDecrypt() { + RawAesKeyring rawAesKeyring = new RawAesKeyring(KEYNAMESPACE, KEYNAME, wrappingKey); + + assertTrue(rawAesKeyring.validToDecrypt(new KeyBlob( + KEYNAMESPACE, KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{}))); + assertTrue(rawAesKeyring.validToDecrypt(new KeyBlob( + KEYNAMESPACE, ArrayUtils.add(KEYNAME.getBytes(StandardCharsets.UTF_8), (byte)5), new byte[]{}))); + //Bad namespace + assertFalse(rawAesKeyring.validToDecrypt(new KeyBlob( + "WrongNamespace", KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{}))); + //Bad provider info + assertFalse(rawAesKeyring.validToDecrypt(new KeyBlob( + KEYNAMESPACE, new byte[]{1,2,3}, new byte[]{}))); + } + + @Test + public void testTraceOnEncrypt() { + RawAesKeyring rawAesKeyring = new RawAesKeyring(KEYNAMESPACE, KEYNAME, wrappingKey); + + KeyringTrace trace = new KeyringTrace(); + + rawAesKeyring.traceOnEncrypt(trace); + assertEquals(1, trace.getEntries().size()); + assertEquals(KEYNAME, trace.getEntries().get(0).getKeyName()); + assertEquals(KEYNAMESPACE, trace.getEntries().get(0).getKeyNamespace()); + assertEquals(3, trace.getEntries().get(0).getFlags().size()); + assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.ENCRYPTED_DATA_KEY)); + assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT)); + assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT)); + } + + @Test + public void testTraceOnDecrypt() { + RawAesKeyring rawAesKeyring = new RawAesKeyring(KEYNAMESPACE, KEYNAME, wrappingKey); + + KeyringTrace trace = new KeyringTrace(); + + rawAesKeyring.traceOnDecrypt(trace); + assertEquals(1, trace.getEntries().size()); + assertEquals(KEYNAME, trace.getEntries().get(0).getKeyName()); + assertEquals(KEYNAMESPACE, trace.getEntries().get(0).getKeyNamespace()); + assertEquals(3, trace.getEntries().get(0).getFlags().size()); + assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.DECRYPTED_DATA_KEY)); + assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT)); + assertTrue(trace.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..842210f80 --- /dev/null +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java @@ -0,0 +1,245 @@ +/* + * 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.DecryptionMaterials; +import com.amazonaws.encryptionsdk.model.EncryptionMaterials; +import com.amazonaws.encryptionsdk.model.KeyBlob; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +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 java.util.function.Function; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class RawKeyringTest { + + static final String KEYNAME = "testKeyname"; + static final String KEYNAMESPACE = "testKeynamespace"; + private static final CryptoAlgorithm ALGORITHM = CryptoAlgorithm.ALG_AES_192_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384; + static final SecretKey DATA_KEY = new SecretKeySpec(new byte[]{10, 11, 12}, ALGORITHM.getDataKeyAlgo()); + private static final EncryptedDataKey ENCRYPTED_DATA_KEY = new KeyBlob("keyProviderId", new byte[]{1, 2, 3}, new byte[]{4, 5, 6}); + private static final Map ENCRYPTION_CONTEXT = Collections.singletonMap("myKey", "myValue"); + private static final KeyringTraceEntry ENCRYPTED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, Collections.singleton(KeyringTraceFlag.ENCRYPTED_DATA_KEY)); + private static final KeyringTraceEntry DECRYPTED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, Collections.singleton(KeyringTraceFlag.DECRYPTED_DATA_KEY)); + private static final KeyringTraceEntry GENERATED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, Collections.singleton(KeyringTraceFlag.GENERATED_DATA_KEY)); + @Mock + private JceKeyCipher jceKeyCipher; + @Captor + private ArgumentCaptor dataKeyCaptor; + + @Test + public void testEncryptDecryptExistingDataKey() throws GeneralSecurityException { + Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> true, ENCRYPTED_DATA_KEY_TRACE, DECRYPTED_DATA_KEY_TRACE); + + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setCleartextDataKey(DATA_KEY) + .setKeyringTrace(new KeyringTrace()) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .build(); + + when(jceKeyCipher.encryptKey(DATA_KEY.getEncoded(), KEYNAME, KEYNAMESPACE, ENCRYPTION_CONTEXT)).thenReturn(ENCRYPTED_DATA_KEY); + 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() + .setAlgorithm(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(new KeyringTrace()) + .build(); + + when(jceKeyCipher.decryptKey(encryptionMaterials.getEncryptedDataKeys().get(0), KEYNAME, ENCRYPTION_CONTEXT)).thenReturn(DATA_KEY.getEncoded()); + keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); + + assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + assertEquals(DECRYPTED_DATA_KEY_TRACE, decryptionMaterials.getKeyringTrace().getEntries().get(0)); + } + + @Test + public void testEncryptNullDataKey() { + Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> true, ENCRYPTED_DATA_KEY_TRACE, null); + + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setKeyringTrace(new KeyringTrace()) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .build(); + + when(jceKeyCipher.encryptKey(dataKeyCaptor.capture(), eq(KEYNAME), eq(KEYNAMESPACE), eq(ENCRYPTION_CONTEXT))).thenReturn(ENCRYPTED_DATA_KEY); + keyring.onEncrypt(encryptionMaterials); + + assertEquals(encryptionMaterials.getCleartextDataKey().getAlgorithm(), ALGORITHM.getDataKeyAlgo()); + assertArrayEquals(encryptionMaterials.getCleartextDataKey().getEncoded(), dataKeyCaptor.getValue()); + assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size()); + assertNotNull(encryptionMaterials.getCleartextDataKey()); + 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(expected = IllegalArgumentException.class) + public void testEncryptBadDataKeyAlgorithm() { + Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> true, null, null); + + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setCleartextDataKey(new SecretKeySpec(DATA_KEY.getEncoded(), "OtherAlgorithm")) + .setKeyringTrace(new KeyringTrace()) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .build(); + + keyring.onEncrypt(encryptionMaterials); + } + + @Test + public void testDecryptAlreadyDecryptedDataKey() { + Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> true, null, null); + + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setCleartextDataKey(DATA_KEY) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(new KeyringTrace()) + .build(); + + keyring.onDecrypt(decryptionMaterials, Collections.singletonList(ENCRYPTED_DATA_KEY)); + + assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + assertEquals(0, decryptionMaterials.getKeyringTrace().getEntries().size()); + } + + @Test + public void testDecryptNoValidDataKey() { + Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> false, null, null); + + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(new KeyringTrace()) + .build(); + + keyring.onDecrypt(decryptionMaterials, Collections.singletonList(ENCRYPTED_DATA_KEY)); + + assertNull(decryptionMaterials.getCleartextDataKey()); + assertEquals(0, decryptionMaterials.getKeyringTrace().getEntries().size()); + } + + @Test + public void testDecryptMultipleKeysOneInvalid() throws GeneralSecurityException { + final EncryptedDataKey BAD_DATA_KEY = new KeyBlob("badProviderId", new byte[]{1, 2, 3}, new byte[]{4, 5, 6}); + + Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> !edk.getProviderId().equals(BAD_DATA_KEY.getProviderId()), null, DECRYPTED_DATA_KEY_TRACE); + + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(new KeyringTrace()) + .build(); + + when(jceKeyCipher.decryptKey(ENCRYPTED_DATA_KEY, KEYNAME, ENCRYPTION_CONTEXT)).thenReturn(DATA_KEY.getEncoded()); + + final List edks = new ArrayList<>(); + edks.add(BAD_DATA_KEY); + edks.add(ENCRYPTED_DATA_KEY); + + keyring.onDecrypt(decryptionMaterials, edks); + + assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + assertEquals(DECRYPTED_DATA_KEY_TRACE, decryptionMaterials.getKeyringTrace().getEntries().get(0)); + } + + @Test + public void testDecryptMultipleKeysOneException() throws GeneralSecurityException { + final EncryptedDataKey BAD_DATA_KEY = new KeyBlob("badProviderId", new byte[]{1, 2, 3}, new byte[]{4, 5, 6}); + + Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> true, null, DECRYPTED_DATA_KEY_TRACE); + + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(new KeyringTrace()) + .build(); + + when(jceKeyCipher.decryptKey(BAD_DATA_KEY, KEYNAME, ENCRYPTION_CONTEXT)) + .thenThrow(new GeneralSecurityException("could not decrypt key")); + when(jceKeyCipher.decryptKey(ENCRYPTED_DATA_KEY, KEYNAME, ENCRYPTION_CONTEXT)).thenReturn(DATA_KEY.getEncoded()); + + final List edks = new ArrayList<>(); + edks.add(BAD_DATA_KEY); + edks.add(ENCRYPTED_DATA_KEY); + + keyring.onDecrypt(decryptionMaterials, edks); + + assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + assertEquals(DECRYPTED_DATA_KEY_TRACE, decryptionMaterials.getKeyringTrace().getEntries().get(0)); + } + + private Keyring newRawKeyring(JceKeyCipher jceKeyCipher, Function validToDecrypt, + KeyringTraceEntry encryptTraceEntry, KeyringTraceEntry decryptTraceEntry) { + return new RawKeyring(KEYNAMESPACE, KEYNAME, jceKeyCipher) { + @Override + boolean validToDecrypt(EncryptedDataKey encryptedDataKey) { + return validToDecrypt.apply(encryptedDataKey); + } + + @Override + void traceOnEncrypt(KeyringTrace keyringTrace) { + if (encryptTraceEntry != null) { + keyringTrace.add(encryptTraceEntry.getKeyNamespace(), encryptTraceEntry.getKeyName(), + encryptTraceEntry.getFlags().toArray(new KeyringTraceFlag[]{})); + } + } + + @Override + void traceOnDecrypt(KeyringTrace keyringTrace) { + if (decryptTraceEntry != null) { + keyringTrace.add(decryptTraceEntry.getKeyNamespace(), decryptTraceEntry.getKeyName(), + decryptTraceEntry.getFlags().toArray(new KeyringTraceFlag[]{})); + } + } + }; + } + + 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..a5c79a350 --- /dev/null +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java @@ -0,0 +1,84 @@ +/* + * 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.model.KeyBlob; +import org.apache.commons.lang3.ArrayUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import java.nio.charset.StandardCharsets; +import java.security.PrivateKey; +import java.security.PublicKey; + +import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.KEYNAME; +import static com.amazonaws.encryptionsdk.keyrings.RawKeyringTest.KEYNAMESPACE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@RunWith(MockitoJUnitRunner.class) +public class RawRsaKeyringTest { + + @Mock + PublicKey publicKey; + @Mock + PrivateKey privateKey; + private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding"; + + @Test + public void testValidToDecrypt() { + RawRsaKeyring rawRsaKeyring = new RawRsaKeyring(KEYNAMESPACE, KEYNAME, publicKey, privateKey, TRANSFORMATION); + + assertTrue(rawRsaKeyring.validToDecrypt(new KeyBlob( + KEYNAMESPACE, KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{}))); + //Provider info has extra data + assertFalse(rawRsaKeyring.validToDecrypt(new KeyBlob( + KEYNAMESPACE, ArrayUtils.add(KEYNAME.getBytes(StandardCharsets.UTF_8), (byte)5), new byte[]{}))); + //Bad namespace + assertFalse(rawRsaKeyring.validToDecrypt(new KeyBlob( + "WrongNamespace", KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{}))); + } + + @Test + public void testTraceOnEncrypt() { + RawRsaKeyring rawRsaKeyring = new RawRsaKeyring(KEYNAMESPACE, KEYNAME, publicKey, privateKey, TRANSFORMATION); + + KeyringTrace trace = new KeyringTrace(); + + rawRsaKeyring.traceOnEncrypt(trace); + assertEquals(1, trace.getEntries().size()); + assertEquals(KEYNAME, trace.getEntries().get(0).getKeyName()); + assertEquals(KEYNAMESPACE, trace.getEntries().get(0).getKeyNamespace()); + assertEquals(1, trace.getEntries().get(0).getFlags().size()); + assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.ENCRYPTED_DATA_KEY)); + } + + @Test + public void testTraceOnDecrypt() { + RawRsaKeyring rawRsaKeyring = new RawRsaKeyring(KEYNAMESPACE, KEYNAME, publicKey, privateKey, TRANSFORMATION); + + KeyringTrace trace = new KeyringTrace(); + + rawRsaKeyring.traceOnDecrypt(trace); + assertEquals(1, trace.getEntries().size()); + assertEquals(KEYNAME, trace.getEntries().get(0).getKeyName()); + assertEquals(KEYNAMESPACE, trace.getEntries().get(0).getKeyNamespace()); + assertEquals(1, trace.getEntries().get(0).getFlags().size()); + assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.DECRYPTED_DATA_KEY)); + } + +} From b65226bc7561cddb03740adf24627a71fea740c6 Mon Sep 17 00:00:00 2001 From: Wesley Rosenblum Date: Mon, 11 Nov 2019 16:44:14 -0800 Subject: [PATCH 2/9] Moving factory methods to StandardKeyrings and correcting RawAes trace. --- .../encryptionsdk/keyrings/Keyring.java | 28 ---------- .../encryptionsdk/keyrings/RawAesKeyring.java | 6 +- .../encryptionsdk/keyrings/RawRsaKeyring.java | 2 +- .../keyrings/StandardKeyrings.java | 56 +++++++++++++++++++ .../keyrings/RawAesKeyringTest.java | 6 +- 5 files changed, 61 insertions(+), 37 deletions(-) create mode 100644 src/main/java/com/amazonaws/encryptionsdk/keyrings/StandardKeyrings.java diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java index cfb331ae6..36f7c2c81 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java @@ -42,32 +42,4 @@ public interface Keyring { */ void onDecrypt(DecryptionMaterials decryptionMaterials, List encryptedDataKeys); - /** - * Constructs a {@code Keyring} which does local AES-GCM encryption - * decryption of data keys using the provided wrapping key. - * - * @param keyNamespace A UTF-8 encoded value that, together with the key name, identifies the wrapping key. - * @param keyName A UTF-8 encoded 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} - */ - 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 UTF-8 encoded value that, together with the key name, identifies the wrapping key. - * @param keyName A UTF-8 encoded 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} - */ - 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/keyrings/RawAesKeyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java index 6785e67d9..1b9b0a59e 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java @@ -23,7 +23,7 @@ * A {@code Keyring} which does local AES-GCM encryption * decryption of data keys using the provided wrapping key. * - * Instantiate by using the {@code Keyring.rawAes(...)} factory method. + * Instantiate by using the {@code StandardKeyrings.rawAes(...)} factory method. */ class RawAesKeyring extends RawKeyring { @@ -53,15 +53,13 @@ boolean validToDecrypt(EncryptedDataKey encryptedDataKey) { void traceOnEncrypt(KeyringTrace keyringTrace) { keyringTrace.add(keyNamespace, keyName, KeyringTraceFlag.ENCRYPTED_DATA_KEY, - KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT, - KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT); + KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT); } @Override void traceOnDecrypt(KeyringTrace keyringTrace) { keyringTrace.add(keyNamespace, keyName, KeyringTraceFlag.DECRYPTED_DATA_KEY, - KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT, KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT); } } diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java index 0ba858efd..2168d44ce 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java @@ -24,7 +24,7 @@ * 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 Keyring.rawRsa(...)} factory method. + * Instantiate by using the {@code StandardKeyrings.rawRsa(...)} factory method. */ class RawRsaKeyring extends RawKeyring { 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..1f8d24b52 --- /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 UTF-8 encoded value that, together with the key name, identifies the wrapping key. + * @param keyName A UTF-8 encoded 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 UTF-8 encoded value that, together with the key name, identifies the wrapping key. + * @param keyName A UTF-8 encoded 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/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java index eb8148f55..e611f0fbb 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java @@ -61,10 +61,9 @@ public void testTraceOnEncrypt() { assertEquals(1, trace.getEntries().size()); assertEquals(KEYNAME, trace.getEntries().get(0).getKeyName()); assertEquals(KEYNAMESPACE, trace.getEntries().get(0).getKeyNamespace()); - assertEquals(3, trace.getEntries().get(0).getFlags().size()); + assertEquals(2, trace.getEntries().get(0).getFlags().size()); assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.ENCRYPTED_DATA_KEY)); assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT)); - assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT)); } @Test @@ -77,9 +76,8 @@ public void testTraceOnDecrypt() { assertEquals(1, trace.getEntries().size()); assertEquals(KEYNAME, trace.getEntries().get(0).getKeyName()); assertEquals(KEYNAMESPACE, trace.getEntries().get(0).getKeyNamespace()); - assertEquals(3, trace.getEntries().get(0).getFlags().size()); + assertEquals(2, trace.getEntries().get(0).getFlags().size()); assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.DECRYPTED_DATA_KEY)); - assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT)); assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT)); } From 48c9cdde6a0aaa8477e38fcdb9ad28dc4051d9b5 Mon Sep 17 00:00:00 2001 From: Wesley Rosenblum Date: Tue, 12 Nov 2019 16:42:37 -0800 Subject: [PATCH 3/9] Adding additional tests for RawAesKeyring and RawRsaKeyring --- .../keyrings/RawAesKeyringTest.java | 117 ++++++++++++------ .../keyrings/RawKeyringTest.java | 94 ++++++-------- .../keyrings/RawRsaKeyringTest.java | 111 ++++++++++++----- 3 files changed, 192 insertions(+), 130 deletions(-) diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java index e611f0fbb..78311eeb7 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java @@ -13,72 +13,113 @@ package com.amazonaws.encryptionsdk.keyrings; +import com.amazonaws.encryptionsdk.model.DecryptionMaterials; +import com.amazonaws.encryptionsdk.model.EncryptionMaterials; import com.amazonaws.encryptionsdk.model.KeyBlob; import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import javax.crypto.SecretKey; +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.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -@RunWith(MockitoJUnitRunner.class) public class RawAesKeyringTest { - @Mock - private SecretKey wrappingKey; + private final RawAesKeyring keyring = new RawAesKeyring(KEYNAMESPACE, KEYNAME, new SecretKeySpec(generate(32), "AES")); @Test public void testValidToDecrypt() { - RawAesKeyring rawAesKeyring = new RawAesKeyring(KEYNAMESPACE, KEYNAME, wrappingKey); - - assertTrue(rawAesKeyring.validToDecrypt(new KeyBlob( + assertTrue(keyring.validToDecrypt(new KeyBlob( KEYNAMESPACE, KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{}))); - assertTrue(rawAesKeyring.validToDecrypt(new KeyBlob( - KEYNAMESPACE, ArrayUtils.add(KEYNAME.getBytes(StandardCharsets.UTF_8), (byte)5), new byte[]{}))); + assertTrue(keyring.validToDecrypt(new KeyBlob( + KEYNAMESPACE, ArrayUtils.add(KEYNAME.getBytes(StandardCharsets.UTF_8), (byte) 5), new byte[]{}))); //Bad namespace - assertFalse(rawAesKeyring.validToDecrypt(new KeyBlob( + assertFalse(keyring.validToDecrypt(new KeyBlob( "WrongNamespace", KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{}))); //Bad provider info - assertFalse(rawAesKeyring.validToDecrypt(new KeyBlob( + assertFalse(keyring.validToDecrypt(new KeyBlob( KEYNAMESPACE, new byte[]{1,2,3}, new byte[]{}))); } @Test - public void testTraceOnEncrypt() { - RawAesKeyring rawAesKeyring = new RawAesKeyring(KEYNAMESPACE, KEYNAME, wrappingKey); - - KeyringTrace trace = new KeyringTrace(); - - rawAesKeyring.traceOnEncrypt(trace); - assertEquals(1, trace.getEntries().size()); - assertEquals(KEYNAME, trace.getEntries().get(0).getKeyName()); - assertEquals(KEYNAMESPACE, trace.getEntries().get(0).getKeyNamespace()); - assertEquals(2, trace.getEntries().get(0).getFlags().size()); - assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.ENCRYPTED_DATA_KEY)); - assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT)); + public void testEncryptDecryptExistingDataKey() { + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setCleartextDataKey(DATA_KEY) + .setKeyringTrace(new KeyringTrace()) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .build(); + + keyring.onEncrypt(encryptionMaterials); + + assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size()); + 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() + .setAlgorithm(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(new KeyringTrace()) + .build(); + + keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); + + assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + 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 - public void testTraceOnDecrypt() { - RawAesKeyring rawAesKeyring = new RawAesKeyring(KEYNAMESPACE, KEYNAME, wrappingKey); - - KeyringTrace trace = new KeyringTrace(); - - rawAesKeyring.traceOnDecrypt(trace); - assertEquals(1, trace.getEntries().size()); - assertEquals(KEYNAME, trace.getEntries().get(0).getKeyName()); - assertEquals(KEYNAMESPACE, trace.getEntries().get(0).getKeyNamespace()); - assertEquals(2, trace.getEntries().get(0).getFlags().size()); - assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.DECRYPTED_DATA_KEY)); - assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.VERIFIED_ENCRYPTION_CONTEXT)); + public void testEncryptDecryptGenerateDataKey() { + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setKeyringTrace(new KeyringTrace()) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .build(); + + keyring.onEncrypt(encryptionMaterials); + + assertNotNull(encryptionMaterials.getCleartextDataKey()); + assertEquals(encryptionMaterials.getCleartextDataKey().getAlgorithm(), ALGORITHM.getDataKeyAlgo()); + assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size()); + 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() + .setAlgorithm(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(new KeyringTrace()) + .build(); + + keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); + + assertEquals(encryptionMaterials.getCleartextDataKey(), decryptionMaterials.getCleartextDataKey()); + 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 index 842210f80..63c45bc8e 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java @@ -19,10 +19,10 @@ import com.amazonaws.encryptionsdk.model.DecryptionMaterials; import com.amazonaws.encryptionsdk.model.EncryptionMaterials; import com.amazonaws.encryptionsdk.model.KeyBlob; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -33,7 +33,6 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.function.Function; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -47,22 +46,43 @@ public class RawKeyringTest { static final String KEYNAME = "testKeyname"; static final String KEYNAMESPACE = "testKeynamespace"; - private static final CryptoAlgorithm ALGORITHM = CryptoAlgorithm.ALG_AES_192_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384; + static final CryptoAlgorithm ALGORITHM = CryptoAlgorithm.ALG_AES_192_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384; static final SecretKey DATA_KEY = new SecretKeySpec(new byte[]{10, 11, 12}, 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}, new byte[]{4, 5, 6}); - private static final Map ENCRYPTION_CONTEXT = Collections.singletonMap("myKey", "myValue"); + private static final EncryptedDataKey INVALID_DATA_KEY = new KeyBlob("invalidProviderId", new byte[]{1, 2, 3}, new byte[]{4, 5, 6}); private static final KeyringTraceEntry ENCRYPTED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, Collections.singleton(KeyringTraceFlag.ENCRYPTED_DATA_KEY)); private static final KeyringTraceEntry DECRYPTED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, Collections.singleton(KeyringTraceFlag.DECRYPTED_DATA_KEY)); private static final KeyringTraceEntry GENERATED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, Collections.singleton(KeyringTraceFlag.GENERATED_DATA_KEY)); @Mock private JceKeyCipher jceKeyCipher; - @Captor - private ArgumentCaptor dataKeyCaptor; + private Keyring keyring; - @Test - public void testEncryptDecryptExistingDataKey() throws GeneralSecurityException { - Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> true, ENCRYPTED_DATA_KEY_TRACE, DECRYPTED_DATA_KEY_TRACE); + @Before + public 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 + void traceOnEncrypt(KeyringTrace keyringTrace) { + keyringTrace.add(KEYNAMESPACE, KEYNAME, ENCRYPTED_DATA_KEY_TRACE.getFlags().toArray(new KeyringTraceFlag[]{})); + } + @Override + void traceOnDecrypt(KeyringTrace keyringTrace) { + keyringTrace.add(KEYNAMESPACE, KEYNAME, DECRYPTED_DATA_KEY_TRACE.getFlags().toArray(new KeyringTraceFlag[]{})); + } + }; + } + + @Test + public void testEncryptDecryptExistingDataKey() { EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() .setAlgorithm(ALGORITHM) .setCleartextDataKey(DATA_KEY) @@ -70,7 +90,6 @@ public void testEncryptDecryptExistingDataKey() throws GeneralSecurityException .setEncryptionContext(ENCRYPTION_CONTEXT) .build(); - when(jceKeyCipher.encryptKey(DATA_KEY.getEncoded(), KEYNAME, KEYNAMESPACE, ENCRYPTION_CONTEXT)).thenReturn(ENCRYPTED_DATA_KEY); keyring.onEncrypt(encryptionMaterials); assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size()); @@ -84,8 +103,7 @@ public void testEncryptDecryptExistingDataKey() throws GeneralSecurityException .setKeyringTrace(new KeyringTrace()) .build(); - when(jceKeyCipher.decryptKey(encryptionMaterials.getEncryptedDataKeys().get(0), KEYNAME, ENCRYPTION_CONTEXT)).thenReturn(DATA_KEY.getEncoded()); - keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); + keyring.onDecrypt(decryptionMaterials, Collections.singletonList(ENCRYPTED_DATA_KEY)); assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); assertEquals(DECRYPTED_DATA_KEY_TRACE, decryptionMaterials.getKeyringTrace().getEntries().get(0)); @@ -93,14 +111,13 @@ public void testEncryptDecryptExistingDataKey() throws GeneralSecurityException @Test public void testEncryptNullDataKey() { - Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> true, ENCRYPTED_DATA_KEY_TRACE, null); - EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() .setAlgorithm(ALGORITHM) .setKeyringTrace(new KeyringTrace()) .setEncryptionContext(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); @@ -116,8 +133,6 @@ public void testEncryptNullDataKey() { @Test(expected = IllegalArgumentException.class) public void testEncryptBadDataKeyAlgorithm() { - Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> true, null, null); - EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() .setAlgorithm(ALGORITHM) .setCleartextDataKey(new SecretKeySpec(DATA_KEY.getEncoded(), "OtherAlgorithm")) @@ -130,8 +145,6 @@ public void testEncryptBadDataKeyAlgorithm() { @Test public void testDecryptAlreadyDecryptedDataKey() { - Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> true, null, null); - DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() .setAlgorithm(ALGORITHM) .setCleartextDataKey(DATA_KEY) @@ -147,36 +160,28 @@ public void testDecryptAlreadyDecryptedDataKey() { @Test public void testDecryptNoValidDataKey() { - Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> false, null, null); - DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() .setAlgorithm(ALGORITHM) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(new KeyringTrace()) .build(); - keyring.onDecrypt(decryptionMaterials, Collections.singletonList(ENCRYPTED_DATA_KEY)); + keyring.onDecrypt(decryptionMaterials, Collections.singletonList(INVALID_DATA_KEY)); assertNull(decryptionMaterials.getCleartextDataKey()); assertEquals(0, decryptionMaterials.getKeyringTrace().getEntries().size()); } @Test - public void testDecryptMultipleKeysOneInvalid() throws GeneralSecurityException { - final EncryptedDataKey BAD_DATA_KEY = new KeyBlob("badProviderId", new byte[]{1, 2, 3}, new byte[]{4, 5, 6}); - - Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> !edk.getProviderId().equals(BAD_DATA_KEY.getProviderId()), null, DECRYPTED_DATA_KEY_TRACE); - + public void testDecryptMultipleKeysOneInvalid() { DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() .setAlgorithm(ALGORITHM) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(new KeyringTrace()) .build(); - when(jceKeyCipher.decryptKey(ENCRYPTED_DATA_KEY, KEYNAME, ENCRYPTION_CONTEXT)).thenReturn(DATA_KEY.getEncoded()); - final List edks = new ArrayList<>(); - edks.add(BAD_DATA_KEY); + edks.add(INVALID_DATA_KEY); edks.add(ENCRYPTED_DATA_KEY); keyring.onDecrypt(decryptionMaterials, edks); @@ -187,9 +192,7 @@ public void testDecryptMultipleKeysOneInvalid() throws GeneralSecurityException @Test public void testDecryptMultipleKeysOneException() throws GeneralSecurityException { - final EncryptedDataKey BAD_DATA_KEY = new KeyBlob("badProviderId", new byte[]{1, 2, 3}, new byte[]{4, 5, 6}); - - Keyring keyring = newRawKeyring(jceKeyCipher, (edk) -> true, null, DECRYPTED_DATA_KEY_TRACE); + final EncryptedDataKey BAD_DATA_KEY = new KeyBlob("exceptionProvider", new byte[]{1, 2, 3}, new byte[]{4, 5, 6}); DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() .setAlgorithm(ALGORITHM) @@ -199,7 +202,6 @@ public void testDecryptMultipleKeysOneException() throws GeneralSecurityExceptio when(jceKeyCipher.decryptKey(BAD_DATA_KEY, KEYNAME, ENCRYPTION_CONTEXT)) .thenThrow(new GeneralSecurityException("could not decrypt key")); - when(jceKeyCipher.decryptKey(ENCRYPTED_DATA_KEY, KEYNAME, ENCRYPTION_CONTEXT)).thenReturn(DATA_KEY.getEncoded()); final List edks = new ArrayList<>(); edks.add(BAD_DATA_KEY); @@ -211,32 +213,6 @@ public void testDecryptMultipleKeysOneException() throws GeneralSecurityExceptio assertEquals(DECRYPTED_DATA_KEY_TRACE, decryptionMaterials.getKeyringTrace().getEntries().get(0)); } - private Keyring newRawKeyring(JceKeyCipher jceKeyCipher, Function validToDecrypt, - KeyringTraceEntry encryptTraceEntry, KeyringTraceEntry decryptTraceEntry) { - return new RawKeyring(KEYNAMESPACE, KEYNAME, jceKeyCipher) { - @Override - boolean validToDecrypt(EncryptedDataKey encryptedDataKey) { - return validToDecrypt.apply(encryptedDataKey); - } - - @Override - void traceOnEncrypt(KeyringTrace keyringTrace) { - if (encryptTraceEntry != null) { - keyringTrace.add(encryptTraceEntry.getKeyNamespace(), encryptTraceEntry.getKeyName(), - encryptTraceEntry.getFlags().toArray(new KeyringTraceFlag[]{})); - } - } - - @Override - void traceOnDecrypt(KeyringTrace keyringTrace) { - if (decryptTraceEntry != null) { - keyringTrace.add(decryptTraceEntry.getKeyNamespace(), decryptTraceEntry.getKeyName(), - decryptTraceEntry.getFlags().toArray(new KeyringTraceFlag[]{})); - } - } - }; - } - private void assertEncryptedDataKeyEquals(EncryptedDataKey expected, EncryptedDataKey actual) { assertEquals(expected.getProviderId(), actual.getProviderId()); assertArrayEquals(expected.getProviderInformation(), actual.getProviderInformation()); diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java index a5c79a350..ed314a7ca 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java @@ -13,72 +13,117 @@ package com.amazonaws.encryptionsdk.keyrings; +import com.amazonaws.encryptionsdk.model.DecryptionMaterials; +import com.amazonaws.encryptionsdk.model.EncryptionMaterials; import com.amazonaws.encryptionsdk.model.KeyBlob; import org.apache.commons.lang3.ArrayUtils; +import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; import java.nio.charset.StandardCharsets; -import java.security.PrivateKey; -import java.security.PublicKey; +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.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -@RunWith(MockitoJUnitRunner.class) public class RawRsaKeyringTest { - @Mock - PublicKey publicKey; - @Mock - PrivateKey privateKey; private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding"; + private RawRsaKeyring keyring; + + @Before + public 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 public void testValidToDecrypt() { - RawRsaKeyring rawRsaKeyring = new RawRsaKeyring(KEYNAMESPACE, KEYNAME, publicKey, privateKey, TRANSFORMATION); - - assertTrue(rawRsaKeyring.validToDecrypt(new KeyBlob( + assertTrue(keyring.validToDecrypt(new KeyBlob( KEYNAMESPACE, KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{}))); //Provider info has extra data - assertFalse(rawRsaKeyring.validToDecrypt(new KeyBlob( + assertFalse(keyring.validToDecrypt(new KeyBlob( KEYNAMESPACE, ArrayUtils.add(KEYNAME.getBytes(StandardCharsets.UTF_8), (byte)5), new byte[]{}))); //Bad namespace - assertFalse(rawRsaKeyring.validToDecrypt(new KeyBlob( + assertFalse(keyring.validToDecrypt(new KeyBlob( "WrongNamespace", KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{}))); } @Test - public void testTraceOnEncrypt() { - RawRsaKeyring rawRsaKeyring = new RawRsaKeyring(KEYNAMESPACE, KEYNAME, publicKey, privateKey, TRANSFORMATION); + public void testEncryptDecryptExistingDataKey() { + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setCleartextDataKey(DATA_KEY) + .setKeyringTrace(new KeyringTrace()) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .build(); + + keyring.onEncrypt(encryptionMaterials); + + assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size()); + 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)); - KeyringTrace trace = new KeyringTrace(); + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(new KeyringTrace()) + .build(); - rawRsaKeyring.traceOnEncrypt(trace); - assertEquals(1, trace.getEntries().size()); - assertEquals(KEYNAME, trace.getEntries().get(0).getKeyName()); - assertEquals(KEYNAMESPACE, trace.getEntries().get(0).getKeyNamespace()); - assertEquals(1, trace.getEntries().get(0).getFlags().size()); - assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.ENCRYPTED_DATA_KEY)); + keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); + + assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + 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 - public void testTraceOnDecrypt() { - RawRsaKeyring rawRsaKeyring = new RawRsaKeyring(KEYNAMESPACE, KEYNAME, publicKey, privateKey, TRANSFORMATION); + public void testEncryptDecryptGenerateDataKey() { + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() + .setAlgorithm(ALGORITHM) + .setKeyringTrace(new KeyringTrace()) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .build(); + + keyring.onEncrypt(encryptionMaterials); + + assertNotNull(encryptionMaterials.getCleartextDataKey()); + assertEquals(encryptionMaterials.getCleartextDataKey().getAlgorithm(), ALGORITHM.getDataKeyAlgo()); + assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size()); + 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() + .setAlgorithm(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(new KeyringTrace()) + .build(); - KeyringTrace trace = new KeyringTrace(); + keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); - rawRsaKeyring.traceOnDecrypt(trace); - assertEquals(1, trace.getEntries().size()); - assertEquals(KEYNAME, trace.getEntries().get(0).getKeyName()); - assertEquals(KEYNAMESPACE, trace.getEntries().get(0).getKeyNamespace()); - assertEquals(1, trace.getEntries().get(0).getFlags().size()); - assertTrue(trace.getEntries().get(0).getFlags().contains(KeyringTraceFlag.DECRYPTED_DATA_KEY)); + assertEquals(encryptionMaterials.getCleartextDataKey(), decryptionMaterials.getCleartextDataKey()); + 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)); } } From ea1886d2f81e6a76408df47f9d014153c37a3257 Mon Sep 17 00:00:00 2001 From: Wesley Rosenblum Date: Thu, 14 Nov 2019 15:16:56 -0800 Subject: [PATCH 4/9] Creating separate Encryption/Decryption materials for Keyring usage To maintain backward compatibility with MasterKey/MasterKeyProviders, new EncryptionMaterials and DecryptionMaterials classes are defined for use in Keyrings, so they can include names inline with the spec and additional validation. This change also adds test dependencies for JUnit5. --- pom.xml | 19 +- .../DefaultCryptoMaterialsManager.java | 8 +- .../internal/DecryptionHandler.java | 11 +- .../keyrings/DecryptionMaterials.java | 189 ++++++++++++++ .../keyrings/EncryptionMaterials.java | 236 ++++++++++++++++++ .../encryptionsdk/keyrings/Keyring.java | 5 - .../encryptionsdk/keyrings/KeyringTrace.java | 13 +- .../keyrings/KeyringTraceEntry.java | 8 +- .../encryptionsdk/keyrings/RawAesKeyring.java | 8 +- .../encryptionsdk/keyrings/RawKeyring.java | 42 ++-- .../encryptionsdk/keyrings/RawRsaKeyring.java | 11 +- .../model/DecryptionMaterials.java | 113 +-------- .../model/EncryptionMaterials.java | 37 +-- .../DefaultCryptoMaterialsManagerTest.java | 3 +- .../caching/CacheTestFixtures.java | 9 +- ...alCryptoMaterialsCacheThreadStormTest.java | 12 +- .../keyrings/DecryptionMaterialsTest.java | 139 +++++++++++ .../keyrings/EncryptionMaterialsTest.java | 166 ++++++++++++ .../keyrings/KeyringTraceTest.java | 22 +- .../keyrings/RawAesKeyringTest.java | 56 +++-- .../keyrings/RawKeyringTest.java | 125 +++++----- .../keyrings/RawRsaKeyringTest.java | 62 ++--- 22 files changed, 954 insertions(+), 340 deletions(-) create mode 100644 src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java create mode 100644 src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java create mode 100644 src/test/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterialsTest.java create mode 100644 src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java diff --git a/pom.xml b/pom.xml index 6c485750c..c426db5e6 100644 --- a/pom.xml +++ b/pom.xml @@ -53,16 +53,23 @@ - org.mockito - mockito-core - 2.28.1 + org.junit.jupiter + junit-jupiter-engine + 5.5.2 + test + + + + org.junit.vintage + junit-vintage-engine + 5.5.2 test - junit - junit - 4.12 + org.mockito + mockito-junit-jupiter + 3.1.0 test diff --git a/src/main/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManager.java b/src/main/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManager.java index 25b4d9c14..d31c615b5 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManager.java +++ b/src/main/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManager.java @@ -131,11 +131,9 @@ public DefaultCryptoMaterialsManager(MasterKeyProvider mkp) { } return DecryptionMaterials.newBuilder() - .setAlgorithm(request.getAlgorithm()) - .setCleartextDataKey(dataKey.getKey()) - .setMasterKey(dataKey.getMasterKey()) - .setTrailingSignatureKey(pubKey) - .build(); + .setDataKey(dataKey) + .setTrailingSignatureKey(pubKey) + .build(); } private PublicKey deserializeTrailingKeyFromEc(CryptoAlgorithm algo, String pubKey) { diff --git a/src/main/java/com/amazonaws/encryptionsdk/internal/DecryptionHandler.java b/src/main/java/com/amazonaws/encryptionsdk/internal/DecryptionHandler.java index 5f2729155..386a4d867 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/internal/DecryptionHandler.java +++ b/src/main/java/com/amazonaws/encryptionsdk/internal/DecryptionHandler.java @@ -28,6 +28,7 @@ import com.amazonaws.encryptionsdk.CryptoAlgorithm; import com.amazonaws.encryptionsdk.CryptoMaterialsManager; +import com.amazonaws.encryptionsdk.DataKey; import com.amazonaws.encryptionsdk.DefaultCryptoMaterialsManager; import com.amazonaws.encryptionsdk.MasterKey; import com.amazonaws.encryptionsdk.MasterKeyProvider; @@ -60,8 +61,7 @@ public class DecryptionHandler> implements MessageCryptoH private CryptoHandler contentCryptoHandler_; - private SecretKey dataKey_; - private K masterKey_; + private DataKey dataKey_; private SecretKey decryptionKey_; private CryptoAlgorithm cryptoAlgo_; private Signature trailingSig_; @@ -454,13 +454,12 @@ private void readHeaderFields(final CiphertextHeaders ciphertextHeaders) { DecryptionMaterials result = materialsManager_.decryptMaterials(request); - dataKey_ = result.getCleartextDataKey(); //noinspection unchecked - masterKey_ = (K)result.getMasterKey(); + dataKey_ = (DataKey)result.getDataKey(); PublicKey trailingPublicKey = result.getTrailingSignatureKey(); try { - decryptionKey_ = cryptoAlgo_.getEncryptionKeyFromDataKey(dataKey_, ciphertextHeaders); + decryptionKey_ = cryptoAlgo_.getEncryptionKeyFromDataKey(dataKey_.getKey(), ciphertextHeaders); } catch (final InvalidKeyException ex) { throw new AwsCryptoException(ex); } @@ -537,7 +536,7 @@ public CiphertextHeaders getHeaders() { @Override public List getMasterKeys() { - return Collections.singletonList(masterKey_); + return Collections.singletonList(dataKey_.getMasterKey()); } @Override diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java new file mode 100644 index 000000000..3d6821a5c --- /dev/null +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java @@ -0,0 +1,189 @@ +/* + * 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 javax.crypto.SecretKey; +import java.security.PublicKey; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.apache.commons.lang3.Validate.isTrue; +import static org.apache.commons.lang3.Validate.notNull; + +/** + * Contains the cryptographic materials needed for a decryption operation. + */ +public final class DecryptionMaterials { + private final CryptoAlgorithm algorithm; + private SecretKey plaintextDataKey; + private final PublicKey verificationKey; + private final Map encryptionContext; + private final KeyringTrace keyringTrace; + + private DecryptionMaterials(Builder b) { + notNull(b.algorithm, "algorithm is required"); + notNull(b.keyringTrace, "keyringTrace is required"); + validatePlaintextDataKey(b.algorithm, b.plaintextDataKey); + validateVerificationKey(b.algorithm, b.verificationKey); + + algorithm = b.algorithm; + plaintextDataKey = b.plaintextDataKey; + verificationKey = b.verificationKey; + encryptionContext = b.encryptionContext; + keyringTrace = b.keyringTrace; + } + + /** + * The algorithm to use for this decryption operation. Must match the algorithm in DecryptionMaterialsRequest, if that + * algorithm was non-null. + */ + public CryptoAlgorithm getAlgorithm() { + return algorithm; + } + + public SecretKey getPlaintextDataKey() { + return plaintextDataKey; + } + + /** + * Sets the plaintext data key. The plaintext data key must not already be populated. + * @param plaintextDataKey The plaintext data key. + * @param keyringTraceEntry The keyring trace entry recording this action. + */ + public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry keyringTraceEntry) { + if(this.plaintextDataKey != null) { + throw new IllegalStateException("plaintextDataKey was already populated"); + } + notNull(plaintextDataKey, "plaintextDataKey is required"); + notNull(keyringTraceEntry, "keyringTraceEntry is required"); + validatePlaintextDataKey(algorithm, plaintextDataKey); + this.plaintextDataKey = plaintextDataKey; + keyringTrace.add(keyringTraceEntry); + } + + public PublicKey getVerificationKey() { + return verificationKey; + } + + public Map getEncryptionContext() { + return encryptionContext; + } + + public KeyringTrace getKeyringTrace() { + return keyringTrace; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DecryptionMaterials that = (DecryptionMaterials) o; + return algorithm == that.algorithm && + Objects.equals(plaintextDataKey, that.plaintextDataKey) && + Objects.equals(verificationKey, that.verificationKey) && + Objects.equals(encryptionContext, that.encryptionContext) && + Objects.equals(keyringTrace, that.keyringTrace); + } + + @Override + public int hashCode() { + return Objects.hash(algorithm, plaintextDataKey, verificationKey, encryptionContext, keyringTrace); + } + + public static Builder newBuilder(CryptoAlgorithm algorithm) { + return new Builder(algorithm); + } + + public Builder toBuilder() { + return new Builder(this); + } + + private void validatePlaintextDataKey(CryptoAlgorithm algorithm, SecretKey plaintextDataKey) throws IllegalArgumentException { + if(plaintextDataKey != null) { + isTrue(algorithm.getDataKeyLength() == plaintextDataKey.getEncoded().length, + String.format("Incorrect key length. Expected %s but got %s", + algorithm.getDataKeyLength(), plaintextDataKey.getEncoded().length)); + isTrue(algorithm.getDataKeyAlgo().equalsIgnoreCase(plaintextDataKey.getAlgorithm()), + String.format("Incorrect key algorithm. Expected %s but got %s", + algorithm.getDataKeyAlgo(), plaintextDataKey.getAlgorithm())); + } + } + + /** + * Validates that a verification key is specified only if and only if + * the given algorithm suite supports signature verification. + */ + private void validateVerificationKey(CryptoAlgorithm algorithm, PublicKey verificationKey) throws IllegalArgumentException { + if (algorithm.getTrailingSignatureAlgo() == null && verificationKey != null) { + throw new IllegalArgumentException( + String.format("Algorithm %s does not support signature verification", algorithm.name())); + } else if (algorithm.getTrailingSignatureAlgo() != null && verificationKey == null) { + throw new IllegalArgumentException( + String.format("Algorithm %s requires a verification key for signature verification", algorithm.name())); + } + } + + public static final class Builder { + private CryptoAlgorithm algorithm; + private SecretKey plaintextDataKey; + private PublicKey verificationKey; + private Map encryptionContext; + private KeyringTrace keyringTrace = new KeyringTrace(); + + private Builder(CryptoAlgorithm algorithm) { + this.algorithm = algorithm; + } + + private Builder(DecryptionMaterials result) { + this.algorithm = result.getAlgorithm(); + this.plaintextDataKey = result.getPlaintextDataKey(); + this.verificationKey = result.getVerificationKey(); + this.encryptionContext = result.getEncryptionContext(); + this.keyringTrace = result.getKeyringTrace(); + } + + public Builder setAlgorithm(CryptoAlgorithm algorithm) { + this.algorithm = algorithm; + return this; + } + + public Builder setPlaintextDataKey(SecretKey plaintextDataKey) { + this.plaintextDataKey = plaintextDataKey; + return this; + } + + public Builder setVerificationKey(PublicKey verificationKey) { + this.verificationKey = verificationKey; + return this; + } + + public Builder setEncryptionContext(Map encryptionContext) { + this.encryptionContext = Collections.unmodifiableMap(new HashMap<>(encryptionContext)); + return this; + } + + 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/keyrings/EncryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java new file mode 100644 index 000000000..61c9b8cce --- /dev/null +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java @@ -0,0 +1,236 @@ +/* + * 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.model.EncryptionMaterialsRequest; + +import javax.crypto.SecretKey; +import java.security.PrivateKey; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static org.apache.commons.lang3.Validate.isTrue; +import static org.apache.commons.lang3.Validate.notNull; + +/** + * Contains the cryptographic materials needed for an encryption operation. + * + * @see com.amazonaws.encryptionsdk.CryptoMaterialsManager#getMaterialsForEncrypt(EncryptionMaterialsRequest) + */ +public final class EncryptionMaterials { + private final CryptoAlgorithm algorithm; + private final Map encryptionContext; + private final List encryptedDataKeys; + private SecretKey plaintextDataKey; + private final PrivateKey signingKey; + private final KeyringTrace keyringTrace; + + private EncryptionMaterials(Builder b) { + notNull(b.algorithm, "algorithm is required"); + notNull(b.keyringTrace, "keyringTrace is required"); + validatePlaintextDataKey(b.algorithm, b.plaintextDataKey); + validateSigningKey(b.algorithm, b.signingKey); + this.algorithm = b.algorithm; + this.encryptionContext = b.encryptionContext; + this.encryptedDataKeys = b.encryptedDataKeys; + this.plaintextDataKey = b.plaintextDataKey; + this.signingKey = b.signingKey; + this.keyringTrace = b.keyringTrace; + } + + public Builder toBuilder() { + return new Builder(this); + } + + public static Builder newBuilder(CryptoAlgorithm algorithm) { + return new Builder(algorithm); + } + + /** + * The algorithm suite to be used for encryption. + */ + public CryptoAlgorithm getAlgorithm() { + return algorithm; + } + + /** + * The encryption context associated with this encryption. + */ + public Map getEncryptionContext() { + return encryptionContext; + } + + /** + * An unmodifiable list of the encrypted data keys that correspond to the plaintext data key. + */ + public List getEncryptedDataKeys() { + return Collections.unmodifiableList(encryptedDataKeys); + } + + /** + * Add an encrypted data key to the list of encrypted data keys. + * @param encryptedDataKey The encrypted data key to add. + * @param keyringTraceEntry The keyring trace entry recording this action. + */ + public void addEncryptedDataKey(EncryptedDataKey encryptedDataKey, KeyringTraceEntry keyringTraceEntry) { + notNull(encryptedDataKey, "encryptedDataKey is required"); + notNull(keyringTraceEntry, "keyringTraceEntry is required"); + encryptedDataKeys.add(encryptedDataKey); + keyringTrace.add(keyringTraceEntry); + } + + /** + * A data key to be used as input for encryption. + */ + public SecretKey getPlaintextDataKey() { + return plaintextDataKey; + } + + /** + * Sets the plaintext data key. The plaintext data key must not already be populated. + * @param plaintextDataKey The plaintext data key. + * @param keyringTraceEntry The keyring trace entry recording this action. + */ + public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry keyringTraceEntry) { + if(this.plaintextDataKey != null) { + throw new IllegalStateException("plaintextDataKey was already populated"); + } + notNull(plaintextDataKey, "plaintextDataKey is required"); + notNull(keyringTraceEntry, "keyringTraceEntry is required"); + validatePlaintextDataKey(algorithm, plaintextDataKey); + this.plaintextDataKey = plaintextDataKey; + keyringTrace.add(keyringTraceEntry); + } + + /** + * The key to be used as the signing key for signature verification during encryption. + */ + public PrivateKey getSigningKey() { + return signingKey; + } + + /** + * A keyring trace containing all of the actions that keyrings have taken on this set of encryption materials. + */ + public KeyringTrace getKeyringTrace() { + return keyringTrace; + } + + /** + * Validates that the given plaintext data key fits the specification + * for the data key algorithm specified in the given algorithm suite. + */ + private void validatePlaintextDataKey(CryptoAlgorithm algorithm, SecretKey plaintextDataKey) throws IllegalArgumentException { + if(plaintextDataKey != null) { + isTrue(algorithm.getDataKeyLength() == plaintextDataKey.getEncoded().length, + String.format("Incorrect data key length. Expected %s but got %s", + algorithm.getDataKeyLength(), plaintextDataKey.getEncoded().length)); + isTrue(algorithm.getDataKeyAlgo().equalsIgnoreCase(plaintextDataKey.getAlgorithm()), + String.format("Incorrect data key algorithm. Expected %s but got %s", + algorithm.getDataKeyAlgo(), plaintextDataKey.getAlgorithm())); + } + } + + /** + * Validates that a signing key is specified only if and only if + * the given algorithm suite supports signature verification. + */ + private void validateSigningKey(CryptoAlgorithm algorithm, PrivateKey signingKey) throws IllegalArgumentException { + if (algorithm.getTrailingSignatureAlgo() == null && signingKey != null) { + throw new IllegalArgumentException( + String.format("Algorithm %s does not support signature verification", algorithm.name())); + } else if (algorithm.getTrailingSignatureAlgo() != null && signingKey == null) { + throw new IllegalArgumentException( + String.format("Algorithm %s requires a signing key for signature verification", algorithm.name())); + } + } + + @Override public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EncryptionMaterials that = (EncryptionMaterials) o; + return algorithm == that.algorithm && + Objects.equals(encryptionContext, that.encryptionContext) && + Objects.equals(encryptedDataKeys, that.encryptedDataKeys) && + Objects.equals(plaintextDataKey, that.plaintextDataKey) && + Objects.equals(signingKey, that.signingKey) && + Objects.equals(keyringTrace, that.keyringTrace); + } + + @Override public int hashCode() { + return Objects.hash(algorithm, encryptionContext, encryptedDataKeys, plaintextDataKey, signingKey, keyringTrace); + } + + public static class Builder { + private CryptoAlgorithm algorithm; + private Map encryptionContext = Collections.emptyMap(); + private List encryptedDataKeys = new ArrayList<>(); + private SecretKey plaintextDataKey; + private PrivateKey signingKey; + private KeyringTrace keyringTrace = new KeyringTrace(); + + private Builder(CryptoAlgorithm algorithm) { + this.algorithm = algorithm; + } + + private Builder(EncryptionMaterials r) { + algorithm = r.algorithm; + encryptionContext = r.encryptionContext; + encryptedDataKeys = r.encryptedDataKeys; + plaintextDataKey = r.plaintextDataKey; + signingKey = r.signingKey; + keyringTrace = r.keyringTrace; + } + + public EncryptionMaterials build() { + return new EncryptionMaterials(this); + } + + public Builder setAlgorithm(CryptoAlgorithm algorithm) { + this.algorithm = algorithm; + return this; + } + + public Builder setEncryptionContext(Map encryptionContext) { + this.encryptionContext = Collections.unmodifiableMap(new HashMap<>(encryptionContext)); + return this; + } + + public Builder setEncryptedDataKeys(List encryptedDataKeys) { + this.encryptedDataKeys = new ArrayList<>(encryptedDataKeys); + return this; + } + + public Builder setPlaintextDataKey(SecretKey plaintextDataKey) { + this.plaintextDataKey = plaintextDataKey; + return this; + } + + public Builder setSigningKey(PrivateKey signingKey) { + this.signingKey = signingKey; + return this; + } + + public Builder setKeyringTrace(KeyringTrace keyringTrace) { + this.keyringTrace = keyringTrace; + return this; + } + } +} diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java index 36f7c2c81..e79f87b08 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java @@ -14,12 +14,7 @@ package com.amazonaws.encryptionsdk.keyrings; import com.amazonaws.encryptionsdk.EncryptedDataKey; -import com.amazonaws.encryptionsdk.model.DecryptionMaterials; -import com.amazonaws.encryptionsdk.model.EncryptionMaterials; -import javax.crypto.SecretKey; -import java.security.PrivateKey; -import java.security.PublicKey; import java.util.List; /** diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTrace.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTrace.java index 7759d70d7..e21673ce8 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTrace.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTrace.java @@ -17,9 +17,7 @@ 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; /** @@ -38,8 +36,15 @@ public class KeyringTrace { * 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)))); + add(new KeyringTraceEntry(keyNamespace, keyName, flags)); + } + + /** + * Add a new entry to the keyring trace. + * @param entry The entry to add. + */ + public void add(KeyringTraceEntry entry) { + entries.add(entry); } /** diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceEntry.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceEntry.java index 64a14a268..4f656c7be 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceEntry.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceEntry.java @@ -16,7 +16,9 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.Objects; import java.util.Set; @@ -37,17 +39,17 @@ public class 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 + * @param flags One or more KeyringTraceFlags * indicating what actions were taken by a keyring. */ - KeyringTraceEntry(final String keyNamespace, final String keyName, final Set 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 index 1b9b0a59e..0d05bdbb9 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java @@ -50,15 +50,15 @@ boolean validToDecrypt(EncryptedDataKey encryptedDataKey) { } @Override - void traceOnEncrypt(KeyringTrace keyringTrace) { - keyringTrace.add(keyNamespace, keyName, + KeyringTraceEntry traceOnEncrypt() { + return new KeyringTraceEntry(keyNamespace, keyName, KeyringTraceFlag.ENCRYPTED_DATA_KEY, KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT); } @Override - void traceOnDecrypt(KeyringTrace keyringTrace) { - keyringTrace.add(keyNamespace, keyName, + 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 index fd090e104..2e7290bdf 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java @@ -16,9 +16,6 @@ import com.amazonaws.encryptionsdk.EncryptedDataKey; import com.amazonaws.encryptionsdk.internal.JceKeyCipher; import com.amazonaws.encryptionsdk.internal.Utils; -import com.amazonaws.encryptionsdk.model.DecryptionMaterials; -import com.amazonaws.encryptionsdk.model.EncryptionMaterials; -import com.amazonaws.encryptionsdk.model.KeyBlob; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -63,39 +60,31 @@ abstract class RawKeyring implements Keyring { abstract boolean validToDecrypt(EncryptedDataKey encryptedDataKey); /** - * Records trace entries for the given keyring upon successful encryption. + * Gets the trace entry to add the the keyring trace upon successful encryption. * - * @param keyringTrace The keyring trace to record to. + * @return The keyring trace entry. */ - abstract void traceOnEncrypt(KeyringTrace keyringTrace); + abstract KeyringTraceEntry traceOnEncrypt(); /** - * Records trace entries for the given keyring upon successful decryption. + * Gets the trace entry to add to the keyring trace upon successful decryption. * - * @param keyringTrace The keyring trace to record to. + * @return The keyring trace entry. */ - abstract void traceOnDecrypt(KeyringTrace keyringTrace); + abstract KeyringTraceEntry traceOnDecrypt(); @Override public void onEncrypt(EncryptionMaterials encryptionMaterials) { notNull(encryptionMaterials, "encryptionMaterials are required"); - if (encryptionMaterials.getCleartextDataKey() == null) { + if (encryptionMaterials.getPlaintextDataKey() == null) { generateDataKey(encryptionMaterials); } - final SecretKey cleartextDataKey = encryptionMaterials.getCleartextDataKey(); - - if (!cleartextDataKey.getAlgorithm().equalsIgnoreCase(encryptionMaterials.getAlgorithm().getDataKeyAlgo())) { - throw new IllegalArgumentException("Incorrect key algorithm. Expected " + cleartextDataKey.getAlgorithm() - + " but got " + encryptionMaterials.getAlgorithm().getDataKeyAlgo()); - } - final EncryptedDataKey encryptedDataKey = jceKeyCipher.encryptKey( - cleartextDataKey.getEncoded(), keyName, keyNamespace, encryptionMaterials.getEncryptionContext()); - encryptionMaterials.getEncryptedDataKeys().add(new KeyBlob(encryptedDataKey)); - - traceOnEncrypt(encryptionMaterials.getKeyringTrace()); + encryptionMaterials.getPlaintextDataKey().getEncoded(), + keyName, keyNamespace, encryptionMaterials.getEncryptionContext()); + encryptionMaterials.addEncryptedDataKey(encryptedDataKey, traceOnEncrypt()); } @Override @@ -103,7 +92,7 @@ public void onDecrypt(DecryptionMaterials decryptionMaterials, List masterKey; + private final DataKey dataKey; private final PublicKey trailingSignatureKey; - private final Map encryptionContext; - private final KeyringTrace keyringTrace; private DecryptionMaterials(Builder b) { - algorithm = b.getAlgorithm(); - cleartextDataKey = b.getCleartextDataKey(); - masterKey = b.getMasterKey(); + dataKey = b.getDataKey(); trailingSignatureKey = b.getTrailingSignatureKey(); - encryptionContext = b.getEncryptionContext(); - keyringTrace = b.getKeyringTrace(); - } - - /** - * The algorithm to use for this decryption operation. Must match the algorithm in DecryptionMaterialsRequest, if that - * algorithm was non-null. - */ - public CryptoAlgorithm getAlgorithm() { - return algorithm; - } - - public SecretKey getCleartextDataKey() { - return cleartextDataKey; - } - - public void setCleartextDataKey(SecretKey cleartextDataKey) { - if(this.cleartextDataKey != null) { - throw new IllegalStateException("cleartextDataKey was already populated"); - } - - this.cleartextDataKey = cleartextDataKey; } - /** - * Gets the MasterKey (if any) used for decrypting the data key. Will be null - * if a KeyRing was used instead of a MasterKeyProvider. - * @return The MasterKey - */ - public MasterKey getMasterKey() { - return masterKey; + public DataKey getDataKey() { + return dataKey; } public PublicKey getTrailingSignatureKey() { return trailingSignatureKey; } - public Map getEncryptionContext() { - return encryptionContext; - } - - public KeyringTrace getKeyringTrace() { - return keyringTrace; - } - public static Builder newBuilder() { return new Builder(); } @@ -78,47 +30,22 @@ public Builder toBuilder() { } public static final class Builder { - private CryptoAlgorithm algorithm; - private SecretKey cleartextDataKey; - private MasterKey masterKey; + private DataKey dataKey; private PublicKey trailingSignatureKey; - private Map encryptionContext; - private KeyringTrace keyringTrace; private Builder(DecryptionMaterials result) { - this.algorithm = result.getAlgorithm(); - this.cleartextDataKey = result.getCleartextDataKey(); - this.masterKey = result.getMasterKey(); + this.dataKey = result.getDataKey(); this.trailingSignatureKey = result.getTrailingSignatureKey(); - this.keyringTrace = result.getKeyringTrace(); } private Builder() {} - public CryptoAlgorithm getAlgorithm() { - return algorithm; + public DataKey getDataKey() { + return dataKey; } - public Builder setAlgorithm(CryptoAlgorithm algorithm) { - this.algorithm = algorithm; - return this; - } - - public SecretKey getCleartextDataKey() { - return cleartextDataKey; - } - - public Builder setCleartextDataKey(SecretKey cleartextDataKey) { - this.cleartextDataKey = cleartextDataKey; - return this; - } - - public MasterKey getMasterKey() { - return masterKey; - } - - public Builder setMasterKey(MasterKey masterKey) { - this.masterKey = masterKey; + public Builder setDataKey(DataKey dataKey) { + this.dataKey = dataKey; return this; } @@ -131,24 +58,6 @@ public Builder setTrailingSignatureKey(PublicKey trailingSignatureKey) { return this; } - public Map getEncryptionContext() { - return encryptionContext; - } - - public Builder setEncryptionContext(Map encryptionContext) { - this.encryptionContext = Collections.unmodifiableMap(new HashMap<>(encryptionContext)); - 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 8c912adc1..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. @@ -22,10 +21,9 @@ public final class EncryptionMaterials { private final CryptoAlgorithm algorithm; private final Map encryptionContext; private final List encryptedDataKeys; - private SecretKey cleartextDataKey; + 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() { @@ -75,14 +72,6 @@ public SecretKey getCleartextDataKey() { return cleartextDataKey; } - public void setCleartextDataKey(SecretKey cleartextDataKey) { - if(this.cleartextDataKey != null) { - throw new IllegalStateException("cleartextDataKey was already populated"); - } - - this.cleartextDataKey = cleartextDataKey; - } - /** * The private key to be used to sign the message trailer. Must be present if any only if required by the * crypto algorithm, and the key type must likewise match the algorithm in use. @@ -95,10 +84,6 @@ public PrivateKey getTrailingSignatureKey() { return trailingSignatureKey; } - public KeyringTrace getKeyringTrace() { - return keyringTrace; - } - /** * Contains a list of all MasterKeys that could decrypt this message. */ @@ -115,23 +100,21 @@ 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 { private CryptoAlgorithm algorithm; private Map encryptionContext = Collections.emptyMap(); - private List encryptedDataKeys = new ArrayList<>(); + private List encryptedDataKeys = null; private SecretKey cleartextDataKey; private PrivateKey trailingSignatureKey; private List masterKeys = Collections.emptyList(); - private KeyringTrace keyringTrace; private Builder() {} @@ -142,7 +125,6 @@ private Builder(EncryptionMaterials r) { cleartextDataKey = r.cleartextDataKey; trailingSignatureKey = r.trailingSignatureKey; setMasterKeys(r.masterKeys); - keyringTrace = r.keyringTrace; } public EncryptionMaterials build() { @@ -172,7 +154,7 @@ public List getEncryptedDataKeys() { } public Builder setEncryptedDataKeys(List encryptedDataKeys) { - this.encryptedDataKeys = new ArrayList<>(encryptedDataKeys); + this.encryptedDataKeys = Collections.unmodifiableList(new ArrayList<>(encryptedDataKeys)); return this; } @@ -202,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/test/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManagerTest.java b/src/test/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManagerTest.java index d831e3c8b..9f693fe28 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManagerTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/DefaultCryptoMaterialsManagerTest.java @@ -2,6 +2,7 @@ import static com.amazonaws.encryptionsdk.multi.MultipleProviderFactory.buildMultiProvider; import static java.util.Collections.singletonMap; +import static org.hamcrest.Matchers.hasEntry; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -249,7 +250,7 @@ public void decrypt_testSimpleRoundTrip() throws Exception { DecryptionMaterials decryptMaterials = new DefaultCryptoMaterialsManager(mk1).decryptMaterials(decryptReqFromMaterials(encryptMaterials)); - assertArrayEquals(decryptMaterials.getCleartextDataKey().getEncoded(), + assertArrayEquals(decryptMaterials.getDataKey().getKey().getEncoded(), encryptMaterials.getCleartextDataKey().getEncoded()); if (encryptMaterials.getTrailingSignatureKey() == null) { diff --git a/src/test/java/com/amazonaws/encryptionsdk/caching/CacheTestFixtures.java b/src/test/java/com/amazonaws/encryptionsdk/caching/CacheTestFixtures.java index 4d385ca5f..bda4343d3 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/caching/CacheTestFixtures.java +++ b/src/test/java/com/amazonaws/encryptionsdk/caching/CacheTestFixtures.java @@ -1,9 +1,12 @@ package com.amazonaws.encryptionsdk.caching; +import static org.mockito.ArgumentMatchers.eq; + import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.util.Collections; +import com.amazonaws.encryptionsdk.DataKey; import com.amazonaws.encryptionsdk.DefaultCryptoMaterialsManager; import com.amazonaws.encryptionsdk.MasterKey; import com.amazonaws.encryptionsdk.TestUtils; @@ -53,8 +56,10 @@ public static DecryptionMaterials createDecryptResult(DecryptionMaterialsRequest DecryptionMaterials realResult = new DefaultCryptoMaterialsManager(FIXED_KEY).decryptMaterials(request); return realResult .toBuilder() - .setCleartextDataKey(realResult.getCleartextDataKey()) - .setMasterKey(realResult.getMasterKey()) + .setDataKey(new DataKey(new SentinelKey(), + realResult.getDataKey().getEncryptedDataKey(), + realResult.getDataKey().getProviderInformation(), + realResult.getDataKey().getMasterKey())) .build(); } diff --git a/src/test/java/com/amazonaws/encryptionsdk/caching/LocalCryptoMaterialsCacheThreadStormTest.java b/src/test/java/com/amazonaws/encryptionsdk/caching/LocalCryptoMaterialsCacheThreadStormTest.java index e2ac53637..804b148ac 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/caching/LocalCryptoMaterialsCacheThreadStormTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/caching/LocalCryptoMaterialsCacheThreadStormTest.java @@ -1,6 +1,9 @@ package com.amazonaws.encryptionsdk.caching; +import static com.amazonaws.encryptionsdk.caching.CacheTestFixtures.createMaterialsResult; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.lang.reflect.Field; @@ -25,6 +28,7 @@ import org.junit.Test; +import com.amazonaws.encryptionsdk.DataKey; import com.amazonaws.encryptionsdk.caching.CryptoMaterialsCache.UsageStats; import com.amazonaws.encryptionsdk.model.DecryptionMaterials; import com.amazonaws.encryptionsdk.model.EncryptionMaterials; @@ -133,9 +137,9 @@ public void decryptAddThread() { ref[0] = 0; CacheTestFixtures.SentinelKey key = new CacheTestFixtures.SentinelKey(); - DecryptionMaterials result = BASE_DECRYPT.toBuilder() - .setCleartextDataKey(key) - .setMasterKey(BASE_DECRYPT.getMasterKey()).build(); + DecryptionMaterials result = BASE_DECRYPT.toBuilder().setDataKey( + new DataKey(key, new byte[0], new byte[0], BASE_DECRYPT.getDataKey().getMasterKey()) + ).build(); ConcurrentHashMap expectedDecryptMap = possibleDecrypts.computeIfAbsent(ByteBuffer.wrap(ref), @@ -179,7 +183,7 @@ public void decryptCheckThread() { CacheTestFixtures.SentinelKey cachedKey = null; if (result != null) { inc("decrypt: hit"); - cachedKey = (CacheTestFixtures.SentinelKey) result.getResult().getCleartextDataKey(); + cachedKey = (CacheTestFixtures.SentinelKey) result.getResult().getDataKey().getKey(); if (expectedDecryptMap.containsKey(cachedKey)) { inc("decrypt: found key in expected"); } else { 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..3ee3bdff7 --- /dev/null +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterialsTest.java @@ -0,0 +1,139 @@ +/* + * 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 = 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.getDataKeyLength()), ALGORITHM.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).generateKey(); + VERIFICATION_KEY = keyPair.getPublic(); + } + + @Test + void testBuilderNullCryptoAlgorithm() { + assertThrows(NullPointerException.class, () -> DecryptionMaterials.newBuilder(null).build()); + } + + @Test + void testBuilder() { + DecryptionMaterials result = DecryptionMaterials.newBuilder(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(KEYRING_TRACE) + .setPlaintextDataKey(PLAINTEXT_DATA_KEY) + .setVerificationKey(VERIFICATION_KEY) + .build(); + + assertEquals(ALGORITHM, result.getAlgorithm()); + 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.getDataKeyLength() + 1), ALGORITHM.getDataKeyAlgo()); + assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM) + .setPlaintextDataKey(wrongLength) + .setVerificationKey(VERIFICATION_KEY) + .build()); + + SecretKey wrongAlgorithm = new SecretKeySpec(generate(ALGORITHM.getDataKeyLength()), "InvalidAlgorithm"); + assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM) + .setPlaintextDataKey(wrongAlgorithm) + .setVerificationKey(VERIFICATION_KEY) + .build()); + + DecryptionMaterials materials = DecryptionMaterials.newBuilder(ALGORITHM) + .setVerificationKey(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) + .setVerificationKey(null) + .build()); + assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256) + .setVerificationKey(VERIFICATION_KEY) + .build()); + + } + + @Test + void testToBuilder() { + DecryptionMaterials expected = DecryptionMaterials.newBuilder(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(KEYRING_TRACE) + .setPlaintextDataKey(PLAINTEXT_DATA_KEY) + .setVerificationKey(VERIFICATION_KEY) + .build(); + + DecryptionMaterials actual = expected.toBuilder().build(); + + assertEquals(expected, actual); + assertNotSame(expected, actual); + } + + @Test + void testSetPlaintextDataKey() { + DecryptionMaterials materials = DecryptionMaterials.newBuilder(ALGORITHM) + .setVerificationKey(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)); + } + +} 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..cafe1ec2e --- /dev/null +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java @@ -0,0 +1,166 @@ +/* + * 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 = 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.getDataKeyLength()), ALGORITHM.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).generateKey(); + SIGNING_KEY = keyPair.getPrivate(); + } + + @Test + void testBuilderNullCryptoAlgorithm() { + assertThrows(NullPointerException.class, () -> EncryptionMaterials.newBuilder(null).build()); + } + + @Test + void testBuilder() { + EncryptionMaterials result = EncryptionMaterials.newBuilder(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(KEYRING_TRACE) + .setPlaintextDataKey(PLAINTEXT_DATA_KEY) + .setEncryptedDataKeys(Collections.singletonList(ENCRYPTED_DATA_KEY)) + .setSigningKey(SIGNING_KEY) + .build(); + + assertEquals(ALGORITHM, result.getAlgorithm()); + 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.getDataKeyLength() + 1), ALGORITHM.getDataKeyAlgo()); + assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM) + .setPlaintextDataKey(wrongLength) + .setSigningKey(SIGNING_KEY) + .build()); + + SecretKey wrongAlgorithm = new SecretKeySpec(generate(ALGORITHM.getDataKeyLength()), "InvalidAlgorithm"); + assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM) + .setPlaintextDataKey(wrongAlgorithm) + .setSigningKey(SIGNING_KEY) + .build()); + + EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM) + .setSigningKey(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) + .setSigningKey(null) + .build()); + assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256) + .setSigningKey(SIGNING_KEY) + .build()); + + } + + @Test + void testToBuilder() { + EncryptionMaterials expected = EncryptionMaterials.newBuilder(ALGORITHM) + .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(KEYRING_TRACE) + .setPlaintextDataKey(PLAINTEXT_DATA_KEY) + .setEncryptedDataKeys(Collections.singletonList(ENCRYPTED_DATA_KEY)) + .setSigningKey(SIGNING_KEY) + .build(); + + EncryptionMaterials actual = expected.toBuilder().build(); + + assertEquals(expected, actual); + assertNotSame(expected, actual); + } + + @Test + void testAddEncryptedDataKey() { + EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM) + .setSigningKey(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) + .setSigningKey(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)); + } + +} diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java index c67fcbe77..b315e61cc 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java @@ -15,7 +15,6 @@ import org.junit.Test; -import static java.util.Collections.singleton; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -23,12 +22,9 @@ 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)); + 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()); @@ -45,18 +41,14 @@ 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))); + 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)); + 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 index 78311eeb7..f5b3ed297 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java @@ -13,11 +13,11 @@ package com.amazonaws.encryptionsdk.keyrings; -import com.amazonaws.encryptionsdk.model.DecryptionMaterials; -import com.amazonaws.encryptionsdk.model.EncryptionMaterials; +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.Test; +import org.junit.jupiter.api.Test; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; @@ -28,17 +28,17 @@ 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.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +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; -public class RawAesKeyringTest { +class RawAesKeyringTest { private final RawAesKeyring keyring = new RawAesKeyring(KEYNAMESPACE, KEYNAME, new SecretKeySpec(generate(32), "AES")); @Test - public void testValidToDecrypt() { + void testValidToDecrypt() { assertTrue(keyring.validToDecrypt(new KeyBlob( KEYNAMESPACE, KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{}))); assertTrue(keyring.validToDecrypt(new KeyBlob( @@ -52,10 +52,9 @@ public void testValidToDecrypt() { } @Test - public void testEncryptDecryptExistingDataKey() { - EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() - .setAlgorithm(ALGORITHM) - .setCleartextDataKey(DATA_KEY) + void testEncryptDecryptExistingDataKey() { + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) + .setPlaintextDataKey(DATA_KEY) .setKeyringTrace(new KeyringTrace()) .setEncryptionContext(ENCRYPTION_CONTEXT) .build(); @@ -63,6 +62,12 @@ public void testEncryptDecryptExistingDataKey() { 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()); @@ -70,15 +75,14 @@ public void testEncryptDecryptExistingDataKey() { 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() - .setAlgorithm(ALGORITHM) + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); - assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + 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()); @@ -87,18 +91,23 @@ public void testEncryptDecryptExistingDataKey() { } @Test - public void testEncryptDecryptGenerateDataKey() { - EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() - .setAlgorithm(ALGORITHM) + void testEncryptDecryptGenerateDataKey() { + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) .setKeyringTrace(new KeyringTrace()) .setEncryptionContext(ENCRYPTION_CONTEXT) .build(); keyring.onEncrypt(encryptionMaterials); - assertNotNull(encryptionMaterials.getCleartextDataKey()); - assertEquals(encryptionMaterials.getCleartextDataKey().getAlgorithm(), ALGORITHM.getDataKeyAlgo()); + 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)); @@ -106,15 +115,14 @@ public void testEncryptDecryptGenerateDataKey() { 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() - .setAlgorithm(ALGORITHM) + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); - assertEquals(encryptionMaterials.getCleartextDataKey(), decryptionMaterials.getCleartextDataKey()); + 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()); diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java index 63c45bc8e..b43238826 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java @@ -16,15 +16,13 @@ import com.amazonaws.encryptionsdk.CryptoAlgorithm; import com.amazonaws.encryptionsdk.EncryptedDataKey; import com.amazonaws.encryptionsdk.internal.JceKeyCipher; -import com.amazonaws.encryptionsdk.model.DecryptionMaterials; -import com.amazonaws.encryptionsdk.model.EncryptionMaterials; import com.amazonaws.encryptionsdk.model.KeyBlob; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +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.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -34,32 +32,32 @@ import java.util.List; import java.util.Map; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +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.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; -@RunWith(MockitoJUnitRunner.class) -public class RawKeyringTest { +@ExtendWith(MockitoExtension.class) +class RawKeyringTest { static final String KEYNAME = "testKeyname"; static final String KEYNAMESPACE = "testKeynamespace"; - static final CryptoAlgorithm ALGORITHM = CryptoAlgorithm.ALG_AES_192_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384; - static final SecretKey DATA_KEY = new SecretKeySpec(new byte[]{10, 11, 12}, ALGORITHM.getDataKeyAlgo()); + 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}, new byte[]{4, 5, 6}); - private static final EncryptedDataKey INVALID_DATA_KEY = new KeyBlob("invalidProviderId", new byte[]{1, 2, 3}, new byte[]{4, 5, 6}); - private static final KeyringTraceEntry ENCRYPTED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, Collections.singleton(KeyringTraceFlag.ENCRYPTED_DATA_KEY)); - private static final KeyringTraceEntry DECRYPTED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, Collections.singleton(KeyringTraceFlag.DECRYPTED_DATA_KEY)); - private static final KeyringTraceEntry GENERATED_DATA_KEY_TRACE = new KeyringTraceEntry(KEYNAMESPACE, KEYNAME, Collections.singleton(KeyringTraceFlag.GENERATED_DATA_KEY)); - @Mock - private JceKeyCipher jceKeyCipher; + 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; - @Before - public void setup() throws Exception { + @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()); @@ -70,22 +68,21 @@ boolean validToDecrypt(EncryptedDataKey encryptedDataKey) { } @Override - void traceOnEncrypt(KeyringTrace keyringTrace) { - keyringTrace.add(KEYNAMESPACE, KEYNAME, ENCRYPTED_DATA_KEY_TRACE.getFlags().toArray(new KeyringTraceFlag[]{})); + KeyringTraceEntry traceOnEncrypt() { + return ENCRYPTED_DATA_KEY_TRACE; } @Override - void traceOnDecrypt(KeyringTrace keyringTrace) { - keyringTrace.add(KEYNAMESPACE, KEYNAME, DECRYPTED_DATA_KEY_TRACE.getFlags().toArray(new KeyringTraceFlag[]{})); + KeyringTraceEntry traceOnDecrypt() { + return DECRYPTED_DATA_KEY_TRACE; } }; } @Test - public void testEncryptDecryptExistingDataKey() { - EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() - .setAlgorithm(ALGORITHM) - .setCleartextDataKey(DATA_KEY) + void testEncryptDecryptExistingDataKey() { + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) + .setPlaintextDataKey(DATA_KEY) .setKeyringTrace(new KeyringTrace()) .setEncryptionContext(ENCRYPTION_CONTEXT) .build(); @@ -97,22 +94,20 @@ public void testEncryptDecryptExistingDataKey() { assertEquals(1, encryptionMaterials.getKeyringTrace().getEntries().size()); assertEquals(ENCRYPTED_DATA_KEY_TRACE, encryptionMaterials.getKeyringTrace().getEntries().get(0)); - DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() - .setAlgorithm(ALGORITHM) + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, Collections.singletonList(ENCRYPTED_DATA_KEY)); - assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + assertEquals(DATA_KEY, decryptionMaterials.getPlaintextDataKey()); assertEquals(DECRYPTED_DATA_KEY_TRACE, decryptionMaterials.getKeyringTrace().getEntries().get(0)); } @Test - public void testEncryptNullDataKey() { - EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() - .setAlgorithm(ALGORITHM) + void testEncryptNullDataKey() { + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) .setKeyringTrace(new KeyringTrace()) .setEncryptionContext(ENCRYPTION_CONTEXT) .build(); @@ -121,61 +116,60 @@ public void testEncryptNullDataKey() { when(jceKeyCipher.encryptKey(dataKeyCaptor.capture(), eq(KEYNAME), eq(KEYNAMESPACE), eq(ENCRYPTION_CONTEXT))).thenReturn(ENCRYPTED_DATA_KEY); keyring.onEncrypt(encryptionMaterials); - assertEquals(encryptionMaterials.getCleartextDataKey().getAlgorithm(), ALGORITHM.getDataKeyAlgo()); - assertArrayEquals(encryptionMaterials.getCleartextDataKey().getEncoded(), dataKeyCaptor.getValue()); + assertEquals(encryptionMaterials.getPlaintextDataKey().getAlgorithm(), ALGORITHM.getDataKeyAlgo()); + assertArrayEquals(encryptionMaterials.getPlaintextDataKey().getEncoded(), dataKeyCaptor.getValue()); assertEquals(1, encryptionMaterials.getEncryptedDataKeys().size()); - assertNotNull(encryptionMaterials.getCleartextDataKey()); + 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(expected = IllegalArgumentException.class) - public void testEncryptBadDataKeyAlgorithm() { - EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() - .setAlgorithm(ALGORITHM) - .setCleartextDataKey(new SecretKeySpec(DATA_KEY.getEncoded(), "OtherAlgorithm")) - .setKeyringTrace(new KeyringTrace()) + @Test + void testDecryptAlreadyDecryptedDataKey() { + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) + .setPlaintextDataKey(DATA_KEY) .setEncryptionContext(ENCRYPTION_CONTEXT) + .setKeyringTrace(new KeyringTrace()) .build(); - keyring.onEncrypt(encryptionMaterials); + keyring.onDecrypt(decryptionMaterials, Collections.singletonList(ENCRYPTED_DATA_KEY)); + + assertEquals(DATA_KEY, decryptionMaterials.getPlaintextDataKey()); + assertEquals(0, decryptionMaterials.getKeyringTrace().getEntries().size()); } @Test - public void testDecryptAlreadyDecryptedDataKey() { - DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() - .setAlgorithm(ALGORITHM) - .setCleartextDataKey(DATA_KEY) + void testDecryptNoValidDataKey() { + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(new KeyringTrace()) .build(); - keyring.onDecrypt(decryptionMaterials, Collections.singletonList(ENCRYPTED_DATA_KEY)); + keyring.onDecrypt(decryptionMaterials, Collections.singletonList(INVALID_DATA_KEY)); - assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + assertNull(decryptionMaterials.getPlaintextDataKey()); assertEquals(0, decryptionMaterials.getKeyringTrace().getEntries().size()); } @Test - public void testDecryptNoValidDataKey() { - DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() - .setAlgorithm(ALGORITHM) + void testDecryptNoDataKey() { + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(new KeyringTrace()) .build(); - keyring.onDecrypt(decryptionMaterials, Collections.singletonList(INVALID_DATA_KEY)); + keyring.onDecrypt(decryptionMaterials, Collections.emptyList()); - assertNull(decryptionMaterials.getCleartextDataKey()); + assertNull(decryptionMaterials.getPlaintextDataKey()); assertEquals(0, decryptionMaterials.getKeyringTrace().getEntries().size()); } + @Test - public void testDecryptMultipleKeysOneInvalid() { - DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder() - .setAlgorithm(ALGORITHM) + void testDecryptMultipleKeysOneInvalid() { + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(new KeyringTrace()) .build(); @@ -186,16 +180,15 @@ public void testDecryptMultipleKeysOneInvalid() { keyring.onDecrypt(decryptionMaterials, edks); - assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + assertEquals(DATA_KEY, decryptionMaterials.getPlaintextDataKey()); assertEquals(DECRYPTED_DATA_KEY_TRACE, decryptionMaterials.getKeyringTrace().getEntries().get(0)); } @Test - public void testDecryptMultipleKeysOneException() throws GeneralSecurityException { + 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() - .setAlgorithm(ALGORITHM) + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(new KeyringTrace()) .build(); @@ -209,7 +202,7 @@ public void testDecryptMultipleKeysOneException() throws GeneralSecurityExceptio keyring.onDecrypt(decryptionMaterials, edks); - assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + assertEquals(DATA_KEY, decryptionMaterials.getPlaintextDataKey()); assertEquals(DECRYPTED_DATA_KEY_TRACE, decryptionMaterials.getKeyringTrace().getEntries().get(0)); } diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java index ed314a7ca..fee585a56 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java @@ -13,12 +13,11 @@ package com.amazonaws.encryptionsdk.keyrings; -import com.amazonaws.encryptionsdk.model.DecryptionMaterials; -import com.amazonaws.encryptionsdk.model.EncryptionMaterials; +import com.amazonaws.encryptionsdk.EncryptedDataKey; import com.amazonaws.encryptionsdk.model.KeyBlob; import org.apache.commons.lang3.ArrayUtils; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import java.nio.charset.StandardCharsets; import java.security.KeyPair; @@ -29,18 +28,19 @@ 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.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +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; -public class RawRsaKeyringTest { +class RawRsaKeyringTest { private static final String TRANSFORMATION = "RSA/ECB/PKCS1Padding"; - private RawRsaKeyring keyring; + private static RawRsaKeyring keyring; - @Before - public void setup() throws Exception { + @BeforeAll + static void setup() throws Exception { final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); final KeyPair keyPair = keyPairGenerator.generateKeyPair(); @@ -48,7 +48,7 @@ public void setup() throws Exception { } @Test - public void testValidToDecrypt() { + void testValidToDecrypt() { assertTrue(keyring.validToDecrypt(new KeyBlob( KEYNAMESPACE, KEYNAME.getBytes(StandardCharsets.UTF_8), new byte[]{}))); //Provider info has extra data @@ -60,10 +60,9 @@ public void testValidToDecrypt() { } @Test - public void testEncryptDecryptExistingDataKey() { - EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() - .setAlgorithm(ALGORITHM) - .setCleartextDataKey(DATA_KEY) + void testEncryptDecryptExistingDataKey() { + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) + .setPlaintextDataKey(DATA_KEY) .setKeyringTrace(new KeyringTrace()) .setEncryptionContext(ENCRYPTION_CONTEXT) .build(); @@ -71,21 +70,25 @@ public void testEncryptDecryptExistingDataKey() { 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() - .setAlgorithm(ALGORITHM) + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); - assertEquals(DATA_KEY, decryptionMaterials.getCleartextDataKey()); + 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()); @@ -93,33 +96,36 @@ public void testEncryptDecryptExistingDataKey() { } @Test - public void testEncryptDecryptGenerateDataKey() { - EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder() - .setAlgorithm(ALGORITHM) + void testEncryptDecryptGenerateDataKey() { + EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) .setKeyringTrace(new KeyringTrace()) .setEncryptionContext(ENCRYPTION_CONTEXT) .build(); keyring.onEncrypt(encryptionMaterials); - assertNotNull(encryptionMaterials.getCleartextDataKey()); - assertEquals(encryptionMaterials.getCleartextDataKey().getAlgorithm(), ALGORITHM.getDataKeyAlgo()); + 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() - .setAlgorithm(ALGORITHM) + DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); - assertEquals(encryptionMaterials.getCleartextDataKey(), decryptionMaterials.getCleartextDataKey()); + 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()); From 8310ae2c7b273a10a08f6386e58b5684f2a6d2c4 Mon Sep 17 00:00:00 2001 From: Wesley Rosenblum Date: Thu, 14 Nov 2019 15:20:55 -0800 Subject: [PATCH 5/9] Minor formatting fixes --- .../keyrings/DecryptionMaterials.java | 7 ++++--- .../keyrings/EncryptionMaterials.java | 16 ++++++++++------ .../encryptionsdk/keyrings/KeyringTrace.java | 1 + .../encryptionsdk/keyrings/RawAesKeyring.java | 2 +- .../encryptionsdk/keyrings/RawRsaKeyring.java | 2 +- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java index 3d6821a5c..4265bd73c 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java @@ -62,11 +62,12 @@ public SecretKey getPlaintextDataKey() { /** * Sets the plaintext data key. The plaintext data key must not already be populated. - * @param plaintextDataKey The plaintext data key. + * + * @param plaintextDataKey The plaintext data key. * @param keyringTraceEntry The keyring trace entry recording this action. */ public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry keyringTraceEntry) { - if(this.plaintextDataKey != null) { + if (this.plaintextDataKey != null) { throw new IllegalStateException("plaintextDataKey was already populated"); } notNull(plaintextDataKey, "plaintextDataKey is required"); @@ -114,7 +115,7 @@ public Builder toBuilder() { } private void validatePlaintextDataKey(CryptoAlgorithm algorithm, SecretKey plaintextDataKey) throws IllegalArgumentException { - if(plaintextDataKey != null) { + if (plaintextDataKey != null) { isTrue(algorithm.getDataKeyLength() == plaintextDataKey.getEncoded().length, String.format("Incorrect key length. Expected %s but got %s", algorithm.getDataKeyLength(), plaintextDataKey.getEncoded().length)); diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java index 61c9b8cce..a8ba80566 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java @@ -86,7 +86,8 @@ public List getEncryptedDataKeys() { /** * Add an encrypted data key to the list of encrypted data keys. - * @param encryptedDataKey The encrypted data key to add. + * + * @param encryptedDataKey The encrypted data key to add. * @param keyringTraceEntry The keyring trace entry recording this action. */ public void addEncryptedDataKey(EncryptedDataKey encryptedDataKey, KeyringTraceEntry keyringTraceEntry) { @@ -105,11 +106,12 @@ public SecretKey getPlaintextDataKey() { /** * Sets the plaintext data key. The plaintext data key must not already be populated. - * @param plaintextDataKey The plaintext data key. + * + * @param plaintextDataKey The plaintext data key. * @param keyringTraceEntry The keyring trace entry recording this action. */ public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry keyringTraceEntry) { - if(this.plaintextDataKey != null) { + if (this.plaintextDataKey != null) { throw new IllegalStateException("plaintextDataKey was already populated"); } notNull(plaintextDataKey, "plaintextDataKey is required"); @@ -138,7 +140,7 @@ public KeyringTrace getKeyringTrace() { * for the data key algorithm specified in the given algorithm suite. */ private void validatePlaintextDataKey(CryptoAlgorithm algorithm, SecretKey plaintextDataKey) throws IllegalArgumentException { - if(plaintextDataKey != null) { + if (plaintextDataKey != null) { isTrue(algorithm.getDataKeyLength() == plaintextDataKey.getEncoded().length, String.format("Incorrect data key length. Expected %s but got %s", algorithm.getDataKeyLength(), plaintextDataKey.getEncoded().length)); @@ -162,7 +164,8 @@ private void validateSigningKey(CryptoAlgorithm algorithm, PrivateKey signingKey } } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; EncryptionMaterials that = (EncryptionMaterials) o; @@ -174,7 +177,8 @@ private void validateSigningKey(CryptoAlgorithm algorithm, PrivateKey signingKey Objects.equals(keyringTrace, that.keyringTrace); } - @Override public int hashCode() { + @Override + public int hashCode() { return Objects.hash(algorithm, encryptionContext, encryptedDataKeys, plaintextDataKey, signingKey, keyringTrace); } diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTrace.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTrace.java index e21673ce8..c9528c08f 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTrace.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/KeyringTrace.java @@ -41,6 +41,7 @@ public void add(String keyNamespace, String keyName, KeyringTraceFlag... flags) /** * Add a new entry to the keyring trace. + * * @param entry The entry to add. */ public void add(KeyringTraceEntry entry) { diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java index 0d05bdbb9..5832658a9 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyring.java @@ -22,7 +22,7 @@ /** * 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 { diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java index 10f96b29d..486cd26e6 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyring.java @@ -23,7 +23,7 @@ /** * 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 { From 61d992c08fbf16dcdea5238880b4b9b44632ddec Mon Sep 17 00:00:00 2001 From: Wesley Rosenblum Date: Thu, 14 Nov 2019 15:28:46 -0800 Subject: [PATCH 6/9] Fixing comments and migrating KeyringTraceTest to JUnit5 --- .../keyrings/DecryptionMaterials.java | 5 ++--- .../keyrings/EncryptionMaterials.java | 5 +---- .../keyrings/KeyringTraceTest.java | 20 ++++++++++--------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java index 4265bd73c..bb8ac55c7 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java @@ -26,7 +26,7 @@ import static org.apache.commons.lang3.Validate.notNull; /** - * Contains the cryptographic materials needed for a decryption operation. + * Contains the cryptographic materials needed for a decryption operation with Keyrings. */ public final class DecryptionMaterials { private final CryptoAlgorithm algorithm; @@ -49,8 +49,7 @@ private DecryptionMaterials(Builder b) { } /** - * The algorithm to use for this decryption operation. Must match the algorithm in DecryptionMaterialsRequest, if that - * algorithm was non-null. + * The algorithm to use for this decryption operation. */ public CryptoAlgorithm getAlgorithm() { return algorithm; diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java index a8ba80566..6d2acd1f2 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java @@ -15,7 +15,6 @@ import com.amazonaws.encryptionsdk.CryptoAlgorithm; import com.amazonaws.encryptionsdk.EncryptedDataKey; -import com.amazonaws.encryptionsdk.model.EncryptionMaterialsRequest; import javax.crypto.SecretKey; import java.security.PrivateKey; @@ -30,9 +29,7 @@ import static org.apache.commons.lang3.Validate.notNull; /** - * Contains the cryptographic materials needed for an encryption operation. - * - * @see com.amazonaws.encryptionsdk.CryptoMaterialsManager#getMaterialsForEncrypt(EncryptionMaterialsRequest) + * Contains the cryptographic materials needed for an encryption operation with Keyrings. */ public final class EncryptionMaterials { private final CryptoAlgorithm algorithm; diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java index b315e61cc..5b6105070 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/KeyringTraceTest.java @@ -13,15 +13,16 @@ package com.amazonaws.encryptionsdk.keyrings; -import org.junit.Test; +import org.junit.jupiter.api.Test; -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() { + 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); @@ -36,16 +37,17 @@ 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", KeyringTraceFlag.GENERATED_DATA_KEY)); + assertThrows(UnsupportedOperationException.class, () -> + trace.getEntries().add(new KeyringTraceEntry("ns1", "name1", KeyringTraceFlag.GENERATED_DATA_KEY))); } @Test - public void testKeyringTraceEntryEquals() { + 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); From f3a9aa6874f24c90042f512346daccc2647acf5c Mon Sep 17 00:00:00 2001 From: Wesley Rosenblum Date: Mon, 18 Nov 2019 12:35:42 -0800 Subject: [PATCH 7/9] Renaming algorithm to algorithmSuite --- .../keyrings/DecryptionMaterials.java | 54 +++++++++--------- .../keyrings/EncryptionMaterials.java | 56 +++++++++---------- .../encryptionsdk/keyrings/RawKeyring.java | 6 +- .../keyrings/DecryptionMaterialsTest.java | 26 ++++----- .../keyrings/EncryptionMaterialsTest.java | 28 +++++----- 5 files changed, 85 insertions(+), 85 deletions(-) diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java index bb8ac55c7..bfc9bed3e 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java @@ -29,19 +29,19 @@ * Contains the cryptographic materials needed for a decryption operation with Keyrings. */ public final class DecryptionMaterials { - private final CryptoAlgorithm algorithm; + private final CryptoAlgorithm algorithmSuite; private SecretKey plaintextDataKey; private final PublicKey verificationKey; private final Map encryptionContext; private final KeyringTrace keyringTrace; private DecryptionMaterials(Builder b) { - notNull(b.algorithm, "algorithm is required"); + notNull(b.algorithmSuite, "algorithmSuite is required"); notNull(b.keyringTrace, "keyringTrace is required"); - validatePlaintextDataKey(b.algorithm, b.plaintextDataKey); - validateVerificationKey(b.algorithm, b.verificationKey); + validatePlaintextDataKey(b.algorithmSuite, b.plaintextDataKey); + validateVerificationKey(b.algorithmSuite, b.verificationKey); - algorithm = b.algorithm; + algorithmSuite = b.algorithmSuite; plaintextDataKey = b.plaintextDataKey; verificationKey = b.verificationKey; encryptionContext = b.encryptionContext; @@ -49,10 +49,10 @@ private DecryptionMaterials(Builder b) { } /** - * The algorithm to use for this decryption operation. + * The algorithm suite to use for this decryption operation. */ - public CryptoAlgorithm getAlgorithm() { - return algorithm; + public CryptoAlgorithm getAlgorithmSuite() { + return algorithmSuite; } public SecretKey getPlaintextDataKey() { @@ -71,7 +71,7 @@ public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry ke } notNull(plaintextDataKey, "plaintextDataKey is required"); notNull(keyringTraceEntry, "keyringTraceEntry is required"); - validatePlaintextDataKey(algorithm, plaintextDataKey); + validatePlaintextDataKey(algorithmSuite, plaintextDataKey); this.plaintextDataKey = plaintextDataKey; keyringTrace.add(keyringTraceEntry); } @@ -93,7 +93,7 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DecryptionMaterials that = (DecryptionMaterials) o; - return algorithm == that.algorithm && + return algorithmSuite == that.algorithmSuite && Objects.equals(plaintextDataKey, that.plaintextDataKey) && Objects.equals(verificationKey, that.verificationKey) && Objects.equals(encryptionContext, that.encryptionContext) && @@ -102,7 +102,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(algorithm, plaintextDataKey, verificationKey, encryptionContext, keyringTrace); + return Objects.hash(algorithmSuite, plaintextDataKey, verificationKey, encryptionContext, keyringTrace); } public static Builder newBuilder(CryptoAlgorithm algorithm) { @@ -113,14 +113,14 @@ public Builder toBuilder() { return new Builder(this); } - private void validatePlaintextDataKey(CryptoAlgorithm algorithm, SecretKey plaintextDataKey) throws IllegalArgumentException { + private void validatePlaintextDataKey(CryptoAlgorithm algorithmSuite, SecretKey plaintextDataKey) throws IllegalArgumentException { if (plaintextDataKey != null) { - isTrue(algorithm.getDataKeyLength() == plaintextDataKey.getEncoded().length, + isTrue(algorithmSuite.getDataKeyLength() == plaintextDataKey.getEncoded().length, String.format("Incorrect key length. Expected %s but got %s", - algorithm.getDataKeyLength(), plaintextDataKey.getEncoded().length)); - isTrue(algorithm.getDataKeyAlgo().equalsIgnoreCase(plaintextDataKey.getAlgorithm()), + algorithmSuite.getDataKeyLength(), plaintextDataKey.getEncoded().length)); + isTrue(algorithmSuite.getDataKeyAlgo().equalsIgnoreCase(plaintextDataKey.getAlgorithm()), String.format("Incorrect key algorithm. Expected %s but got %s", - algorithm.getDataKeyAlgo(), plaintextDataKey.getAlgorithm())); + algorithmSuite.getDataKeyAlgo(), plaintextDataKey.getAlgorithm())); } } @@ -128,37 +128,37 @@ private void validatePlaintextDataKey(CryptoAlgorithm algorithm, SecretKey plain * Validates that a verification key is specified only if and only if * the given algorithm suite supports signature verification. */ - private void validateVerificationKey(CryptoAlgorithm algorithm, PublicKey verificationKey) throws IllegalArgumentException { - if (algorithm.getTrailingSignatureAlgo() == null && verificationKey != null) { + private void validateVerificationKey(CryptoAlgorithm algorithmSuite, PublicKey verificationKey) throws IllegalArgumentException { + if (algorithmSuite.getTrailingSignatureAlgo() == null && verificationKey != null) { throw new IllegalArgumentException( - String.format("Algorithm %s does not support signature verification", algorithm.name())); - } else if (algorithm.getTrailingSignatureAlgo() != null && verificationKey == null) { + String.format("Algorithm Suite %s does not support signature verification", algorithmSuite.name())); + } else if (algorithmSuite.getTrailingSignatureAlgo() != null && verificationKey == null) { throw new IllegalArgumentException( - String.format("Algorithm %s requires a verification key for signature verification", algorithm.name())); + String.format("Algorithm %s requires a verification key for signature verification", algorithmSuite.name())); } } public static final class Builder { - private CryptoAlgorithm algorithm; + private CryptoAlgorithm algorithmSuite; private SecretKey plaintextDataKey; private PublicKey verificationKey; private Map encryptionContext; private KeyringTrace keyringTrace = new KeyringTrace(); - private Builder(CryptoAlgorithm algorithm) { - this.algorithm = algorithm; + private Builder(CryptoAlgorithm algorithmSuite) { + this.algorithmSuite = algorithmSuite; } private Builder(DecryptionMaterials result) { - this.algorithm = result.getAlgorithm(); + this.algorithmSuite = result.getAlgorithmSuite(); this.plaintextDataKey = result.getPlaintextDataKey(); this.verificationKey = result.getVerificationKey(); this.encryptionContext = result.getEncryptionContext(); this.keyringTrace = result.getKeyringTrace(); } - public Builder setAlgorithm(CryptoAlgorithm algorithm) { - this.algorithm = algorithm; + public Builder setAlgorithmSuite(CryptoAlgorithm algorithmSuite) { + this.algorithmSuite = algorithmSuite; return this; } diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java index 6d2acd1f2..da0781726 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java @@ -32,7 +32,7 @@ * Contains the cryptographic materials needed for an encryption operation with Keyrings. */ public final class EncryptionMaterials { - private final CryptoAlgorithm algorithm; + private final CryptoAlgorithm algorithmSuite; private final Map encryptionContext; private final List encryptedDataKeys; private SecretKey plaintextDataKey; @@ -40,11 +40,11 @@ public final class EncryptionMaterials { private final KeyringTrace keyringTrace; private EncryptionMaterials(Builder b) { - notNull(b.algorithm, "algorithm is required"); + notNull(b.algorithmSuite, "algorithmSuite is required"); notNull(b.keyringTrace, "keyringTrace is required"); - validatePlaintextDataKey(b.algorithm, b.plaintextDataKey); - validateSigningKey(b.algorithm, b.signingKey); - this.algorithm = b.algorithm; + validatePlaintextDataKey(b.algorithmSuite, b.plaintextDataKey); + validateSigningKey(b.algorithmSuite, b.signingKey); + this.algorithmSuite = b.algorithmSuite; this.encryptionContext = b.encryptionContext; this.encryptedDataKeys = b.encryptedDataKeys; this.plaintextDataKey = b.plaintextDataKey; @@ -56,15 +56,15 @@ public Builder toBuilder() { return new Builder(this); } - public static Builder newBuilder(CryptoAlgorithm algorithm) { - return new Builder(algorithm); + public static Builder newBuilder(CryptoAlgorithm algorithmSuite) { + return new Builder(algorithmSuite); } /** * The algorithm suite to be used for encryption. */ - public CryptoAlgorithm getAlgorithm() { - return algorithm; + public CryptoAlgorithm getAlgorithmSuite() { + return algorithmSuite; } /** @@ -113,7 +113,7 @@ public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry ke } notNull(plaintextDataKey, "plaintextDataKey is required"); notNull(keyringTraceEntry, "keyringTraceEntry is required"); - validatePlaintextDataKey(algorithm, plaintextDataKey); + validatePlaintextDataKey(algorithmSuite, plaintextDataKey); this.plaintextDataKey = plaintextDataKey; keyringTrace.add(keyringTraceEntry); } @@ -136,14 +136,14 @@ public KeyringTrace getKeyringTrace() { * Validates that the given plaintext data key fits the specification * for the data key algorithm specified in the given algorithm suite. */ - private void validatePlaintextDataKey(CryptoAlgorithm algorithm, SecretKey plaintextDataKey) throws IllegalArgumentException { + private void validatePlaintextDataKey(CryptoAlgorithm algorithmSuite, SecretKey plaintextDataKey) throws IllegalArgumentException { if (plaintextDataKey != null) { - isTrue(algorithm.getDataKeyLength() == plaintextDataKey.getEncoded().length, + isTrue(algorithmSuite.getDataKeyLength() == plaintextDataKey.getEncoded().length, String.format("Incorrect data key length. Expected %s but got %s", - algorithm.getDataKeyLength(), plaintextDataKey.getEncoded().length)); - isTrue(algorithm.getDataKeyAlgo().equalsIgnoreCase(plaintextDataKey.getAlgorithm()), + algorithmSuite.getDataKeyLength(), plaintextDataKey.getEncoded().length)); + isTrue(algorithmSuite.getDataKeyAlgo().equalsIgnoreCase(plaintextDataKey.getAlgorithm()), String.format("Incorrect data key algorithm. Expected %s but got %s", - algorithm.getDataKeyAlgo(), plaintextDataKey.getAlgorithm())); + algorithmSuite.getDataKeyAlgo(), plaintextDataKey.getAlgorithm())); } } @@ -151,13 +151,13 @@ private void validatePlaintextDataKey(CryptoAlgorithm algorithm, SecretKey plain * Validates that a signing key is specified only if and only if * the given algorithm suite supports signature verification. */ - private void validateSigningKey(CryptoAlgorithm algorithm, PrivateKey signingKey) throws IllegalArgumentException { - if (algorithm.getTrailingSignatureAlgo() == null && signingKey != null) { + private void validateSigningKey(CryptoAlgorithm algorithmSuite, PrivateKey signingKey) throws IllegalArgumentException { + if (algorithmSuite.getTrailingSignatureAlgo() == null && signingKey != null) { throw new IllegalArgumentException( - String.format("Algorithm %s does not support signature verification", algorithm.name())); - } else if (algorithm.getTrailingSignatureAlgo() != null && signingKey == null) { + String.format("Algorithm Suite %s does not support signature verification", algorithmSuite.name())); + } else if (algorithmSuite.getTrailingSignatureAlgo() != null && signingKey == null) { throw new IllegalArgumentException( - String.format("Algorithm %s requires a signing key for signature verification", algorithm.name())); + String.format("Algorithm Suite %s requires a signing key for signature verification", algorithmSuite.name())); } } @@ -166,7 +166,7 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; EncryptionMaterials that = (EncryptionMaterials) o; - return algorithm == that.algorithm && + return algorithmSuite == that.algorithmSuite && Objects.equals(encryptionContext, that.encryptionContext) && Objects.equals(encryptedDataKeys, that.encryptedDataKeys) && Objects.equals(plaintextDataKey, that.plaintextDataKey) && @@ -176,23 +176,23 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(algorithm, encryptionContext, encryptedDataKeys, plaintextDataKey, signingKey, keyringTrace); + return Objects.hash(algorithmSuite, encryptionContext, encryptedDataKeys, plaintextDataKey, signingKey, keyringTrace); } public static class Builder { - private CryptoAlgorithm algorithm; + private CryptoAlgorithm algorithmSuite; private Map encryptionContext = Collections.emptyMap(); private List encryptedDataKeys = new ArrayList<>(); private SecretKey plaintextDataKey; private PrivateKey signingKey; private KeyringTrace keyringTrace = new KeyringTrace(); - private Builder(CryptoAlgorithm algorithm) { - this.algorithm = algorithm; + private Builder(CryptoAlgorithm algorithmSuite) { + this.algorithmSuite = algorithmSuite; } private Builder(EncryptionMaterials r) { - algorithm = r.algorithm; + algorithmSuite = r.algorithmSuite; encryptionContext = r.encryptionContext; encryptedDataKeys = r.encryptedDataKeys; plaintextDataKey = r.plaintextDataKey; @@ -204,8 +204,8 @@ public EncryptionMaterials build() { return new EncryptionMaterials(this); } - public Builder setAlgorithm(CryptoAlgorithm algorithm) { - this.algorithm = algorithm; + public Builder setAlgorithmSuite(CryptoAlgorithm algorithmSuite) { + this.algorithmSuite = algorithmSuite; return this; } diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java index 2e7290bdf..4b10199e4 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java @@ -102,7 +102,7 @@ public void onDecrypt(DecryptionMaterials decryptionMaterials, List 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.getDataKeyLength()), ALGORITHM.getDataKeyAlgo()); + private static final SecretKey PLAINTEXT_DATA_KEY = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength()), ALGORITHM_SUITE.getDataKeyAlgo()); private static PublicKey VERIFICATION_KEY; @BeforeAll @@ -45,7 +45,7 @@ static void setup() throws Exception { final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); - final KeyPair keyPair = TrailingSignatureAlgorithm.forCryptoAlgorithm(ALGORITHM).generateKey(); + final KeyPair keyPair = TrailingSignatureAlgorithm.forCryptoAlgorithm(ALGORITHM_SUITE).generateKey(); VERIFICATION_KEY = keyPair.getPublic(); } @@ -56,14 +56,14 @@ void testBuilderNullCryptoAlgorithm() { @Test void testBuilder() { - DecryptionMaterials result = DecryptionMaterials.newBuilder(ALGORITHM) + DecryptionMaterials result = DecryptionMaterials.newBuilder(ALGORITHM_SUITE) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(KEYRING_TRACE) .setPlaintextDataKey(PLAINTEXT_DATA_KEY) .setVerificationKey(VERIFICATION_KEY) .build(); - assertEquals(ALGORITHM, result.getAlgorithm()); + assertEquals(ALGORITHM_SUITE, result.getAlgorithmSuite()); assertEquals(ENCRYPTION_CONTEXT, result.getEncryptionContext()); assertEquals(KEYRING_TRACE, result.getKeyringTrace()); assertEquals(PLAINTEXT_DATA_KEY, result.getPlaintextDataKey()); @@ -72,19 +72,19 @@ void testBuilder() { @Test void testInvalidPlaintextDataKey() { - SecretKey wrongLength = new SecretKeySpec(generate(ALGORITHM.getDataKeyLength() + 1), ALGORITHM.getDataKeyAlgo()); - assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM) + SecretKey wrongLength = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength() + 1), ALGORITHM_SUITE.getDataKeyAlgo()); + assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM_SUITE) .setPlaintextDataKey(wrongLength) .setVerificationKey(VERIFICATION_KEY) .build()); - SecretKey wrongAlgorithm = new SecretKeySpec(generate(ALGORITHM.getDataKeyLength()), "InvalidAlgorithm"); - assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM) + SecretKey wrongAlgorithm = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength()), "InvalidAlgorithm"); + assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM_SUITE) .setPlaintextDataKey(wrongAlgorithm) .setVerificationKey(VERIFICATION_KEY) .build()); - DecryptionMaterials materials = DecryptionMaterials.newBuilder(ALGORITHM) + DecryptionMaterials materials = DecryptionMaterials.newBuilder(ALGORITHM_SUITE) .setVerificationKey(VERIFICATION_KEY) .build(); assertThrows(IllegalArgumentException.class, () -> materials @@ -95,7 +95,7 @@ void testInvalidPlaintextDataKey() { @Test void testInvalidVerificationKey() { - assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM) + assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM_SUITE) .setVerificationKey(null) .build()); assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256) @@ -106,7 +106,7 @@ void testInvalidVerificationKey() { @Test void testToBuilder() { - DecryptionMaterials expected = DecryptionMaterials.newBuilder(ALGORITHM) + DecryptionMaterials expected = DecryptionMaterials.newBuilder(ALGORITHM_SUITE) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(KEYRING_TRACE) .setPlaintextDataKey(PLAINTEXT_DATA_KEY) @@ -121,7 +121,7 @@ void testToBuilder() { @Test void testSetPlaintextDataKey() { - DecryptionMaterials materials = DecryptionMaterials.newBuilder(ALGORITHM) + DecryptionMaterials materials = DecryptionMaterials.newBuilder(ALGORITHM_SUITE) .setVerificationKey(VERIFICATION_KEY) .build(); diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java index cafe1ec2e..7f3d4dc89 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java @@ -38,11 +38,11 @@ @ExtendWith(MockitoExtension.class) class EncryptionMaterialsTest { - private static final CryptoAlgorithm ALGORITHM = CryptoAlgorithm.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384; + 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.getDataKeyLength()), ALGORITHM.getDataKeyAlgo()); + 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; @@ -52,7 +52,7 @@ static void setup() throws Exception { final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); - final KeyPair keyPair = TrailingSignatureAlgorithm.forCryptoAlgorithm(ALGORITHM).generateKey(); + final KeyPair keyPair = TrailingSignatureAlgorithm.forCryptoAlgorithm(ALGORITHM_SUITE).generateKey(); SIGNING_KEY = keyPair.getPrivate(); } @@ -63,7 +63,7 @@ void testBuilderNullCryptoAlgorithm() { @Test void testBuilder() { - EncryptionMaterials result = EncryptionMaterials.newBuilder(ALGORITHM) + EncryptionMaterials result = EncryptionMaterials.newBuilder(ALGORITHM_SUITE) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(KEYRING_TRACE) .setPlaintextDataKey(PLAINTEXT_DATA_KEY) @@ -71,7 +71,7 @@ void testBuilder() { .setSigningKey(SIGNING_KEY) .build(); - assertEquals(ALGORITHM, result.getAlgorithm()); + assertEquals(ALGORITHM_SUITE, result.getAlgorithmSuite()); assertEquals(ENCRYPTION_CONTEXT, result.getEncryptionContext()); assertEquals(KEYRING_TRACE, result.getKeyringTrace()); assertEquals(PLAINTEXT_DATA_KEY, result.getPlaintextDataKey()); @@ -82,19 +82,19 @@ void testBuilder() { @Test void testInvalidPlaintextDataKey() { - SecretKey wrongLength = new SecretKeySpec(generate(ALGORITHM.getDataKeyLength() + 1), ALGORITHM.getDataKeyAlgo()); - assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM) + SecretKey wrongLength = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength() + 1), ALGORITHM_SUITE.getDataKeyAlgo()); + assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM_SUITE) .setPlaintextDataKey(wrongLength) .setSigningKey(SIGNING_KEY) .build()); - SecretKey wrongAlgorithm = new SecretKeySpec(generate(ALGORITHM.getDataKeyLength()), "InvalidAlgorithm"); - assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM) + SecretKey wrongAlgorithm = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength()), "InvalidAlgorithm"); + assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM_SUITE) .setPlaintextDataKey(wrongAlgorithm) .setSigningKey(SIGNING_KEY) .build()); - EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM) + EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM_SUITE) .setSigningKey(SIGNING_KEY) .build(); assertThrows(IllegalArgumentException.class, () -> materials @@ -105,7 +105,7 @@ void testInvalidPlaintextDataKey() { @Test void testInvalidSigningKey() { - assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM) + assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM_SUITE) .setSigningKey(null) .build()); assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256) @@ -116,7 +116,7 @@ void testInvalidSigningKey() { @Test void testToBuilder() { - EncryptionMaterials expected = EncryptionMaterials.newBuilder(ALGORITHM) + EncryptionMaterials expected = EncryptionMaterials.newBuilder(ALGORITHM_SUITE) .setEncryptionContext(ENCRYPTION_CONTEXT) .setKeyringTrace(KEYRING_TRACE) .setPlaintextDataKey(PLAINTEXT_DATA_KEY) @@ -132,7 +132,7 @@ void testToBuilder() { @Test void testAddEncryptedDataKey() { - EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM) + EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM_SUITE) .setSigningKey(SIGNING_KEY) .build(); @@ -148,7 +148,7 @@ void testAddEncryptedDataKey() { @Test void testSetPlaintextDataKey() { - EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM) + EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM_SUITE) .setSigningKey(SIGNING_KEY) .build(); From ebb61662a7c7f0c2787405dd62c373566ca32145 Mon Sep 17 00:00:00 2001 From: Wesley Rosenblum Date: Mon, 18 Nov 2019 14:04:09 -0800 Subject: [PATCH 8/9] Making optional materials properties throw exceptions if not populated. --- .../keyrings/DecryptionMaterials.java | 58 +++++++++++++++---- .../keyrings/EncryptionMaterials.java | 43 ++++++++++++-- .../encryptionsdk/keyrings/RawKeyring.java | 4 +- .../keyrings/DecryptionMaterialsTest.java | 9 +++ .../keyrings/EncryptionMaterialsTest.java | 9 +++ .../keyrings/RawKeyringTest.java | 6 +- 6 files changed, 109 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java index bfc9bed3e..f31df5df4 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java @@ -38,6 +38,7 @@ public final class DecryptionMaterials { private DecryptionMaterials(Builder b) { notNull(b.algorithmSuite, "algorithmSuite is required"); notNull(b.keyringTrace, "keyringTrace is required"); + notNull(b.encryptionContext, "encryptionContext is required"); validatePlaintextDataKey(b.algorithmSuite, b.plaintextDataKey); validateVerificationKey(b.algorithmSuite, b.verificationKey); @@ -55,7 +56,25 @@ public CryptoAlgorithm getAlgorithmSuite() { return algorithmSuite; } - public SecretKey getPlaintextDataKey() { + /** + * Returns true if a plaintext data key has been populated. + * + * @return True if plaintext data key is populated, false otherwise. + */ + public boolean hasPlaintextDataKey() { + return this.plaintextDataKey != null; + } + + /** + * A data key to be used as input for encryption. + * + * @return The plaintext data key. + * @throws IllegalStateException if plaintext data key has not been populated. + */ + public SecretKey getPlaintextDataKey() throws IllegalStateException { + if (!hasPlaintextDataKey()) { + throw new IllegalStateException("plaintextDataKey has not been populated"); + } return plaintextDataKey; } @@ -66,7 +85,7 @@ public SecretKey getPlaintextDataKey() { * @param keyringTraceEntry The keyring trace entry recording this action. */ public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry keyringTraceEntry) { - if (this.plaintextDataKey != null) { + if (hasPlaintextDataKey()) { throw new IllegalStateException("plaintextDataKey was already populated"); } notNull(plaintextDataKey, "plaintextDataKey is required"); @@ -76,7 +95,26 @@ public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry ke keyringTrace.add(keyringTraceEntry); } - public PublicKey getVerificationKey() { + /** + * Returns true if verification key has been populated. + * + * @return True if verification key is populated, false otherwise. + */ + public boolean hasVerificationKey() { + return verificationKey != null; + } + + /** + * The verification key used for signature verification. + * + * @return The verification key. + * @throws IllegalStateException if a verification key has not been populated. + */ + public PublicKey getVerificationKey() throws IllegalStateException { + if (!hasVerificationKey()) { + throw new IllegalStateException(String.format( + "Signature verification is not supported by AlgorithmSuite %s", algorithmSuite.name())); + } return verificationKey; } @@ -125,7 +163,7 @@ private void validatePlaintextDataKey(CryptoAlgorithm algorithmSuite, SecretKey } /** - * Validates that a verification key is specified only if and only if + * Validates that a verification key is specified if and only if * the given algorithm suite supports signature verification. */ private void validateVerificationKey(CryptoAlgorithm algorithmSuite, PublicKey verificationKey) throws IllegalArgumentException { @@ -142,7 +180,7 @@ public static final class Builder { private CryptoAlgorithm algorithmSuite; private SecretKey plaintextDataKey; private PublicKey verificationKey; - private Map encryptionContext; + private Map encryptionContext = Collections.emptyMap(); private KeyringTrace keyringTrace = new KeyringTrace(); private Builder(CryptoAlgorithm algorithmSuite) { @@ -150,11 +188,11 @@ private Builder(CryptoAlgorithm algorithmSuite) { } private Builder(DecryptionMaterials result) { - this.algorithmSuite = result.getAlgorithmSuite(); - this.plaintextDataKey = result.getPlaintextDataKey(); - this.verificationKey = result.getVerificationKey(); - this.encryptionContext = result.getEncryptionContext(); - this.keyringTrace = result.getKeyringTrace(); + this.algorithmSuite = result.algorithmSuite; + this.plaintextDataKey = result.plaintextDataKey; + this.verificationKey = result.verificationKey; + this.encryptionContext = result.encryptionContext; + this.keyringTrace = result.keyringTrace; } public Builder setAlgorithmSuite(CryptoAlgorithm algorithmSuite) { diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java index da0781726..99b480e0a 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java @@ -42,6 +42,7 @@ public final class EncryptionMaterials { private EncryptionMaterials(Builder b) { notNull(b.algorithmSuite, "algorithmSuite is required"); notNull(b.keyringTrace, "keyringTrace is required"); + notNull(b.encryptionContext, "encryptionContext is required"); validatePlaintextDataKey(b.algorithmSuite, b.plaintextDataKey); validateSigningKey(b.algorithmSuite, b.signingKey); this.algorithmSuite = b.algorithmSuite; @@ -94,10 +95,25 @@ public void addEncryptedDataKey(EncryptedDataKey encryptedDataKey, KeyringTraceE keyringTrace.add(keyringTraceEntry); } + /** + * Returns true if a plaintext data key has been populated. + * + * @return True if plaintext data key is populated, false otherwise. + */ + public boolean hasPlaintextDataKey() { + return this.plaintextDataKey != null; + } + /** * A data key to be used as input for encryption. + * + * @return The plaintext data key. + * @throws IllegalStateException if plain text data key has not been populated. */ - public SecretKey getPlaintextDataKey() { + public SecretKey getPlaintextDataKey() throws IllegalStateException { + if (!hasPlaintextDataKey()) { + throw new IllegalStateException("plaintextDataKey has not been populated"); + } return plaintextDataKey; } @@ -108,7 +124,7 @@ public SecretKey getPlaintextDataKey() { * @param keyringTraceEntry The keyring trace entry recording this action. */ public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry keyringTraceEntry) { - if (this.plaintextDataKey != null) { + if (hasPlaintextDataKey()) { throw new IllegalStateException("plaintextDataKey was already populated"); } notNull(plaintextDataKey, "plaintextDataKey is required"); @@ -118,10 +134,27 @@ public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry ke keyringTrace.add(keyringTraceEntry); } + /** + * Returns true if a signing key has been populated. + * + * @return True if signing key is populated, false otherwise. + */ + public boolean hasSigningKey() { + return this.signingKey != null; + } + + /** * The key to be used as the signing key for signature verification during encryption. + * + * @return The signing key. + * @throws IllegalStateException if signing key has not been populated. */ - public PrivateKey getSigningKey() { + public PrivateKey getSigningKey() throws IllegalStateException { + if (!hasSigningKey()) { + throw new IllegalStateException(String.format( + "Signing is not supported by AlgorithmSuite %s", algorithmSuite.name())); + } return signingKey; } @@ -154,10 +187,10 @@ private void validatePlaintextDataKey(CryptoAlgorithm algorithmSuite, SecretKey private void validateSigningKey(CryptoAlgorithm algorithmSuite, PrivateKey signingKey) throws IllegalArgumentException { if (algorithmSuite.getTrailingSignatureAlgo() == null && signingKey != null) { throw new IllegalArgumentException( - String.format("Algorithm Suite %s does not support signature verification", algorithmSuite.name())); + String.format("Algorithm Suite %s does not support signing", algorithmSuite.name())); } else if (algorithmSuite.getTrailingSignatureAlgo() != null && signingKey == null) { throw new IllegalArgumentException( - String.format("Algorithm Suite %s requires a signing key for signature verification", algorithmSuite.name())); + String.format("Algorithm Suite %s requires a signing key for signing", algorithmSuite.name())); } } diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java index 4b10199e4..21a466723 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java @@ -77,7 +77,7 @@ abstract class RawKeyring implements Keyring { public void onEncrypt(EncryptionMaterials encryptionMaterials) { notNull(encryptionMaterials, "encryptionMaterials are required"); - if (encryptionMaterials.getPlaintextDataKey() == null) { + if (!encryptionMaterials.hasPlaintextDataKey()) { generateDataKey(encryptionMaterials); } @@ -92,7 +92,7 @@ public void onDecrypt(DecryptionMaterials decryptionMaterials, List 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 index 7f3d4dc89..79eff921c 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java @@ -163,4 +163,13 @@ void testSetPlaintextDataKey() { 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/RawKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java index b43238826..196a025cb 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java @@ -35,8 +35,8 @@ 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.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @@ -149,7 +149,7 @@ void testDecryptNoValidDataKey() { keyring.onDecrypt(decryptionMaterials, Collections.singletonList(INVALID_DATA_KEY)); - assertNull(decryptionMaterials.getPlaintextDataKey()); + assertFalse(decryptionMaterials.hasPlaintextDataKey()); assertEquals(0, decryptionMaterials.getKeyringTrace().getEntries().size()); } @@ -162,7 +162,7 @@ void testDecryptNoDataKey() { keyring.onDecrypt(decryptionMaterials, Collections.emptyList()); - assertNull(decryptionMaterials.getPlaintextDataKey()); + assertFalse(decryptionMaterials.hasPlaintextDataKey()); assertEquals(0, decryptionMaterials.getKeyringTrace().getEntries().size()); } From 443d3d22f36c10e2292084dd238e8b8a11c63d30 Mon Sep 17 00:00:00 2001 From: Wesley Rosenblum Date: Thu, 21 Nov 2019 12:14:56 -0800 Subject: [PATCH 9/9] Using Objects.requireNonNull and renaming builder methods --- .../encryptionsdk/EncryptedDataKey.java | 4 ++ .../keyrings/DecryptionMaterials.java | 22 +++++------ .../keyrings/EncryptionMaterials.java | 28 +++++++------- .../encryptionsdk/keyrings/Keyring.java | 2 +- .../encryptionsdk/keyrings/RawKeyring.java | 16 ++++---- .../keyrings/StandardKeyrings.java | 8 ++-- .../encryptionsdk/model/KeyBlob.java | 4 +- .../keyrings/DecryptionMaterialsTest.java | 32 ++++++++-------- .../keyrings/EncryptionMaterialsTest.java | 38 +++++++++---------- .../keyrings/RawAesKeyringTest.java | 18 ++++----- .../keyrings/RawKeyringTest.java | 36 +++++++++--------- .../keyrings/RawRsaKeyringTest.java | 18 ++++----- 12 files changed, 114 insertions(+), 112 deletions(-) diff --git a/src/main/java/com/amazonaws/encryptionsdk/EncryptedDataKey.java b/src/main/java/com/amazonaws/encryptionsdk/EncryptedDataKey.java index 4629a9e07..aa5cfeb89 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/EncryptedDataKey.java +++ b/src/main/java/com/amazonaws/encryptionsdk/EncryptedDataKey.java @@ -16,9 +16,13 @@ //@ model import java.util.Arrays; //@ model import java.nio.charset.StandardCharsets; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; //@ nullable_by_default public interface EncryptedDataKey { + + Charset PROVIDER_ENCODING = StandardCharsets.UTF_8; //@// An EncryptedDataKey object abstractly contains 3 pieces of data. //@// These are represented by 3 byte arrays: diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java index f31df5df4..1cf84058e 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterials.java @@ -22,8 +22,8 @@ import java.util.Map; import java.util.Objects; +import static java.util.Objects.requireNonNull; import static org.apache.commons.lang3.Validate.isTrue; -import static org.apache.commons.lang3.Validate.notNull; /** * Contains the cryptographic materials needed for a decryption operation with Keyrings. @@ -36,9 +36,9 @@ public final class DecryptionMaterials { private final KeyringTrace keyringTrace; private DecryptionMaterials(Builder b) { - notNull(b.algorithmSuite, "algorithmSuite is required"); - notNull(b.keyringTrace, "keyringTrace is required"); - notNull(b.encryptionContext, "encryptionContext is required"); + requireNonNull(b.algorithmSuite, "algorithmSuite is required"); + requireNonNull(b.keyringTrace, "keyringTrace is required"); + requireNonNull(b.encryptionContext, "encryptionContext is required"); validatePlaintextDataKey(b.algorithmSuite, b.plaintextDataKey); validateVerificationKey(b.algorithmSuite, b.verificationKey); @@ -88,8 +88,8 @@ public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry ke if (hasPlaintextDataKey()) { throw new IllegalStateException("plaintextDataKey was already populated"); } - notNull(plaintextDataKey, "plaintextDataKey is required"); - notNull(keyringTraceEntry, "keyringTraceEntry is required"); + requireNonNull(plaintextDataKey, "plaintextDataKey is required"); + requireNonNull(keyringTraceEntry, "keyringTraceEntry is required"); validatePlaintextDataKey(algorithmSuite, plaintextDataKey); this.plaintextDataKey = plaintextDataKey; keyringTrace.add(keyringTraceEntry); @@ -195,27 +195,27 @@ private Builder(DecryptionMaterials result) { this.keyringTrace = result.keyringTrace; } - public Builder setAlgorithmSuite(CryptoAlgorithm algorithmSuite) { + public Builder algorithmSuite(CryptoAlgorithm algorithmSuite) { this.algorithmSuite = algorithmSuite; return this; } - public Builder setPlaintextDataKey(SecretKey plaintextDataKey) { + public Builder plaintextDataKey(SecretKey plaintextDataKey) { this.plaintextDataKey = plaintextDataKey; return this; } - public Builder setVerificationKey(PublicKey verificationKey) { + public Builder verificationKey(PublicKey verificationKey) { this.verificationKey = verificationKey; return this; } - public Builder setEncryptionContext(Map encryptionContext) { + public Builder encryptionContext(Map encryptionContext) { this.encryptionContext = Collections.unmodifiableMap(new HashMap<>(encryptionContext)); return this; } - public Builder setKeyringTrace(KeyringTrace keyringTrace) { + public Builder keyringTrace(KeyringTrace keyringTrace) { this.keyringTrace = keyringTrace; return this; } diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java index 99b480e0a..d52f5d355 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterials.java @@ -25,8 +25,8 @@ import java.util.Map; import java.util.Objects; +import static java.util.Objects.requireNonNull; import static org.apache.commons.lang3.Validate.isTrue; -import static org.apache.commons.lang3.Validate.notNull; /** * Contains the cryptographic materials needed for an encryption operation with Keyrings. @@ -40,9 +40,9 @@ public final class EncryptionMaterials { private final KeyringTrace keyringTrace; private EncryptionMaterials(Builder b) { - notNull(b.algorithmSuite, "algorithmSuite is required"); - notNull(b.keyringTrace, "keyringTrace is required"); - notNull(b.encryptionContext, "encryptionContext is required"); + requireNonNull(b.algorithmSuite, "algorithmSuite is required"); + requireNonNull(b.keyringTrace, "keyringTrace is required"); + requireNonNull(b.encryptionContext, "encryptionContext is required"); validatePlaintextDataKey(b.algorithmSuite, b.plaintextDataKey); validateSigningKey(b.algorithmSuite, b.signingKey); this.algorithmSuite = b.algorithmSuite; @@ -89,8 +89,8 @@ public List getEncryptedDataKeys() { * @param keyringTraceEntry The keyring trace entry recording this action. */ public void addEncryptedDataKey(EncryptedDataKey encryptedDataKey, KeyringTraceEntry keyringTraceEntry) { - notNull(encryptedDataKey, "encryptedDataKey is required"); - notNull(keyringTraceEntry, "keyringTraceEntry is required"); + requireNonNull(encryptedDataKey, "encryptedDataKey is required"); + requireNonNull(keyringTraceEntry, "keyringTraceEntry is required"); encryptedDataKeys.add(encryptedDataKey); keyringTrace.add(keyringTraceEntry); } @@ -127,8 +127,8 @@ public void setPlaintextDataKey(SecretKey plaintextDataKey, KeyringTraceEntry ke if (hasPlaintextDataKey()) { throw new IllegalStateException("plaintextDataKey was already populated"); } - notNull(plaintextDataKey, "plaintextDataKey is required"); - notNull(keyringTraceEntry, "keyringTraceEntry is required"); + requireNonNull(plaintextDataKey, "plaintextDataKey is required"); + requireNonNull(keyringTraceEntry, "keyringTraceEntry is required"); validatePlaintextDataKey(algorithmSuite, plaintextDataKey); this.plaintextDataKey = plaintextDataKey; keyringTrace.add(keyringTraceEntry); @@ -237,32 +237,32 @@ public EncryptionMaterials build() { return new EncryptionMaterials(this); } - public Builder setAlgorithmSuite(CryptoAlgorithm algorithmSuite) { + public Builder algorithmSuite(CryptoAlgorithm algorithmSuite) { this.algorithmSuite = algorithmSuite; return this; } - public Builder setEncryptionContext(Map encryptionContext) { + public Builder encryptionContext(Map encryptionContext) { this.encryptionContext = Collections.unmodifiableMap(new HashMap<>(encryptionContext)); return this; } - public Builder setEncryptedDataKeys(List encryptedDataKeys) { + public Builder encryptedDataKeys(List encryptedDataKeys) { this.encryptedDataKeys = new ArrayList<>(encryptedDataKeys); return this; } - public Builder setPlaintextDataKey(SecretKey plaintextDataKey) { + public Builder plaintextDataKey(SecretKey plaintextDataKey) { this.plaintextDataKey = plaintextDataKey; return this; } - public Builder setSigningKey(PrivateKey signingKey) { + public Builder signingKey(PrivateKey signingKey) { this.signingKey = signingKey; return this; } - public Builder setKeyringTrace(KeyringTrace keyringTrace) { + public Builder keyringTrace(KeyringTrace keyringTrace) { this.keyringTrace = keyringTrace; return this; } diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java index e79f87b08..20f4c69f5 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/Keyring.java @@ -23,7 +23,7 @@ public interface Keyring { /** - * Generate a data key if not present and encrypt it using any available wrapping key + * Attempt to encrypt either the given data key (if present) or one that may be generated * * @param encryptionMaterials Materials needed for encryption that the keyring may modify. */ diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java index 21a466723..8daa567f8 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/RawKeyring.java @@ -20,13 +20,12 @@ import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; 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; -import static org.apache.commons.lang3.Validate.notNull; /** * A keyring supporting local encryption and decryption using either RSA or AES-GCM. @@ -37,17 +36,16 @@ abstract class RawKeyring implements Keyring { final String keyName; final byte[] keyNameBytes; private final JceKeyCipher jceKeyCipher; - private static final Charset KEY_NAME_ENCODING = StandardCharsets.UTF_8; 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"); - notNull(jceKeyCipher, "jceKeyCipher is required"); + requireNonNull(jceKeyCipher, "jceKeyCipher is required"); this.keyNamespace = keyNamespace; this.keyName = keyName; - this.keyNameBytes = keyName.getBytes(KEY_NAME_ENCODING); + this.keyNameBytes = keyName.getBytes(PROVIDER_ENCODING); this.jceKeyCipher = jceKeyCipher; } @@ -75,7 +73,7 @@ abstract class RawKeyring implements Keyring { @Override public void onEncrypt(EncryptionMaterials encryptionMaterials) { - notNull(encryptionMaterials, "encryptionMaterials are required"); + requireNonNull(encryptionMaterials, "encryptionMaterials are required"); if (!encryptionMaterials.hasPlaintextDataKey()) { generateDataKey(encryptionMaterials); @@ -89,8 +87,8 @@ public void onEncrypt(EncryptionMaterials encryptionMaterials) { @Override public void onDecrypt(DecryptionMaterials decryptionMaterials, List encryptedDataKeys) { - notNull(decryptionMaterials, "decryptionMaterials are required"); - notNull(encryptedDataKeys, "encryptedDataKeys are required"); + requireNonNull(decryptionMaterials, "decryptionMaterials are required"); + requireNonNull(encryptedDataKeys, "encryptedDataKeys are required"); if (decryptionMaterials.hasPlaintextDataKey() || encryptedDataKeys.isEmpty()) { return; diff --git a/src/main/java/com/amazonaws/encryptionsdk/keyrings/StandardKeyrings.java b/src/main/java/com/amazonaws/encryptionsdk/keyrings/StandardKeyrings.java index 1f8d24b52..d36dae07e 100644 --- a/src/main/java/com/amazonaws/encryptionsdk/keyrings/StandardKeyrings.java +++ b/src/main/java/com/amazonaws/encryptionsdk/keyrings/StandardKeyrings.java @@ -29,8 +29,8 @@ private StandardKeyrings() { * Constructs a {@code Keyring} which does local AES-GCM encryption * decryption of data keys using the provided wrapping key. * - * @param keyNamespace A UTF-8 encoded value that, together with the key name, identifies the wrapping key. - * @param keyName A UTF-8 encoded value that, together with the key namespace, identifies the 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} */ @@ -43,8 +43,8 @@ public static Keyring rawAes(String keyNamespace, String keyName, SecretKey wrap * 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 UTF-8 encoded value that, together with the key name, identifies the wrapping key. - * @param keyName A UTF-8 encoded value that, together with the key namespace, identifies the 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 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. 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 index 520660104..68687d4ad 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterialsTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/DecryptionMaterialsTest.java @@ -57,10 +57,10 @@ void testBuilderNullCryptoAlgorithm() { @Test void testBuilder() { DecryptionMaterials result = DecryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(KEYRING_TRACE) - .setPlaintextDataKey(PLAINTEXT_DATA_KEY) - .setVerificationKey(VERIFICATION_KEY) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(KEYRING_TRACE) + .plaintextDataKey(PLAINTEXT_DATA_KEY) + .verificationKey(VERIFICATION_KEY) .build(); assertEquals(ALGORITHM_SUITE, result.getAlgorithmSuite()); @@ -74,18 +74,18 @@ void testBuilder() { void testInvalidPlaintextDataKey() { SecretKey wrongLength = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength() + 1), ALGORITHM_SUITE.getDataKeyAlgo()); assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setPlaintextDataKey(wrongLength) - .setVerificationKey(VERIFICATION_KEY) + .plaintextDataKey(wrongLength) + .verificationKey(VERIFICATION_KEY) .build()); SecretKey wrongAlgorithm = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength()), "InvalidAlgorithm"); assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setPlaintextDataKey(wrongAlgorithm) - .setVerificationKey(VERIFICATION_KEY) + .plaintextDataKey(wrongAlgorithm) + .verificationKey(VERIFICATION_KEY) .build()); DecryptionMaterials materials = DecryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setVerificationKey(VERIFICATION_KEY) + .verificationKey(VERIFICATION_KEY) .build(); assertThrows(IllegalArgumentException.class, () -> materials .setPlaintextDataKey(wrongAlgorithm, KEYRING_TRACE_ENTRY)); @@ -96,10 +96,10 @@ void testInvalidPlaintextDataKey() { @Test void testInvalidVerificationKey() { assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setVerificationKey(null) + .verificationKey(null) .build()); assertThrows(IllegalArgumentException.class, () -> DecryptionMaterials.newBuilder(CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256) - .setVerificationKey(VERIFICATION_KEY) + .verificationKey(VERIFICATION_KEY) .build()); } @@ -107,10 +107,10 @@ void testInvalidVerificationKey() { @Test void testToBuilder() { DecryptionMaterials expected = DecryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(KEYRING_TRACE) - .setPlaintextDataKey(PLAINTEXT_DATA_KEY) - .setVerificationKey(VERIFICATION_KEY) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(KEYRING_TRACE) + .plaintextDataKey(PLAINTEXT_DATA_KEY) + .verificationKey(VERIFICATION_KEY) .build(); DecryptionMaterials actual = expected.toBuilder().build(); @@ -122,7 +122,7 @@ void testToBuilder() { @Test void testSetPlaintextDataKey() { DecryptionMaterials materials = DecryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setVerificationKey(VERIFICATION_KEY) + .verificationKey(VERIFICATION_KEY) .build(); assertThrows(NullPointerException.class, () -> materials.setPlaintextDataKey(null, KEYRING_TRACE_ENTRY)); diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java index 79eff921c..d1c207dbd 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/EncryptionMaterialsTest.java @@ -64,11 +64,11 @@ void testBuilderNullCryptoAlgorithm() { @Test void testBuilder() { EncryptionMaterials result = EncryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(KEYRING_TRACE) - .setPlaintextDataKey(PLAINTEXT_DATA_KEY) - .setEncryptedDataKeys(Collections.singletonList(ENCRYPTED_DATA_KEY)) - .setSigningKey(SIGNING_KEY) + .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()); @@ -84,18 +84,18 @@ void testBuilder() { void testInvalidPlaintextDataKey() { SecretKey wrongLength = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength() + 1), ALGORITHM_SUITE.getDataKeyAlgo()); assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setPlaintextDataKey(wrongLength) - .setSigningKey(SIGNING_KEY) + .plaintextDataKey(wrongLength) + .signingKey(SIGNING_KEY) .build()); SecretKey wrongAlgorithm = new SecretKeySpec(generate(ALGORITHM_SUITE.getDataKeyLength()), "InvalidAlgorithm"); assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setPlaintextDataKey(wrongAlgorithm) - .setSigningKey(SIGNING_KEY) + .plaintextDataKey(wrongAlgorithm) + .signingKey(SIGNING_KEY) .build()); EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setSigningKey(SIGNING_KEY) + .signingKey(SIGNING_KEY) .build(); assertThrows(IllegalArgumentException.class, () -> materials .setPlaintextDataKey(wrongAlgorithm, KEYRING_TRACE_ENTRY)); @@ -106,10 +106,10 @@ void testInvalidPlaintextDataKey() { @Test void testInvalidSigningKey() { assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setSigningKey(null) + .signingKey(null) .build()); assertThrows(IllegalArgumentException.class, () -> EncryptionMaterials.newBuilder(CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256) - .setSigningKey(SIGNING_KEY) + .signingKey(SIGNING_KEY) .build()); } @@ -117,11 +117,11 @@ void testInvalidSigningKey() { @Test void testToBuilder() { EncryptionMaterials expected = EncryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(KEYRING_TRACE) - .setPlaintextDataKey(PLAINTEXT_DATA_KEY) - .setEncryptedDataKeys(Collections.singletonList(ENCRYPTED_DATA_KEY)) - .setSigningKey(SIGNING_KEY) + .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(); @@ -133,7 +133,7 @@ void testToBuilder() { @Test void testAddEncryptedDataKey() { EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setSigningKey(SIGNING_KEY) + .signingKey(SIGNING_KEY) .build(); assertThrows(NullPointerException.class, () -> materials.addEncryptedDataKey(null, KEYRING_TRACE_ENTRY)); @@ -149,7 +149,7 @@ void testAddEncryptedDataKey() { @Test void testSetPlaintextDataKey() { EncryptionMaterials materials = EncryptionMaterials.newBuilder(ALGORITHM_SUITE) - .setSigningKey(SIGNING_KEY) + .signingKey(SIGNING_KEY) .build(); assertThrows(NullPointerException.class, () -> materials.setPlaintextDataKey(null, KEYRING_TRACE_ENTRY)); diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java index f5b3ed297..4183e9a06 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawAesKeyringTest.java @@ -54,9 +54,9 @@ void testValidToDecrypt() { @Test void testEncryptDecryptExistingDataKey() { EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) - .setPlaintextDataKey(DATA_KEY) - .setKeyringTrace(new KeyringTrace()) - .setEncryptionContext(ENCRYPTION_CONTEXT) + .plaintextDataKey(DATA_KEY) + .keyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) .build(); keyring.onEncrypt(encryptionMaterials); @@ -76,8 +76,8 @@ void testEncryptDecryptExistingDataKey() { assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT)); DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); @@ -93,8 +93,8 @@ void testEncryptDecryptExistingDataKey() { @Test void testEncryptDecryptGenerateDataKey() { EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) - .setKeyringTrace(new KeyringTrace()) - .setEncryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) .build(); keyring.onEncrypt(encryptionMaterials); @@ -116,8 +116,8 @@ void testEncryptDecryptGenerateDataKey() { assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(1).getFlags().contains(KeyringTraceFlag.SIGNED_ENCRYPTION_CONTEXT)); DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java index 196a025cb..945aa17bc 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawKeyringTest.java @@ -82,9 +82,9 @@ KeyringTraceEntry traceOnDecrypt() { @Test void testEncryptDecryptExistingDataKey() { EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) - .setPlaintextDataKey(DATA_KEY) - .setKeyringTrace(new KeyringTrace()) - .setEncryptionContext(ENCRYPTION_CONTEXT) + .plaintextDataKey(DATA_KEY) + .keyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) .build(); keyring.onEncrypt(encryptionMaterials); @@ -95,8 +95,8 @@ void testEncryptDecryptExistingDataKey() { assertEquals(ENCRYPTED_DATA_KEY_TRACE, encryptionMaterials.getKeyringTrace().getEntries().get(0)); DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, Collections.singletonList(ENCRYPTED_DATA_KEY)); @@ -108,8 +108,8 @@ void testEncryptDecryptExistingDataKey() { @Test void testEncryptNullDataKey() { EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) - .setKeyringTrace(new KeyringTrace()) - .setEncryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) .build(); ArgumentCaptor dataKeyCaptor = ArgumentCaptor.forClass(byte[].class); @@ -129,9 +129,9 @@ void testEncryptNullDataKey() { @Test void testDecryptAlreadyDecryptedDataKey() { DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) - .setPlaintextDataKey(DATA_KEY) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(new KeyringTrace()) + .plaintextDataKey(DATA_KEY) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, Collections.singletonList(ENCRYPTED_DATA_KEY)); @@ -143,8 +143,8 @@ void testDecryptAlreadyDecryptedDataKey() { @Test void testDecryptNoValidDataKey() { DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, Collections.singletonList(INVALID_DATA_KEY)); @@ -156,8 +156,8 @@ void testDecryptNoValidDataKey() { @Test void testDecryptNoDataKey() { DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, Collections.emptyList()); @@ -170,8 +170,8 @@ void testDecryptNoDataKey() { @Test void testDecryptMultipleKeysOneInvalid() { DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) .build(); final List edks = new ArrayList<>(); @@ -189,8 +189,8 @@ 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) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) .build(); when(jceKeyCipher.decryptKey(BAD_DATA_KEY, KEYNAME, ENCRYPTION_CONTEXT)) diff --git a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java index fee585a56..6e43d5d37 100644 --- a/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java +++ b/src/test/java/com/amazonaws/encryptionsdk/keyrings/RawRsaKeyringTest.java @@ -62,9 +62,9 @@ void testValidToDecrypt() { @Test void testEncryptDecryptExistingDataKey() { EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) - .setPlaintextDataKey(DATA_KEY) - .setKeyringTrace(new KeyringTrace()) - .setEncryptionContext(ENCRYPTION_CONTEXT) + .plaintextDataKey(DATA_KEY) + .keyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) .build(); keyring.onEncrypt(encryptionMaterials); @@ -82,8 +82,8 @@ void testEncryptDecryptExistingDataKey() { assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(0).getFlags().contains(KeyringTraceFlag.ENCRYPTED_DATA_KEY)); DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys()); @@ -98,8 +98,8 @@ void testEncryptDecryptExistingDataKey() { @Test void testEncryptDecryptGenerateDataKey() { EncryptionMaterials encryptionMaterials = EncryptionMaterials.newBuilder(ALGORITHM) - .setKeyringTrace(new KeyringTrace()) - .setEncryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) .build(); keyring.onEncrypt(encryptionMaterials); @@ -119,8 +119,8 @@ void testEncryptDecryptGenerateDataKey() { assertTrue(encryptionMaterials.getKeyringTrace().getEntries().get(1).getFlags().contains(KeyringTraceFlag.ENCRYPTED_DATA_KEY)); DecryptionMaterials decryptionMaterials = DecryptionMaterials.newBuilder(ALGORITHM) - .setEncryptionContext(ENCRYPTION_CONTEXT) - .setKeyringTrace(new KeyringTrace()) + .encryptionContext(ENCRYPTION_CONTEXT) + .keyringTrace(new KeyringTrace()) .build(); keyring.onDecrypt(decryptionMaterials, encryptionMaterials.getEncryptedDataKeys());