Skip to content

Commit e576378

Browse files
authored
Implement Crypto Provider Behavior (#41)
* Implement Crypto Provider Behavior
1 parent 924c7d0 commit e576378

File tree

14 files changed

+193
-58
lines changed

14 files changed

+193
-58
lines changed

src/main/java/software/amazon/encryption/s3/S3EncryptionClient.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
44

55
import java.security.KeyPair;
6+
import java.security.Provider;
67
import java.util.ArrayList;
78
import java.util.List;
89
import java.security.SecureRandom;
@@ -148,6 +149,7 @@ public static class Builder {
148149
private String _kmsKeyId;
149150
private boolean _enableLegacyUnauthenticatedModes = false;
150151
private boolean _enableDelayedAuthenticationMode = false;
152+
private Provider _cryptoProvider = null;
151153
private SecureRandom _secureRandom = new SecureRandom();
152154

153155
private Builder() {
@@ -243,6 +245,11 @@ public Builder enableDelayedAuthenticationMode(boolean shouldEnableDelayedAuthen
243245
return this;
244246
}
245247

248+
public Builder cryptoProvider(Provider cryptoProvider) {
249+
this._cryptoProvider = cryptoProvider;
250+
return this;
251+
}
252+
246253
public Builder secureRandom(SecureRandom secureRandom) {
247254
if (secureRandom == null) {
248255
throw new S3EncryptionClientException("SecureRandom provided to S3EncryptionClient cannot be null");
@@ -281,6 +288,7 @@ public S3EncryptionClient build() {
281288
if (_cryptoMaterialsManager == null) {
282289
_cryptoMaterialsManager = DefaultCryptoMaterialsManager.builder()
283290
.keyring(_keyring)
291+
.cryptoPovider(_cryptoProvider)
284292
.build();
285293
}
286294

src/main/java/software/amazon/encryption/s3/internal/BufferedAesGcmContentStrategy.java

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,22 @@
11
package software.amazon.encryption.s3.internal;
22

33
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
4-
5-
import java.io.ByteArrayInputStream;
6-
import java.io.IOException;
7-
import java.io.InputStream;
8-
import java.security.InvalidAlgorithmParameterException;
9-
import java.security.InvalidKeyException;
10-
import java.security.NoSuchAlgorithmException;
11-
import java.security.SecureRandom;
12-
13-
import javax.crypto.BadPaddingException;
14-
import javax.crypto.Cipher;
15-
import javax.crypto.IllegalBlockSizeException;
16-
import javax.crypto.NoSuchPaddingException;
17-
import javax.crypto.SecretKey;
18-
import javax.crypto.spec.GCMParameterSpec;
19-
import javax.crypto.spec.SecretKeySpec;
20-
214
import software.amazon.awssdk.utils.IoUtils;
225
import software.amazon.encryption.s3.S3EncryptionClientException;
236
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
247
import software.amazon.encryption.s3.materials.DecryptionMaterials;
258
import software.amazon.encryption.s3.materials.EncryptionMaterials;
269

10+
import javax.crypto.Cipher;
11+
import javax.crypto.SecretKey;
12+
import javax.crypto.spec.GCMParameterSpec;
13+
import javax.crypto.spec.SecretKeySpec;
14+
import java.io.ByteArrayInputStream;
15+
import java.io.IOException;
16+
import java.io.InputStream;
17+
import java.security.GeneralSecurityException;
18+
import java.security.SecureRandom;
19+
2720
/**
2821
* This class will encrypt data according to the algorithm suite constants
2922
*/
@@ -52,7 +45,7 @@ public EncryptedContent encryptContent(EncryptionMaterials materials, byte[] con
5245

5346
final String cipherName = algorithmSuite.cipherName();
5447
try {
55-
final Cipher cipher = Cipher.getInstance(cipherName);
48+
final Cipher cipher = CryptoFactory.createCipher(algorithmSuite.cipherName(), materials.cryptoProvider());
5649

5750
cipher.init(Cipher.ENCRYPT_MODE,
5851
materials.dataKey(),
@@ -63,12 +56,7 @@ public EncryptedContent encryptContent(EncryptionMaterials materials, byte[] con
6356
result.ciphertext = cipher.doFinal(content);
6457

6558
return result;
66-
} catch (NoSuchAlgorithmException
67-
| NoSuchPaddingException
68-
| InvalidAlgorithmParameterException
69-
| InvalidKeyException
70-
| IllegalBlockSizeException
71-
| BadPaddingException e) {
59+
} catch (GeneralSecurityException e) {
7260
throw new S3EncryptionClientException("Unable to " + cipherName + " content encrypt.", e);
7361
}
7462
}
@@ -101,15 +89,10 @@ public InputStream decryptContent(ContentMetadata contentMetadata, DecryptionMat
10189
final Cipher cipher;
10290
byte[] plaintext;
10391
try {
104-
cipher = Cipher.getInstance(algorithmSuite.cipherName());
92+
cipher = CryptoFactory.createCipher(algorithmSuite.cipherName(), materials.cryptoProvider());
10593
cipher.init(Cipher.DECRYPT_MODE, contentKey, new GCMParameterSpec(tagLength, iv));
10694
plaintext = cipher.doFinal(ciphertext);
107-
} catch (NoSuchAlgorithmException
108-
| NoSuchPaddingException
109-
| InvalidAlgorithmParameterException
110-
| InvalidKeyException
111-
| IllegalBlockSizeException
112-
| BadPaddingException e) {
95+
} catch (GeneralSecurityException e) {
11396
throw new S3EncryptionClientException("Unable to " + algorithmSuite.cipherName() + " content decrypt.", e);
11497
}
11598

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package software.amazon.encryption.s3.internal;
2+
3+
import software.amazon.encryption.s3.S3EncryptionClientException;
4+
5+
import javax.crypto.Cipher;
6+
import javax.crypto.KeyGenerator;
7+
import javax.crypto.NoSuchPaddingException;
8+
import java.security.NoSuchAlgorithmException;
9+
import java.security.Provider;
10+
11+
public class CryptoFactory {
12+
public static Cipher createCipher(String algorithm, Provider provider)
13+
throws NoSuchPaddingException, NoSuchAlgorithmException {
14+
// if the user has specified a provider, go with that.
15+
if (provider != null) {
16+
return Cipher.getInstance(algorithm, provider);
17+
}
18+
19+
// Otherwise, go with the default provider.
20+
return Cipher.getInstance(algorithm);
21+
}
22+
23+
public static KeyGenerator generateKey(String algorithm, Provider provider) {
24+
KeyGenerator generator;
25+
try {
26+
if (provider == null) {
27+
generator = KeyGenerator.getInstance(algorithm);
28+
} else {
29+
generator = KeyGenerator.getInstance(algorithm, provider);
30+
}
31+
} catch (NoSuchAlgorithmException e) {
32+
throw new S3EncryptionClientException("Unable to generate a(n) " + algorithm + " data key", e);
33+
}
34+
return generator;
35+
}
36+
}

src/main/java/software/amazon/encryption/s3/legacy/internal/UnauthenticatedContentStrategy.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import software.amazon.encryption.s3.internal.CipherInputStream;
1313
import software.amazon.encryption.s3.internal.ContentDecryptionStrategy;
1414
import software.amazon.encryption.s3.internal.ContentMetadata;
15+
import software.amazon.encryption.s3.internal.CryptoFactory;
1516
import software.amazon.encryption.s3.materials.DecryptionMaterials;
1617

1718
/**
@@ -39,7 +40,7 @@ public InputStream decryptContent(ContentMetadata contentMetadata, DecryptionMat
3940
SecretKey contentKey = new SecretKeySpec(materials.plaintextDataKey(), algorithmSuite.dataKeyAlgorithm());
4041
try {
4142
// TODO: Allow configurable Cryptographic provider
42-
final Cipher cipher = Cipher.getInstance(algorithmSuite.cipherName());
43+
final Cipher cipher = CryptoFactory.createCipher(algorithmSuite.cipherName(), materials.cryptoProvider());
4344
cipher.init(Cipher.DECRYPT_MODE, contentKey, new IvParameterSpec(iv));
4445
InputStream plaintext = new CipherInputStream(ciphertextStream, cipher);
4546
return RangedGetUtils.adjustToDesiredRange(plaintext, desiredRange, contentMetadata.contentRange(), algorithmSuite.cipherTagLengthBits());

src/main/java/software/amazon/encryption/s3/materials/AesKeyring.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import software.amazon.encryption.s3.S3EncryptionClientException;
1414
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
15+
import software.amazon.encryption.s3.internal.CryptoFactory;
1516

1617
/**
1718
* This keyring can wrap keys with the active keywrap algorithm and
@@ -40,7 +41,7 @@ public String keyProviderInfo() {
4041

4142
@Override
4243
public byte[] decryptDataKey(DecryptionMaterials materials, byte[] encryptedDataKey) throws GeneralSecurityException {
43-
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
44+
final Cipher cipher = CryptoFactory.createCipher(CIPHER_ALGORITHM, materials.cryptoProvider());
4445
cipher.init(Cipher.DECRYPT_MODE, _wrappingKey);
4546

4647
return cipher.doFinal(encryptedDataKey);
@@ -64,7 +65,7 @@ public String keyProviderInfo() {
6465

6566
@Override
6667
public byte[] decryptDataKey(DecryptionMaterials materials, byte[] encryptedDataKey) throws GeneralSecurityException {
67-
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
68+
final Cipher cipher = CryptoFactory.createCipher(CIPHER_ALGORITHM, materials.cryptoProvider());
6869
cipher.init(Cipher.UNWRAP_MODE, _wrappingKey);
6970

7071
Key plaintextKey = cipher.unwrap(encryptedDataKey, CIPHER_ALGORITHM, Cipher.SECRET_KEY);
@@ -98,7 +99,7 @@ public byte[] encryptDataKey(SecureRandom secureRandom,
9899
secureRandom.nextBytes(nonce);
99100
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH_BITS, nonce);
100101

101-
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
102+
final Cipher cipher = CryptoFactory.createCipher(CIPHER_ALGORITHM, materials.cryptoProvider());
102103
cipher.init(Cipher.ENCRYPT_MODE, _wrappingKey, gcmParameterSpec, secureRandom);
103104

104105
final byte[] aADBytes = AlgorithmSuite.ALG_AES_256_GCM_IV12_TAG16_NO_KDF.cipherName().getBytes(StandardCharsets.UTF_8);
@@ -123,7 +124,7 @@ public byte[] decryptDataKey(DecryptionMaterials materials, byte[] encryptedData
123124
System.arraycopy(encodedBytes, nonce.length, ciphertext, 0, ciphertext.length);
124125

125126
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(TAG_LENGTH_BITS, nonce);
126-
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
127+
final Cipher cipher = CryptoFactory.createCipher(CIPHER_ALGORITHM, materials.cryptoProvider());
127128
cipher.init(Cipher.DECRYPT_MODE, _wrappingKey, gcmParameterSpec);
128129

129130
final byte[] aADBytes = AlgorithmSuite.ALG_AES_256_GCM_IV12_TAG16_NO_KDF.cipherName().getBytes(StandardCharsets.UTF_8);

src/main/java/software/amazon/encryption/s3/materials/DataKeyGenerator.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
import javax.crypto.SecretKey;
44
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
55

6+
import java.security.Provider;
7+
68
@FunctionalInterface
79
public interface DataKeyGenerator {
8-
SecretKey generateDataKey(AlgorithmSuite algorithmSuite);
10+
SecretKey generateDataKey(AlgorithmSuite algorithmSuite, Provider provider);
911
}

src/main/java/software/amazon/encryption/s3/materials/DecryptionMaterials.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
44

5+
import java.security.Provider;
56
import java.util.Collections;
67
import java.util.Map;
78

@@ -26,13 +27,15 @@ final public class DecryptionMaterials implements CryptographicMaterials {
2627
private final byte[] _plaintextDataKey;
2728

2829
private long _ciphertextLength;
30+
private Provider _cryptoProvider;
2931

3032
private DecryptionMaterials(Builder builder) {
3133
this._s3Request = builder._s3Request;
3234
this._algorithmSuite = builder._algorithmSuite;
3335
this._encryptionContext = builder._encryptionContext;
3436
this._plaintextDataKey = builder._plaintextDataKey;
3537
this._ciphertextLength = builder._ciphertextLength;
38+
this._cryptoProvider = builder._cryptoProvider;
3639
}
3740

3841
static public Builder builder() {
@@ -68,6 +71,10 @@ public SecretKey dataKey() {
6871
return new SecretKeySpec(_plaintextDataKey, "AES");
6972
}
7073

74+
public Provider cryptoProvider() {
75+
return _cryptoProvider;
76+
}
77+
7178
public long ciphertextLength() {
7279
return _ciphertextLength;
7380
}
@@ -78,12 +85,14 @@ public Builder toBuilder() {
7885
.algorithmSuite(_algorithmSuite)
7986
.encryptionContext(_encryptionContext)
8087
.plaintextDataKey(_plaintextDataKey)
81-
.ciphertextLength(_ciphertextLength);
88+
.ciphertextLength(_ciphertextLength)
89+
.cryptoProvider(_cryptoProvider);
8290
}
8391

8492
static public class Builder {
8593

8694
public GetObjectRequest _s3Request = null;
95+
private Provider _cryptoProvider = null;
8796
private AlgorithmSuite _algorithmSuite = AlgorithmSuite.ALG_AES_256_GCM_IV12_TAG16_NO_KDF;
8897
private Map<String, String> _encryptionContext = Collections.emptyMap();
8998
private byte[] _plaintextDataKey = null;
@@ -119,6 +128,11 @@ public Builder ciphertextLength(long ciphertextLength) {
119128
return this;
120129
}
121130

131+
public Builder cryptoProvider(Provider cryptoProvider) {
132+
_cryptoProvider = cryptoProvider;
133+
return this;
134+
}
135+
122136
public DecryptionMaterials build() {
123137
return new DecryptionMaterials(this);
124138
}

src/main/java/software/amazon/encryption/s3/materials/DefaultCryptoMaterialsManager.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
44

5+
import java.security.Provider;
6+
57
public class DefaultCryptoMaterialsManager implements CryptographicMaterialsManager {
68
private final Keyring _keyring;
7-
9+
private final Provider _cryptoProvider;
810

911
private DefaultCryptoMaterialsManager(Builder builder) {
1012
_keyring = builder._keyring;
13+
_cryptoProvider = builder._cryptoProvider;
1114
}
1215

1316
public static Builder builder() {
@@ -19,6 +22,7 @@ public EncryptionMaterials getEncryptionMaterials(EncryptionMaterialsRequest req
1922
.s3Request(request.s3Request())
2023
.algorithmSuite(AlgorithmSuite.ALG_AES_256_GCM_IV12_TAG16_NO_KDF)
2124
.encryptionContext(request.encryptionContext())
25+
.cryptoProvider(_cryptoProvider)
2226
.build();
2327

2428
return _keyring.onEncrypt(materials);
@@ -30,13 +34,15 @@ public DecryptionMaterials decryptMaterials(DecryptMaterialsRequest request) {
3034
.algorithmSuite(request.algorithmSuite())
3135
.encryptionContext(request.encryptionContext())
3236
.ciphertextLength(request.ciphertextLength())
37+
.cryptoProvider(_cryptoProvider)
3338
.build();
3439

3540
return _keyring.onDecrypt(materials, request.encryptedDataKeys());
3641
}
3742

3843
public static class Builder {
3944
private Keyring _keyring;
45+
private Provider _cryptoProvider;
4046

4147
private Builder() {}
4248

@@ -45,6 +51,11 @@ public Builder keyring(Keyring keyring) {
4551
return this;
4652
}
4753

54+
public Builder cryptoPovider(Provider cryptoProvider) {
55+
this._cryptoProvider = cryptoProvider;
56+
return this;
57+
}
58+
4859
public DefaultCryptoMaterialsManager build() {
4960
return new DefaultCryptoMaterialsManager(this);
5061
}

src/main/java/software/amazon/encryption/s3/materials/DefaultDataKeyGenerator.java

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
package software.amazon.encryption.s3.materials;
22

3-
import java.security.NoSuchAlgorithmException;
3+
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
4+
import software.amazon.encryption.s3.internal.CryptoFactory;
5+
46
import javax.crypto.KeyGenerator;
57
import javax.crypto.SecretKey;
6-
import software.amazon.encryption.s3.S3EncryptionClientException;
7-
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
8+
import java.security.Provider;
89

910
public class DefaultDataKeyGenerator implements DataKeyGenerator {
1011

11-
public SecretKey generateDataKey(AlgorithmSuite algorithmSuite) {
12-
KeyGenerator generator;
13-
try {
14-
generator = KeyGenerator.getInstance(algorithmSuite.dataKeyAlgorithm());
15-
} catch (NoSuchAlgorithmException e) {
16-
throw new S3EncryptionClientException("Unable to generate a(n) " + algorithmSuite.dataKeyAlgorithm() + " data key", e);
17-
}
18-
12+
public SecretKey generateDataKey(AlgorithmSuite algorithmSuite, Provider provider) {
13+
KeyGenerator generator = CryptoFactory.generateKey(algorithmSuite.dataKeyAlgorithm(), provider);
1914
generator.init(algorithmSuite.dataKeyLengthBits());
2015
return generator.generateKey();
2116
}

0 commit comments

Comments
 (0)