1
votes

I need to decrypt text encrypted using AES/CBC/PKCS5Padding scheme. The encrypted text I got was generated using Coldfusion.

CFML example below:

<table border="1" cellpadding="5" cellspacing="0">
    <tr bgcolor="c0c0c0">
        <th>Decrypted string</th>
    <th>3DESKey</th>
    </tr>
        <cfset variables.algorithm ="AES/CBC/PKCS5Padding">
        <cfset variables.seed ="C610297CE8570750">
        <cfset variables.password = "Vza0O49SHpIe/mR4+4jHXhApmKhEyl5O2nzzDxVNQbo=">
        <cfset variables.decryptedString = Decrypt(variables.password, generate3DesKey("#variables.seed#"), "#variables.algorithm#", "Base64")>
        <cfoutput>
        <tr>
            <td>#variables.decryptedString#</td>
        <td><cfoutput>#generate3DesKey("variables.seed")#</cfoutput></td>
        </tr>
        </cfoutput>
</table>

Output is:

Decrypted String: Name322big563
3DESKey: QzYxMDI5N0NFODU3MDc1MA==

I tried with ruby:

require 'openssl'
require 'base64'

string = "Vza0O49SHpIe/mR4+4jHXhApmKhEyl5O2nzzDxVNQbo="

def decrypt(cpass)
  des = OpenSSL::Cipher::Cipher.new('AES-256-CBC')
  des.decrypt
  des.key = 'C610297CE8570750'
  return des.update(Base64.decode64(cpass)) + des.final
end

decrypted = decrypt(string)

puts "decrypted string: #{decrypted}"

I get key length too short (OpenSSL::Cipher::CipherError) The problem is I don't know the key but only the seed used C610297CE8570750, because the key returned by the CFML script is base64 but I need a hex key. I tried also with OpenSSL::Cipher::AES256.new(:CBC) same error.

require 'openssl'
require 'base64'
# decryption

aes = OpenSSL::Cipher::AES256.new(:CBC)
aes.decrypt
aes.padding = 1 # actually it's on by default
aes.key = "QzYxMDI5N0NFODU3MDc1MA=="
aes.iv = "C610297CE8570750"
aes.update(Base64::decode64("Vza0O49SHpIe/mR4+4jHXhApmKhEyl5O2nzzDxVNQbo="))+aes.final

Any idea?

EDIT:

As hinted by @Leigh, need to use AES-128-CBC, so I did this:

require 'openssl'
require 'base64'

string = "Vza0O49SHpIe/mR4+4jHXhApmKhEyl5O2nzzDxVNQbo="

def decrypt(cpass)
  des = OpenSSL::Cipher::Cipher.new('AES-128-CBC')
  des.decrypt
  des.key = 'C610297CE8570750'
  return des.update(Base64.decode64(cpass)) + des.final
end

decrypted = decrypt(string)

puts "decrypted string: #{decrypted}"

actually seems to kinda work (...ish).

decrypted string: ▒▒.ϥD▒▒       ▒▒▒▒▒Name322big563

any idea what's still wrong?

2
RE: but I need a hex key Then convert it from base64 to hex. However, it looks there are a few other problems A) The CF code generates a 128 bit key, but the ruby code is using AES 256 bit B) The CF code is generating a random IV. I am not sure if you can derive it from the values.Leigh
I will look further and get back.bsteo

2 Answers

1
votes

(Expanded from comments)

but I need a hex key

Then convert it from base64 to hex. In CF, you can use the BinaryEncode() and BinaryDecode functions:

binaryEncode(binaryDecode("QzYxMDI5N0NFODU3MDc1MA==", "base64"), "hex")

Looks like there are a few other problems:

  1. The CF code generates a 128 bit key, but the ruby code is using AES 256. It needs to use AES 128.

  2. The CF code is generating a random IV. The Ruby code is using a totally different iv. With CBC mode, both sides must use the same iv to get the expected results. "Decrypting with the incorrect IV causes the first block of plaintext to be corrupt ...", which is why your decrypted value is off. To resolve it, the Ruby code should use the same iv that was used to encrypt.


Update:

When CF generates the IV automatically (as it does here), it prepends that IV to the encrypted value:

When ColdFusion creates an IV automatically, it generates a secure, random IV and prepends this to the encrypted data. When ColdFusion decrypts the data, this IV is recovered and used. It is cryptologically important that the IV varies between encryptions. This is why the encrypted value changes when you repeatedly encrypt the same string with an algorithm that uses an IV, like DES/CBC/PKCS5Padding. Unlike the encryption key, it is not necessary for the IV to be kept secret.

So the IV value can be extracted by removing the first "block" of the encrypted binary. The block size depends on the algorithm. For AES, it is 16. I do not know the exact Ruby code, but in CF you could extract the IV like so:

blockSize = 16;
rawBinary = binaryDecode(encryptedString, "base64");
// IV is always the first block 
ivBytes   = arraySlice(rawBinary, 1, blockSize);
// Remaining bytes are the encrypted value
dataBytes = arraySlice(rawBinary, blockSize+1, arrayLen(rawBinary)-blockSize);
0
votes

Unless I'm very much mistaken, this is a problem I encountered years ago.

PHP Encryption Code Converted to ColdFusion