Skip to content

Commit 1b1813d

Browse files
Adding example code
1 parent 8d9ae5d commit 1b1813d

File tree

3 files changed

+335
-0
lines changed

3 files changed

+335
-0
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright 2016 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 java.io.FileInputStream;
17+
import java.io.FileOutputStream;
18+
import java.security.GeneralSecurityException;
19+
import java.security.KeyPair;
20+
import java.security.KeyPairGenerator;
21+
import java.security.PrivateKey;
22+
import java.security.PublicKey;
23+
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;
31+
32+
/**
33+
* <p>
34+
* Encrypts a file using both KMS and an asymmetric key pair.
35+
*
36+
* <p>
37+
* Arguments:
38+
* <ol>
39+
* <li>KMS KeyArn
40+
* <li>File Name
41+
* </ol>
42+
*
43+
* Some organizations want the ability to decrypt their data even if KMS is unavailable. This
44+
* program demonstrates one possible way of accomplishing this by generating an "Escrow" RSA
45+
* key-pair and using that in addition to the KMS key for encryption. The organization would keep
46+
* the RSA private key someplace secure (such as an offline HSM) and distribute the public key their
47+
* developers. This way all standard use would use KMS for decryption, however the organization
48+
* maintains the ability to decrypt all ciphertexts in a completely offline manner.
49+
*/
50+
public class EscrowedEncryptExample {
51+
private static PublicKey publicEscrowKey;
52+
private static PrivateKey privateEscrowKey;
53+
54+
public static void main(final String[] args) throws Exception {
55+
// In the real world, the public key would be distributed by the organization.
56+
// For this demo, we'll just generate a new random one each time.
57+
generateEscrowKeyPair();
58+
59+
final String kmsArn = args[0];
60+
final String fileName = args[1];
61+
62+
standardEncrypt(kmsArn, fileName);
63+
standardDecrypt(kmsArn, fileName);
64+
65+
escrowDecrypt(fileName);
66+
}
67+
68+
private static void standardEncrypt(final String kmsArn, final String fileName) throws Exception {
69+
// Standard user encrypting to both KMS and the escrow public key
70+
// 1. Instantiate the SDK
71+
final AwsCrypto crypto = new AwsCrypto();
72+
73+
// 2. Instantiate the providers
74+
final KmsMasterKeyProvider kms = new KmsMasterKeyProvider(kmsArn);
75+
// Note that the standard user does not have access to the private escrow
76+
// key and so simply passes in "null"
77+
final JceMasterKey escrowPub = JceMasterKey.getInstance(publicEscrowKey, null, "Escrow", "Escrow",
78+
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
79+
80+
// 3. Combine the providers into a single one
81+
final MasterKeyProvider<?> provider = MultipleProviderFactory.buildMultiProvider(kms, escrowPub);
82+
83+
// 4. Encrypt the file
84+
// To simplify the code, we'll be omitted Encryption Context this time. Production code
85+
// should always use Encryption Context. Please see the other examples for more information.
86+
final FileInputStream in = new FileInputStream(fileName);
87+
final FileOutputStream out = new FileOutputStream(fileName + ".encrypted");
88+
final CryptoOutputStream<?> encryptingStream = crypto.createEncryptingStream(provider, out);
89+
90+
IOUtils.copy(in, encryptingStream);
91+
in.close();
92+
encryptingStream.close();
93+
}
94+
95+
private static void standardDecrypt(final String kmsArn, final String fileName) throws Exception {
96+
// A standard user decrypts the file. They can just use the same provider from before
97+
// or could use a provider just referring to the KMS key. It doesn't matter.
98+
99+
// 1. Instantiate the SDK
100+
final AwsCrypto crypto = new AwsCrypto();
101+
102+
// 2. Instantiate the providers
103+
final KmsMasterKeyProvider kms = new KmsMasterKeyProvider(kmsArn);
104+
// Note that the standard user does not have access to the private escrow
105+
// key and so simply passes in "null"
106+
final JceMasterKey escrowPub = JceMasterKey.getInstance(publicEscrowKey, null, "Escrow", "Escrow",
107+
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
108+
109+
// 3. Combine the providers into a single one
110+
final MasterKeyProvider<?> provider = MultipleProviderFactory.buildMultiProvider(kms, escrowPub);
111+
112+
// 4. Decrypt the file
113+
// To simplify the code, we'll be omitted Encryption Context this time. Production code
114+
// should always use Encryption Context. Please see the other examples for more information.
115+
final FileInputStream in = new FileInputStream(fileName + ".encrypted");
116+
final FileOutputStream out = new FileOutputStream(fileName + ".decrypted");
117+
final CryptoOutputStream<?> decryptingStream = crypto.createDecryptingStream(provider, out);
118+
IOUtils.copy(in, decryptingStream);
119+
in.close();
120+
decryptingStream.close();
121+
}
122+
123+
private static void escrowDecrypt(final String fileName) throws Exception {
124+
// The organization can decrypt using just the private escrow key with no calls to KMS
125+
126+
// 1. Instantiate the SDK
127+
final AwsCrypto crypto = new AwsCrypto();
128+
129+
// 2. Instantiate the provider
130+
// Note that the organization does have access to the private escrow key and can use it.
131+
final JceMasterKey escrowPriv = JceMasterKey.getInstance(publicEscrowKey, privateEscrowKey, "Escrow", "Escrow",
132+
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
133+
134+
// 3. Decrypt the file
135+
// To simplify the code, we'll be omitted Encryption Context this time. Production code
136+
// should always use Encryption Context. Please see the other examples for more information.
137+
final FileInputStream in = new FileInputStream(fileName + ".encrypted");
138+
final FileOutputStream out = new FileOutputStream(fileName + ".deescrowed");
139+
final CryptoOutputStream<?> decryptingStream = crypto.createDecryptingStream(escrowPriv, out);
140+
IOUtils.copy(in, decryptingStream);
141+
in.close();
142+
decryptingStream.close();
143+
144+
}
145+
146+
private static void generateEscrowKeyPair() throws GeneralSecurityException {
147+
final KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA");
148+
kg.initialize(4096); // Escrow keys should be very strong
149+
final KeyPair keyPair = kg.generateKeyPair();
150+
publicEscrowKey = keyPair.getPublic();
151+
privateEscrowKey = keyPair.getPrivate();
152+
153+
}
154+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2016 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 java.io.FileInputStream;
17+
import java.io.FileOutputStream;
18+
import java.io.IOException;
19+
import java.security.SecureRandom;
20+
import java.util.Collections;
21+
import java.util.Map;
22+
23+
import javax.crypto.SecretKey;
24+
import javax.crypto.spec.SecretKeySpec;
25+
26+
import com.amazonaws.encryptionsdk.AwsCrypto;
27+
import com.amazonaws.encryptionsdk.CryptoInputStream;
28+
import com.amazonaws.encryptionsdk.MasterKey;
29+
import com.amazonaws.encryptionsdk.jce.JceMasterKey;
30+
import com.amazonaws.util.IOUtils;
31+
32+
/**
33+
* <p>
34+
* Encrypts and then decrypts a file under a random key.
35+
*
36+
* <p>
37+
* Arguments:
38+
* <ol>
39+
* <li>fileName
40+
* </ol>
41+
*
42+
* <p>
43+
* This program demonstrates using a normal java {@link SecretKey} object as a {@link MasterKey} to
44+
* encrypt and decrypt streaming data.
45+
*/
46+
public class FileStreamingExample {
47+
private static String srcFile;
48+
49+
public static void main(String[] args) throws IOException {
50+
srcFile = args[0];
51+
52+
// In this example, we'll pretend that we loaded this key from
53+
// some existing store but actually just generate a random one
54+
SecretKey cryptoKey = retrieveEncryptionKey();
55+
56+
// Convert key into a provider. We'll use AES GCM because it is
57+
// a good secure algorithm.
58+
JceMasterKey masterKey = JceMasterKey.getInstance(cryptoKey, "Example", "RandomKey", "AES/GCM/NoPadding");
59+
60+
// Instantiate the SDKs
61+
AwsCrypto crypto = new AwsCrypto();
62+
63+
// Create the encryption context to identify this ciphertext
64+
Map<String, String> context = Collections.singletonMap("Example", "FileStreaming");
65+
66+
// The file might be *really* big, so we don't want
67+
// to load it all into memory. Streaming is necessary.
68+
FileInputStream in = new FileInputStream(srcFile);
69+
CryptoInputStream<JceMasterKey> encryptingStream = crypto.createEncryptingStream(masterKey, in, context);
70+
71+
FileOutputStream out = new FileOutputStream(srcFile + ".encrypted");
72+
IOUtils.copy(encryptingStream, out);
73+
encryptingStream.close();
74+
out.close();
75+
76+
// Let's decrypt the file now, remembering to check the encryption context
77+
in = new FileInputStream(srcFile + ".encrypted");
78+
CryptoInputStream<JceMasterKey> decryptingStream = crypto.createDecryptingStream(masterKey, in);
79+
// Does it have the right encryption context?
80+
if (!"FileStreaming".equals(decryptingStream.getCryptoResult().getEncryptionContext().get("Example"))) {
81+
throw new IllegalStateException("Bad encryption context");
82+
}
83+
84+
// Finally, actually write out the data
85+
out = new FileOutputStream(srcFile + ".decrypted");
86+
IOUtils.copy(decryptingStream, out);
87+
decryptingStream.close();
88+
out.close();
89+
}
90+
91+
/**
92+
* In the real world, this key will need to be persisted somewhere. For this demo we'll generate
93+
* a new random one each time.
94+
*/
95+
private static SecretKey retrieveEncryptionKey() {
96+
SecureRandom rnd = new SecureRandom();
97+
byte[] rawKey = new byte[16]; // 128 bits
98+
rnd.nextBytes(rawKey);
99+
return new SecretKeySpec(rawKey, "AES");
100+
}
101+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2016 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 java.util.Collections;
17+
import java.util.Map;
18+
19+
import com.amazonaws.encryptionsdk.AwsCrypto;
20+
import com.amazonaws.encryptionsdk.CryptoResult;
21+
import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
22+
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;
23+
24+
/**
25+
* <p>
26+
* Encrypts and then decrypts a string under a KMS key
27+
*
28+
* <p>
29+
* Arguments:
30+
* <ol>
31+
* <li>KMS Key Arn
32+
* <li>String to encrypt
33+
* </ol>
34+
*/
35+
public class StringExample {
36+
private static String keyArn;
37+
private static String data;
38+
39+
public static void main(final String[] args) {
40+
keyArn = args[0];
41+
data = args[1];
42+
43+
// Instantiate the SDK
44+
final AwsCrypto crypto = new AwsCrypto();
45+
46+
// Set up the KmsMasterKeyProvider backed by the default credentials
47+
final KmsMasterKeyProvider prov = new KmsMasterKeyProvider(keyArn);
48+
49+
// Encrypt the data
50+
//
51+
// Most encrypted data should have associated encryption context
52+
// to protect integrity. Here, we'll just use a placeholder value.
53+
//
54+
// For more information see:
55+
// blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
56+
final Map<String, String> context = Collections.singletonMap("Example", "String");
57+
58+
final String ciphertext = crypto.encryptString(prov, data, context).getResult();
59+
System.out.println("Ciphertext: " + ciphertext);
60+
61+
// Decrypt the data
62+
final CryptoResult<String, KmsMasterKey> decryptResult = crypto.decryptString(prov, ciphertext);
63+
// We need to check the encryption context (and ideally key) to ensure that
64+
// this was the ciphertext we expected
65+
if (!decryptResult.getMasterKeyIds().get(0).equals(keyArn)) {
66+
throw new IllegalStateException("Wrong key id!");
67+
}
68+
69+
// The SDK may add information to the encryption context, so we check to ensure
70+
// that all of our values are present
71+
for (final Map.Entry<String, String> e : context.entrySet()) {
72+
if (!e.getValue().equals(decryptResult.getEncryptionContext().get(e.getKey()))) {
73+
throw new IllegalStateException("Wrong Encryption Context!");
74+
}
75+
}
76+
77+
// Now that we know we have the correct data, we can output it.
78+
System.out.println("Decrypted: " + decryptResult.getResult());
79+
}
80+
}

0 commit comments

Comments
 (0)