Skip to content

Commit 1e17d4d

Browse files
committed
chore(duvet): duvet for updated spec
1 parent 4ca11bd commit 1e17d4d

File tree

7 files changed

+66
-12
lines changed

7 files changed

+66
-12
lines changed

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,15 @@ public static Cipher createAndInitCipher(final CryptographicMaterials materials,
195195
}
196196
//= specification/s3-encryption/decryption.md#cbc-decryption
197197
//# If an object is encrypted with ALG_AES_256_CBC_IV16_NO_KDF and [legacy unauthenticated algorithm suites](#legacy-decryption) is enabled,
198-
//# then the S3EC MUST create a cipher object using the cipher transformation "AES/CBC/PKCS5Padding".
199-
// NOTE: PKCS5Padding is specified above in CryptoFactory.createCipher(materials.algorithmSuite().cipherName(), materials.cryptoProvider())
198+
//# then the S3EC MUST create a cipher with AES in CBC Mode with PKCS5Padding or PKCS7Padding compatible padding for a 16-byte block cipher (example: for the Java JCE, this is "AES/CBC/PKCS5Padding").
199+
// NOTE: CBC and PKCS5Padding is specified above in CryptoFactory.createCipher(materials.algorithmSuite().cipherName(), materials.cryptoProvider())
200+
//= specification/s3-encryption/decryption.md#cbc-decryption
201+
//# If the cipher object cannot be created as described above,
202+
//# Decryption MUST fail.
203+
//= specification/s3-encryption/decryption.md#cbc-decryption
204+
//= type=exception
205+
//# The error SHOULD detail why the cipher could not be initialized
206+
//# (such as CBC or PKCS5Padding is not supported by the underlying crypto provider).
200207
cipher.init(materials.cipherMode().opMode(), materials.dataKey(), new IvParameterSpec(iv));
201208
break;
202209
case ALG_AES_256_CTR_HKDF_SHA512_COMMIT_KEY:

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ public PutObjectRequest encodeMetadata(EncryptionMaterials materials, byte[] iv,
5454
} else {
5555
//= specification/s3-encryption/data-format/metadata-strategy.md#object-metadata
5656
//# By default, the S3EC MUST store content metadata in the S3 Object Metadata.
57+
//= specification/s3-encryption/data-format/content-metadata.md#us-ascii-preferred-string
58+
//= type=exception
59+
//= reason=It would be a breaking change to introduce this.
60+
//# Thus,
61+
//# Content Metadata MapKeys SHOULD be restricted to US-ASCII.
5762
Map<String, String> newMetadata = addMetadataToMap(putObjectRequest.metadata(), materials, iv);
5863
return putObjectRequest.toBuilder()
5964
.metadata(newMetadata)
@@ -80,6 +85,11 @@ public CreateMultipartUploadRequest encodeMetadata(EncryptionMaterials materials
8085
return createMultipartUploadRequest.toBuilder()
8186
.metadata(objectMetadata).build();
8287
} else {
88+
//= specification/s3-encryption/data-format/content-metadata.md#us-ascii-preferred-string
89+
//= type=exception
90+
//= reason=It would be a breaking change to introduce this.
91+
//# Thus,
92+
//# Content Metadata MapKeys SHOULD be restricted to US-ASCII.
8393
Map<String, String> newMetadata = addMetadataToMap(createMultipartUploadRequest.metadata(), materials, iv);
8494
return createMultipartUploadRequest.toBuilder()
8595
.metadata(newMetadata)
@@ -159,6 +169,8 @@ private Map<String, String> addMetadataToMapV3(Map<String, String> map, Encrypti
159169
jsonWriter.writeFieldName(entry.getKey()).writeValue(entry.getValue());
160170
}
161171
jsonWriter.writeEndObject();
172+
//= specification/s3-encryption/data-format/content-metadata.md#us-ascii-preferred-string
173+
//# An implementation MAY support UTF-8.
162174
String jsonEncryptionContext = new String(jsonWriter.getBytes(), StandardCharsets.UTF_8);
163175
//= specification/s3-encryption/data-format/metadata-strategy.md#v3-instruction-files
164176
//# - The V3 message format MUST store the mapkey "x-amz-t" and its value (when present in the content metadata) in the Instruction File.
@@ -169,6 +181,8 @@ private Map<String, String> addMetadataToMapV3(Map<String, String> map, Encrypti
169181
jsonWriter.writeFieldName(entry.getKey()).writeValue(entry.getValue());
170182
}
171183
jsonWriter.writeEndObject();
184+
//= specification/s3-encryption/data-format/content-metadata.md#us-ascii-preferred-string
185+
//# An implementation MAY support UTF-8.
172186
String jsonEncryptionContext = new String(jsonWriter.getBytes(), StandardCharsets.UTF_8);
173187
//= specification/s3-encryption/data-format/metadata-strategy.md#v3-instruction-files
174188
//# - The V3 message format MUST store the mapkey "x-amz-m" and its value (when present in the content metadata) in the Instruction File.
@@ -220,6 +234,8 @@ private Map<String, String> addMetadataToMapV2(Map<String, String> map, Encrypti
220234
}
221235
}
222236
jsonWriter.writeEndObject();
237+
//= specification/s3-encryption/data-format/content-metadata.md#us-ascii-preferred-string
238+
//# An implementation MAY support UTF-8.
223239
String jsonEncryptionContext = new String(jsonWriter.getBytes(), StandardCharsets.UTF_8);
224240
metadata.put(MetadataKeyConstants.ENCRYPTED_DATA_KEY_MATDESC_OR_EC, jsonEncryptionContext);
225241
} catch (JsonWriter.JsonGenerationException e) {

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

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,6 @@
1111
import java.security.Provider;
1212

1313
public class CryptoFactory {
14-
//= specification/s3-encryption/decryption.md#cbc-decryption
15-
//# If the cipher object cannot be created as described above,
16-
//# Decryption MUST fail.
17-
//= specification/s3-encryption/decryption.md#cbc-decryption
18-
//= type=exception
19-
//# The error SHOULD detail why the cipher could not be initialized
20-
//# (such as CBC or PKCS5Padding is not supported by the underlying crypto provider).
2114
public static Cipher createCipher(String algorithm, Provider provider)
2215
throws NoSuchPaddingException, NoSuchAlgorithmException {
2316
// if the user has specified a provider, go with that.

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ public static boolean isV1Format(Map<String, String> metadata) {
7272
return metadata.containsKey(CONTENT_IV) &&
7373
metadata.containsKey(ENCRYPTED_DATA_KEY_MATDESC_OR_EC) &&
7474
metadata.containsKey(ENCRYPTED_DATA_KEY_V1) &&
75-
//= specification/s3-encryption/data-format/content-metadata.md#content-metadata-mapkeys
76-
//= type=implication
77-
//# - Mapkeys exclusive to other format versions MUST NOT be present.
75+
///= specification/s3-encryption/data-format/content-metadata.md#content-metadata-mapkeys
76+
///= type=implication
77+
///# - Mapkeys exclusive to other format versions MUST NOT be present.
7878
!metadata.containsKey(ENCRYPTED_DATA_KEY_V2) &&
7979
!metadata.containsKey(ENCRYPTED_DATA_KEY_V3);
8080
}

src/test/java/software/amazon/encryption/s3/S3EncryptionClientBuilderValidationTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,10 @@ public void testBuilderWithLegacyAlgorithmFails() throws NoSuchAlgorithmExceptio
181181
S3EncryptionClientException exception = assertThrows(S3EncryptionClientException.class, () ->
182182
S3EncryptionClient.builderV4()
183183
.aesKey(aesKey)
184+
//= specification/s3-encryption/decryption.md#cbc-decryption
185+
//= type=test
186+
//# If an object is encrypted with ALG_AES_256_CBC_IV16_NO_KDF and [legacy unauthenticated algorithm suites](#legacy-decryption) is NOT enabled,
187+
//# the S3EC MUST throw an error which details that client was not configured to decrypt objects with ALG_AES_256_CBC_IV16_NO_KDF.
184188
.encryptionAlgorithm(AlgorithmSuite.ALG_AES_256_CBC_IV16_NO_KDF)
185189
.build()
186190
);

src/test/java/software/amazon/encryption/s3/internal/CipherProviderTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,21 @@ public void testCreateAndInitCipherALG_AES_256_CBC_IV16_NO_KDF_DecryptionSucceed
300300
Cipher cipher = CipherProvider.createAndInitCipher(materials, iv, messageId);
301301

302302
assertNotNull(cipher);
303+
//= specification/s3-encryption/decryption.md#cbc-decryption
304+
//= type=exception
305+
//= reason=Well cipher creation failure does throw an error, we do not catch the error and throw a reasonable message
306+
//# If the cipher object cannot be created as described above,
307+
//# Decryption MUST fail.
308+
//= specification/s3-encryption/decryption.md#cbc-decryption
309+
//= type=TODO
310+
//# The error SHOULD detail why the cipher could not be initialized
311+
//# (such as CBC or PKCS5Padding is not supported by the underlying crypto provider).
312+
// If we ever refactor so that the cipher creation failure is a modeled error, we should add tests for it.
313+
314+
//= specification/s3-encryption/decryption.md#cbc-decryption
315+
//= type=test
316+
//# If an object is encrypted with ALG_AES_256_CBC_IV16_NO_KDF and [legacy unauthenticated algorithm suites](#legacy-decryption) is enabled,
317+
//# then the S3EC MUST create a cipher with AES in CBC Mode with PKCS5Padding or PKCS7Padding compatible padding for a 16-byte block cipher (example: for the Java JCE, this is "AES/CBC/PKCS5Padding").
303318
assertEquals("AES/CBC/PKCS5Padding", cipher.getAlgorithm());
304319
}
305320

src/test/java/software/amazon/encryption/s3/internal/ContentMetadataStrategyTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,25 @@ public void testMissingKeysV1() {
427427
assertTrue(exception.getMessage().contains("Content metadata is tampered, required metadata to decrypt the object are missing"));
428428
}
429429

430+
@Test
431+
public void testMissingKeysV1Colliding() {
432+
Map<String, String> metadata = new HashMap<>();
433+
metadata.put("x-amz-iv", "dGVzdC1pdi0xMi1i"); // base64 of "test-iv-12-b"
434+
metadata.put("x-amz-key", "ZW5jcnlwdGVkLWtleS1kYXRh"); // base64 of "encrypted-key-data"
435+
metadata.put("x-amz-matdesc", "{}");
436+
metadata.put("x-amz-key-v2", "ZW5jcnlwdGVkLWtleS1kYXRh");
437+
438+
GetObjectResponse response = GetObjectResponse.builder()
439+
.metadata(metadata)
440+
.build();
441+
//= specification/s3-encryption/data-format/content-metadata.md#content-metadata-mapkeys
442+
//= type=test
443+
//# - If mapkeys exclusive to other (non-V1) format versions is present,the S3EC SHOULD throw an exception.
444+
S3EncryptionClientException exception = assertThrows(S3EncryptionClientException.class, () -> decodingStrategy.decode(getObjectRequest, response));
445+
System.out.println(exception.getMessage());
446+
assertTrue(exception.getMessage().contains("Content metadata is tampered, required metadata combination is illegal."));
447+
}
448+
430449
@Test
431450
public void testExclusiveKeysCollision() {
432451
Map<String, String> metadata = new HashMap<>();

0 commit comments

Comments
 (0)