Skip to content

Merge head of master into keyring #141

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 4 commits into from
Nov 9, 2019
Merged
Show file tree
Hide file tree
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
27 changes: 22 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
# Changelog

## 1.6.1 -- Unreleased
## 1.6.1 -- 2019-10-29

### Deprecation Warnings
* Deprecated `AwsCrypto.encryptString()` and `AwsCrypto.decryptString()`.
Replace your calls to these methods with calls to AwsCrypto.encryptData() and AwsCrypto.decryptData().
Unlike the deprecated methods, these methods don't perform any Base64 encoding or decoding, so they are fully compatible with other language implementations of the AWS Encryption SDK.

If you need Base64 encoding or decoding for your application, you can add it outside of the AWS Encryption SDK.
[PR #120](https://github.com/aws/aws-encryption-sdk-java/pull/120)

### Patches
* Correctly validate version [PR #116](https://github.com/aws/aws-encryption-sdk-java/pull/116)
* `ParsedCiphertext` now handles truncated input properly [PR #119](https://github.com/aws/aws-encryption-sdk-java/pull/119)

### Maintenance
* Add support for standard test vectors via `testVectorZip` system property.
* No longer require use of BouncyCastle with RSA `JceMasterKey`s
* No longer use BouncyCastle for Elliptic Curve key generation and point compression/decompression
* Add support for standard test vectors via `testVectorZip` system property. [PR #127](https://github.com/aws/aws-encryption-sdk-java/pull/127)
* Remove all explicit cryptographic dependencies on BouncyCastle. The AWS Encryption SDK for Java still uses Bouncy Castle for other tasks. PRs
[#128](https://github.com/aws/aws-encryption-sdk-java/pull/128),
[#129](https://github.com/aws/aws-encryption-sdk-java/pull/129),
[#130](https://github.com/aws/aws-encryption-sdk-java/pull/130),
[#131](https://github.com/aws/aws-encryption-sdk-java/pull/131),
and [#132](https://github.com/aws/aws-encryption-sdk-java/pull/132).

## 1.6.0 -- 2019-05-31

Expand All @@ -17,7 +34,7 @@
## 1.5.0 -- 2019-05-30

### Minor Changes
* Add dependency on Apache Commons Codec 1.12.
* Added dependency on Apache Commons Codec 1.12.
* Use org.apache.commons.codec.binary.Base64 instead of java.util.Base64 so
that the SDK can be used on systems that do not have java.util.Base64 but
support Java 8 language features.
Expand Down
52 changes: 21 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,31 @@ For more details about the design and architecture of the SDK, see the [official
### Required Prerequisites
To use this SDK you must have:

* **A Java 8 development environment**
* **A Java 8 or newer development environment**

If you do not have one, go to [Java SE Downloads](https://www.oracle.com/technetwork/java/javase/downloads/index.html) on the Oracle website, then download and install the Java SE Development Kit (JDK). Java 8 or higher is required.
If you do not have one, we recommend [Amazon Corretto](https://aws.amazon.com/corretto/).

**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).

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

Bouncy Castle provides a cryptography API for Java. If you do not have Bouncy Castle, go to https://bouncycastle.org/latest_releases.html, then download the provider file that corresponds to your JDK. Or, you can pick it up from Maven:
The AWS Encryption SDK for Java uses Bouncy Castle to serialize and deserialize cryptographic objects.
It does not explicitly use Bouncy Castle (or any other [JCA Provider](https://docs.oracle.com/javase/8/docs/api/java/security/Provider.html)) for the underlying cryptography.
Instead, it uses the platform default, which you can configure or override as documented in the
[Java Cryptography Architecture (JCA) Reference Guide](https://docs.oracle.com/javase/9/security/java-cryptography-architecture-jca-reference-guide.htm#JSSEC-GUID-2BCFDD85-D533-4E6C-8CE9-29990DEB0190).

```xml
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-ext-jdk15on</artifactId>
<version>1.61</version>
</dependency>
```
If you do not have Bouncy Castle, go to https://bouncycastle.org/latest_releases.html, then download the provider file that corresponds to your JDK.
Or, you can pick it up from Maven (groupId: `org.bouncycastle`, artifactId: `bcprov-ext-jdk15on`).

Beginning in version 1.6.1,
the AWS Encryption SDK also works with Bouncy Castle FIPS (groupId: `org.bouncycastle`, artifactId: `bc-fips`)
as an alternative to non-FIPS Bouncy Castle.
For help installing and configuring Bouncy Castle FIPS properly, see [BC FIPS documentation](https://www.bouncycastle.org/documentation.html),
in particular, **User Guides** and **Security Policy**.

### Optional Prerequisites

#### AWS Integration
You don't need an Amazon Web Services (AWS) account to use this SDK, but some of the [example code][examples] requires an AWS account, a customer master key (CMK) in AWS KMS, and the AWS SDK for Java.

* **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.
Expand All @@ -37,6 +42,10 @@ You don't need an Amazon Web Services (AWS) account to use this SDK, but some of

* **To download and install the AWS SDK for Java**, go to [Installing the AWS SDK for Java](https://docs.aws.amazon.com/AWSSdkDocsJava/latest/DeveloperGuide/java-dg-install-sdk.html) in the AWS SDK for Java documentation and then follow the instructions on that page.

#### Amazon Corretto Crypto Provider
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 [ACCP GitHub Respository](https://github.com/corretto/amazon-corretto-crypto-provider) .

### Download

You can get the latest release from Maven:
Expand All @@ -45,29 +54,10 @@ You can get the latest release from Maven:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-encryption-sdk-java</artifactId>
<version>1.6.0</version>
<version>1.6.1</version>
</dependency>
```

Don't forget to enable the download of snapshot jars from Maven:

```xml
<profiles>
<profile>
<id>allow-snapshots</id>
<activation><activeByDefault>true</activeByDefault></activation>
<repositories>
<repository>
<id>snapshots-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
</repositories>
</profile>
</profiles>
```

### Get Started

The following code sample demonstrates how to get started:
Expand Down
28 changes: 27 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>com.amazonaws</groupId>
<artifactId>aws-encryption-sdk-java</artifactId>
<version>1.6.0</version>
<version>1.6.1</version>
<packaging>jar</packaging>

<name>aws-encryption-sdk-java</name>
Expand Down Expand Up @@ -118,6 +118,26 @@
<source>8</source>
</configuration>
</plugin>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>add-test-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/examples/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

Expand Down Expand Up @@ -145,6 +165,12 @@
<goals>
<goal>sign</goal>
</goals>
<configuration>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
</execution>
</executions>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2019 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.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;

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

/**
* <p>
* Encrypts and then decrypts data using an AWS KMS customer master key.
*
* <p>
* Arguments:
* <ol>
* <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
* </ol>
*/
public class BasicEncryptionExample {

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

public static void main(final String[] args) {
final String keyArn = args[0];

encryptAndDecrypt(keyArn);
}

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

// 2. Instantiate a KMS master key provider
final KmsMasterKeyProvider masterKeyProvider = KmsMasterKeyProvider.builder().withKeysForEncryption(keyArn).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
final CryptoResult<byte[], KmsMasterKey> encryptResult = crypto.encryptData(masterKeyProvider, EXAMPLE_DATA, encryptionContext);
final byte[] ciphertext = encryptResult.getResult();

// 5. Decrypt the data
final CryptoResult<byte[], KmsMasterKey> decryptResult = crypto.decryptData(masterKeyProvider, ciphertext);

// 6. Before verifying the plaintext, verify that the customer master key that
// was used in the encryption operation was the one supplied to the master key provider.
if (!decryptResult.getMasterKeyIds().get(0).equals(keyArn)) {
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!");
}

// 8. Verify that the decrypted plaintext matches the original plaintext
assert Arrays.equals(decryptResult.getResult(), EXAMPLE_DATA);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright 2019 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.encryptionsdk.internal;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.util.Map;

/**
* A JceKeyCipher based on the Advanced Encryption Standard in Galois/Counter Mode.
*/
class AesGcmJceKeyCipher extends JceKeyCipher {
private static final int NONCE_LENGTH = 12;
private static final int TAG_LENGTH = 128;
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
private static final int SPEC_LENGTH = Integer.BYTES + Integer.BYTES + NONCE_LENGTH;

AesGcmJceKeyCipher(SecretKey key) {
super(key, key);
}

private static byte[] specToBytes(final GCMParameterSpec spec) {
final byte[] nonce = spec.getIV();
final byte[] result = new byte[SPEC_LENGTH];
final ByteBuffer buffer = ByteBuffer.wrap(result);
buffer.putInt(spec.getTLen());
buffer.putInt(nonce.length);
buffer.put(nonce);
return result;
}

private static GCMParameterSpec bytesToSpec(final byte[] data, final int offset) throws InvalidKeyException {
if (data.length - offset != SPEC_LENGTH) {
throw new InvalidKeyException("Algorithm specification was an invalid data size");
}

final ByteBuffer buffer = ByteBuffer.wrap(data, offset, SPEC_LENGTH);
final int tagLen = buffer.getInt();
final int nonceLen = buffer.getInt();

if (tagLen != TAG_LENGTH) {
throw new InvalidKeyException(String.format("Authentication tag length must be %s", TAG_LENGTH));
}

if (nonceLen != NONCE_LENGTH) {
throw new InvalidKeyException(String.format("Initialization vector (IV) length must be %s", NONCE_LENGTH));
}

final byte[] nonce = new byte[nonceLen];
buffer.get(nonce);

return new GCMParameterSpec(tagLen, nonce);
}

@Override
WrappingData buildWrappingCipher(final Key key, final Map<String, String> encryptionContext)
throws GeneralSecurityException {
final byte[] nonce = new byte[NONCE_LENGTH];
Utils.getSecureRandom().nextBytes(nonce);
final GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH, nonce);
final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
final byte[] aad = EncryptionContextSerializer.serialize(encryptionContext);
cipher.updateAAD(aad);
return new WrappingData(cipher, specToBytes(spec));
}

@Override
Cipher buildUnwrappingCipher(final Key key, final byte[] extraInfo, final int offset,
final Map<String, String> encryptionContext) throws GeneralSecurityException {
final GCMParameterSpec spec = bytesToSpec(extraInfo, offset);
final Cipher cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, key, spec);
final byte[] aad = EncryptionContextSerializer.serialize(encryptionContext);
cipher.updateAAD(aad);
return cipher;
}
}
Loading