@Override public byte[] decrypt(byte[] ciphertext, EncryptionContext context) { try { final CryptoResult<byte[], KmsMasterKey> decryptResult = crypto.decryptData(getProvider(), ciphertext); verify(decryptResult, context); return decryptResult.getResult(); } catch (AwsCryptoException e) { if (isInvalidKeyException(e)) { throw new UnlimitedEncryptionNotSetException(); } else { throw e; } } }
@Test public void testMultipleKmsKeys() { final MockKMSClient kms = new MockKMSClient(); final String arn1 = kms.createKey().getKeyMetadata().getArn(); final String arn2 = kms.createKey().getKeyMetadata().getArn(); MasterKeyProvider<KmsMasterKey> prov = legacyConstruct(kms, arn1, arn2); KmsMasterKey mk1 = prov.getMasterKey(arn1); AwsCrypto crypto = new AwsCrypto(); CryptoResult<byte[], KmsMasterKey> ct = crypto.encryptData(prov, PLAINTEXT); assertEquals(2, ct.getMasterKeyIds().size()); CryptoResult<byte[], KmsMasterKey> result = crypto.decryptData(prov, ct.getResult()); assertArrayEquals(PLAINTEXT, result.getResult()); // Only the first found key should be used assertEquals(1, result.getMasterKeys().size()); assertEquals(mk1, result.getMasterKeys().get(0)); }
@Test public void testMixedKeys() { final SecretKeySpec k1 = new SecretKeySpec(generate(32), "AES"); final JceMasterKey mk1 = JceMasterKey.getInstance(k1, "jce", "1", WRAPPING_ALG); final MockKMSClient kms = new MockKMSClient(); final String arn2 = kms.createKey().getKeyMetadata().getArn(); MasterKeyProvider<KmsMasterKey> prov = legacyConstruct(kms); KmsMasterKey mk2 = prov.getMasterKey(arn2); final MasterKeyProvider<?> mkp = MultipleProviderFactory.buildMultiProvider(mk1, mk2); AwsCrypto crypto = new AwsCrypto(); CryptoResult<byte[], ?> ct = crypto.encryptData(mkp, PLAINTEXT); assertEquals(2, ct.getMasterKeyIds().size()); CryptoResult<byte[], ?> result = crypto.decryptData(mkp, ct.getResult()); assertArrayEquals(PLAINTEXT, result.getResult()); // Only the first found key should be used assertEquals(1, result.getMasterKeys().size()); assertEquals(mk1, result.getMasterKeys().get(0)); assertMultiReturnsKeys(mkp, mk1, mk2); }
@Test public void testMixedKeysSingleDecrypt() { final SecretKeySpec k1 = new SecretKeySpec(generate(32), "AES"); final JceMasterKey mk1 = JceMasterKey.getInstance(k1, "jce", "1", WRAPPING_ALG); final MockKMSClient kms = new MockKMSClient(); final String arn2 = kms.createKey().getKeyMetadata().getArn(); MasterKeyProvider<KmsMasterKey> prov = legacyConstruct(kms); KmsMasterKey mk2 = prov.getMasterKey(arn2); final MasterKeyProvider<?> mkp = MultipleProviderFactory.buildMultiProvider(mk1, mk2); AwsCrypto crypto = new AwsCrypto(); CryptoResult<byte[], ?> ct = crypto.encryptData(mkp, PLAINTEXT); assertEquals(2, ct.getMasterKeyIds().size()); CryptoResult<byte[], ?> result = crypto.decryptData(mk1, ct.getResult()); assertArrayEquals(PLAINTEXT, result.getResult()); // Only the first found key should be used assertEquals(1, result.getMasterKeys().size()); assertEquals(mk1, result.getMasterKeys().get(0)); result = crypto.decryptData(mk2, ct.getResult()); assertArrayEquals(PLAINTEXT, result.getResult()); // Only the first found key should be used assertEquals(1, result.getMasterKeys().size()); assertEquals(mk2, result.getMasterKeys().get(0)); }
private MasterKeyProvider<?> masterKeyProvider() { final AWSCredentialsProvider credentials = new DefaultAWSCredentialsProviderChain(); List<KmsMasterKey> masterKeys = new LinkedList<>(); for (String region : this.regions) { KmsMasterKeyProvider provider = new KmsMasterKeyProvider( credentials, Region.getRegion( Regions.fromName( region)), new ClientConfiguration(), this.keyId); masterKeys.add( provider.getMasterKey( this.keyId)); } return MultipleProviderFactory .buildMultiProvider( masterKeys); }
@Override public String decrypt(String ciphertext, EncryptionContext context) { final CryptoResult<String, KmsMasterKey> decryptResult = crypto.decryptString(getProvider(), ciphertext); verify(decryptResult, context); return decryptResult.getResult(); }
private void verify(CryptoResult<?, KmsMasterKey> decryptResult, EncryptionContext context) { if (!decryptResult.getMasterKeyIds().get(0).equals(getKeyArn())) { throw new IllegalStateException("Wrong key id!"); } for (final Map.Entry<String, String> e : context.toMap().entrySet()) { if (!e.getValue().equals(decryptResult.getEncryptionContext().get(e.getKey()))) { throw new IllegalStateException("Wrong Encryption Context!"); } } }
@Test public void testMultipleKmsKeysSingleDecrypt() { final MockKMSClient kms = new MockKMSClient(); final String arn1 = kms.createKey().getKeyMetadata().getArn(); final String arn2 = kms.createKey().getKeyMetadata().getArn(); MasterKeyProvider<KmsMasterKey> prov = legacyConstruct(kms, arn1, arn2); KmsMasterKey mk1 = prov.getMasterKey(arn1); KmsMasterKey mk2 = prov.getMasterKey(arn2); AwsCrypto crypto = new AwsCrypto(); CryptoResult<byte[], KmsMasterKey> ct = crypto.encryptData(prov, PLAINTEXT); assertEquals(2, ct.getMasterKeyIds().size()); CryptoResult<byte[], KmsMasterKey> result = crypto.decryptData(mk1, ct.getResult()); assertArrayEquals(PLAINTEXT, result.getResult()); assertEquals(1, result.getMasterKeys().size()); assertEquals(mk1, result.getMasterKeys().get(0)); result = crypto.decryptData(mk2, ct.getResult()); assertArrayEquals(PLAINTEXT, result.getResult()); assertEquals(1, result.getMasterKeys().size()); assertEquals(mk2, result.getMasterKeys().get(0)); // Delete one of the two keys and ensure it's still decryptable kms.deleteKey(arn1); result = crypto.decryptData(prov, ct.getResult()); assertArrayEquals(PLAINTEXT, result.getResult()); // Only the first found key should be used assertEquals(1, result.getMasterKeys().size()); assertEquals(mk2, result.getMasterKeys().get(0)); }
@Test public void testMultipleRegionKmsKeys() { final MockKMSClient us_east_1 = new MockKMSClient(); us_east_1.setRegion(Region.getRegion(Regions.US_EAST_1)); final MockKMSClient eu_west_1 = new MockKMSClient(); eu_west_1.setRegion(Region.getRegion(Regions.EU_WEST_1)); final String arn1 = us_east_1.createKey().getKeyMetadata().getArn(); final String arn2 = eu_west_1.createKey().getKeyMetadata().getArn(); KmsMasterKeyProvider provE = legacyConstruct(us_east_1, Region.getRegion(Regions.US_EAST_1)); KmsMasterKeyProvider provW = legacyConstruct(eu_west_1, Region.getRegion(Regions.EU_WEST_1)); KmsMasterKey mk1 = provE.getMasterKey(arn1); KmsMasterKey mk2 = provW.getMasterKey(arn2); final MasterKeyProvider<KmsMasterKey> mkp = MultipleProviderFactory.buildMultiProvider(KmsMasterKey.class, mk1, mk2); AwsCrypto crypto = new AwsCrypto(); CryptoResult<byte[], KmsMasterKey> ct = crypto.encryptData(mkp, PLAINTEXT); assertEquals(2, ct.getMasterKeyIds().size()); CryptoResult<byte[], KmsMasterKey> result = crypto.decryptData(mk1, ct.getResult()); assertArrayEquals(PLAINTEXT, result.getResult()); assertEquals(1, result.getMasterKeys().size()); assertEquals(mk1, result.getMasterKeys().get(0)); result = crypto.decryptData(mk2, ct.getResult()); assertArrayEquals(PLAINTEXT, result.getResult()); assertEquals(1, result.getMasterKeys().size()); assertEquals(mk2, result.getMasterKeys().get(0)); assertMultiReturnsKeys(mkp, mk1, mk2); // Delete one of the two keys and ensure it's still decryptable us_east_1.deleteKey(arn1); result = crypto.decryptData(mkp, ct.getResult()); assertArrayEquals(PLAINTEXT, result.getResult()); // Only the first found key should be used assertEquals(1, result.getMasterKeys().size()); assertEquals(mk2, result.getMasterKeys().get(0)); }
private void assertExplicitCredentialsUsed(final MasterKeyProvider<KmsMasterKey> mkp) { try { MasterKeyRequest mkr = MasterKeyRequest.newBuilder() .setEncryptionContext(Collections.emptyMap()) .setStreaming(true) .build(); mkp.getMasterKeysForEncryption(mkr) .forEach(mk -> mk.generateDataKey(ALG_AES_128_GCM_IV12_TAG16_NO_KDF, Collections.emptyMap())); fail("Expected exception"); } catch (UsedExplicitCredentials e) { // ok } }
public static void main(final String[] args) { keyArn = args[0]; data = args[1]; // Instantiate the SDK final AwsCrypto crypto = new AwsCrypto(); // Set up the KmsMasterKeyProvider backed by the default credentials final KmsMasterKeyProvider prov = new KmsMasterKeyProvider(keyArn); // Encrypt the data // // Most encrypted data should have an associated encryption context // to protect integrity. This sample uses placeholder values. // // For more information see: // blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management final Map<String, String> context = Collections.singletonMap("Example", "String"); final String ciphertext = crypto.encryptString(prov, data, context).getResult(); System.out.println("Ciphertext: " + ciphertext); // Decrypt the data final CryptoResult<String, KmsMasterKey> decryptResult = crypto.decryptString(prov, ciphertext); // Before returning the plaintext, verify that the customer master key that // was used in the encryption operation was the one supplied to the master key provider. if (!decryptResult.getMasterKeyIds().get(0).equals(keyArn)) { throw new IllegalStateException("Wrong key id!"); } // Also, verify that the encryption context in the result contains the // encryption context supplied to the encryptString method. Because the // SDK can add values to the encryption context, don't require that // the entire context matches. for (final Map.Entry<String, String> e : context.entrySet()) { if (!e.getValue().equals(decryptResult.getEncryptionContext().get(e.getKey()))) { throw new IllegalStateException("Wrong Encryption Context!"); } } // Now we can return the plaintext data System.out.println("Decrypted: " + decryptResult.getResult()); }
@Test public void testGrantTokenPassthrough_usingMKsetCall() throws Exception { MockKMSClient client = spy(new MockKMSClient()); RegionalClientSupplier supplier = mock(RegionalClientSupplier.class); when(supplier.getClient(any())).thenReturn(client); String key1 = client.createKey().getKeyMetadata().getArn(); String key2 = client.createKey().getKeyMetadata().getArn(); KmsMasterKeyProvider mkp0 = KmsMasterKeyProvider.builder() .withDefaultRegion("us-west-2") .withCustomClientFactory(supplier) .withKeysForEncryption(key1, key2) .build(); KmsMasterKey mk1 = mkp0.getMasterKey(key1); KmsMasterKey mk2 = mkp0.getMasterKey(key2); mk1.setGrantTokens(singletonList("foo")); mk2.setGrantTokens(singletonList("foo")); MasterKeyProvider<?> mkp = buildMultiProvider(mk1, mk2); byte[] ciphertext = new AwsCrypto().encryptData(mkp, new byte[0]).getResult(); ArgumentCaptor<GenerateDataKeyRequest> gdkr = ArgumentCaptor.forClass(GenerateDataKeyRequest.class); verify(client, times(1)).generateDataKey(gdkr.capture()); assertEquals(key1, gdkr.getValue().getKeyId()); assertEquals(1, gdkr.getValue().getGrantTokens().size()); assertEquals("foo", gdkr.getValue().getGrantTokens().get(0)); ArgumentCaptor<EncryptRequest> er = ArgumentCaptor.forClass(EncryptRequest.class); verify(client, times(1)).encrypt(er.capture()); assertEquals(key2, er.getValue().getKeyId()); assertEquals(1, er.getValue().getGrantTokens().size()); assertEquals("foo", er.getValue().getGrantTokens().get(0)); new AwsCrypto().decryptData(mkp, ciphertext); ArgumentCaptor<DecryptRequest> decrypt = ArgumentCaptor.forClass(DecryptRequest.class); verify(client, times(1)).decrypt(decrypt.capture()); assertEquals(1, decrypt.getValue().getGrantTokens().size()); assertEquals("foo", decrypt.getValue().getGrantTokens().get(0)); verify(supplier, atLeastOnce()).getClient("us-west-2"); verifyNoMoreInteractions(supplier); }