-
Notifications
You must be signed in to change notification settings - Fork 121
Incorporate Keyrings into AwsCrypto and deprecate MasterKeyProviders. #151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 9 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
6bb85a0
Incorporate Keyrings into AwsCrypto and deprecate MasterKeyProviders.
WesleyRosenblum 63ff149
Update example code to use keyrings
WesleyRosenblum d444f52
Using try-with-resources for AwsCrypto streams
WesleyRosenblum 0a3e6e3
Splitting MKP and keyring unit tests
WesleyRosenblum 30c51a9
Making decryptData with ParsedCiphertext public
WesleyRosenblum 4d8614f
Mark KeyStoreProvider as deprecated
WesleyRosenblum 400f521
Reword some comments on the Basic Encryption example
WesleyRosenblum 59e3045
Add test for compability of Keyrings with MasterKeyProviders
WesleyRosenblum 6e473a1
Create individual request types for each AwsCrypto method
WesleyRosenblum 623f6f5
Make EncryptionMaterials, DecryptionMaterials and KeyringTrace immutable
WesleyRosenblum 3af73f0
Rename KmsKeying and related classes to AwsKmsKeyring
WesleyRosenblum 5258475
Create builders for the standard keyrings
WesleyRosenblum e04c285
Create AwsKmsCmkId type to represent AWS KMS Key Ids
WesleyRosenblum 6396c6c
Add factory methods to Keyring builders
WesleyRosenblum 15c1def
Add comment on not making a defensive copy of plaintext/ciphertext
WesleyRosenblum 6af9b02
Limit ability to create discovery AWS KMS Keyrings to explicit creation
WesleyRosenblum c182cd5
Add withKeyring to CachingCMM builder
WesleyRosenblum 37d42bb
Fix DecryptRequestTest
WesleyRosenblum 63057f5
Fix Junit 4 assertions in JUnit5 tests
WesleyRosenblum f415b7f
Renaming StaticKeyring to TestKeyring
WesleyRosenblum 7ec91d6
Adding convenience methods the create builders internally
WesleyRosenblum 876dd5e
Updating wording and adding more Deprecated annotations
WesleyRosenblum 214fabd
Enable AwsKms Client Caching by default to match KmsMasterKeyProvider
WesleyRosenblum cffe776
Making tests opt-out instead of opt-in and update TestVectorRunner (#…
WesleyRosenblum 8ed8619
Renaming StandardKeyring builder methods and other minors changes
WesleyRosenblum 28aeee2
Fixing test
WesleyRosenblum ff9dab6
Updating tests to use assertThrows
WesleyRosenblum 12f0c42
Additional example code for Keyrings (#155)
WesleyRosenblum File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
197 changes: 97 additions & 100 deletions
197
src/examples/java/com/amazonaws/crypto/examples/EscrowedEncryptExample.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,168 +1,165 @@ | ||
/* | ||
* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except | ||
* in compliance with the License. A copy of the License is located at | ||
* | ||
* | ||
* http://aws.amazon.com/apache2.0 | ||
* | ||
* | ||
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations under the License. | ||
*/ | ||
|
||
package com.amazonaws.crypto.examples; | ||
|
||
import java.io.FileInputStream; | ||
import java.io.FileOutputStream; | ||
import com.amazonaws.encryptionsdk.AwsCrypto; | ||
import com.amazonaws.encryptionsdk.DecryptRequest; | ||
import com.amazonaws.encryptionsdk.EncryptRequest; | ||
import com.amazonaws.encryptionsdk.keyrings.Keyring; | ||
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings; | ||
import com.amazonaws.encryptionsdk.kms.KmsClientSupplier; | ||
|
||
import java.nio.charset.StandardCharsets; | ||
import java.security.GeneralSecurityException; | ||
import java.security.KeyPair; | ||
import java.security.KeyPairGenerator; | ||
import java.security.PrivateKey; | ||
import java.security.PublicKey; | ||
import java.util.Arrays; | ||
|
||
import com.amazonaws.encryptionsdk.AwsCrypto; | ||
import com.amazonaws.encryptionsdk.CryptoOutputStream; | ||
import com.amazonaws.encryptionsdk.MasterKeyProvider; | ||
import com.amazonaws.encryptionsdk.jce.JceMasterKey; | ||
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider; | ||
import com.amazonaws.encryptionsdk.multi.MultipleProviderFactory; | ||
import com.amazonaws.util.IOUtils; | ||
import static java.util.Collections.emptyList; | ||
|
||
/** | ||
* <p> | ||
* Encrypts a file using both KMS and an asymmetric key pair. | ||
* Encrypts data using both KMS and an asymmetric key pair. | ||
* | ||
* <p> | ||
* Arguments: | ||
* <ol> | ||
* <li>Key ARN: For help finding the Amazon Resource Name (ARN) of your KMS customer master | ||
* <li>Key ARN: For help finding the Amazon Resource Name (ARN) of your KMS customer master | ||
* key (CMK), see 'Viewing Keys' at http://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html | ||
* | ||
* <li>Name of file containing plaintext data to encrypt | ||
* </ol> | ||
* | ||
* You might use AWS Key Management Service (KMS) for most encryption and decryption operations, but | ||
* still want the option of decrypting your data offline independently of KMS. This sample | ||
* You might use AWS Key Management Service (KMS) for most encryption and decryption operations, but | ||
* still want the option of decrypting your data offline independently of KMS. This sample | ||
* demonstrates one way to do this. | ||
* | ||
* | ||
* The sample encrypts data under both a KMS customer master key (CMK) and an "escrowed" RSA key pair | ||
* so that either key alone can decrypt it. You might commonly use the KMS CMK for decryption. However, | ||
* so that either key alone can decrypt it. You might commonly use the KMS CMK for decryption. However, | ||
* at any time, you can use the private RSA key to decrypt the ciphertext independent of KMS. | ||
* | ||
* This sample uses the JCEMasterKey class to generate a RSA public-private key pair | ||
* and saves the key pair in memory. In practice, you would store the private key in a secure offline | ||
* This sample uses a RawRsaKeyring to generate a RSA public-private key pair | ||
* and saves the key pair in memory. In practice, you would store the private key in a secure offline | ||
* location, such as an offline HSM, and distribute the public key to your development team. | ||
* | ||
*/ | ||
public class EscrowedEncryptExample { | ||
private static PublicKey publicEscrowKey; | ||
private static PrivateKey privateEscrowKey; | ||
private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8); | ||
|
||
public static void main(final String[] args) throws Exception { | ||
public static void main(final String[] args) throws GeneralSecurityException { | ||
final String kmsArn = args[0]; | ||
|
||
escrowEncryptAndDecrypt(kmsArn); | ||
} | ||
|
||
static void escrowEncryptAndDecrypt(String kmsArn) throws GeneralSecurityException { | ||
// This sample generates a new random key for each operation. | ||
// In practice, you would distribute the public key and save the private key in secure | ||
// storage. | ||
generateEscrowKeyPair(); | ||
// In practice, you would distribute the public key and save the private key in secure storage. | ||
final KeyPair escrowKeyPair = generateEscrowKeyPair(); | ||
|
||
final String kmsArn = args[0]; | ||
final String fileName = args[1]; | ||
// Encrypt the data under both a KMS Key and an escrowed RSA Key | ||
byte[] encryptedData = standardEncrypt(kmsArn, escrowKeyPair.getPublic()); | ||
|
||
// Decrypt the data using the KMS Key | ||
byte[] standardDecryptedData = standardDecrypt(kmsArn, encryptedData); | ||
|
||
standardEncrypt(kmsArn, fileName); | ||
standardDecrypt(kmsArn, fileName); | ||
// Decrypt the data using the escrowed RSA Key | ||
byte[] escrowedDecryptedData = escrowDecrypt(encryptedData, escrowKeyPair.getPublic(), escrowKeyPair.getPrivate()); | ||
|
||
escrowDecrypt(fileName); | ||
// Verify both decrypted data instances are the same as the original plaintext | ||
assert Arrays.equals(standardDecryptedData, EXAMPLE_DATA); | ||
assert Arrays.equals(escrowedDecryptedData, EXAMPLE_DATA); | ||
} | ||
|
||
private static void standardEncrypt(final String kmsArn, final String fileName) throws Exception { | ||
private static byte[] standardEncrypt(final String kmsArn, final PublicKey publicEscrowKey) { | ||
// Encrypt with the KMS CMK and the escrowed public key | ||
|
||
// 1. Instantiate the SDK | ||
final AwsCrypto crypto = new AwsCrypto(); | ||
|
||
// 2. Instantiate a KMS master key provider | ||
final KmsMasterKeyProvider kms = new KmsMasterKeyProvider(kmsArn); | ||
|
||
// 3. Instantiate a JCE master key provider | ||
// Because the user does not have access to the private escrow key, | ||
// they pass in "null" for the private key parameter. | ||
final JceMasterKey escrowPub = JceMasterKey.getInstance(publicEscrowKey, null, "Escrow", "Escrow", | ||
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding"); | ||
|
||
// 4. Combine the providers into a single master key provider | ||
final MasterKeyProvider<?> provider = MultipleProviderFactory.buildMultiProvider(kms, escrowPub); | ||
|
||
// 5. Encrypt the file | ||
// To simplify the code, we omit the encryption context. Production code should always | ||
// use an encryption context. For an example, see the other SDK samples. | ||
final FileInputStream in = new FileInputStream(fileName); | ||
final FileOutputStream out = new FileOutputStream(fileName + ".encrypted"); | ||
final CryptoOutputStream<?> encryptingStream = crypto.createEncryptingStream(provider, out); | ||
|
||
IOUtils.copy(in, encryptingStream); | ||
in.close(); | ||
encryptingStream.close(); | ||
// 2. Instantiate a KMS Client Supplier. This example uses the default client supplier but you can | ||
// also configure the credentials provider, client configuration and other settings as necessary | ||
final KmsClientSupplier clientSupplier = KmsClientSupplier.builder().build(); | ||
|
||
// 3. Instantiate a KMS Keyring, supplying the keyArn as the generator for generating a data key. | ||
// For this example, empty lists are provided for grant tokens and additional keys to encrypt the data | ||
// key with, but those can be supplied as necessary. | ||
final Keyring kmsKeyring = StandardKeyrings.kms(clientSupplier, emptyList(), emptyList(), kmsArn); | ||
|
||
// 4. Instantiate an RawRsaKeyring | ||
// Because the user does not have access to the private escrow key, | ||
// they pass in "null" for the private key parameter. | ||
WesleyRosenblum marked this conversation as resolved.
Show resolved
Hide resolved
|
||
final Keyring rsaKeyring = StandardKeyrings.rawRsa("Escrow", "Escrow", | ||
publicEscrowKey, null, "RSA/ECB/OAEPWithSHA-512AndMGF1Padding"); | ||
|
||
// 5. Combine the providers into a single MultiKeyring | ||
final Keyring keyring = StandardKeyrings.multi(kmsKeyring, rsaKeyring); | ||
|
||
// 6. Encrypt the data with the keyring. | ||
// To simplify the code, we omit the encryption context. Production code should always | ||
// use an encryption context. For an example, see the other SDK samples. | ||
return crypto.encrypt(EncryptRequest.builder() | ||
.keyring(keyring) | ||
.plaintext(EXAMPLE_DATA).build()) | ||
.getResult(); | ||
} | ||
|
||
private static void standardDecrypt(final String kmsArn, final String fileName) throws Exception { | ||
// Decrypt with the KMS CMK and the escrow public key. You can use a combined provider, | ||
// as shown here, or just the KMS master key provider. | ||
private static byte[] standardDecrypt(final String kmsArn, final byte[] cipherText) { | ||
// Decrypt with the KMS CMK | ||
|
||
// 1. Instantiate the SDK | ||
final AwsCrypto crypto = new AwsCrypto(); | ||
|
||
// 2. Instantiate a KMS master key provider | ||
final KmsMasterKeyProvider kms = new KmsMasterKeyProvider(kmsArn); | ||
|
||
// 3. Instantiate a JCE master key provider | ||
// Because the user does not have access to the private | ||
// escrow key, they pass in "null" for the private key parameter. | ||
final JceMasterKey escrowPub = JceMasterKey.getInstance(publicEscrowKey, null, "Escrow", "Escrow", | ||
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding"); | ||
|
||
// 4. Combine the providers into a single master key provider | ||
final MasterKeyProvider<?> provider = MultipleProviderFactory.buildMultiProvider(kms, escrowPub); | ||
|
||
// 5. Decrypt the file | ||
// To simplify the code, we omit the encryption context. Production code should always | ||
// use an encryption context. For an example, see the other SDK samples. | ||
final FileInputStream in = new FileInputStream(fileName + ".encrypted"); | ||
final FileOutputStream out = new FileOutputStream(fileName + ".decrypted"); | ||
final CryptoOutputStream<?> decryptingStream = crypto.createDecryptingStream(provider, out); | ||
IOUtils.copy(in, decryptingStream); | ||
in.close(); | ||
decryptingStream.close(); | ||
// 2. Instantiate a KMS Client Supplier. This example uses the default client supplier but you can | ||
// also configure the credentials provider, client configuration and other settings as necessary | ||
final KmsClientSupplier clientSupplier = KmsClientSupplier.builder().build(); | ||
|
||
// 3. Instantiate a KMS Keyring, supplying the keyArn as the generator for generating a data key. | ||
// For this example, empty lists are provided for grant tokens and additional keys to encrypt the data | ||
// key with, but those can be supplied as necessary. | ||
final Keyring kmsKeyring = StandardKeyrings.kms(clientSupplier, emptyList(), emptyList(), kmsArn); | ||
|
||
// 4. Decrypt the data with the keyring. | ||
// To simplify the code, we omit the encryption context. Production code should always | ||
// use an encryption context. For an example, see the other SDK samples. | ||
return crypto.decrypt(DecryptRequest.builder() | ||
.keyring(kmsKeyring) | ||
.ciphertext(cipherText).build()).getResult(); | ||
} | ||
|
||
private static void escrowDecrypt(final String fileName) throws Exception { | ||
private static byte[] escrowDecrypt(final byte[] cipherText, final PublicKey publicEscrowKey, final PrivateKey privateEscrowKey) { | ||
// You can decrypt the stream using only the private key. | ||
// This method does not call KMS. | ||
|
||
// 1. Instantiate the SDK | ||
final AwsCrypto crypto = new AwsCrypto(); | ||
|
||
// 2. Instantiate a JCE master key provider | ||
// This method call uses the escrowed private key, not null | ||
final JceMasterKey escrowPriv = JceMasterKey.getInstance(publicEscrowKey, privateEscrowKey, "Escrow", "Escrow", | ||
"RSA/ECB/OAEPWithSHA-512AndMGF1Padding"); | ||
|
||
// 3. Decrypt the file | ||
// To simplify the code, we omit the encryption context. Production code should always | ||
// use an encryption context. For an example, see the other SDK samples. | ||
final FileInputStream in = new FileInputStream(fileName + ".encrypted"); | ||
final FileOutputStream out = new FileOutputStream(fileName + ".deescrowed"); | ||
final CryptoOutputStream<?> decryptingStream = crypto.createDecryptingStream(escrowPriv, out); | ||
IOUtils.copy(in, decryptingStream); | ||
in.close(); | ||
decryptingStream.close(); | ||
// 2. Instantiate a RawRsaKeyring using the escrowed private key | ||
final Keyring rsaKeyring = StandardKeyrings.rawRsa("Escrow", "Escrow", | ||
publicEscrowKey, privateEscrowKey, "RSA/ECB/OAEPWithSHA-512AndMGF1Padding"); | ||
|
||
// 3. Decrypt the data with the keyring | ||
// To simplify the code, we omit the encryption context. Production code should always | ||
// use an encryption context. For an example, see the other SDK samples. | ||
return crypto.decrypt(DecryptRequest.builder() | ||
.keyring(rsaKeyring) | ||
.ciphertext(cipherText).build()).getResult(); | ||
} | ||
|
||
private static void generateEscrowKeyPair() throws GeneralSecurityException { | ||
private static KeyPair generateEscrowKeyPair() throws GeneralSecurityException { | ||
final KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA"); | ||
kg.initialize(4096); // Escrow keys should be very strong | ||
final KeyPair keyPair = kg.generateKeyPair(); | ||
publicEscrowKey = keyPair.getPublic(); | ||
privateEscrowKey = keyPair.getPrivate(); | ||
|
||
return kg.generateKeyPair(); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.