1
1
/*
2
- * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
5
5
* in compliance with the License. A copy of the License is located at
36
36
* <p>
37
37
* Arguments:
38
38
* <ol>
39
- * <li>KMS KeyArn
40
- * <li>File Name
39
+ * <li>Key ARN: For help finding the Amazon Resource Name (ARN) of your KMS customer master
40
+ * 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
41
43
* </ol>
42
44
*
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.
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
47
+ * demonstrates one way to do this.
48
+ *
49
+ * 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,
51
+ * at any time, you can use the private RSA key to decrypt the ciphertext independent of KMS.
52
+ *
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
55
+ * location, such as an offline HSM, and distribute the public key to your development team.
56
+ *
49
57
*/
50
58
public class EscrowedEncryptExample {
51
59
private static PublicKey publicEscrowKey ;
52
60
private static PrivateKey privateEscrowKey ;
53
61
54
62
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.
63
+ // 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.
57
66
generateEscrowKeyPair ();
58
67
59
68
final String kmsArn = args [0 ];
@@ -66,23 +75,25 @@ public static void main(final String[] args) throws Exception {
66
75
}
67
76
68
77
private static void standardEncrypt (final String kmsArn , final String fileName ) throws Exception {
69
- // Standard user encrypting to both KMS and the escrow public key
78
+ // Encrypt with the KMS CMK and the escrowed public key
70
79
// 1. Instantiate the SDK
71
80
final AwsCrypto crypto = new AwsCrypto ();
72
81
73
- // 2. Instantiate the providers
82
+ // 2. Instantiate a KMS master key provider
74
83
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"
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.
77
88
final JceMasterKey escrowPub = JceMasterKey .getInstance (publicEscrowKey , null , "Escrow" , "Escrow" ,
78
89
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding" );
79
90
80
- // 3 . Combine the providers into a single one
91
+ // 4 . Combine the providers into a single master key provider
81
92
final MasterKeyProvider <?> provider = MultipleProviderFactory .buildMultiProvider (kms , escrowPub );
82
93
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 .
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 .
86
97
final FileInputStream in = new FileInputStream (fileName );
87
98
final FileOutputStream out = new FileOutputStream (fileName + ".encrypted" );
88
99
final CryptoOutputStream <?> encryptingStream = crypto .createEncryptingStream (provider , out );
@@ -93,25 +104,27 @@ private static void standardEncrypt(final String kmsArn, final String fileName)
93
104
}
94
105
95
106
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 .
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 .
98
109
99
110
// 1. Instantiate the SDK
100
111
final AwsCrypto crypto = new AwsCrypto ();
101
112
102
- // 2. Instantiate the providers
113
+ // 2. Instantiate a KMS master key provider
103
114
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"
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.
106
119
final JceMasterKey escrowPub = JceMasterKey .getInstance (publicEscrowKey , null , "Escrow" , "Escrow" ,
107
120
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding" );
108
121
109
- // 3 . Combine the providers into a single one
122
+ // 4 . Combine the providers into a single master key provider
110
123
final MasterKeyProvider <?> provider = MultipleProviderFactory .buildMultiProvider (kms , escrowPub );
111
124
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 .
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 .
115
128
final FileInputStream in = new FileInputStream (fileName + ".encrypted" );
116
129
final FileOutputStream out = new FileOutputStream (fileName + ".decrypted" );
117
130
final CryptoOutputStream <?> decryptingStream = crypto .createDecryptingStream (provider , out );
@@ -121,19 +134,20 @@ private static void standardDecrypt(final String kmsArn, final String fileName)
121
134
}
122
135
123
136
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
137
+ // You can decrypt the stream using only the private key.
138
+ // This method does not call KMS.
125
139
126
140
// 1. Instantiate the SDK
127
141
final AwsCrypto crypto = new AwsCrypto ();
128
142
129
- // 2. Instantiate the provider
130
- // Note that the organization does have access to the private escrow key and can use it.
143
+ // 2. Instantiate a JCE master key provider
144
+ // This method call uses the escrowed private key, not null
131
145
final JceMasterKey escrowPriv = JceMasterKey .getInstance (publicEscrowKey , privateEscrowKey , "Escrow" , "Escrow" ,
132
146
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding" );
133
147
134
148
// 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 .
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 .
137
151
final FileInputStream in = new FileInputStream (fileName + ".encrypted" );
138
152
final FileOutputStream out = new FileOutputStream (fileName + ".deescrowed" );
139
153
final CryptoOutputStream <?> decryptingStream = crypto .createDecryptingStream (escrowPriv , out );
0 commit comments