If you attempt to read encrypted data from a DynamoDB table which has been restored from a backup to a DynamoDB table which doesn’t match the original table name, you may see the following errors:

InvalidCiphertextException: An error occurred (InvalidCiphertextException) when calling the Decrypt operation

and

UnwrappingError: Failed to unwrap AWS KMS protected materials

In this case:

  • A backup of the DynamoDB table “Notes” had been restored to a new DynamoDB table “Notes-Restored”
  • The table was using encryption at rest
  • One of the columns of the DynamoDB table had been encrypted using a CMK.
  • I was using the boto3 DynamoDB client, and dynamodb-encryption-sdk

TL;DR the restored DynamoDB table must have the same name as the original DynamoDB table, and be restored to the same account that it was originally created in.

What’s causing this error?

In its requests to AWS KMS, DynamoDB uses an encryption context with two key–value pairs.

{
    "aws:dynamodb:tableName": "<table-name>"
    "aws:dynamodb:subscriberId": "<account-id>"
}

i.e. if your original table name was ‘Notes’, and the account id that the table was created in is ‘12345678’, and attempted to read or write some encrypted data, the encryption context would look like:

{
    "aws:dynamodb:tableName": "Notes"
    "aws:dynamodb:subscriberId": "12345678"
}

Then if you restored a backup of the “Notes” table to a table such as ‘Notes-Restored’, and attempted to access the same encrypted data, the encryption context would look like:

{
    "aws:dynamodb:tableName": "Notes-Restored"
    "aws:dynamodb:subscriberId": "12345678"
}

The encryption context would no longer match the encryption context which was originally used to encrypt the data, resulting in an UnwrappingError and InvalidCiphertextException.

Restore the database to a table with the same name as the original table. This will ensure that the encryption context matches the original.

More details on the DynamoDB encryption context here: https://docs.aws.amazon.com/kms/latest/developerguide/services-dynamodb.html#dynamodb-encryption-context

Is there a better way?

The solution above is really just a workaround.

In my case, restoring to a table with the same name as the original only worked for me because I’d (intentionally) deleted the original table.

You can’t have two DynamoDB tables with the same name in the same region. If the original table still exists, you’ll need to explore other options.

There may be a way to provide the encryption context, specifying the original table name. If you know how, or have any other suggestions, feel free to leave a comment below.