Skip to content
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

Remove use of BouncyCastle from JceMasterKey #128

Merged
merged 1 commit into from
Oct 8, 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## 1.6.1 -- Unreleased
### Maintenance
* Add support for standard test vectors via `testVectorZip` system property.
* Add support for standard test vectors via `testVectorZip` system property.
* No longer require use of BouncyCastle with RSA `JceMasterKey`s

## 1.6.0 -- 2019-05-31

Expand Down
62 changes: 54 additions & 8 deletions src/main/java/com/amazonaws/encryptionsdk/jce/JceMasterKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,22 @@
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.MGF1ParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import javax.crypto.spec.SecretKeySpec;

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

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

private Rsa(PublicKey wrappingKey, PrivateKey unwrappingKey, String providerName, String keyId,
String transformation) {
super(wrappingKey, unwrappingKey, providerName, keyId);
transformation_ = transformation;
if (!SUPPORTED_TRANSFORMATIONS.matcher(transformation_).matches()) {
LOGGER.warning(transformation_ + " is not officially supported by the JceMasterKey");

final Matcher matcher = SUPPORTED_TRANSFORMATIONS.matcher(transformation);
if (matcher.matches()) {
final String hashUnknownCase = matcher.group(1);
if (hashUnknownCase != null) {
// OAEP mode a.k.a PKCS #1v2
final String hash = hashUnknownCase.toUpperCase();
transformation_ = "RSA/ECB/OAEPPadding";

final MGF1ParameterSpec mgf1Spec;
switch (hash) {
case "SHA-1":
mgf1Spec = MGF1ParameterSpec.SHA1;
break;
case "SHA-224":
LOGGER.warning(transformation + " is not officially supported by the JceMasterKey");
mgf1Spec = MGF1ParameterSpec.SHA224;
break;
case "SHA-256":
mgf1Spec = MGF1ParameterSpec.SHA256;
break;
case "SHA-384":
mgf1Spec = MGF1ParameterSpec.SHA384;
break;
case "SHA-512":
mgf1Spec = MGF1ParameterSpec.SHA512;
break;
default:
throw new IllegalArgumentException("Unsupported algorithm: " + transformation);
}
parameterSpec_ = new OAEPParameterSpec(hash, "MGF1", mgf1Spec, PSource.PSpecified.DEFAULT);
} else {
// PKCS #1 v1.x
transformation_ = transformation;
parameterSpec_ = null;
}
} else {
LOGGER.warning(transformation + " is not officially supported by the JceMasterKey");
// Unsupported transformation, just use exactly what we are given
transformation_ = transformation;
parameterSpec_ = null;
}
}

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

Expand All @@ -269,8 +315,8 @@ protected Cipher buildUnwrappingCipher(Key key, byte[] extraInfo, int offset,
}
// We require BouncyCastle to avoid some bugs in the default Java implementation
// of OAEP.
final Cipher cipher = Cipher.getInstance(transformation_, "BC");
cipher.init(Cipher.DECRYPT_MODE, key);
final Cipher cipher = Cipher.getInstance(transformation_);
cipher.init(Cipher.DECRYPT_MODE, key, parameterSpec_);
return cipher;
}
}
Expand Down