19

I have code that retrieves a string that was encrypted using Amazon's aws kms encrypt function. I would like to call aws kms decrypt to get back the unencrypted value, but I would like to do this without writing the string to a binary file. All the examples I've found assume you will convert the base64 encoded encrypted value into a binary file using either linux's base64 command or Window's certutil command. I'm trying to do this on a Windows system. It seems to me you should be able to run:

aws kms encrypt --key-id <mykey> --plaintext "mysecret"

Which for me generates this result:

{
"KeyId": "arn:aws:kms:us-east-1:192491131326:key/<mykey>",
"CiphertextBlob": "AQICAHjQ7sViXQdeS4wWbFZpkOQWvCdNXqiy4Cnz0/xEBe39SQGz0vofeAo0+SyOXv172fqkAAAAZjBkBgkqhkiG9w0BBwagVzBVAgEAMFAGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMhchHh0ugGzwRTC4gAgEQgCMlkhYlCYk2SfYIkfQ6ruwA71KBcN7ih/OPzSE86OT/eBOz3Q=="
}

And that I should then be able to run:

aws kms decrypt --ciphertext-blob AQICAHjQ7sViXQdeS4wWbFZpkOQWvCdNXqiy4Cnz0/xEBe39SQGz0vofeAo0+SyOXv172fqkAAAAZjBkBgkqhkiG9w0BBwagVzBVAgEAMFAGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMhchHh0ugGzwRTC4gAgEQgCMlkhYlCYk2SfYIkfQ6ruwA71KBcN7ih/OPzSE86OT/eBOz3Q==

To get back the result. But so far I've been unable to get anything except:

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

Is there some set of parameters I can pass into the decrypt command so that it will decrypt this string?

Bert Cushman
  • 771
  • 2
  • 8
  • 27
  • In your example, the returned `CiphertextBlob` and the passed `--ciphertext-blob` are similar... but not identical... values. – Michael - sqlbot Mar 28 '18 at 23:53
  • I'm very impressed that you noticed that, but it was just me making a mistake of copying from multiple sources when forming the question, and not the source of the problem. I just repeated the test and verified that the cipher text blob was the same in both commands, and yet I get the same error. – Bert Cushman Mar 29 '18 at 14:32
  • I also got same error when I tried same thing as you did. It turns out that you can not combine certutil with kms decrypt commands. That's why in the official document, we need to save binary file for windows. https://docs.aws.amazon.com/cli/latest/reference/kms/decrypt.html – Ming M Zheng Feb 28 '19 at 18:10

4 Answers4

30

Not sure if you've already found this, but this seems to work:

aws kms decrypt --ciphertext-blob fileb://<(echo "{YOUR CIPHERTEXTBLOB HERE}" | base64 -d) --output text --query Plaintext --region {REGION} | base64 -d

This is for a Mac. On Windows I think you need base64 -d.

Hope this helps.

Idan Str
  • 614
  • 1
  • 11
  • 33
MarkT
  • 341
  • 3
  • 4
8

I do a stuff with aws kms so I wanted a way to work with streams rather than files. I have define 2 functions in my shell that could also be put into scripts. (I left the semicolons in because I have these condensed to oneliners in my .bash_profile but I like to break things up when I'm "teaching".)

export KMS_KEY=b31ef212-168e-4f7c-ab2a-fe8a623ee465

kmse(){
  local key=${1:-$KMS_KEY};
  aws kms encrypt \
    --key-id $key \
    --plaintext "$(cat /dev/stdin)" \
    --query CiphertextBlob \
    --output text;
}

kmsd(){
  aws kms decrypt \
    --ciphertext-blob fileb://<( \
      cat /dev/stdin | \
      sed 's/.*kmscrypt:://' | \
      tr -d '\n' | \
      base64 -D
    ) \
    --output text \
    --query Plaintext | \
  base64 -D;
}

The kmse function takes an options argument which is the UUID of the key to use. Otherwise it uses the key specified in the KMS_KEY environment var. Both functions read /dev/stdin to get what needs to be encrypted/decrypted. Therefore, the following examples all work:

## Encrypting

$ tar -czf - /etc | kmse > etc.tgz.encrypted

$ kmse 77ed1d23-6013-47ce-b48a-2a968ef0ddaa < ~/.ssh/id_rsa > id_rsa.pem.encrypted

$ cat | kmse | netcat 10.0.0.123 8080
<content_pasted_from_my_clipboard>
^D

## Decrypting

$ kmsd < etc.tgz.encrypted | tar -zxf -

$ kmsd < id_rsa.pem.encrypted > ~/.ssh/id_rsa.pem

$ cat | kmsd | tee output.txt
<content_pasted_from_my_clipboard>
^D

# Note: ^D is a CTRL-D character that tells `cat` this is the End Of File.

While the cat paste CTRL-D is a cool trick. I have a script called cb that I use for getting data in and out of my clipboard via stdin and stdout. And it now works on Mac, Linux, Windows Cygwin, and Windows WSL! So, I can encrypt and decrypt what is in my clipboard with:

## Encrypt

$ cb | kmse | cb

## Decrypt

$ cb | kmsd | cb

A similar concept that is Mac OSX specific is:

## Encrypt

$ pbpaste | kmse | pbcopy

## Decrypt

$ pbpaste | kmsd | pbcopy
Bruno Bronosky
  • 66,273
  • 12
  • 162
  • 149
  • I strip out `kmscrypt::` before decrypting because some sources add that before the base64 encoded, encrypted data. I suspect those sources are coming from or are influenced by https://gruntwork.io (And it's safe to always try to do it because `::` is not valid base64 and shouldn't be there anyway.) – Bruno Bronosky Dec 12 '18 at 03:48
  • You can even leave out /dev/stdin in your cat commands. cat reads from stdin by default if you do not pass a file name. – toaster Feb 04 '22 at 10:41
0

I don't know if it's because of any change on the AWS CLI v2, but this worked for me.

$ aws --version
aws-cli/2.11.3 Python/3.11.2 Darwin/22.3.0 source/arm64 prompt/off

I recommend to always use the --region flag just to be sure you're using the right KMS key from the region you want.

Encrypt

$ aws kms encrypt --region us-east-1 --key-id alias/my-kms-key --plaintext "$(echo 'MY_SECRET_TO_ENCRYPT' | base64)"
{
    "CiphertextBlob": "AQICAHjmSj9FB9J0...",
    "KeyId": "arn:aws:kms:us-east-1:1234567890:key/...",
    "EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}

To have just the CiphertextBlob:

$ aws kms encrypt --region us-east-1 --key-id alias/my-kms-key --plaintext "$(echo 'MY_SECRET_TO_ENCRYPT' | base64)" --output text --query CiphertextBlob
AQICAHjmSj9FB9J0...

Please note that if you encrypt the SAME string twice, you will most probably have a different CiphertextBlob and it's normal.

Decrypt

$ aws kms decrypt --region us-east-1 --ciphertext-blob 'AQICAHjmSj9FB9J0...' --key-id alias/my-kms-key
{
    "KeyId": "arn:aws:kms:us-east-1:1234567890:key/...",
    "Plaintext": "TVlfU0VDUkVUX1RPX0VOQ1JZUFQK",
    "EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}

The Plaintext is encoded in base64, so to decode it:

$ echo 'TVlfU0VDUkVUX1RPX0VOQ1JZUFQK' | base64 -d
MY_SECRET_TO_ENCRYPT

To have the decoded Plaintext directly:

$ aws kms decrypt --region us-east-1 --ciphertext-blob 'AQICAHjmSj9FB9J0...' --key-id alias/my-kms-key --output text --query Plaintext | base64 -d
MY_SECRET_TO_ENCRYPT
Samuel Phan
  • 4,218
  • 2
  • 17
  • 18
  • I just repeated the steps of my initial question, and now it works. I suspect you are right that AWS enhanced something recently which eliminated the need for the base64 encoding. – Bert Cushman Mar 17 '23 at 17:37
0

To Decrypt on Amazon Linux

aws kms decrypt
     --ciphertext-blob "AQICAHjTIwSfITu1jx7fnG6XeOdEq/wgc7tOiGB+jW84ELp62wHTKddotXn/QbwoN0fW0Q....."     
     --key-id "alias/test-keys"
     --output text
     --query Plaintext | base64
     --decode > decrypted.txt

This should work. It decrypts the cypher text and parses the plain text into the file decrypted.txt.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
Philip A
  • 1
  • 1