Search code examples
rubyencryption3des

Decrypt hex strings using 3DES in Ruby from .NET


I'm working on a Ruby project that is interacting with a webservice that I'm exchanging some encrypted data with.

I am having a very hard time decrypting something I get back from the webservice in Ruby, although in the .NET side, it's working fine, and a number of other web-based or desktop-based tools can deal with this.

The encryption method was 3DES with ECB and no padding.

Below is a test script I have been working on. I've tried everything I can think of to get these strings unpacked correctly, but to no avail.

require 'openssl'
require 'base64'

def cipher(key, encrypted)
  key = key.unpack('a2'*32).map{|x| x.hex}.pack('c'*32)
  encrypted = encrypted.unpack('a2'*32).map{|x| x.hex}.pack('c'*32)
  OpenSSL::Cipher::ciphers.select{|c| c.include? 'des3' }.map do |cipher_name|
    begin
      cipher = OpenSSL::Cipher.new(cipher_name)
      cipher.padding = 0
      cipher.decrypt
      cipher.key=key

      plain = cipher.update(encrypted) + cipher.final

      p "Cipher #{cipher_name} success: #{plain} #{plain.class} #{plain.length} #{plain.encoding.to_s}"
      plain
    rescue => e
      p "Cipher #{cipher_name} failed #{e}"
      nil
    end
  end

end

key = '202FA9B21843D7022B6466DB68327E1F'
encrypted = 'ff6f07e270ebd5c0878c67c999d87ebf'

res1 = cipher key, encrypted

key = '49CE85147B24123718AB3F4539AB1A21'
encrypted = '995604ed8016da8897f1875ebd725529'

res2 = cipher key, encrypted


p res1 == res2 ? "SUCCESS" : "FAIL"

# In both cases, the correct output should be '25588015543912470222703296730936'

BC-Tools Decryption


Solution

  • A 3DES key is 24-bytes, use a full length key.

    3DES uses triple encryption with essentially a 24-byte key. 202FA9B21843D7022B6466DB68327E1F is hex encoded 16-byte key.

    Try repeating the first 8-bytes of the key:
    202FA9B21843D7022B6466DB68327E1F202FA9B21843D702

    Some 3DES implementations will repeat 8-bytes of a 16-byte key but relying on such implementation details is not a good idea.

    Note: 3DES actually uses a 168-bit key because the LSb of each byte is not used. Further because there are actually three DES calls the security is only 112-bits. Additionally DES has some weak keys. There are two common modes, ede and ded, in an effort to facilitate moving from DES to 3DES thus adding more confusion.

    Finally: Move from 3DES to AES in CBC mode with a random IV. Please don't continue poor security practices.