Skip to content

Commit 713bcd2

Browse files
Remaining fixes to allow BouncyCastle to be swapped out with other implementations. (#131)
* *Issue #, if available:* #41 *Description of changes:* Remaining fixes to allow BouncyCastle to be swapped out with other implementations. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. # Check any applicable: - [ ] Were any files moved? Moving files changes their URL, which breaks all hyperlinks to the files.
1 parent 18377b6 commit 713bcd2

File tree

6 files changed

+57
-101
lines changed

6 files changed

+57
-101
lines changed

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

+4-14
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import javax.crypto.SecretKey;
2525
import javax.crypto.spec.SecretKeySpec;
2626

27-
import com.amazonaws.encryptionsdk.internal.BouncyCastleConfiguration;
2827
import com.amazonaws.encryptionsdk.internal.HmacKeyDerivationFunction;
2928

3029
import com.amazonaws.encryptionsdk.internal.Constants;
@@ -99,27 +98,19 @@ public enum CryptoAlgorithm {
9998
private final int dataKeyLen_;
10099
private final boolean safeToCache_;
101100

102-
/**
103-
* This block is used to ensure static blocks of BouncyCastleConfiguration are evaluated as a dependency of
104-
* the CryptoAlgorithm class
105-
*/
106-
static {
107-
BouncyCastleConfiguration.init();
108-
}
109-
110101
/*
111102
* Create a mapping between the CiphertextType object and its byte value representation. Make
112103
* this is a static method so the map is created when the object is created. This enables fast
113104
* lookups of the CryptoAlgorithm given its short value representation.
114105
*/
115-
private static final Map<Short, CryptoAlgorithm> ID_MAPPING = new HashMap<Short, CryptoAlgorithm>();
106+
private static final Map<Short, CryptoAlgorithm> ID_MAPPING = new HashMap<>();
116107
static {
117108
for (final CryptoAlgorithm s : EnumSet.allOf(CryptoAlgorithm.class)) {
118109
ID_MAPPING.put(s.value_, s);
119110
}
120111
}
121112

122-
private CryptoAlgorithm(
113+
CryptoAlgorithm(
123114
final int blockSizeBits, final int nonceLenBytes, final int tagLenBytes,
124115
final long maxContentLen, final String keyAlgo, final int keyLenBytes, final int value,
125116
final String dataKeyAlgo, final int dataKeyLen, boolean safeToCache
@@ -130,7 +121,7 @@ private CryptoAlgorithm(
130121

131122
}
132123

133-
private CryptoAlgorithm(
124+
CryptoAlgorithm(
134125
final int blockSizeBits, final int nonceLenBytes, final int tagLenBytes,
135126
final long maxContentLen, final String keyAlgo, final int keyLenBytes, final int value,
136127
final String dataKeyAlgo, final int dataKeyLen,
@@ -164,8 +155,7 @@ private CryptoAlgorithm(
164155
* @return the CryptoAlgorithm object that matches the given value, null if no match is found.
165156
*/
166157
public static CryptoAlgorithm deserialize(final short value) {
167-
final CryptoAlgorithm result = ID_MAPPING.get(value);
168-
return result;
158+
return ID_MAPPING.get(value);
169159
}
170160

171161
/**

src/main/java/com/amazonaws/encryptionsdk/internal/BouncyCastleConfiguration.java

-37
This file was deleted.

src/main/java/com/amazonaws/encryptionsdk/internal/TrailingSignatureAlgorithm.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@ private static final class ECDSASignatureAlgorithm extends TrailingSignatureAlgo
5959
private static final BigInteger THREE = BigInteger.valueOf(3);
6060
private static final BigInteger FOUR = BigInteger.valueOf(4);
6161

62-
private ECDSASignatureAlgorithm(ECGenParameterSpec ecSpec, String messageDigestAlgorithm) {
62+
private ECDSASignatureAlgorithm(ECGenParameterSpec ecSpec, String messageDigestAlgorithm, String hashAndSignAlgorithm) {
6363
if (!ecSpec.getName().startsWith(SEC_PRIME_FIELD_PREFIX)) {
6464
throw new IllegalStateException("Non-prime curves are not supported at this time");
6565
}
6666

6767
this.ecSpec = ecSpec;
6868
this.messageDigestAlgorithm = messageDigestAlgorithm;
69-
this.hashAndSignAlgorithm = messageDigestAlgorithm + "withECDSA";
69+
this.hashAndSignAlgorithm = hashAndSignAlgorithm;
7070

7171
try {
7272
final AlgorithmParameters parameters = AlgorithmParameters.getInstance(ELLIPTIC_CURVE_ALGORITHM);
@@ -190,9 +190,9 @@ public KeyPair generateKey() throws GeneralSecurityException {
190190
}
191191

192192
private static final ECDSASignatureAlgorithm SHA256_ECDSA_P256
193-
= new ECDSASignatureAlgorithm(new ECGenParameterSpec(SEC_PRIME_FIELD_PREFIX + "256r1"), "SHA256");
193+
= new ECDSASignatureAlgorithm(new ECGenParameterSpec(SEC_PRIME_FIELD_PREFIX + "256r1"), "SHA-256", "SHA256withECDSA");
194194
private static final ECDSASignatureAlgorithm SHA384_ECDSA_P384
195-
= new ECDSASignatureAlgorithm(new ECGenParameterSpec(SEC_PRIME_FIELD_PREFIX + "384r1"), "SHA384");
195+
= new ECDSASignatureAlgorithm(new ECGenParameterSpec(SEC_PRIME_FIELD_PREFIX + "384r1"), "SHA-384", "SHA384withECDSA");
196196

197197
public static TrailingSignatureAlgorithm forCryptoAlgorithm(CryptoAlgorithm algorithm) {
198198
switch (algorithm) {

src/main/java/com/amazonaws/encryptionsdk/internal/Utils.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.WeakHashMap;
2525
import java.util.concurrent.atomic.AtomicLong;
2626

27+
import org.apache.commons.lang3.ArrayUtils;
2728
import org.bouncycastle.util.encoders.Base64;
2829

2930
/**
@@ -268,7 +269,7 @@ public static ByteBuffer limit(final ByteBuffer buff, final int newLimit) {
268269
* @return decoded data as a byte array
269270
*/
270271
public static byte[] decodeBase64String(final String encoded) {
271-
return Base64.decode(encoded);
272+
return encoded.isEmpty() ? ArrayUtils.EMPTY_BYTE_ARRAY : Base64.decode(encoded);
272273
}
273274

274275
/**

src/test/java/com/amazonaws/encryptionsdk/internal/CipherHandlerTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public void tamperCiphertext() {
4747
final byte[] keyBytes = RandomBytesGenerator.generate(cryptoAlgorithm.getKeyLength());
4848
final byte[] nonce = RandomBytesGenerator.generate(cryptoAlgorithm.getNonceLen());
4949

50-
final SecretKey key = new SecretKeySpec(keyBytes, cryptoAlgorithm.name());
50+
final SecretKey key = new SecretKeySpec(keyBytes, cryptoAlgorithm.getKeyAlgo());
5151
CipherHandler cipherHandler = createCipherHandler(key, cryptoAlgorithm, Cipher.ENCRYPT_MODE);
5252
final byte[] encryptedBytes = cipherHandler.cipherData(nonce, contentAad_, content, 0, content.length);
5353

@@ -72,7 +72,7 @@ private byte[] encryptDecrypt(final byte[] content, final CryptoAlgorithm crypto
7272
final byte[] keyBytes = RandomBytesGenerator.generate(cryptoAlgorithm.getKeyLength());
7373
final byte[] nonce = RandomBytesGenerator.generate(cryptoAlgorithm.getNonceLen());
7474

75-
final SecretKey key = new SecretKeySpec(keyBytes, cryptoAlgorithm.name());
75+
final SecretKey key = new SecretKeySpec(keyBytes, cryptoAlgorithm.getKeyAlgo());
7676
CipherHandler cipherHandler = createCipherHandler(key, cryptoAlgorithm, Cipher.ENCRYPT_MODE);
7777
final byte[] encryptedBytes = cipherHandler.cipherData( nonce, contentAad_, content, 0, content.length);
7878

src/test/java/com/amazonaws/encryptionsdk/jce/KeyStoreProviderTest.java

+45-43
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,14 @@
2727
import java.security.KeyStore.PasswordProtection;
2828
import java.security.KeyStoreException;
2929
import java.security.SecureRandom;
30-
import java.security.Security;
3130
import java.security.cert.Certificate;
3231
import java.security.cert.X509Certificate;
32+
import java.time.Instant;
33+
import java.time.temporal.ChronoUnit;
3334
import java.util.Date;
3435

3536
import javax.crypto.spec.SecretKeySpec;
36-
import javax.security.auth.x500.X500Principal;
3737

38-
import org.bouncycastle.asn1.x509.X509Name;
39-
import org.bouncycastle.jce.provider.BouncyCastleProvider;
40-
import org.bouncycastle.x509.X509V3CertificateGenerator;
4138
import org.junit.Before;
4239
import org.junit.Test;
4340

@@ -47,7 +44,18 @@
4744
import com.amazonaws.encryptionsdk.exception.CannotUnwrapDataKeyException;
4845
import com.amazonaws.encryptionsdk.multi.MultipleProviderFactory;
4946

50-
@SuppressWarnings("deprecation")
47+
/* These internal sun classes are included solely for test purposes as
48+
this test cannot use BouncyCastle cert generation, as there are incompatibilities
49+
between how standard BC and FIPS BC perform cert generation. */
50+
import sun.security.x509.AlgorithmId;
51+
import sun.security.x509.CertificateAlgorithmId;
52+
import sun.security.x509.CertificateSerialNumber;
53+
import sun.security.x509.CertificateValidity;
54+
import sun.security.x509.CertificateX509Key;
55+
import sun.security.x509.X500Name;
56+
import sun.security.x509.X509CertImpl;
57+
import sun.security.x509.X509CertInfo;
58+
5159
public class KeyStoreProviderTest {
5260
private static final SecureRandom RND = new SecureRandom();
5361
private static final KeyPairGenerator KG;
@@ -72,7 +80,7 @@ public void setup() throws Exception {
7280
}
7381

7482
@Test
75-
public void singleKeyPkcs1() throws GeneralSecurityException {
83+
public void singleKeyPkcs1() throws Exception {
7684
addEntry("key1");
7785
final KeyStoreProvider mkp = new KeyStoreProvider(ks, PP, "KeyStore", "RSA/ECB/PKCS1Padding", "key1");
7886
final JceMasterKey mk1 = mkp.getMasterKey("key1");
@@ -87,7 +95,7 @@ public void singleKeyPkcs1() throws GeneralSecurityException {
8795
}
8896

8997
@Test
90-
public void singleKeyOaepSha1() throws GeneralSecurityException {
98+
public void singleKeyOaepSha1() throws Exception {
9199
addEntry("key1");
92100
final KeyStoreProvider mkp = new KeyStoreProvider(ks, PP, "KeyStore", "RSA/ECB/OAEPWithSHA-1AndMGF1Padding",
93101
"key1");
@@ -103,7 +111,7 @@ public void singleKeyOaepSha1() throws GeneralSecurityException {
103111
}
104112

105113
@Test
106-
public void singleKeyOaepSha256() throws GeneralSecurityException {
114+
public void singleKeyOaepSha256() throws Exception {
107115
addEntry("key1");
108116
final KeyStoreProvider mkp = new KeyStoreProvider(ks, PP, "KeyStore", "RSA/ECB/OAEPWithSHA-256AndMGF1Padding",
109117
"key1");
@@ -119,7 +127,7 @@ public void singleKeyOaepSha256() throws GeneralSecurityException {
119127
}
120128

121129
@Test
122-
public void multipleKeys() throws GeneralSecurityException {
130+
public void multipleKeys() throws Exception {
123131
addEntry("key1");
124132
addEntry("key2");
125133
final KeyStoreProvider mkp = new KeyStoreProvider(ks, PP, "KeyStore", "RSA/ECB/OAEPWithSHA-256AndMGF1Padding",
@@ -146,7 +154,7 @@ public void multipleKeys() throws GeneralSecurityException {
146154
}
147155

148156
@Test(expected = CannotUnwrapDataKeyException.class)
149-
public void encryptOnly() throws GeneralSecurityException {
157+
public void encryptOnly() throws Exception {
150158
addPublicEntry("key1");
151159
final KeyStoreProvider mkp = new KeyStoreProvider(ks, PP, "KeyStore", "RSA/ECB/OAEPWithSHA-256AndMGF1Padding",
152160
"key1");
@@ -157,7 +165,7 @@ public void encryptOnly() throws GeneralSecurityException {
157165
}
158166

159167
@Test
160-
public void escrowAndSymmetric() throws GeneralSecurityException {
168+
public void escrowAndSymmetric() throws Exception {
161169
addPublicEntry("key1");
162170
addEntry("key2");
163171
final KeyStoreProvider mkp = new KeyStoreProvider(ks, PP, "KeyStore", "RSA/ECB/OAEPWithSHA-256AndMGF1Padding",
@@ -185,7 +193,7 @@ public void escrowAndSymmetric() throws GeneralSecurityException {
185193
}
186194

187195
@Test
188-
public void escrowAndSymmetricSecondProvider() throws GeneralSecurityException {
196+
public void escrowAndSymmetricSecondProvider() throws GeneralSecurityException, IOException {
189197
addPublicEntry("key1");
190198
addEntry("key2");
191199
final KeyStoreProvider mkp = new KeyStoreProvider(ks, PP, "KeyStore", "RSA/ECB/OAEPWithSHA-256AndMGF1Padding",
@@ -263,40 +271,34 @@ public void keystoreAndRawProvider() throws GeneralSecurityException, IOExceptio
263271
assertArrayEquals(PLAINTEXT, crypto.decryptData(ksp, ct.getResult()).getResult());
264272
}
265273

266-
private void addEntry(final String alias) throws GeneralSecurityException {
274+
private void addEntry(final String alias) throws GeneralSecurityException, IOException {
267275
final KeyPair pair = KG.generateKeyPair();
268-
// build a certificate generator
269-
final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
270-
final X500Principal dnName = new X500Principal("cn=" + alias);
271-
272-
certGen.setSerialNumber(new BigInteger(256, RND));
273-
certGen.setSubjectDN(new X509Name("dc=" + alias));
274-
certGen.setIssuerDN(dnName); // use the same
275-
certGen.setNotBefore(new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000));
276-
certGen.setNotAfter(new Date(System.currentTimeMillis() + 2 * 365 * 24 * 60 * 60 * 1000));
277-
certGen.setPublicKey(pair.getPublic());
278-
certGen.setSignatureAlgorithm("SHA256WithRSA");
279-
final X509Certificate cert = certGen.generate(pair.getPrivate(), "BC");
280-
281-
ks.setEntry(alias, new KeyStore.PrivateKeyEntry(pair.getPrivate(), new X509Certificate[] { cert }), PP);
276+
ks.setEntry(alias, new KeyStore.PrivateKeyEntry(pair.getPrivate(),
277+
new X509Certificate[] { generateCertificate(pair, alias) }), PP);
282278
}
283279

284-
private void addPublicEntry(final String alias) throws GeneralSecurityException {
280+
private void addPublicEntry(final String alias) throws GeneralSecurityException, IOException {
285281
final KeyPair pair = KG.generateKeyPair();
286-
// build a certificate generator
287-
final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
288-
final X500Principal dnName = new X500Principal("cn=" + alias);
289-
290-
certGen.setSerialNumber(new BigInteger(256, RND));
291-
certGen.setSubjectDN(new X509Name("dc=" + alias));
292-
certGen.setIssuerDN(dnName); // use the same
293-
certGen.setNotBefore(new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000));
294-
certGen.setNotAfter(new Date(System.currentTimeMillis() + 2 * 365 * 24 * 60 * 60 * 1000));
295-
certGen.setPublicKey(pair.getPublic());
296-
certGen.setSignatureAlgorithm("SHA256WithRSA");
297-
final X509Certificate cert = certGen.generate(pair.getPrivate(), "BC");
298-
299-
ks.setEntry(alias, new KeyStore.TrustedCertificateEntry(cert), null);
282+
ks.setEntry(alias, new KeyStore.TrustedCertificateEntry(generateCertificate(pair, alias)), null);
283+
}
284+
285+
private X509Certificate generateCertificate(final KeyPair pair, final String alias) throws GeneralSecurityException, IOException {
286+
final X509CertInfo info = new X509CertInfo();
287+
final X500Name name = new X500Name("dc=" + alias);
288+
info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(new BigInteger(256, RND)));
289+
info.set(X509CertInfo.SUBJECT, name);
290+
info.set(X509CertInfo.ISSUER, name);
291+
info.set(X509CertInfo.VALIDITY,
292+
new CertificateValidity(Date.from(Instant.now().minus(1, ChronoUnit.DAYS)),
293+
Date.from(Instant.now().plus(730, ChronoUnit.DAYS))));
294+
info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
295+
info.set(X509CertInfo.ALGORITHM_ID,
296+
new CertificateAlgorithmId(new AlgorithmId(AlgorithmId.sha256WithRSAEncryption_oid)));
297+
298+
final X509CertImpl cert = new X509CertImpl(info);
299+
cert.sign(pair.getPrivate(), AlgorithmId.sha256WithRSAEncryption_oid.toString());
300+
301+
return cert;
300302
}
301303

302304
private void copyPublicPart(final KeyStore src, final KeyStore dst, final String alias) throws KeyStoreException {

0 commit comments

Comments
 (0)