'AWS KMS manual key rotation and old encrypted data

I'm trying to enable client-side encryption for the data uploaded to AWS S3 by following the guide: https://docs.aws.amazon.com/sdk-for-net/v3/developer-guide/kms-keys-s3-encryption.html. I have created a CMK in KMS with the automatic rotation disabled and alias test. It's all working fine, I can upload the encrypted data to s3 and then decrypt it from s3. I'm trying to perform manual rotation by following the guide here: https://docs.aws.amazon.com/kms/latest/developerguide/rotate-keys.html (Rotating keys manually) As per docs I need to create a new KMS key and update the alias to test. Now I want to get and decrypt the data that is already uploaded to s3 but was encrypted with an old key. I'm getting this (I'm using alias not keyId in the app):

The key ID in the request does not identify a CMK that can perform this operation

It makes sense because it's a different key and it would be strange if I can use any key to decrypt the data. From what I read, with the automatic rotation you get this behaviour for free but what about manual rotation? Do I need to decrypt all the data and encrypt it with the new key? Maybe can I somehow create a new KMS key with the same key material so it would work similarly to automatic rotation?

The misleading part is a Note on the docs page saying:

Note
When you begin using the new KMS key, be sure to keep the original KMS key enabled so that AWS KMS can decrypt data that the original KMS key encrypted.

This would suggest that I can just change the alias and should be able to decrypt the data with the new CMS key? What am I missing?

var kmsEncryptionMaterials = new EncryptionMaterialsV2("alias/test", KmsType.KmsContext, new Dictionary<string, string>());

 var s3EncClient = new AmazonS3EncryptionClientV2(credentials, config, kmsEncryptionMaterials);

 var result = await s3EncClient.GetObjectAsync(new GetObjectRequest() {Key = "upload-test", BucketName = configuration.Bucket});


Solution 1:[1]

The answer was actually pretty simple. When AmazonS3EncryptionClientV2 uploads the data it uses "Encrypt" (through GenerateDataKey which gives you an encrypted and an unencrypted version of the key. Encrypted key is then uploaded to S3 in the metadata. Part of the encrypted key has information which CMK was used to produce the key. It means that we no longer need to send KeyId when we Decrypt the data. In AmazonS3EncryptionClientV2 I was using the same encryption materials for PutObjectAsync and GetObjectAsync in the following way:

new EncryptionMaterialsV2(configuration.KeyId, KmsType.KmsContext, new Dictionary<string, string>());

Unfortunately when we call GetObjectAsync, the library uses the provided KeyId to decrypt the data. For symmetric algorithms this is optional argument since KeyId is part of the metadata in the uploaded s3 object so there is no need to provide it again. The solution is pretty simple, we just need to recreate AmazonS3EncryptionClientV2 without providing key id.

 var s3EncClient2 = new AmazonS3EncryptionClientV2(credentials, config, new EncryptionMaterialsV2(null, KmsType.KmsContext, new Dictionary<string, string>()));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MistyK