1
1
package software .amazon .encryption .s3 .internal ;
2
2
3
3
import edu .umd .cs .findbugs .annotations .SuppressFBWarnings ;
4
-
5
4
import software .amazon .awssdk .core .ResponseInputStream ;
6
5
import software .amazon .awssdk .core .async .AsyncResponseTransformer ;
7
6
import software .amazon .awssdk .core .async .SdkPublisher ;
23
22
import javax .crypto .Cipher ;
24
23
import javax .crypto .SecretKey ;
25
24
import javax .crypto .spec .GCMParameterSpec ;
25
+ import javax .crypto .spec .IvParameterSpec ;
26
26
import javax .crypto .spec .SecretKeySpec ;
27
27
import java .io .InputStream ;
28
28
import java .nio .ByteBuffer ;
@@ -64,29 +64,6 @@ public <T> CompletableFuture<T> getObject(GetObjectRequest getObjectRequest, Asy
64
64
getObjectRequest ));
65
65
}
66
66
67
- /**
68
- * This helps reduce code duplication between async and default getObject implementations.
69
- */
70
- private DecryptionMaterials prepareMaterialsFromRequest (final GetObjectRequest getObjectRequest , final GetObjectResponse getObjectResponse ,
71
- final ContentMetadata contentMetadata ) {
72
- AlgorithmSuite algorithmSuite = contentMetadata .algorithmSuite ();
73
- if (!_enableLegacyUnauthenticatedModes && algorithmSuite .isLegacy ()) {
74
- throw new S3EncryptionClientException ("Enable legacy unauthenticated modes to use legacy content decryption: " + algorithmSuite .cipherName ());
75
- }
76
-
77
- List <EncryptedDataKey > encryptedDataKeys = Collections .singletonList (contentMetadata .encryptedDataKey ());
78
-
79
- DecryptMaterialsRequest materialsRequest = DecryptMaterialsRequest .builder ()
80
- .s3Request (getObjectRequest )
81
- .algorithmSuite (algorithmSuite )
82
- .encryptedDataKeys (encryptedDataKeys )
83
- .encryptionContext (contentMetadata .encryptedDataKeyContext ())
84
- .ciphertextLength (getObjectResponse .contentLength ())
85
- .build ();
86
-
87
- return _cryptoMaterialsManager .decryptMaterials (materialsRequest );
88
- }
89
-
90
67
public <T > T getObject (GetObjectRequest getObjectRequest ,
91
68
ResponseTransformer <GetObjectResponse , T > responseTransformer ) {
92
69
ResponseInputStream <GetObjectResponse > objectStream ;
@@ -114,6 +91,29 @@ public <T> T getObject(GetObjectRequest getObjectRequest,
114
91
}
115
92
}
116
93
94
+ /**
95
+ * This helps reduce code duplication between async and default getObject implementations.
96
+ */
97
+ private DecryptionMaterials prepareMaterialsFromRequest (final GetObjectRequest getObjectRequest , final GetObjectResponse getObjectResponse ,
98
+ final ContentMetadata contentMetadata ) {
99
+ AlgorithmSuite algorithmSuite = contentMetadata .algorithmSuite ();
100
+ if (!_enableLegacyUnauthenticatedModes && algorithmSuite .isLegacy ()) {
101
+ throw new S3EncryptionClientException ("Enable legacy unauthenticated modes to use legacy content decryption: " + algorithmSuite .cipherName ());
102
+ }
103
+
104
+ List <EncryptedDataKey > encryptedDataKeys = Collections .singletonList (contentMetadata .encryptedDataKey ());
105
+
106
+ DecryptMaterialsRequest materialsRequest = DecryptMaterialsRequest .builder ()
107
+ .s3Request (getObjectRequest )
108
+ .algorithmSuite (algorithmSuite )
109
+ .encryptedDataKeys (encryptedDataKeys )
110
+ .encryptionContext (contentMetadata .encryptedDataKeyContext ())
111
+ .ciphertextLength (getObjectResponse .contentLength ())
112
+ .build ();
113
+
114
+ return _cryptoMaterialsManager .decryptMaterials (materialsRequest );
115
+ }
116
+
117
117
private ContentDecryptionStrategy selectContentDecryptionStrategy (final DecryptionMaterials materials ) {
118
118
switch (materials .algorithmSuite ()) {
119
119
case ALG_AES_256_CBC_IV16_NO_KDF :
@@ -161,6 +161,9 @@ public CompletableFuture<T> prepare() {
161
161
@ Override
162
162
public void onResponse (GetObjectResponse response ) {
163
163
getObjectResponse = response ;
164
+ if (!_enableLegacyUnauthenticatedModes && getObjectRequest .range () != null ) {
165
+ throw new S3EncryptionClientException ("Enable legacy unauthenticated modes to use Ranged Get." );
166
+ }
164
167
// TODO: Implement instruction file handling - this is a bit less intuitive in async
165
168
contentMetadata = ContentMetadataStrategy .decode (null , getObjectRequest , response );
166
169
materials = prepareMaterialsFromRequest (getObjectRequest , response , contentMetadata );
@@ -180,7 +183,18 @@ public void onStream(SdkPublisher<ByteBuffer> ciphertextPublisher) {
180
183
byte [] iv = contentMetadata .contentNonce ();
181
184
try {
182
185
final Cipher cipher = CryptoFactory .createCipher (algorithmSuite .cipherName (), materials .cryptoProvider ());
183
- cipher .init (Cipher .DECRYPT_MODE , contentKey , new GCMParameterSpec (tagLength , iv ));
186
+ switch (algorithmSuite ) {
187
+ case ALG_AES_256_GCM_IV12_TAG16_NO_KDF :
188
+ cipher .init (Cipher .DECRYPT_MODE , contentKey , new GCMParameterSpec (tagLength , iv ));
189
+ break ;
190
+ case ALG_AES_256_CBC_IV16_NO_KDF :
191
+ cipher .init (Cipher .DECRYPT_MODE , contentKey , new IvParameterSpec (iv ));
192
+ break ;
193
+ case ALG_AES_256_CTR_IV16_TAG16_NO_KDF :
194
+ // TODO: Ranged Get
195
+ default :
196
+ throw new S3EncryptionClientException ("Unknown algorithm: " + algorithmSuite .cipherName ());
197
+ }
184
198
185
199
CipherPublisher plaintextPublisher = new CipherPublisher (cipher , ciphertextPublisher , getObjectResponse .contentLength ());
186
200
wrappedAsyncResponseTransformer .onStream (plaintextPublisher );
0 commit comments