Skip to content

fix: Update DecryptionMaterials code to support legacy custom CMMs #2037

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Jun 11, 2024
Merged
15 changes: 7 additions & 8 deletions src/main/java/com/amazonaws/encryptionsdk/CMMHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import com.amazonaws.encryptionsdk.model.EncryptionMaterialsHandler;
import com.amazonaws.encryptionsdk.model.EncryptionMaterialsRequest;
import com.amazonaws.encryptionsdk.model.KeyBlob;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -65,10 +64,10 @@ private GetEncryptionMaterialsInput getEncryptionMaterialsRequestInput(
public DecryptionMaterialsHandler decryptMaterials(
DecryptionMaterialsRequest request, CommitmentPolicy commitmentPolicy) {
if (cmm != null && mplCMM == null) {
// This is an implementation of the legacy native CryptoMaterialsManager interface from ESDK-Java.
// This is an implementation of the legacy native CryptoMaterialsManager interface from
// ESDK-Java.
DecryptionMaterials materials = cmm.decryptMaterials(request);
if (materials.getEncryptionContext().isEmpty()
&& !request.getEncryptionContext().isEmpty()) {
if (materials.getEncryptionContext().isEmpty() && !request.getEncryptionContext().isEmpty()) {
// If the request specified an encryption context,
// and we are using the legacy native CMM,
// add the encryptionContext to the materials.
Expand All @@ -82,7 +81,8 @@ public DecryptionMaterialsHandler decryptMaterials(
// It now sets the encryptionContext attribute with the value from the ciphertext's headers.
//
// But custom CMMs' behavior was not updated.
// However, there is no custom CMM before version 3.0 that could set an encryptionContext attribute.
// However, there is no custom CMM before version 3.0 that could set an encryptionContext
// attribute.
// The encryptionContext attribute was only introduced to decryptMaterials objects
// in ESDK 3.0, so no CMM could have configured this attribute before 3.0.
// As a result, the ESDK assumes that any native CMM
Expand All @@ -91,9 +91,8 @@ public DecryptionMaterialsHandler decryptMaterials(
//
// If a custom CMM implementation conflicts with this assumption.
// that CMM implementation MUST move to the MPL.
materials = materials.toBuilder()
.setEncryptionContext(request.getEncryptionContext())
.build();
materials =
materials.toBuilder().setEncryptionContext(request.getEncryptionContext()).build();
}
return new DecryptionMaterialsHandler(materials);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,21 @@
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
import org.junit.Test;


public class CustomCMMExampleTest {

@Test
public void testCustomCMMExample() {
CryptoMaterialsManager cmm = new CustomCMMExample.SigningSuiteOnlyCMM(
KmsMasterKeyProvider.builder().buildStrict(KMSTestFixtures.US_WEST_2_KEY_ID)
);
CryptoMaterialsManager cmm =
new CustomCMMExample.SigningSuiteOnlyCMM(
KmsMasterKeyProvider.builder().buildStrict(KMSTestFixtures.US_WEST_2_KEY_ID));
CustomCMMExample.encryptAndDecryptWithCMM(cmm);
}

@Test
public void testV2Cmm() {
V2DefaultCryptoMaterialsManager cmm = new V2DefaultCryptoMaterialsManager(
KmsMasterKeyProvider.builder().buildStrict(KMSTestFixtures.US_WEST_2_KEY_ID)
);
V2DefaultCryptoMaterialsManager cmm =
new V2DefaultCryptoMaterialsManager(
KmsMasterKeyProvider.builder().buildStrict(KMSTestFixtures.US_WEST_2_KEY_ID));
CustomCMMExample.encryptAndDecryptWithCMM(cmm);
}
}


Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.amazonaws.crypto.examples.v2;

import static com.amazonaws.encryptionsdk.internal.Utils.assertNonNull;

import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.encryptionsdk.CryptoAlgorithm;
import com.amazonaws.encryptionsdk.CryptoMaterialsManager;
Expand All @@ -16,7 +18,6 @@
import com.amazonaws.encryptionsdk.model.EncryptionMaterials;
import com.amazonaws.encryptionsdk.model.EncryptionMaterialsRequest;
import com.amazonaws.encryptionsdk.model.KeyBlob;

import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PublicKey;
Expand All @@ -25,28 +26,26 @@
import java.util.List;
import java.util.Map;

import static com.amazonaws.encryptionsdk.internal.Utils.assertNonNull;

/*
This is a copy-paste of the DefaultCryptoMaterialsManager implementation
from the final commit of the V2 ESDK: 1870a082358d59e32c60d74116d6f43c0efa466b
ESDK V3 implicitly changed the contract between CMMs and the ESDK.
After V3, DecryptMaterials has an `encryptionContext` attribute,
and CMMs are expected to set this attribute.
The V3 commit modified this DefaultCMM's `decryptMaterials` implementation
to set encryptionContext on returned DecryptionMaterials objects.
However, there are custom implementations of the legacy native CMM
that do not set encryptionContext.
This CMM is used to explicitly assert that the V2 implementation of
the DefaultCMM is compatible with V3 logic,
which implicitly asserts that custom implementations of V2-compatible CMMs
are also compatible with V3 logic.
*/
This is a copy-paste of the DefaultCryptoMaterialsManager implementation
from the final commit of the V2 ESDK: 1870a082358d59e32c60d74116d6f43c0efa466b
ESDK V3 implicitly changed the contract between CMMs and the ESDK.
After V3, DecryptMaterials has an `encryptionContext` attribute,
and CMMs are expected to set this attribute.
The V3 commit modified this DefaultCMM's `decryptMaterials` implementation
to set encryptionContext on returned DecryptionMaterials objects.
However, there are custom implementations of the legacy native CMM
that do not set encryptionContext.
This CMM is used to explicitly assert that the V2 implementation of
the DefaultCMM is compatible with V3 logic,
which implicitly asserts that custom implementations of V2-compatible CMMs
are also compatible with V3 logic.
*/
public class V2DefaultCryptoMaterialsManager implements CryptoMaterialsManager {
private final MasterKeyProvider<?> mkp;

private final CryptoAlgorithm DEFAULT_CRYPTO_ALGORITHM =
CryptoAlgorithm.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384;
CryptoAlgorithm.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA384_ECDSA_P384;

/** @param mkp The master key provider to delegate to */
public V2DefaultCryptoMaterialsManager(MasterKeyProvider<?> mkp) {
Expand All @@ -73,7 +72,7 @@ public EncryptionMaterials getMaterialsForEncrypt(EncryptionMaterialsRequest req
trailingKeys = generateTrailingSigKeyPair(algo);
if (context.containsKey(Constants.EC_PUBLIC_KEY_FIELD)) {
throw new IllegalArgumentException(
"EncryptionContext contains reserved field " + Constants.EC_PUBLIC_KEY_FIELD);
"EncryptionContext contains reserved field " + Constants.EC_PUBLIC_KEY_FIELD);
}
// make mutable
context = new HashMap<>(context);
Expand All @@ -95,8 +94,8 @@ public EncryptionMaterials getMaterialsForEncrypt(EncryptionMaterialsRequest req

@SuppressWarnings("unchecked")
final List<MasterKey> mks =
(List<MasterKey>)
assertNonNull(mkp, "provider").getMasterKeysForEncryption(mkRequestBuilder.build());
(List<MasterKey>)
assertNonNull(mkp, "provider").getMasterKeysForEncryption(mkRequestBuilder.build());

if (mks.isEmpty()) {
throw new IllegalArgumentException("No master keys provided");
Expand All @@ -114,20 +113,20 @@ public EncryptionMaterials getMaterialsForEncrypt(EncryptionMaterialsRequest req

//noinspection unchecked
return EncryptionMaterials.newBuilder()
.setAlgorithm(algo)
.setCleartextDataKey(dataKey.getKey())
.setEncryptedDataKeys(keyBlobs)
.setEncryptionContext(context)
.setTrailingSignatureKey(trailingKeys == null ? null : trailingKeys.getPrivate())
.setMasterKeys(mks)
.build();
.setAlgorithm(algo)
.setCleartextDataKey(dataKey.getKey())
.setEncryptedDataKeys(keyBlobs)
.setEncryptionContext(context)
.setTrailingSignatureKey(trailingKeys == null ? null : trailingKeys.getPrivate())
.setMasterKeys(mks)
.build();
}

@Override
public DecryptionMaterials decryptMaterials(DecryptionMaterialsRequest request) {
DataKey<?> dataKey =
mkp.decryptDataKey(
request.getAlgorithm(), request.getEncryptedDataKeys(), request.getEncryptionContext());
mkp.decryptDataKey(
request.getAlgorithm(), request.getEncryptedDataKeys(), request.getEncryptionContext());

if (dataKey == null) {
throw new CannotUnwrapDataKeyException("Could not decrypt any data keys");
Expand All @@ -151,9 +150,9 @@ public DecryptionMaterials decryptMaterials(DecryptionMaterialsRequest request)
}

return DecryptionMaterials.newBuilder()
.setDataKey(dataKey)
.setTrailingSignatureKey(pubKey)
.build();
.setDataKey(dataKey)
.setTrailingSignatureKey(pubKey)
.build();
}

private PublicKey deserializeTrailingKeyFromEc(CryptoAlgorithm algo, String pubKey) {
Expand All @@ -162,11 +161,11 @@ private PublicKey deserializeTrailingKeyFromEc(CryptoAlgorithm algo, String pubK

private static String serializeTrailingKeyForEc(CryptoAlgorithm algo, KeyPair trailingKeys) {
return TrailingSignatureAlgorithm.forCryptoAlgorithm(algo)
.serializePublicKey(trailingKeys.getPublic());
.serializePublicKey(trailingKeys.getPublic());
}

private static KeyPair generateTrailingSigKeyPair(CryptoAlgorithm algo)
throws GeneralSecurityException {
throws GeneralSecurityException {
return TrailingSignatureAlgorithm.forCryptoAlgorithm(algo).generateKey();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
import com.amazonaws.encryptionsdk.model.CipherBlockHeadersTest;
import com.amazonaws.encryptionsdk.model.CipherFrameHeadersTest;
import com.amazonaws.encryptionsdk.model.CiphertextHeadersTest;
import com.amazonaws.encryptionsdk.model.DecryptionMaterialsTest;
import com.amazonaws.encryptionsdk.model.DecryptionMaterialsRequestTest;
import com.amazonaws.encryptionsdk.model.DecryptionMaterialsTest;
import com.amazonaws.encryptionsdk.model.EncryptionMaterialsRequestTest;
import com.amazonaws.encryptionsdk.model.KeyBlobTest;
import com.amazonaws.encryptionsdk.multi.MultipleMasterKeyTest;
Expand Down
Loading
Loading