Skip to content

Additional example code for Keyrings #155

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 6 commits into from
Feb 12, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,19 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-events</artifactId>
<version>2.2.7</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.google.code.findbugs</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,18 @@ static void encryptAndDecrypt(final AwsKmsCmkId keyArn) {
.keyring(keyring)
.ciphertext(ciphertext).build());

// 6. Before verifying the plaintext, inspect the Keyring Trace to verify that the CMK used
// to decrypt the encrypted data key was the CMK in the encryption keyring.
// 6. To verify the CMK that was actually used in the decrypt operation, inspect the keyring trace.
if(!decryptResult.getKeyringTrace().getEntries().get(0).getKeyName().equals(keyArn.toString())) {
throw new IllegalStateException("Wrong key ID!");
}

// 7. Also, verify that the encryption context in the result contains the
// encryption context supplied to the encryptData method. Because the
// SDK can add values to the encryption context, don't require that
// the entire context matches.
if (!encryptionContext.entrySet().stream()
.allMatch(e -> e.getValue().equals(decryptResult.getEncryptionContext().get(e.getKey())))) {
throw new IllegalStateException("Wrong Encryption Context!");
}
// 7. To verify that the encryption context used to decrypt the data was the encryption context you expected,
// examine the encryption context in the result. This helps to ensure that you decrypted the ciphertext that
// you intended.
//
// When verifying, test that your expected encryption context is a subset of the actual encryption context,
// not an exact match. The Encryption SDK adds the signing key to the encryption context when appropriate.
assert decryptResult.getEncryptionContext().get("ExampleContextKey").equals("ExampleContextValue");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who is "we?"

To verify that the encryption context used to decrypt the data was the encryption context you expected, use the keyring trace. This helps to ensure that you decrypted the ciphertext that you intended.

When verifying, test that your expected encryption context is a subset of the actual encryption context, not an exact match. The Encryption SDK adds the signing key to the encryption context when appropriate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you intended to mention the keyring trace here, I went with:

To verify that the encryption context used to decrypt the data was the encryption context you expected, examine the encryption context in the result. This helps to ensure that you decrypted the ciphertext that you intended.


// 8. Verify that the decrypted plaintext matches the original plaintext
assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ static void encryptAndDecrypt(final File srcFile, final File encryptedFile, fina
// 1. Instantiate the SDK
final AwsCrypto crypto = new AwsCrypto();

// 2. Retrieve an encryption key. In this example, we generate a random key.
// In practice, you would get a key from an existing store
final SecretKey cryptoKey = retrieveEncryptionKey();
// 2. Get an encryption key. In this example, we generate a random key.
// In practice, you would get a key from an existing key store.
final SecretKey cryptoKey = generateEncryptKey();

// 3. Instantiate a RawAesKeyring using the random key
final Keyring keyring = StandardKeyrings.rawAesBuilder()
Expand Down Expand Up @@ -104,11 +104,12 @@ static void encryptAndDecrypt(final File srcFile, final File encryptedFile, fina
.keyring(keyring)
.inputStream(new FileInputStream(encryptedFile)).build())) {

// 8. Verify that the encryption context in the result contains the
// encryption context supplied to the createEncryptingStream method.
if (!"FileStreaming".equals(decryptingStream.getAwsCryptoResult().getEncryptionContext().get("Example"))) {
throw new IllegalStateException("Bad encryption context");
}
// 8. Verify that the encryption context that was used to decrypt the data is the one that you expect.
// This helps to ensure that the ciphertext that you decrypted was the one that you intended.
//
// When verifying, test that your expected encryption context is a subset of the actual encryption context,
// not an exact match. When appropriate, the Encryption SDK adds the signing key to the encryption context.
assert "FileStreaming".equals(decryptingStream.getAwsCryptoResult().getEncryptionContext().get("Example"));

// 9. Copy the plaintext data to a file
try (FileOutputStream out = new FileOutputStream(decryptedFile)) {
Expand All @@ -122,9 +123,9 @@ static void encryptAndDecrypt(final File srcFile, final File encryptedFile, fina

/**
* In practice, this key would be saved in a secure location.
* For this demo, we generate a new random key for each operation.
* In this example, we generate a new random key for each operation.
*/
private static SecretKey retrieveEncryptionKey() {
private static SecretKey generateEncryptKey() {
SecureRandom rnd = new SecureRandom();
byte[] rawKey = new byte[16]; // 128 bits
rnd.nextBytes(rawKey);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright 2020 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 com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.AwsCryptoResult;
import com.amazonaws.encryptionsdk.DecryptRequest;
import com.amazonaws.encryptionsdk.EncryptRequest;
import com.amazonaws.encryptionsdk.keyrings.Keyring;
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;

/**
* <p>
* Encrypts and then decrypts data using the Raw AES Keyring.
*/
public class RawAesKeyringExample {

private static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);

public static void main(final String[] args) {
encryptAndDecrypt();
}

static void encryptAndDecrypt() {
// 1. Instantiate the SDK
final AwsCrypto crypto = new AwsCrypto();

// 2. Get an encryption key. In this example, we generate a random key.
// In practice, you would get a key from an existing key store
final SecretKey cryptoKey = generateEncryptKey();

// 3. Instantiate a Raw AES Keyring with the encryption key
final Keyring keyring = StandardKeyrings.rawAesBuilder()
.keyNamespace("ExampleKeyNamespace")
.keyName("ExampleKeyName")
.wrappingKey(cryptoKey).build();

// 4. Create an encryption context
//
// Most encrypted data should have an associated encryption context
// to protect integrity. This sample uses placeholder values.
//
// For more information see:
// blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
final Map<String, String> encryptionContext = Collections.singletonMap("ExampleContextKey", "ExampleContextValue");

// 5. Encrypt the data with the keyring and encryption context
final AwsCryptoResult<byte[]> encryptResult = crypto.encrypt(EncryptRequest.builder()
.keyring(keyring)
.encryptionContext(encryptionContext)
.plaintext(EXAMPLE_DATA).build());
final byte[] ciphertext = encryptResult.getResult();

// 6. Decrypt the data
final AwsCryptoResult<byte[]> decryptResult = crypto.decrypt(DecryptRequest.builder()
.keyring(keyring)
.ciphertext(ciphertext).build());

// 7. Verify that the encryption context that was used to decrypt the data is the one that you expect.
// This helps to ensure that the ciphertext that you decrypted was the one that you intended.
//
// When verifying, test that your expected encryption context is a subset of the actual encryption context,
// not an exact match. When appropriate, the Encryption SDK adds the signing key to the encryption context.
assert decryptResult.getEncryptionContext().get("ExampleContextKey").equals("ExampleContextValue");

// 8. Verify that the decrypted plaintext matches the original plaintext
assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
}

/**
* In practice, this key would be saved in a secure location.
* For this demo, we generate a new random key for each operation.
*/
private static SecretKey generateEncryptKey() {
SecureRandom rnd = new SecureRandom();
byte[] rawKey = new byte[16]; // 128 bits
rnd.nextBytes(rawKey);
return new SecretKeySpec(rawKey, "AES");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2020 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 com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.AwsCryptoResult;
import com.amazonaws.encryptionsdk.DecryptRequest;
import com.amazonaws.encryptionsdk.keyrings.Keyring;
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;

import java.security.KeyPair;

/**
* <p>
* Decrypts data using the Raw RSA Keyring.
*/
public class RawRsaKeyringDecryptExample {

public static byte[] decrypt(byte[] ciphertext, KeyPair keyPair) {
// 1. Instantiate the SDK
final AwsCrypto crypto = new AwsCrypto();

// 2. Instantiate a Raw RSA Keyring with the private key
final Keyring keyring = StandardKeyrings.rawRsaBuilder()
.keyNamespace("ExampleKeyNamespace")
.keyName("ExampleKeyName")
.wrappingAlgorithm("RSA/ECB/OAEPWithSHA-512AndMGF1Padding")
.privateKey(keyPair.getPrivate()).build();

// 3. Decrypt the ciphertext with the keyring
final AwsCryptoResult<byte[]> decryptResult = crypto.decrypt(DecryptRequest.builder()
.keyring(keyring)
.ciphertext(ciphertext).build());

// 4. Verify that the encryption context that was used to decrypt the data is the one that you expect.
// This helps to ensure that the ciphertext that you decrypted was the one that you intended.
//
// When verifying, test that your expected encryption context is a subset of the actual encryption context,
// not an exact match. When appropriate, the Encryption SDK adds the signing key to the encryption context.
assert decryptResult.getEncryptionContext().get("ExampleContextKey").equals("ExampleContextValue");

// 5. Return the decrypted byte array result
return decryptResult.getResult();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2020 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 com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.AwsCryptoResult;
import com.amazonaws.encryptionsdk.EncryptRequest;
import com.amazonaws.encryptionsdk.keyrings.Keyring;
import com.amazonaws.encryptionsdk.keyrings.StandardKeyrings;

import java.nio.charset.StandardCharsets;
import java.security.PublicKey;
import java.util.Collections;
import java.util.Map;

/**
* Encrypts data using the Raw RSA Keyring.
*/
public class RawRsaKeyringEncryptExample {

static final byte[] EXAMPLE_DATA = "Hello World".getBytes(StandardCharsets.UTF_8);

public static byte[] encrypt(PublicKey publicKey) {
// 1. Instantiate the SDK
final AwsCrypto crypto = new AwsCrypto();

// 2. Instantiate a Raw RSA Keyring with the public key
final Keyring keyring = StandardKeyrings.rawRsaBuilder()
.keyNamespace("ExampleKeyNamespace")
.keyName("ExampleKeyName")
.wrappingAlgorithm("RSA/ECB/OAEPWithSHA-512AndMGF1Padding")
.publicKey(publicKey).build();

// 3. Create an encryption context
//
// Most encrypted data should have an associated encryption context
// to protect integrity. This sample uses placeholder values.
//
// For more information see:
// blogs.aws.amazon.com/security/post/Tx2LZ6WBJJANTNW/How-to-Protect-the-Integrity-of-Your-Encrypted-Data-by-Using-AWS-Key-Management
final Map<String, String> encryptionContext = Collections.singletonMap("ExampleContextKey", "ExampleContextValue");

// 4. Encrypt the data with the keyring and encryption context
final AwsCryptoResult<byte[]> encryptResult = crypto.encrypt(EncryptRequest.builder()
.keyring(keyring)
.encryptionContext(encryptionContext)
.plaintext(EXAMPLE_DATA).build());

// 5. Return the encrypted byte array result
return encryptResult.getResult();
}
}
Loading