Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decrypting keys from aws-kms in Ruby

I’m using serverless-kms-secrets on serverless frameword to set some ENV variables I want to consume using Ruby.

I can confirm that the plugin works perfectly, it generated the file with the encrypted variable and I can see the encrypted variable in my environment on AWS lambda. The problem is that I can’t decrypt it in Ruby. The code that decrypts it (correctly) in the plugin is here, I understand it gets the string saved in the file and encodes it using Base64, so no big deal. In Ruby:

token = "blablabla"
client = Aws::KMS::Client.new(region: 'us-east-1')
blob = Base64.encode64(token)
client.decrypt({ciphertext_blob: blob})
....
Aws::KMS::Errors::InvalidCiphertextException ()

The client should get my credentials automatically, but I’m not sure I understand how the keyArn is used, doesn’t look relevant though.

Does anybody have any idea how to solve this?

like image 682
ngw Avatar asked Oct 17 '22 05:10

ngw


2 Answers

Instead of encoding the string I had to decode it.

token = "blablabla"
client = Aws::KMS::Client.new(region: 'us-east-1')
blob = Base64.decode64(token)
client.decrypt({ciphertext_blob: blob})
like image 114
ngw Avatar answered Nov 15 '22 06:11

ngw


It looks like the ciphertext_blob argument in Aws::KMS::Client#decrypt expects a binary string that includes the encrypted Ciphertext that you want to decrypt.

In your example, you are passing in an unencrypted Base64 encoded string into decrypt. Instead, you need to to pass in an encrypted binary string.

To get an encrypted string we can call Aws::KMS::Client#encrypt with your keyId (also know as your ARN) and the string you want to encrypt in plaintext.

In the response from that call we get back a ciphertext_blob which is the encrypted binary string that we need to use in order to decode.

Sometimes you might see that binary data "unpacked", which you can demonstrate doing ciphertext_blob.unpack('H*'). If you have unpacked data and want to decrypt it, you will need to pack it: encrypted_upacked_blob.pack('H*').

Here's a full example of a round trip encoding and decoding of a plaintext string:

require 'aws-sdk-kms'

client = Aws::KMS::Client.new

key_id = 'arn:aws:kms:us-east-1:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'

plaintext_to_encrypt = 'blablabla'

encrypt_response = client.encrypt({
  key_id: key_id,
  plaintext: plaintext_to_encrypt,
})

encrypt_response.ciphertext_blob
# => "\x01\x02\x02\x00xt/Jyu\x85B\xCA\x16v\xDAa3DM1$\e8Y\xF9\x812\x1E\xA9\xD3\xE3R\x1E/}\xCA\x...

encrypted_upacked_blob = encrypt_response.ciphertext_blob.unpack('H*')
# => ["0102020078742f4a79758542ca1676da6133444d31241b3859f981321ea9d3e3521e2f7dca01a7f89f2ee03...

encrypted_packed_blob = encrypted_upacked_blob.pack('H*')
# => "\x01\x02\x02\x00xt/Jyu\x85B\xCA\x16v\xDAa3DM1$\e8Y\xF9\x812\x1E\xA9\xD3\xE3R\x1E/}\xCA\x...

decrypt_response = client.decrypt({
  ciphertext_blob: encrypted_packed_blob
})

decrypted_plaintext = decrypt_response.plaintext
# => "blablabla"

This example combines two examples provided by AWS: Encrypting Data in AWS KMS using Ruby SDK and Decrypting a Data Blob in AWS KMS.

For a better understand of what [blob].pack("H*") is doing, check out this StackOverflow post and Ruby's Array#pack documentation.

like image 41
Scott Bartell Avatar answered Nov 15 '22 05:11

Scott Bartell