Skip to content

Commit 63ff149

Browse files
Update example code to use keyrings
1 parent 6bb85a0 commit 63ff149

File tree

6 files changed

+300
-166
lines changed

6 files changed

+300
-166
lines changed

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

+35-19
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@
1919
import java.util.Map;
2020

2121
import com.amazonaws.encryptionsdk.AwsCrypto;
22-
import com.amazonaws.encryptionsdk.CryptoResult;
23-
import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
24-
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
22+
import com.amazonaws.encryptionsdk.AwsCrypto.AwsCryptoConfig;
23+
import com.amazonaws.encryptionsdk.AwsCryptoResult;
24+
import com.amazonaws.encryptionsdk.keyrings.Keyring;
25+
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
26+
import com.amazonaws.encryptionsdk.kms.KmsClientSupplier;
27+
28+
import static java.util.Collections.emptyList;
2529

2630
/**
2731
* <p>
@@ -48,32 +52,44 @@ static void encryptAndDecrypt(final String keyArn) {
4852
// 1. Instantiate the SDK
4953
final AwsCrypto crypto = new AwsCrypto();
5054

51-
// 2. Instantiate a KMS master key provider
52-
final KmsMasterKeyProvider masterKeyProvider = KmsMasterKeyProvider.builder().withKeysForEncryption(keyArn).build();
55+
// 2. Instantiate a KMS Client Supplier. This example uses the default client supplier but you can
56+
// also configure the credentials provider, client configuration and other settings as necessary
57+
final KmsClientSupplier clientSupplier = KmsClientSupplier.builder().build();
58+
59+
// 3. Instantiate a KMS Keyring, supplying the keyArn as the generator for generating a data key.
60+
// For this example, empty lists are provided for grant tokens and additional keys to encrypt the data
61+
// key with, but those can be supplied as necessary.
62+
final Keyring keyring = StandardKeyrings.kms(clientSupplier, emptyList(), emptyList(), keyArn);
5363

54-
// 3. Create an encryption context
64+
// 4. Create an encryption context
5565
//
56-
// Most encrypted data should have an associated encryption context
57-
// to protect integrity. This sample uses placeholder values.
66+
// Most encrypted data should have an associated encryption context
67+
// to protect integrity. This sample uses placeholder values.
5868
//
59-
// For more information see:
60-
// blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
69+
// For more information see:
70+
// blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
6171
final Map<String, String> encryptionContext = Collections.singletonMap("ExampleContextKey", "ExampleContextValue");
6272

63-
// 4. Encrypt the data
64-
final CryptoResult<byte[], KmsMasterKey> encryptResult = crypto.encryptData(masterKeyProvider, EXAMPLE_DATA, encryptionContext);
73+
// 5. Instantiate the AwsCryptoConfig input to AwsCrypto with the keyring and encryption context
74+
final AwsCryptoConfig config = AwsCryptoConfig.builder()
75+
.keyring(keyring)
76+
.encryptionContext(encryptionContext)
77+
.build();
78+
79+
// 6. Encrypt the data
80+
final AwsCryptoResult<byte[]> encryptResult = crypto.encryptData(config, EXAMPLE_DATA);
6581
final byte[] ciphertext = encryptResult.getResult();
6682

67-
// 5. Decrypt the data
68-
final CryptoResult<byte[], KmsMasterKey> decryptResult = crypto.decryptData(masterKeyProvider, ciphertext);
83+
// 7. Decrypt the data
84+
final AwsCryptoResult<byte[]> decryptResult = crypto.decryptData(config, ciphertext);
6985

70-
// 6. Before verifying the plaintext, verify that the customer master key that
71-
// was used in the encryption operation was the one supplied to the master key provider.
72-
if (!decryptResult.getMasterKeyIds().get(0).equals(keyArn)) {
86+
// 8. Before verifying the plaintext, verify that the key that was used in the encryption
87+
// operation was the one used during the decryption operation.
88+
if(!decryptResult.getKeyringTrace().getEntries().get(0).getKeyName().equals(keyArn)) {
7389
throw new IllegalStateException("Wrong key ID!");
7490
}
7591

76-
// 7. Also, verify that the encryption context in the result contains the
92+
// 9. Also, verify that the encryption context in the result contains the
7793
// encryption context supplied to the encryptData method. Because the
7894
// SDK can add values to the encryption context, don't require that
7995
// the entire context matches.
@@ -82,7 +98,7 @@ static void encryptAndDecrypt(final String keyArn) {
8298
throw new IllegalStateException("Wrong Encryption Context!");
8399
}
84100

85-
// 8. Verify that the decrypted plaintext matches the original plaintext
101+
// 10. Verify that the decrypted plaintext matches the original plaintext
86102
assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
87103
}
88104
}
Original file line numberDiff line numberDiff line change
@@ -1,168 +1,171 @@
11
/*
22
* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3-
*
3+
*
44
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
55
* in compliance with the License. A copy of the License is located at
6-
*
6+
*
77
* http://aws.amazon.com/apache2.0
8-
*
8+
*
99
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
1010
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
1111
* specific language governing permissions and limitations under the License.
1212
*/
1313

1414
package com.amazonaws.crypto.examples;
1515

16-
import java.io.FileInputStream;
17-
import java.io.FileOutputStream;
16+
import com.amazonaws.encryptionsdk.AwsCrypto;
17+
import com.amazonaws.encryptionsdk.keyrings.Keyring;
18+
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;
19+
import com.amazonaws.encryptionsdk.kms.KmsClientSupplier;
20+
21+
import java.nio.charset.StandardCharsets;
1822
import java.security.GeneralSecurityException;
1923
import java.security.KeyPair;
2024
import java.security.KeyPairGenerator;
2125
import java.security.PrivateKey;
2226
import java.security.PublicKey;
27+
import java.util.Arrays;
2328

24-
import com.amazonaws.encryptionsdk.AwsCrypto;
25-
import com.amazonaws.encryptionsdk.CryptoOutputStream;
26-
import com.amazonaws.encryptionsdk.MasterKeyProvider;
27-
import com.amazonaws.encryptionsdk.jce.JceMasterKey;
28-
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
29-
import com.amazonaws.encryptionsdk.multi.MultipleProviderFactory;
30-
import com.amazonaws.util.IOUtils;
29+
import static java.util.Collections.emptyList;
3130

3231
/**
3332
* <p>
34-
* Encrypts a file using both KMS and an asymmetric key pair.
33+
* Encrypts data using both KMS and an asymmetric key pair.
3534
*
3635
* <p>
3736
* Arguments:
3837
* <ol>
39-
* <li>Key ARN: For help finding the Amazon Resource Name (ARN) of your KMS customer master
38+
* <li>Key ARN: For help finding the Amazon Resource Name (ARN) of your KMS customer master
4039
* key (CMK), see 'Viewing Keys' at http://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html
41-
*
42-
* <li>Name of file containing plaintext data to encrypt
4340
* </ol>
4441
*
45-
* You might use AWS Key Management Service (KMS) for most encryption and decryption operations, but
46-
* still want the option of decrypting your data offline independently of KMS. This sample
42+
* You might use AWS Key Management Service (KMS) for most encryption and decryption operations, but
43+
* still want the option of decrypting your data offline independently of KMS. This sample
4744
* demonstrates one way to do this.
48-
*
45+
*
4946
* The sample encrypts data under both a KMS customer master key (CMK) and an "escrowed" RSA key pair
50-
* so that either key alone can decrypt it. You might commonly use the KMS CMK for decryption. However,
47+
* so that either key alone can decrypt it. You might commonly use the KMS CMK for decryption. However,
5148
* at any time, you can use the private RSA key to decrypt the ciphertext independent of KMS.
5249
*
53-
* This sample uses the JCEMasterKey class to generate a RSA public-private key pair
54-
* and saves the key pair in memory. In practice, you would store the private key in a secure offline
50+
* This sample uses an RawRsaKeyring to generate a RSA public-private key pair
51+
* and saves the key pair in memory. In practice, you would store the private key in a secure offline
5552
* location, such as an offline HSM, and distribute the public key to your development team.
5653
*
5754
*/
5855
public class EscrowedEncryptExample {
59-
private static PublicKey publicEscrowKey;
60-
private static PrivateKey privateEscrowKey;
56+
private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);
57+
58+
public static void main(final String[] args) throws GeneralSecurityException {
59+
final String kmsArn = args[0];
6160

62-
public static void main(final String[] args) throws Exception {
61+
escrowEncryptAndDecrypt(kmsArn);
62+
}
63+
64+
static void escrowEncryptAndDecrypt(String kmsArn) throws GeneralSecurityException {
6365
// This sample generates a new random key for each operation.
64-
// In practice, you would distribute the public key and save the private key in secure
65-
// storage.
66-
generateEscrowKeyPair();
66+
// In practice, you would distribute the public key and save the private key in secure storage.
67+
final KeyPair escrowKeyPair = generateEscrowKeyPair();
6768

68-
final String kmsArn = args[0];
69-
final String fileName = args[1];
69+
// Encrypt the data under both a KMS Key and an escrowed RSA Key
70+
byte[] encryptedData = standardEncrypt(kmsArn, escrowKeyPair.getPublic());
7071

71-
standardEncrypt(kmsArn, fileName);
72-
standardDecrypt(kmsArn, fileName);
72+
// Decrypt the data using the KMS Key
73+
byte[] standardDecryptedData = standardDecrypt(kmsArn, encryptedData);
7374

74-
escrowDecrypt(fileName);
75+
// Decrypt the data using the escrowed RSA Key
76+
byte[] escrowedDecryptedData = escrowDecrypt(encryptedData, escrowKeyPair.getPublic(), escrowKeyPair.getPrivate());
77+
78+
// Verify both decrypted data instances are the same as the original plaintext
79+
assert Arrays.equals(standardDecryptedData, EXAMPLE_DATA);
80+
assert Arrays.equals(escrowedDecryptedData, EXAMPLE_DATA);
7581
}
7682

77-
private static void standardEncrypt(final String kmsArn, final String fileName) throws Exception {
83+
private static byte[] standardEncrypt(final String kmsArn, final PublicKey publicEscrowKey) {
7884
// Encrypt with the KMS CMK and the escrowed public key
85+
7986
// 1. Instantiate the SDK
8087
final AwsCrypto crypto = new AwsCrypto();
8188

82-
// 2. Instantiate a KMS master key provider
83-
final KmsMasterKeyProvider kms = new KmsMasterKeyProvider(kmsArn);
84-
85-
// 3. Instantiate a JCE master key provider
86-
// Because the user does not have access to the private escrow key,
87-
// they pass in "null" for the private key parameter.
88-
final JceMasterKey escrowPub = JceMasterKey.getInstance(publicEscrowKey, null, "Escrow", "Escrow",
89-
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
90-
91-
// 4. Combine the providers into a single master key provider
92-
final MasterKeyProvider<?> provider = MultipleProviderFactory.buildMultiProvider(kms, escrowPub);
93-
94-
// 5. Encrypt the file
95-
// To simplify the code, we omit the encryption context. Production code should always
96-
// use an encryption context. For an example, see the other SDK samples.
97-
final FileInputStream in = new FileInputStream(fileName);
98-
final FileOutputStream out = new FileOutputStream(fileName + ".encrypted");
99-
final CryptoOutputStream<?> encryptingStream = crypto.createEncryptingStream(provider, out);
100-
101-
IOUtils.copy(in, encryptingStream);
102-
in.close();
103-
encryptingStream.close();
89+
// 2. Instantiate a KMS Client Supplier. This example uses the default client supplier but you can
90+
// also configure the credentials provider, client configuration and other settings as necessary
91+
final KmsClientSupplier clientSupplier = KmsClientSupplier.builder().build();
92+
93+
// 3. Instantiate a KMS Keyring, supplying the keyArn as the generator for generating a data key.
94+
// For this example, empty lists are provided for grant tokens and additional keys to encrypt the data
95+
// key with, but those can be supplied as necessary.
96+
final Keyring kmsKeyring = StandardKeyrings.kms(clientSupplier, emptyList(), emptyList(), kmsArn);
97+
98+
// 4. Instantiate an RawRsaKeyring
99+
// Because the user does not have access to the private escrow key,
100+
// they pass in "null" for the private key parameter.
101+
final Keyring rsaKeyring = StandardKeyrings.rawRsa("Escrow", "Escrow",
102+
publicEscrowKey, null, "RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
103+
104+
// 5. Combine the providers into a single MultiKeyring
105+
final Keyring keyring = StandardKeyrings.multi(kmsKeyring, rsaKeyring);
106+
107+
// 6. Instantiate the AwsCryptoConfig input to AwsCrypto with the keyring
108+
// To simplify the code, we omit the encryption context. Production code should always
109+
// use an encryption context. For an example, see the other SDK samples.
110+
final AwsCrypto.AwsCryptoConfig config = AwsCrypto.AwsCryptoConfig.builder()
111+
.keyring(keyring)
112+
.build();
113+
114+
// 7. Encrypt the data
115+
return crypto.encryptData(config, EXAMPLE_DATA).getResult();
104116
}
105117

106-
private static void standardDecrypt(final String kmsArn, final String fileName) throws Exception {
107-
// Decrypt with the KMS CMK and the escrow public key. You can use a combined provider,
108-
// as shown here, or just the KMS master key provider.
118+
private static byte[] standardDecrypt(final String kmsArn, final byte[] cipherText) {
119+
// Decrypt with the KMS CMK
109120

110121
// 1. Instantiate the SDK
111122
final AwsCrypto crypto = new AwsCrypto();
112123

113-
// 2. Instantiate a KMS master key provider
114-
final KmsMasterKeyProvider kms = new KmsMasterKeyProvider(kmsArn);
115-
116-
// 3. Instantiate a JCE master key provider
117-
// Because the user does not have access to the private
118-
// escrow key, they pass in "null" for the private key parameter.
119-
final JceMasterKey escrowPub = JceMasterKey.getInstance(publicEscrowKey, null, "Escrow", "Escrow",
120-
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
121-
122-
// 4. Combine the providers into a single master key provider
123-
final MasterKeyProvider<?> provider = MultipleProviderFactory.buildMultiProvider(kms, escrowPub);
124-
125-
// 5. Decrypt the file
126-
// To simplify the code, we omit the encryption context. Production code should always
127-
// use an encryption context. For an example, see the other SDK samples.
128-
final FileInputStream in = new FileInputStream(fileName + ".encrypted");
129-
final FileOutputStream out = new FileOutputStream(fileName + ".decrypted");
130-
final CryptoOutputStream<?> decryptingStream = crypto.createDecryptingStream(provider, out);
131-
IOUtils.copy(in, decryptingStream);
132-
in.close();
133-
decryptingStream.close();
124+
// 2. Instantiate a KMS Client Supplier. This example uses the default client supplier but you can
125+
// also configure the credentials provider, client configuration and other settings as necessary
126+
final KmsClientSupplier clientSupplier = KmsClientSupplier.builder().build();
127+
128+
// 3. Instantiate a KMS Keyring, supplying the keyArn as the generator for generating a data key.
129+
// For this example, empty lists are provided for grant tokens and additional keys to encrypt the data
130+
// key with, but those can be supplied as necessary.
131+
final Keyring kmsKeyring = StandardKeyrings.kms(clientSupplier, emptyList(), emptyList(), kmsArn);
132+
133+
// 4. Instantiate the AwsCryptoConfig input to AwsCrypto with the keyring
134+
// To simplify the code, we omit the encryption context. Production code should always
135+
// use an encryption context. For an example, see the other SDK samples.
136+
final AwsCrypto.AwsCryptoConfig config = AwsCrypto.AwsCryptoConfig.builder()
137+
.keyring(kmsKeyring)
138+
.build();
139+
140+
// 5. Decrypt the data
141+
return crypto.decryptData(config, cipherText).getResult();
134142
}
135143

136-
private static void escrowDecrypt(final String fileName) throws Exception {
144+
private static byte[] escrowDecrypt(final byte[] cipherText, final PublicKey publicEscrowKey, final PrivateKey privateEscrowKey) {
137145
// You can decrypt the stream using only the private key.
138146
// This method does not call KMS.
139147

140148
// 1. Instantiate the SDK
141149
final AwsCrypto crypto = new AwsCrypto();
142150

143-
// 2. Instantiate a JCE master key provider
144-
// This method call uses the escrowed private key, not null
145-
final JceMasterKey escrowPriv = JceMasterKey.getInstance(publicEscrowKey, privateEscrowKey, "Escrow", "Escrow",
146-
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
147-
148-
// 3. Decrypt the file
149-
// To simplify the code, we omit the encryption context. Production code should always
150-
// use an encryption context. For an example, see the other SDK samples.
151-
final FileInputStream in = new FileInputStream(fileName + ".encrypted");
152-
final FileOutputStream out = new FileOutputStream(fileName + ".deescrowed");
153-
final CryptoOutputStream<?> decryptingStream = crypto.createDecryptingStream(escrowPriv, out);
154-
IOUtils.copy(in, decryptingStream);
155-
in.close();
156-
decryptingStream.close();
151+
// 2. Instantiate a RawRsaKeyring using the escrowed private key
152+
final Keyring rsaKeyring = StandardKeyrings.rawRsa("Escrow", "Escrow",
153+
publicEscrowKey, privateEscrowKey, "RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
157154

155+
// 3. Instantiate the AwsCryptoConfig input to AwsCrypto with the keyring
156+
// To simplify the code, we omit the encryption context. Production code should always
157+
// use an encryption context. For an example, see the other SDK samples.
158+
final AwsCrypto.AwsCryptoConfig config = AwsCrypto.AwsCryptoConfig.builder()
159+
.keyring(rsaKeyring)
160+
.build();
161+
162+
// 4. Decrypt the data
163+
return crypto.decryptData(config, cipherText).getResult();
158164
}
159165

160-
private static void generateEscrowKeyPair() throws GeneralSecurityException {
166+
private static KeyPair generateEscrowKeyPair() throws GeneralSecurityException {
161167
final KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA");
162168
kg.initialize(4096); // Escrow keys should be very strong
163-
final KeyPair keyPair = kg.generateKeyPair();
164-
publicEscrowKey = keyPair.getPublic();
165-
privateEscrowKey = keyPair.getPrivate();
166-
169+
return kg.generateKeyPair();
167170
}
168171
}

0 commit comments

Comments
 (0)