Skip to content

chore(README): update README.md #1940

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 9 commits into from
Feb 5, 2024
Merged
Changes from all 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
135 changes: 96 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,73 @@ To use the AWS Encryption SDK for Java you must have:

**Note:** If you use the Oracle JDK, you must also download and install the [Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html).

* **Declare a Dependency on the AWS Encryption SDK in Java and its dependencies**

This library requires the AWS Cryptographic Material Providers Library in Java, and the KMS and DynamoDB clients from the AWS Java SDK V2.

The KMS client from the AWS SDK for Java V1 is an **optional** dependency.

**Note:** The AWS Cryptographic Material Providers Library in Java only supports the AWS SDK for Java V2 and requires a HARD dependency on the AWS SDK for Java V2's KMS and DynamoDB clients, regardless of whether a KMS Keyring or Hierarchical Keyring is used.

* **Via Apache Maven**
Add the following to your project's `pom.xml`.
```xml
<project>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bom</artifactId>
<version>2.20.91</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-encryption-sdk-java</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>software.amazon.cryptography</groupId>
<artifactId>aws-cryptographic-material-providers</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>kms</artifactId>
</dependency>
<!-- The following are optional -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>1.12.394</version>
<optional>true</optional>
</dependency>
</dependencies>
...
</project>
```

* **Via Gradle Kotlin**
In a Gradle Java Project, add the following to the _dependencies_ section:
```kotlin
implementation("com.amazonaws:aws-encryption-sdk-java:3.0.0")
implementation("software.amazon.cryptography:aws-cryptographic-material-providers:1.0.2")
implementation(platform("software.amazon.awssdk:bom:2.20.91"))
implementation("software.amazon.awssdk:kms")
implementation("software.amazon.awssdk:dynamodb")
// The following are optional:
implementation("com.amazonaws:aws-java-sdk:1.12.394")
```

* **Bouncy Castle** or **Bouncy Castle FIPS**

The AWS Encryption SDK for Java uses Bouncy Castle to serialize and deserialize cryptographic objects.
Expand All @@ -41,7 +108,7 @@ You don't need an Amazon Web Services (AWS) account to use the AWS Encryption SD

* **To create an AWS account**, go to [Sign In or Create an AWS Account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) and then choose **I am a new user.** Follow the instructions to create an AWS account.

* **To create a symmetric encryption KMS key in AWS KMS**, see [Creating Keys](https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html).
* **To create a key in AWS KMS**, see [Creating Keys](https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html).

* **To download and install the AWS SDK for Java 2.x**, see [Installing the AWS SDK for Java 2.x](https://docs.aws.amazon.com/sdk-for-java/v2/developer-guide/getting-started.html).

Expand All @@ -51,40 +118,31 @@ You don't need an Amazon Web Services (AWS) account to use the AWS Encryption SD
Many users find that the Amazon Corretto Crypto Provider (ACCP) significantly improves the performance of the AWS Encryption SDK.
For help installing and using ACCP, see the [amazon-corretto-crypto-provider repository](https://github.com/corretto/amazon-corretto-crypto-provider).

### Download the AWS Encryption SDK for Java
You can get the latest release from Maven:

```xml
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-encryption-sdk-java</artifactId>
<version>3.0.0</version>
</dependency>
```

### Get Started
To get started with the AWS Encryption SDK for Java

1. Instantiate the AWS Encryption SDK.
2. Define the master key provider.
2. Create a Keyring from the AWS Cryptographic Material Providers Library.
3. Encrypt and decrypt data.

```java
// This sample code encrypts and then decrypts a string using an AWS KMS key.
// You provide the KMS key ARN and plaintext string as arguments.
package com.amazonaws.crypto.examples;

import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.encryptionsdk.CryptoResult;
import software.amazon.cryptography.materialproviders.IKeyring;
import software.amazon.cryptography.materialproviders.MaterialProviders;
import software.amazon.cryptography.materialproviders.model.CreateAwsKmsMultiKeyringInput;
import software.amazon.cryptography.materialproviders.model.MaterialProvidersConfig;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;

import com.amazonaws.encryptionsdk.AwsCrypto;
import com.amazonaws.encryptionsdk.CommitmentPolicy;
import com.amazonaws.encryptionsdk.CryptoResult;
import com.amazonaws.encryptionsdk.kms.KmsMasterKey;
import com.amazonaws.encryptionsdk.kms.KmsMasterKeyProvider;

public class StringExample {
private static String keyArn;
private static String plaintext;
Expand All @@ -95,37 +153,36 @@ public class StringExample {

// Instantiate the SDK
final AwsCrypto crypto = AwsCrypto.standard();

// Set up the master key provider
final KmsMasterKeyProvider prov = KmsMasterKeyProvider.builder().buildStrict(keyArn);


// Create the AWS KMS keyring.
// We create a multi keyring, as this interface creates the KMS client for us automatically.
final MaterialProviders materialProviders = MaterialProviders.builder()
.MaterialProvidersConfig(MaterialProvidersConfig.builder().build())
.build();
final CreateAwsKmsMultiKeyringInput keyringInput =
CreateAwsKmsMultiKeyringInput.builder().generator(keyArn).build();
final IKeyring kmsKeyring = materialProviders.CreateAwsKmsMultiKeyring(keyringInput);

// Set up the encryption context
// NOTE: Encrypted data should have associated encryption context
// to protect its integrity. This example uses placeholder values.
// For more information about the encryption context, see
// https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/concepts.html#encryption-context
final Map<String, String> context = Collections.singletonMap("ExampleContextKey", "ExampleContextValue");
final Map<String, String> encryptionContext = Collections.singletonMap("ExampleContextKey", "ExampleContextValue");

// Encrypt the data
//
final CryptoResult<byte[], KmsMasterKey> encryptResult = crypto.encryptData(prov, plaintext.getBytes(StandardCharsets.UTF_8), context);
final CryptoResult<byte[], ?> encryptResult = crypto.encryptData(kmsKeyring, plaintext.getBytes(StandardCharsets.UTF_8), encryptionContext);
Copy link
Contributor

Choose a reason for hiding this comment

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

why the ? in
CryptoResult<byte[], ?>

Copy link
Contributor

Choose a reason for hiding this comment

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

The ? is a wild card to keep encryptData API compatible with previous releases.

ESDK-Java's CryptoResult includes a definition of the actual Cryptographic Material Provider (MasterKey or MasterKeyProvider) as a Generic that can be refined at class initialization.

I am not sure if we ever refactored that CryptoResult class so
IKeyring or ICryptographicMaterialProvider could refine the Generic...

Copy link
Contributor

Choose a reason for hiding this comment

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

We clearly did not:
https://github.com/aws/aws-encryption-sdk-java/blob/master/src/main/java/com/amazonaws/encryptionsdk/CryptoResult.java#L31

This means that following APIs are now broken for Keyring users:

Which... is not Great.
@imabhichow we should bring this up at Stand up.

Those APIs are NOT critical; one of them is even marked as deprecated.

Copy link
Contributor

Choose a reason for hiding this comment

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

Which... is not Great.

Looking into the details here, this is not bad or even an issue.

K is would be an explicit MasterKey.
If no MaterKey or MasterKeyProviders are used,
then no one SHOULD expect a list of MasterKeyIDs to be populated.

We should probably write a test to assert that nothing wild happens,
like an Exception.

Copy link
Contributor Author

@imabhichow imabhichow Feb 1, 2024

Choose a reason for hiding this comment

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

When using keyrings, the CryptoResult.getMasterKeyIds method returns an empty list during encryption.

However, during decryption, CryptoResult.getMasterKeyIds throws a NULL POINTER EXCEPTION. This could be due to returning a DataKey with the master key set to null. I suppose we should expect similar behavior to encryption which is returning an empty llist of masterkeys. I'll try to look more into this.

I also think we should deprecate this method CryptoResult.getMasterKeyIds

Copy link
Contributor

Choose a reason for hiding this comment

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

We should have, yes.
And we should cut a PR to prevent the NPE.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With this pull request, CryptoResult.getMasterKeyIds is now deprecated and will return an empty list when we use keyrings.

final byte[] ciphertext = encryptResult.getResult();
System.out.println("Ciphertext: " + Arrays.toString(ciphertext));

// Decrypt the data
final CryptoResult<byte[], KmsMasterKey> decryptResult = crypto.decryptData(prov, ciphertext);
// Your application should verify the encryption context and the KMS key to
// ensure this is the expected ciphertext before returning the plaintext
if (!decryptResult.getMasterKeyIds().get(0).equals(keyArn)) {
throw new IllegalStateException("Wrong key id!");
}

// The AWS Encryption SDK may add information to the encryption context, so check to
// ensure all of the values that you specified when encrypting are *included* in the returned encryption context.
if (!context.entrySet().stream()
.allMatch( e -> e.getValue().equals(decryptResult.getEncryptionContext().get(e.getKey())))) {
throw new IllegalStateException("Wrong Encryption Context!");
}
final CryptoResult<byte[], ?> decryptResult =
crypto.decryptData(
kmsKeyring,
ciphertext,
// Verify that the encryption context in the result contains the
// encryption context supplied to the encryptData method
encryptionContext);

assert Arrays.equals(decryptResult.getResult(), plaintext.getBytes(StandardCharsets.UTF_8));

Expand Down