Skip to content

Commit 6e33ad5

Browse files
Additional example code for Keyrings
1 parent 876dd5e commit 6e33ad5

10 files changed

+570
-1
lines changed

pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,19 @@
8080
<scope>test</scope>
8181
</dependency>
8282

83+
<dependency>
84+
<groupId>com.amazonaws</groupId>
85+
<artifactId>aws-lambda-java-core</artifactId>
86+
<version>1.2.0</version>
87+
<scope>test</scope>
88+
</dependency>
89+
90+
<dependency>
91+
<groupId>com.amazonaws</groupId>
92+
<artifactId>aws-lambda-java-events</artifactId>
93+
<version>2.2.7</version>
94+
<scope>test</scope>
95+
</dependency>
8396

8497
<dependency>
8598
<groupId>com.google.code.findbugs</groupId>

src/examples/java/com/amazonaws/crypto/examples/BasicEncryptionExample.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ static void encryptAndDecrypt(final AwsKmsCmkId keyArn) {
8585
}
8686

8787
// 7. Also, verify that the encryption context in the result contains the
88-
// encryption context supplied to the encryptData method. Because the
88+
// encryption context supplied to the encrypt method. Because the
8989
// SDK can add values to the encryption context, don't require that
9090
// the entire context matches.
9191
if (!encryptionContext.entrySet().stream()
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
5+
* in compliance with the License. A copy of the License is located at
6+
*
7+
* http://aws.amazon.com/apache2.0
8+
*
9+
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package com.amazonaws.crypto.examples;
15+
16+
import com.amazonaws.encryptionsdk.AwsCrypto;
17+
import com.amazonaws.encryptionsdk.AwsCryptoResult;
18+
import com.amazonaws.encryptionsdk.DecryptRequest;
19+
import com.amazonaws.encryptionsdk.EncryptRequest;
20+
import com.amazonaws.encryptionsdk.keyrings.Keyring;
21+
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
22+
23+
import javax.crypto.SecretKey;
24+
import javax.crypto.spec.SecretKeySpec;
25+
import java.nio.charset.StandardCharsets;
26+
import java.security.SecureRandom;
27+
import java.util.Arrays;
28+
import java.util.Collections;
29+
import java.util.Map;
30+
31+
/**
32+
* <p>
33+
* Encrypts and then decrypts data using the Raw AES Keyring.
34+
*/
35+
public class RawAesKeyringExample {
36+
37+
private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
38+
39+
public static void main(final String[] args) {
40+
encryptAndDecrypt();
41+
}
42+
43+
static void encryptAndDecrypt() {
44+
// 1. Instantiate the SDK
45+
final AwsCrypto crypto = new AwsCrypto();
46+
47+
// 2. Retrieve an encryption key. In this example, we generate a random key.
48+
// In practice, you would get a key from an existing store
49+
final SecretKey cryptoKey = retrieveEncryptionKey();
50+
51+
// 3. Instantiate a Raw AES Keyring with the encryption key
52+
final Keyring keyring = StandardKeyrings.rawAes()
53+
.keyNamespace("ExampleKeyNamespace")
54+
.keyName("ExampleKeyName")
55+
.wrappingKey(cryptoKey).build();
56+
57+
// 4. Create an encryption context
58+
//
59+
// Most encrypted data should have an associated encryption context
60+
// to protect integrity. This sample uses placeholder values.
61+
//
62+
// For more information see:
63+
// blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
64+
final Map<String, String> encryptionContext = Collections.singletonMap("ExampleContextKey", "ExampleContextValue");
65+
66+
// 5. Encrypt the data with the keyring and encryption context
67+
final AwsCryptoResult<byte[]> encryptResult = crypto.encrypt(EncryptRequest.builder()
68+
.keyring(keyring)
69+
.encryptionContext(encryptionContext)
70+
.plaintext(EXAMPLE_DATA).build());
71+
final byte[] ciphertext = encryptResult.getResult();
72+
73+
// 6. Decrypt the data
74+
final AwsCryptoResult<byte[]> decryptResult = crypto.decrypt(DecryptRequest.builder()
75+
.keyring(keyring)
76+
.ciphertext(ciphertext).build());
77+
78+
// 7. Before verifying the plaintext, verify that the key that was used in the encryption
79+
// operation was the one used during the decryption operation.
80+
if (!decryptResult.getKeyringTrace().getEntries().get(0).getKeyName().equals("ExampleKeyName")) {
81+
throw new IllegalStateException("Wrong key ID!");
82+
}
83+
84+
// 8. Also, verify that the encryption context in the result contains the
85+
// encryption context supplied to the encrypt method. Because the
86+
// SDK can add values to the encryption context, don't require that
87+
// the entire context matches.
88+
if (!encryptionContext.entrySet().stream()
89+
.allMatch(e -> e.getValue().equals(decryptResult.getEncryptionContext().get(e.getKey())))) {
90+
throw new IllegalStateException("Wrong Encryption Context!");
91+
}
92+
93+
// 9. Verify that the decrypted plaintext matches the original plaintext
94+
assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
95+
}
96+
97+
/**
98+
* In practice, this key would be saved in a secure location.
99+
* For this demo, we generate a new random key for each operation.
100+
*/
101+
private static SecretKey retrieveEncryptionKey() {
102+
SecureRandom rnd = new SecureRandom();
103+
byte[] rawKey = new byte[16]; // 128 bits
104+
rnd.nextBytes(rawKey);
105+
return new SecretKeySpec(rawKey, "AES");
106+
}
107+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
5+
* in compliance with the License. A copy of the License is located at
6+
*
7+
* http://aws.amazon.com/apache2.0
8+
*
9+
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package com.amazonaws.crypto.examples;
15+
16+
import com.amazonaws.encryptionsdk.AwsCrypto;
17+
import com.amazonaws.encryptionsdk.AwsCryptoResult;
18+
import com.amazonaws.encryptionsdk.DecryptRequest;
19+
import com.amazonaws.encryptionsdk.keyrings.Keyring;
20+
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
21+
22+
import java.security.KeyPair;
23+
24+
/**
25+
* <p>
26+
* Decrypts data using the Raw RSA Keyring.
27+
*/
28+
public class RawRsaKeyringDecryptExample {
29+
30+
public static byte[] decrypt(byte[] ciphertext, KeyPair keyPair) {
31+
// 1. Instantiate the SDK
32+
final AwsCrypto crypto = new AwsCrypto();
33+
34+
// 2. Instantiate a Raw RSA Keyring with the private key
35+
final Keyring keyring = StandardKeyrings.rawRsa()
36+
.keyNamespace("ExampleKeyNamespace")
37+
.keyName("ExampleKeyName")
38+
.wrappingAlgorithm("RSA/ECB/OAEPWithSHA-512AndMGF1Padding")
39+
.privateKey(keyPair.getPrivate()).build();
40+
41+
// 3. Decrypt the ciphertext with the keyring
42+
final AwsCryptoResult<byte[]> decryptResult = crypto.decrypt(DecryptRequest.builder()
43+
.keyring(keyring)
44+
.ciphertext(ciphertext).build());
45+
46+
// 4. Return the decrypted byte array result
47+
return decryptResult.getResult();
48+
}
49+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
5+
* in compliance with the License. A copy of the License is located at
6+
*
7+
* http://aws.amazon.com/apache2.0
8+
*
9+
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package com.amazonaws.crypto.examples;
15+
16+
import com.amazonaws.encryptionsdk.AwsCrypto;
17+
import com.amazonaws.encryptionsdk.AwsCryptoResult;
18+
import com.amazonaws.encryptionsdk.EncryptRequest;
19+
import com.amazonaws.encryptionsdk.keyrings.Keyring;
20+
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
21+
22+
import java.nio.charset.StandardCharsets;
23+
import java.security.PublicKey;
24+
import java.util.Collections;
25+
import java.util.Map;
26+
27+
/**
28+
* Encrypts data using the Raw RSA Keyring.
29+
*/
30+
public class RawRsaKeyringEncryptExample {
31+
32+
static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
33+
34+
public static byte[] encrypt(PublicKey publicKey) {
35+
// 1. Instantiate the SDK
36+
final AwsCrypto crypto = new AwsCrypto();
37+
38+
// 2. Instantiate a Raw RSA Keyring with the public key
39+
final Keyring keyring = StandardKeyrings.rawRsa()
40+
.keyNamespace("ExampleKeyNamespace")
41+
.keyName("ExampleKeyName")
42+
.wrappingAlgorithm("RSA/ECB/OAEPWithSHA-512AndMGF1Padding")
43+
.publicKey(publicKey).build();
44+
45+
// 3. Create an encryption context
46+
//
47+
// Most encrypted data should have an associated encryption context
48+
// to protect integrity. This sample uses placeholder values.
49+
//
50+
// For more information see:
51+
// blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
52+
final Map<String, String> encryptionContext = Collections.singletonMap("ExampleContextKey", "ExampleContextValue");
53+
54+
// 4. Encrypt the data with the keyring and encryption context
55+
final AwsCryptoResult<byte[]> encryptResult = crypto.encrypt(EncryptRequest.builder()
56+
.keyring(keyring)
57+
.encryptionContext(encryptionContext)
58+
.plaintext(EXAMPLE_DATA).build());
59+
60+
// 5. Return the encrypted byte array result
61+
return encryptResult.getResult();
62+
}
63+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
5+
* in compliance with the License. A copy of the License is located at
6+
*
7+
* http://aws.amazon.com/apache2.0
8+
*
9+
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package com.amazonaws.crypto.examples.datakeycaching;
15+
16+
import java.nio.ByteBuffer;
17+
import java.nio.charset.StandardCharsets;
18+
import java.util.concurrent.TimeUnit;
19+
20+
import com.amazonaws.encryptionsdk.AwsCrypto;
21+
import com.amazonaws.encryptionsdk.AwsCryptoResult;
22+
import com.amazonaws.encryptionsdk.DecryptRequest;
23+
import com.amazonaws.encryptionsdk.caching.CachingCryptoMaterialsManager;
24+
import com.amazonaws.encryptionsdk.caching.LocalCryptoMaterialsCache;
25+
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
26+
import com.amazonaws.encryptionsdk.kms.AwsKmsCmkId;
27+
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
28+
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
29+
import com.amazonaws.services.dynamodbv2.document.Item;
30+
import com.amazonaws.services.dynamodbv2.document.Table;
31+
import com.amazonaws.services.lambda.runtime.Context;
32+
import com.amazonaws.services.lambda.runtime.RequestHandler;
33+
import com.amazonaws.services.lambda.runtime.events.KinesisEvent;
34+
import com.amazonaws.services.lambda.runtime.events.KinesisEvent.KinesisEventRecord;
35+
import com.amazonaws.util.BinaryUtils;
36+
37+
/**
38+
* Decrypts all incoming Kinesis records and writes records to DynamoDB.
39+
*/
40+
public class LambdaDecryptAndWriteExample implements RequestHandler<KinesisEvent, Void> {
41+
private static final long MAX_ENTRY_AGE_MILLISECONDS = 600000;
42+
private static final int MAX_CACHE_ENTRIES = 100;
43+
private final CachingCryptoMaterialsManager cachingMaterialsManager_;
44+
private final AwsCrypto crypto_;
45+
private final Table table_;
46+
47+
/**
48+
* Because the cache is used only for decryption, the code doesn't set
49+
* the max bytes or max message security thresholds that are enforced
50+
* only on on data keys used for encryption.
51+
*
52+
* @param cmkArn The AWS KMS customer master key to use for decryption
53+
* @param tableName The DynamoDB table name to store decrypted messages in
54+
*/
55+
public LambdaDecryptAndWriteExample(final String cmkArn, final String tableName) {
56+
cachingMaterialsManager_ = CachingCryptoMaterialsManager.newBuilder()
57+
.withKeyring(StandardKeyrings.awsKms(AwsKmsCmkId.fromString(cmkArn)))
58+
.withCache(new LocalCryptoMaterialsCache(MAX_CACHE_ENTRIES))
59+
.withMaxAge(MAX_ENTRY_AGE_MILLISECONDS, TimeUnit.MILLISECONDS)
60+
.build();
61+
crypto_ = new AwsCrypto();
62+
table_ = new DynamoDB(AmazonDynamoDBClientBuilder.defaultClient()).getTable(tableName);
63+
}
64+
65+
/**
66+
* Decrypts Kinesis events and writes the data to DynamoDB
67+
*
68+
* @param event The KinesisEvent to decrypt
69+
* @param context The lambda context
70+
*/
71+
@Override
72+
public Void handleRequest(KinesisEvent event, Context context) {
73+
for (KinesisEventRecord record : event.getRecords()) {
74+
ByteBuffer ciphertextBuffer = record.getKinesis().getData();
75+
byte[] ciphertext = BinaryUtils.copyAllBytesFrom(ciphertextBuffer);
76+
77+
// Decrypt and unpack record
78+
AwsCryptoResult<byte[]> plaintextResult = crypto_.decrypt(
79+
DecryptRequest.builder()
80+
.cryptoMaterialsManager(cachingMaterialsManager_)
81+
.ciphertext(ciphertext).build());
82+
83+
// Verify the encryption context value
84+
String streamArn = record.getEventSourceARN();
85+
String streamName = streamArn.substring(streamArn.indexOf("/") + 1);
86+
if (!streamName.equals(plaintextResult.getEncryptionContext().get("stream"))) {
87+
throw new IllegalStateException("Wrong Encryption Context!");
88+
}
89+
90+
// Write record to DynamoDB
91+
String jsonItem = new String(plaintextResult.getResult(), StandardCharsets.UTF_8);
92+
table_.putItem(Item.fromJSON(jsonItem));
93+
}
94+
95+
return null;
96+
}
97+
}

0 commit comments

Comments
 (0)