2
votes

I have data encrypted in ColdFusion which I am trying to decrypt in Ruby. I can't get the output to match though.

On the ColdFusion side I have something like this:

<cfset key = 'DiYVka4mAYk=' /> 
<cfset str = 'hello' />

<cfset enc = encrypt(str, key, 'des', "base64") />
<cfset dec = decrypt(enc, key, 'des', "base64") />

<cfoutput>
#str#   <!--- 'hello' --->
<br />
#enc#   <!--- '3rNKAnEu+VA=' --->
<br />
#dec#   <!--- 'hello' --->
</cfoutput>

The same, implemented in Ruby:

require 'openssl'
require 'base64'

str = 'hello'
key = 'DiYVka4mAYk='

des = OpenSSL::Cipher.new('des')

des.encrypt 
des.key = key
data = des.update(str) + des.final  
enc = Base64.encode64(data)

des.decrypt
des.key = key
dec = des.update(Base64.decode64(enc)) + des.final  

puts str  # => 'hello'
puts enc  # => 'wVQs6NjOZwM='
puts dec  # => 'hello'

Both work, but the encrypted strings are different. So passing encrypted data between ColdFusion and Ruby is not going to work.

The key was generated using ColdFusion's generateSecretKey() function. It looks Base64 encoded, so I tried setting the key like this in Ruby:

key = Base64.decode64('DiYVka4mAYk=')

Again, the code works but the encrypted string is different.

Is there anything I am missing regards key encoding?

Also, I thought maybe there is more info implied when setting the algorithm to 'des' in ColdFusion. So I tried creating the Cipher in ruby with the following:

  • des
  • des-cbc
  • des-cfb
  • des-ecb
  • des-ede
  • des-ede-cbc
  • des-ede-cfb
  • des-ede-ofb
  • des-ofb

Again, some variation in the encrypted string. But none matching the original ColdFusion version.

Note: the ColdFusion encryption has been in use for a long time, so I can't make any edits on that side. The 'fix' must be in Ruby.

1
Can you see if the coldfusion result is different if it's DES instead of des in the encrypt/decrypt code? I have a hunch.Brenton Fletcher
I just tested in cf9, it does not appear to be case sensitive. <cfset enc = encrypt(str, key, 'des', "base64") /> was the same result as <cfset enc2 = encrypt(str, key, 'DES', "base64") /> 3rNKAnEu+VA=Travis
I don't know thing 1 about ruby or if the namespace you're using for cipher is a bit different (looks like it's used for backwards compatibility only) but according to the cipher documentation the string to create a cipher is <name>-<key length>-<mode> where you have just the name, or you could use something like cipher = OpenSSL::Cipher::AES.new(128, 'CBC') ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/…Travis
Yes, sorry, I think the case was a red herring. I know nothing about CF, but looking at the docs for both, it looks like ECB mode with PKCS5Padding and no IV are the defaults for BOTH ruby and CF. When I run the ruby example you give, I actually get AfbQrCUXOcs= as the encoded value, not the one in the ruby source. That's on both 1.9.3 and 1.8.7. This is pretty left field, but could it be an endianness issue?Brenton Fletcher
Thanks guys. I've updated the code to remove the extra "Cipher" - as you say, appears to be legacy only. The code still runs as before. RE key length: I think that's AES specific. DES does not have variable length keys (again, I think). When I output OpenSSL::Cipher.ciphers I see a list that includes both "AES-128-CBC" and just "DES"stubotnik

1 Answers

4
votes

As asked, I'll transfer my comment to an answer:

You have to ensure that the cipher modes, IVs, and padding match from both ends.

The Ruby defaults in 1.8.7 and 1.9.3 are ECB and no IV, and PCKS padding. The ColdFusion defaults are the same.

However it appears that in ruby 1.9.2, or in your particular environment, the default cipher mode is not ECB, which is changing the output. As you commented, setting the cipher mode to ECB manually (OpenSSL::Cipher.new("DES-ECB")) fixes the issue.