Skip to content

Commit 22a90bf

Browse files
authored
Merge branch 'master' into update-deprecated-api-flags
2 parents 2248c40 + f2daec3 commit 22a90bf

File tree

11 files changed

+481
-14
lines changed

11 files changed

+481
-14
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ target/
55
.classpath
66
/bin/
77
.idea/
8+
*.iml

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ jdk:
66
- openjdk11
77
- oraclejdk8
88
- oraclejdk9
9-
script: mvn install -Dgpg.skip=true
9+
script: mvn install -Dgpg.skip=true '-DtestVectorZip=https://github.com/awslabs/aws-encryption-sdk-test-vectors/raw/master/vectors/awses-decrypt/python-1.3.8.zip'
1010
sudo: false
1111
dist: trusty

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## 1.6.1 -- Unreleased
4+
### Maintenance
5+
* Add support for standard test vectors via `testVectorZip` system property.
6+
* No longer require use of BouncyCastle with RSA `JceMasterKey`s
7+
38
## 1.6.0 -- 2019-05-31
49

510
### Minor Changes

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@
156156
<extensions>true</extensions>
157157
<configuration>
158158
<serverId>sonatype-nexus-staging</serverId>
159-
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
159+
<nexusUrl>https://aws.oss.sonatype.org</nexusUrl>
160160
</configuration>
161161
</plugin>
162162
</plugins>

src/main/java/com/amazonaws/encryptionsdk/ParsedCiphertext.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/*
2-
* Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3-
*
2+
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
44
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
55
* in compliance with the License. A copy of the License is located at
6-
*
6+
*
77
* http://aws.amazon.com/apache2.0
8-
*
8+
*
99
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
1010
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
1111
* specific language governing permissions and limitations under the License.
@@ -15,6 +15,7 @@
1515

1616
import com.amazonaws.encryptionsdk.internal.Utils;
1717
import com.amazonaws.encryptionsdk.model.CiphertextHeaders;
18+
import com.amazonaws.encryptionsdk.exception.BadCiphertextException;
1819

1920
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
2021

@@ -36,6 +37,9 @@ public class ParsedCiphertext extends CiphertextHeaders {
3637
public ParsedCiphertext(final byte[] ciphertext) {
3738
ciphertext_ = Utils.assertNonNull(ciphertext, "ciphertext");
3839
offset_ = deserialize(ciphertext_, 0);
40+
if (!this.isComplete()) {
41+
throw new BadCiphertextException("Incomplete ciphertext.");
42+
}
3943
}
4044

4145
/**

src/main/java/com/amazonaws/encryptionsdk/jce/JceMasterKey.java

+54-8
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,22 @@
2424
import java.security.PrivateKey;
2525
import java.security.PublicKey;
2626
import java.security.SecureRandom;
27+
import java.security.spec.AlgorithmParameterSpec;
28+
import java.security.spec.MGF1ParameterSpec;
2729
import java.util.ArrayList;
2830
import java.util.Arrays;
2931
import java.util.Collection;
3032
import java.util.List;
3133
import java.util.Map;
3234
import java.util.logging.Logger;
35+
import java.util.regex.Matcher;
3336
import java.util.regex.Pattern;
3437

3538
import javax.crypto.Cipher;
3639
import javax.crypto.SecretKey;
3740
import javax.crypto.spec.GCMParameterSpec;
41+
import javax.crypto.spec.OAEPParameterSpec;
42+
import javax.crypto.spec.PSource;
3843
import javax.crypto.spec.SecretKeySpec;
3944

4045
import com.amazonaws.encryptionsdk.CryptoAlgorithm;
@@ -237,17 +242,58 @@ public WrappingData(final Cipher cipher, final byte[] extraInfo) {
237242
}
238243

239244
private static class Rsa extends JceMasterKey {
245+
// MGF1 with SHA-224 isn't really supported, but we include it in the regex because we need it
246+
// for proper handling of the algorithm.
240247
private static final Pattern SUPPORTED_TRANSFORMATIONS =
241-
Pattern.compile("RSA/ECB/(?:PKCS1Padding|OAEPWithSHA-(?:1|256|384|512)AndMGF1Padding)",
248+
Pattern.compile("RSA/ECB/(?:PKCS1Padding|OAEPWith(SHA-(?:1|224|256|384|512))AndMGF1Padding)",
242249
Pattern.CASE_INSENSITIVE);
250+
private final AlgorithmParameterSpec parameterSpec_;
243251
private final String transformation_;
244252

245253
private Rsa(PublicKey wrappingKey, PrivateKey unwrappingKey, String providerName, String keyId,
246254
String transformation) {
247255
super(wrappingKey, unwrappingKey, providerName, keyId);
248-
transformation_ = transformation;
249-
if (!SUPPORTED_TRANSFORMATIONS.matcher(transformation_).matches()) {
250-
LOGGER.warning(transformation_ + " is not officially supported by the JceMasterKey");
256+
257+
final Matcher matcher = SUPPORTED_TRANSFORMATIONS.matcher(transformation);
258+
if (matcher.matches()) {
259+
final String hashUnknownCase = matcher.group(1);
260+
if (hashUnknownCase != null) {
261+
// OAEP mode a.k.a PKCS #1v2
262+
final String hash = hashUnknownCase.toUpperCase();
263+
transformation_ = "RSA/ECB/OAEPPadding";
264+
265+
final MGF1ParameterSpec mgf1Spec;
266+
switch (hash) {
267+
case "SHA-1":
268+
mgf1Spec = MGF1ParameterSpec.SHA1;
269+
break;
270+
case "SHA-224":
271+
LOGGER.warning(transformation + " is not officially supported by the JceMasterKey");
272+
mgf1Spec = MGF1ParameterSpec.SHA224;
273+
break;
274+
case "SHA-256":
275+
mgf1Spec = MGF1ParameterSpec.SHA256;
276+
break;
277+
case "SHA-384":
278+
mgf1Spec = MGF1ParameterSpec.SHA384;
279+
break;
280+
case "SHA-512":
281+
mgf1Spec = MGF1ParameterSpec.SHA512;
282+
break;
283+
default:
284+
throw new IllegalArgumentException("Unsupported algorithm: " + transformation);
285+
}
286+
parameterSpec_ = new OAEPParameterSpec(hash, "MGF1", mgf1Spec, PSource.PSpecified.DEFAULT);
287+
} else {
288+
// PKCS #1 v1.x
289+
transformation_ = transformation;
290+
parameterSpec_ = null;
291+
}
292+
} else {
293+
LOGGER.warning(transformation + " is not officially supported by the JceMasterKey");
294+
// Unsupported transformation, just use exactly what we are given
295+
transformation_ = transformation;
296+
parameterSpec_ = null;
251297
}
252298
}
253299

@@ -256,8 +302,8 @@ protected WrappingData buildWrappingCipher(Key key, Map<String, String> encrypti
256302
throws GeneralSecurityException {
257303
// We require BouncyCastle to avoid some bugs in the default Java implementation
258304
// of OAEP.
259-
final Cipher cipher = Cipher.getInstance(transformation_, "BC");
260-
cipher.init(Cipher.ENCRYPT_MODE, key);
305+
final Cipher cipher = Cipher.getInstance(transformation_);
306+
cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec_);
261307
return new WrappingData(cipher, EMPTY_ARRAY);
262308
}
263309

@@ -269,8 +315,8 @@ protected Cipher buildUnwrappingCipher(Key key, byte[] extraInfo, int offset,
269315
}
270316
// We require BouncyCastle to avoid some bugs in the default Java implementation
271317
// of OAEP.
272-
final Cipher cipher = Cipher.getInstance(transformation_, "BC");
273-
cipher.init(Cipher.DECRYPT_MODE, key);
318+
final Cipher cipher = Cipher.getInstance(transformation_);
319+
cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec_);
274320
return cipher;
275321
}
276322
}

src/main/java/com/amazonaws/encryptionsdk/model/CiphertextHeaders.java

+4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.amazonaws.encryptionsdk.internal.Constants;
3131
import com.amazonaws.encryptionsdk.internal.EncryptionContextSerializer;
3232
import com.amazonaws.encryptionsdk.internal.PrimitivesParser;
33+
import com.amazonaws.encryptionsdk.internal.VersionInfo;
3334

3435
/**
3536
* This class implements the headers for the message (ciphertext) produced by
@@ -179,6 +180,9 @@ public Boolean isComplete() {
179180
*/
180181
private int parseVersion(final byte[] b, final int off) throws ParseException {
181182
version_ = PrimitivesParser.parseByte(b, off);
183+
if (version_ != VersionInfo.CURRENT_CIPHERTEXT_VERSION) {
184+
throw new BadCiphertextException("Invalid version ");
185+
}
182186
return 1;
183187
}
184188

src/test/java/com/amazonaws/encryptionsdk/AllTestsSuite.java

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
AwsCryptoTest.class,
4747
CryptoInputStreamTest.class,
4848
CryptoOutputStreamTest.class,
49+
TestVectorRunner.class,
4950
XCompatDecryptTest.class,
5051
DefaultCryptoMaterialsManagerTest.class,
5152
NullCryptoMaterialsCacheTest.class,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except
5+
* in compliance with the License. A copy of the License is located at
6+
*
7+
* http://aws.amazon.com/apache2.0
8+
*
9+
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package com.amazonaws.encryptionsdk;
15+
16+
import com.amazonaws.encryptionsdk.internal.StaticMasterKey;
17+
import com.amazonaws.encryptionsdk.internal.VersionInfo;
18+
import com.amazonaws.encryptionsdk.model.CiphertextHeaders;
19+
import org.junit.Before;
20+
import org.junit.Test;
21+
22+
import com.amazonaws.encryptionsdk.exception.BadCiphertextException;
23+
24+
import java.util.HashMap;
25+
import java.util.Map;
26+
import java.util.Arrays;
27+
28+
import static org.junit.Assert.*;
29+
import static org.mockito.Mockito.spy;
30+
31+
public class ParsedCiphertextTest extends CiphertextHeaders {
32+
private StaticMasterKey masterKeyProvider;
33+
private AwsCrypto encryptionClient_;
34+
35+
@Before
36+
public void init() {
37+
masterKeyProvider = spy(new StaticMasterKey("testmaterial"));
38+
39+
encryptionClient_ = new AwsCrypto();
40+
encryptionClient_.setEncryptionAlgorithm(CryptoAlgorithm.ALG_AES_128_GCM_IV12_TAG16_HKDF_SHA256);
41+
}
42+
43+
@Test()
44+
public void goodParsedCiphertext() {
45+
final int byteSize = 0;
46+
final int frameSize = 0;
47+
final byte[] plaintextBytes = new byte[byteSize];
48+
49+
final Map<String, String> encryptionContext = new HashMap<String, String>(1);
50+
encryptionContext.put("ENC1", "ParsedCiphertext test with %d" + byteSize);
51+
52+
encryptionClient_.setEncryptionFrameSize(frameSize);
53+
54+
final byte[] cipherText = encryptionClient_.encryptData(
55+
masterKeyProvider,
56+
plaintextBytes,
57+
encryptionContext).getResult();
58+
final ParsedCiphertext pCt = new ParsedCiphertext(cipherText);
59+
60+
assertNotNull(pCt.getCiphertext());
61+
assertTrue(pCt.getOffset() > 0);
62+
}
63+
64+
@Test(expected = BadCiphertextException.class)
65+
public void incompleteZeroByteCiphertext() {
66+
final byte[] cipherText = {};
67+
ParsedCiphertext pCt = new ParsedCiphertext(cipherText);
68+
}
69+
70+
@Test(expected = BadCiphertextException.class)
71+
public void incompleteSingleByteCiphertext() {
72+
final byte[] cipherText = {VersionInfo.CURRENT_CIPHERTEXT_VERSION};
73+
ParsedCiphertext pCt = new ParsedCiphertext(cipherText);
74+
}
75+
76+
@Test(expected = BadCiphertextException.class)
77+
public void incompleteCiphertext() {
78+
final int byteSize = 0;
79+
final int frameSize = 0;
80+
final byte[] plaintextBytes = new byte[byteSize];
81+
82+
final Map<String, String> encryptionContext = new HashMap<String, String>(1);
83+
encryptionContext.put("ENC1", "ParsedCiphertext test with %d" + byteSize);
84+
85+
encryptionClient_.setEncryptionFrameSize(frameSize);
86+
87+
final byte[] cipherText = encryptionClient_.encryptData(
88+
masterKeyProvider,
89+
plaintextBytes,
90+
encryptionContext).getResult();
91+
ParsedCiphertext pCt = new ParsedCiphertext(cipherText);
92+
93+
byte[] incompleteCiphertext = Arrays.copyOf(pCt.getCiphertext(), pCt.getOffset() - 1);
94+
ParsedCiphertext badPCt = new ParsedCiphertext(incompleteCiphertext);
95+
}
96+
}

0 commit comments

Comments
 (0)