// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package com.amazonaws.encryptionsdk; import static com.amazonaws.encryptionsdk.TestUtils.assertThrows; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import com.amazonaws.encryptionsdk.exception.BadCiphertextException; import com.amazonaws.encryptionsdk.internal.EncryptionHandler; import com.amazonaws.encryptionsdk.internal.StaticMasterKey; import com.amazonaws.encryptionsdk.internal.Utils; import com.amazonaws.encryptionsdk.model.CiphertextHeaders; import com.amazonaws.encryptionsdk.model.EncryptionMaterials; import com.amazonaws.encryptionsdk.model.EncryptionMaterialsRequest; import java.security.InvalidKeyException; import java.util.Collections; import java.util.Map; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import org.junit.Test; public class CryptoAlgorithmTest { @Test public void testDeserialization() { for (CryptoAlgorithm algorithm : CryptoAlgorithm.values()) { assertEquals( algorithm.toString(), algorithm, CryptoAlgorithm.deserialize(algorithm.getMessageFormatVersion(), algorithm.getValue())); } } @Test public void testGetCommittedEncryptionKey() throws InvalidKeyException { CryptoAlgorithm algorithm = TestUtils.messageWithCommitKeyCryptoAlgorithm; SecretKeySpec secretKey = new SecretKeySpec( Utils.decodeBase64String(TestUtils.messageWithCommitKeyDEKBase64), algorithm.getDataKeyAlgo()); CiphertextHeaders headers = new ParsedCiphertext(Utils.decodeBase64String(TestUtils.messageWithCommitKeyBase64)); SecretKey key = algorithm.getEncryptionKeyFromDataKey(secretKey, headers); assertNotNull(key); assertEquals(algorithm.getKeyAlgo(), key.getAlgorithm()); } @Test public void testGetCommittedEncryptionKeyIncorrectCommitment() throws InvalidKeyException { CryptoAlgorithm algorithm = TestUtils.messageWithCommitKeyCryptoAlgorithm; SecretKeySpec secretKey = new SecretKeySpec( Utils.decodeBase64String(TestUtils.messageWithCommitKeyDEKBase64), algorithm.getDataKeyAlgo()); CiphertextHeaders headers = new ParsedCiphertext(Utils.decodeBase64String(TestUtils.messageWithCommitKeyBase64)); // Set header to an incorrect commitment value headers.setSuiteData(new byte[algorithm.getSuiteDataLength()]); assertThrows( BadCiphertextException.class, "Key commitment validation failed. Key identity does not match the " + "identity asserted in the message. Halting processing of this message.", () -> algorithm.getEncryptionKeyFromDataKey(secretKey, headers)); } @Test public void testGetCommittedEncryptionKeyIncorrectKeySpecAlgorithm() throws InvalidKeyException { CryptoAlgorithm algorithm = TestUtils.messageWithCommitKeyCryptoAlgorithm; SecretKeySpec secretKey = new SecretKeySpec(new byte[algorithm.getDataKeyLength()], "incorrectAlgorithm"); CiphertextHeaders headers = new ParsedCiphertext(Utils.decodeBase64String(TestUtils.messageWithCommitKeyBase64)); assertThrows( InvalidKeyException.class, "DataKey of incorrect algorithm.", () -> algorithm.getEncryptionKeyFromDataKey(secretKey, headers)); } @Test public void testGetCommittedEncryptionKeyIncorrectLength() throws InvalidKeyException { CryptoAlgorithm algorithm = TestUtils.messageWithCommitKeyCryptoAlgorithm; SecretKeySpec secretKey = new SecretKeySpec(new byte[1], "HkdfSHA512"); CiphertextHeaders headers = new ParsedCiphertext(Utils.decodeBase64String(TestUtils.messageWithCommitKeyBase64)); assertThrows( IllegalArgumentException.class, "DataKey of incorrect length.", () -> algorithm.getEncryptionKeyFromDataKey(secretKey, headers)); } @Test public void testGetUnCommittedEncryptionKey() throws InvalidKeyException { CryptoAlgorithm algo = CryptoAlgorithm.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA256; SecretKeySpec secretKey = new SecretKeySpec(new byte[algo.getDataKeyLength()], algo.getDataKeyAlgo()); CiphertextHeaders headers = getTestHeaders(algo); SecretKey key = algo.getEncryptionKeyFromDataKey(secretKey, headers); assertNotNull(key); assertEquals(algo.getKeyAlgo(), key.getAlgorithm()); } @Test public void testGetUnCommittedEncryptionKeyFromDataKeyIncorrectKeySpecAlgorithm() throws InvalidKeyException { CryptoAlgorithm algo = CryptoAlgorithm.ALG_AES_256_GCM_IV12_TAG16_HKDF_SHA256; SecretKeySpec secretKey = new SecretKeySpec(new byte[algo.getDataKeyLength()], "incorrectAlgorithm"); CiphertextHeaders headers = getTestHeaders(algo); assertThrows( InvalidKeyException.class, "DataKey of incorrect algorithm.", () -> TestUtils.messageWithCommitKeyCryptoAlgorithm.getEncryptionKeyFromDataKey( secretKey, headers)); } @Test public void testGetUnCommittedEncryptionKeyIncorrectLength() throws InvalidKeyException { SecretKeySpec secretKey = new SecretKeySpec(new byte[1], "HkdfSHA512"); CiphertextHeaders headers = new ParsedCiphertext(Utils.decodeBase64String(TestUtils.messageWithCommitKeyBase64)); assertThrows( IllegalArgumentException.class, "DataKey of incorrect length.", () -> TestUtils.messageWithCommitKeyCryptoAlgorithm.getEncryptionKeyFromDataKey( secretKey, headers)); } private ParsedCiphertext getTestHeaders(CryptoAlgorithm algo) { // Generate test headers final int frameSize_ = AwsCrypto.getDefaultFrameSize(); final Map encryptionContext = Collections.emptyMap(); final CommitmentPolicy policy = CommitmentPolicy.ForbidEncryptAllowDecrypt; final EncryptionMaterialsRequest encryptionMaterialsRequest = EncryptionMaterialsRequest.newBuilder() .setContext(encryptionContext) .setRequestedAlgorithm(algo) .setCommitmentPolicy(policy) .build(); final StaticMasterKey masterKeyProvider = new StaticMasterKey("mock"); final EncryptionMaterials encryptionMaterials = new DefaultCryptoMaterialsManager(masterKeyProvider) .getMaterialsForEncrypt(encryptionMaterialsRequest); final EncryptionHandler encryptionHandler = new EncryptionHandler(frameSize_, encryptionMaterials, policy); final byte[] in = new byte[0]; final int ciphertextLen = encryptionHandler.estimateOutputSize(in.length); final byte[] ciphertext = new byte[ciphertextLen]; encryptionHandler.processBytes(in, 0, in.length, ciphertext, 0); return new ParsedCiphertext(ciphertext); } }