Search code examples
c#rubyencryptionopenssl3des

Decrypt a TripleDES ciphertext with static KEY and IV through the OpenSSL tool


I have the following snippet that decrypts a string encrypted with 3DES:

private static byte[] KEY_192 = new byte[]
{
    37, 19, 88, 164, 71, 3, 227, 30, 19,
    174, 45, 84, 23, 253, 149, 108, 12,
    107, 16, 192, 98, 22, 179, 200
};

private static byte[] IV_192 = new byte[]
{
    47, 108, 239, 71, 33, 98, 177, 13,
    36, 51, 69, 88, 189, 17, 210, 14,
    174, 230, 20, 60, 174, 100, 12, 22
};

public static string DecryptTripleDES(string value)
{
    if (!string.IsNullOrEmpty(value))
    {
        System.Security.Cryptography.TripleDESCryptoServiceProvider cryptoProvider = new System.Security.Cryptography.TripleDESCryptoServiceProvider();
        byte[] buffer = System.Convert.FromBase64String(value);
        System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer);
        System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(ms, cryptoProvider.CreateDecryptor(DataEncryptionEngine.KEY_192, DataEncryptionEngine.IV_192), System.Security.Cryptography.CryptoStreamMode.Read);
        System.IO.StreamReader sr = new System.IO.StreamReader(cs);
        return sr.ReadToEnd();
    }
    return null;
}

I'm trying to replicate it with Openssl or Ruby but with no luck, an example of encrypted base64 encoded string is:

JDiLOoP3iIY=

When trying this under Linux I'm getting the following error.

$ echo JDiLOoP3iIY= | openssl enc -d -des3 -a -K 371988164713227301917445842325314910812107161929822179200 -iv 471082397133981771336516988189172101417423020601741001222; hex string is too long invalid hex iv value

What am I missing? Thanks!

Edit: If it helps, this is the function that encrypts the string:

public static string EncryptTripleDES(string value)
{
    if (!string.IsNullOrEmpty(value))
    {
        System.Security.Cryptography.TripleDESCryptoServiceProvider cryptoProvider = new System.Security.Cryptography.TripleDESCryptoServiceProvider();
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        System.Security.Cryptography.CryptoStream cs = new System.Security.Cryptography.CryptoStream(ms, cryptoProvider.CreateEncryptor(DataEncryptionEngine.KEY_192, DataEncryptionEngine.IV_192), System.Security.Cryptography.CryptoStreamMode.Write);
        System.IO.StreamWriter sw = new System.IO.StreamWriter(cs);
        sw.Write(value);
        sw.Flush();
        cs.FlushFinalBlock();
        ms.Flush();
        return System.Convert.ToBase64String(ms.GetBuffer(), 0, System.Convert.ToInt32(ms.Length));
    }
    return null;
}

Tried this on ruby too, same, I get 'bad decrypt'

#!/usr/bin/env ruby

require 'openssl'
require 'base64'

string = 'JDiLOoP3iIY='

def decrypt(cpass)
  cipher = OpenSSL::Cipher::Cipher.new("des-ede-cbc")
  cipher.decrypt
  cipher.key = "251358A44703E31E13AE2D5417FD956C0C6B10C06216B3C8"
  cipher.iv = "2F6CEF472162B10D24334558BD11D20EAEE6143CAE640C16"
  return cipher.update(Base64.decode64(cpass)) + cipher.final
end

decrypted = decrypt(string)

puts "decrypted string: #{decrypted}"

Solution

    1. The IV size needs to match the block-size, not the key size. So 3DES needs 64 bit IVs, not 192 bit IVs.

      I guess that your existing code simply ignores everything beyond the first 64 bits. Try truncating it to 64 bits (16 hex characters) in rubu/OpenSSL.

    2. You didn't convert these to hex correctly. The values in C# are decimal, you can't simply concatenate them to form a hex string.

      Converting to hex I'm getting:

      Key = 25-13-58-A4-47-03-E3-1E-13-AE-2D-54-17-FD-95-6C-0C-6B-10-C0-62-16-B3-C8
      IV  = 2F-6C-EF-47-21-62-B1-0D-24-33-45-58-BD-11-D2-0E-AE-E6-14-3C-AE-64-0C-16
      

      So I guess you need to use

      Key = 251358A44703E31E13AE2D5417FD956C0C6B10C06216B3C8
      IV  = 2F6CEF472162B10D
      
    3. The C# output is Base64 encoded. I don't see anything Base64 related in your ruby code.

    4. I don't know what the default padding for ruby is, but for C# it's PKCS#5 / PKCS#7 padding (those are two names for the same thing).

    This is not secure. Using a static IV misses the point of an IV, which should be different for each message. And it lacks a MAC, so it suffers from active attacks, including padding oracles. And finally 64 bit block ciphers shouldn't encrypt more that a few GB using a single key.