9292import java .util .function .Consumer ;
9393
9494import static software .amazon .encryption .s3 .S3EncryptionClientUtilities .DEFAULT_BUFFER_SIZE_BYTES ;
95- import static software .amazon .encryption .s3 .S3EncryptionClientUtilities .INSTRUCTION_FILE_SUFFIX ;
95+
96+ import static software .amazon .encryption .s3 .S3EncryptionClientUtilities .DEFAULT_INSTRUCTION_FILE_SUFFIX ;
9697import static software .amazon .encryption .s3 .S3EncryptionClientUtilities .MAX_ALLOWED_BUFFER_SIZE_BYTES ;
9798import static software .amazon .encryption .s3 .S3EncryptionClientUtilities .MIN_ALLOWED_BUFFER_SIZE_BYTES ;
9899import static software .amazon .encryption .s3 .S3EncryptionClientUtilities .instructionFileKeysToDelete ;
@@ -201,27 +202,19 @@ public static Consumer<AwsRequestOverrideConfiguration.Builder> withAdditionalCo
201202 * Re-encrypts an instruction file with a new keyring while preserving the original encrypted object in S3.
202203 * This enables:
203204 * 1. Key rotation by updating instruction file metadata without re-encrypting object content
204- * 2. Sharing encrypted objects with partners by creating new instruction files with their public keys
205+ * 2. Sharing encrypted objects with partners by creating new instruction files with a custom suffix using their public keys
205206 * <p>
206207 * Key rotation scenarios:
207- * - Legacy to V3: Can rotate same key from V1/V2 to V3's improved algorithms
208- * - Within V3: Cannot rotate to the current key
209- * <p>
210- * Instruction file behavior:
211- * - AES keyrings: Uses default ".instruction" suffix
212- * - RSA keyrings: Requires custom suffix for multiple access patterns
213- * <p>
214- * Requirements:
215- * - New keyring must have different materials description
216- * - Custom instruction file suffix required for RSA keyrings
217- * - Default instruction file suffix required for AES keyrings
208+ * - Legacy to V3: Can rotate same wrapping key from legacy wrapping algorithms to fully supported wrapping algorithms
209+ * - Within V3: When rotating the wrapping key, the new keyring must be different from the current keyring
218210 *
219211 * @param reEncryptInstructionFileRequest the request containing bucket, object key, new keyring, and optional instruction file suffix
220212 * @return ReEncryptInstructionFileResponse containing the bucket, object key, and instruction file suffix used
221213 * @throws S3EncryptionClientException if the new keyring has the same materials description as the current one
222214 */
223215 public ReEncryptInstructionFileResponse reEncryptInstructionFile (ReEncryptInstructionFileRequest reEncryptInstructionFileRequest ) {
224- GetObjectRequest request = GetObjectRequest .builder ()
216+ //GetObjectRequest MUST be kept the same
217+ final GetObjectRequest request = GetObjectRequest .builder ()
225218 .bucket (reEncryptInstructionFileRequest .bucket ())
226219 .key (reEncryptInstructionFileRequest .key ())
227220 .build ();
@@ -230,19 +223,24 @@ public ReEncryptInstructionFileResponse reEncryptInstructionFile(ReEncryptInstru
230223 ContentMetadataDecodingStrategy decodingStrategy = new ContentMetadataDecodingStrategy (_instructionFileConfig );
231224 ContentMetadata contentMetadata = decodingStrategy .decode (request , response .response ());
232225
233- AlgorithmSuite algorithmSuite = contentMetadata .algorithmSuite ();
234- EncryptedDataKey originalEncryptedDataKeys = contentMetadata .encryptedDataKey ();
235- Map <String , String > currentKeyringMaterialsDescription = contentMetadata .encryptedDataKeyContext ();
236- byte [] iv = contentMetadata .contentIv ();
226+ // Algorithm Suite MUST be kept the same
227+ final AlgorithmSuite algorithmSuite = contentMetadata .algorithmSuite ();
228+ // Original Encrypted Data Key MUST be kept the same
229+ final EncryptedDataKey originalEncryptedDataKey = contentMetadata .encryptedDataKey ();
230+ // Current Keyring's Materials Description MUST be kept the same
231+ final Map <String , String > currentKeyringMaterialsDescription = contentMetadata .encryptedDataKeyMatDescOrContext ();
232+ // Content IV MUST be kept the same
233+ final byte [] iv = contentMetadata .contentIv ();
237234
238235 DecryptionMaterials decryptedMaterials = this ._cryptoMaterialsManager .decryptMaterials (
239236 DecryptMaterialsRequest .builder ()
240237 .algorithmSuite (algorithmSuite )
241- .encryptedDataKeys (Collections .singletonList (originalEncryptedDataKeys ))
238+ .encryptedDataKeys (Collections .singletonList (originalEncryptedDataKey ))
242239 .s3Request (request )
243240 .build ()
244241 );
245- byte [] plaintextDataKey = decryptedMaterials .plaintextDataKey ();
242+ //Plaintext Data Key MUST be kept the same
243+ final byte [] plaintextDataKey = decryptedMaterials .plaintextDataKey ();
246244
247245 EncryptionMaterials encryptionMaterials = EncryptionMaterials .builder ()
248246 .algorithmSuite (algorithmSuite )
@@ -251,27 +249,22 @@ public ReEncryptInstructionFileResponse reEncryptInstructionFile(ReEncryptInstru
251249 .build ();
252250
253251 RawKeyring newKeyring = reEncryptInstructionFileRequest .newKeyring ();
254- EncryptionMaterials encryptedMaterials = newKeyring .onEncrypt (encryptionMaterials );
255-
256- Map <String , String > newMaterialsDescription = encryptedMaterials .materialsDescription ().getMaterialsDescription ();
252+ //Encrypted Materials MUST be kept the same
253+ final EncryptionMaterials encryptedMaterials = newKeyring .onEncrypt (encryptionMaterials );
254+ //New Keyring's Materials Description MUST be kept the same
255+ final Map <String , String > newMaterialsDescription = encryptedMaterials .materialsDescription ().getMaterialsDescription ();
257256
258257 if (newMaterialsDescription .equals (currentKeyringMaterialsDescription )) {
259258 throw new S3EncryptionClientException ("New keyring must have new materials description!" );
260259 }
261260
262261 ContentMetadataEncodingStrategy encodeStrategy = new ContentMetadataEncodingStrategy (_instructionFileConfig );
263262
264- if (reEncryptInstructionFileRequest .instructionFileSuffix ().equals (INSTRUCTION_FILE_SUFFIX )) {
265- encodeStrategy .encodeMetadata (encryptedMaterials , iv , PutObjectRequest .builder ()
266- .bucket (reEncryptInstructionFileRequest .bucket ())
267- .key (reEncryptInstructionFileRequest .key ())
268- .build ());
269- } else {
270- encodeStrategy .encodeMetadata (encryptedMaterials , iv , PutObjectRequest .builder ()
271- .bucket (reEncryptInstructionFileRequest .bucket ())
272- .key (reEncryptInstructionFileRequest .key ())
273- .build (), reEncryptInstructionFileRequest .instructionFileSuffix ());
274- }
263+ encodeStrategy .encodeMetadata (encryptedMaterials , iv , PutObjectRequest .builder ()
264+ .bucket (reEncryptInstructionFileRequest .bucket ())
265+ .key (reEncryptInstructionFileRequest .key ())
266+ .build (), reEncryptInstructionFileRequest .instructionFileSuffix ());
267+
275268 return new ReEncryptInstructionFileResponse (reEncryptInstructionFileRequest .bucket (),
276269 reEncryptInstructionFileRequest .key (), reEncryptInstructionFileRequest .instructionFileSuffix ());
277270
@@ -485,7 +478,7 @@ public DeleteObjectResponse deleteObject(DeleteObjectRequest deleteObjectRequest
485478 // Delete the object
486479 DeleteObjectResponse deleteObjectResponse = _wrappedAsyncClient .deleteObject (actualRequest ).join ();
487480 // If Instruction file exists, delete the instruction file as well.
488- String instructionObjectKey = deleteObjectRequest .key () + INSTRUCTION_FILE_SUFFIX ;
481+ String instructionObjectKey = deleteObjectRequest .key () + DEFAULT_INSTRUCTION_FILE_SUFFIX ;
489482 _wrappedAsyncClient .deleteObject (builder -> builder
490483 .overrideConfiguration (API_NAME_INTERCEPTOR )
491484 .bucket (deleteObjectRequest .bucket ())
0 commit comments