1

I have a legacy application which uses OpenSSL to encrypt a string using DES3.

These are the parameters that are set for OpenSSL:

OpenSSL enc -des3 -nosalt -a -A -iv 1234567890123456 -K 1234567890123456...48

The key is a string of 48 digits and the iv is a substring of the first 16 digits of this key.

Now, I am trying to replicate this functionality with C#'s System.Cryptography library and without the use of OpenSSL if possible.

My goal is not to have to use OpenSSL and have the encryption done in native C# code.

Here is what I have got so far:

public string Encrypt(string toEncrypt, bool useHashing)
{
    var _key = "48...digits...";
    byte[] keyArray;
    var toEncryptArray = Encoding.UTF8.GetBytes(toEncrypt);

    if (useHashing)
    {
        var hashmd5 = new MD5CryptoServiceProvider();
        keyArray = hashmd5.ComputeHash(Encoding.UTF8.GetBytes(_key));

        hashmd5.Clear();
    }
    else
    {
        keyArray = Encoding.UTF8.GetBytes(_key);
    }

    var tdes = new TripleDESCryptoServiceProvider();

    tdes.Key = keyArray;

    // Is this even the correct cipher mode?
    tdes.Mode = CipherMode.CBC;

    // Should the PaddingMode be None?
    tdes.Padding = PaddingMode.PKCS7;

    // THIS is the line where I am currently stuck on:
    tdes.IV = Encoding.UTF8.GetBytes(_key.Substring(0, 16));

    var cTransform = tdes.CreateEncryptor();

    var resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

    return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}

As written as comments in the code, I am not quite sure if I am using the correct cipher, maybe even the padding mode is incorrect and my iv has a length of 16 bytes but only 8 bytes are expected.

Also, I did try my luck already with or without hashing the key/iv.

Is it even possible to convert the above mentioned OpenSSL logic into plain C#?

jrn
  • 2,640
  • 4
  • 29
  • 51

1 Answers1

2

Key and IV must be specified for openssl enc with -K and -iv as hexadecimal values. This is missing in the C# code, so that essentially the following expressions

tdes.Key = Encoding.UTF8.GetBytes(_key);
tdes.IV = Encoding.UTF8.GetBytes(_key.Substring(0, 16));

would have to be replaced by

tdes.Key = StringToByteArray(_key);
tdes.IV = StringToByteArray(_key.Substring(0, 16));

to produce the same ciphertext for useHashing == false. Here StringToByteArray is a method that converts a hexadecimal string into the corresponding byte array, e.g. here.

It should also be noted that .NET does not accept keys that are too weak, e.g.:

123456789012345612345678901234561234567890123456

In case of such a key a CryptographicException is thrown (Specified key is a known weak key for 'TripleDES' and cannot be used). OpenSSL accepts this key.

Regarding security:

  • MD5 shouldn't be used nowadays to generate a key, more here.
  • In addition, MD5 generates a 16 byte hash. Thus, always keying option 2 is used, which is weaker than keying option 1 (Keying options).
  • Generally it's insecure to use the key as IV, more here.
  • TripleDES is slow compared to today's standard AES, more here.
Topaco
  • 40,594
  • 4
  • 35
  • 62
  • Thank you very much for your help @Topaco. I also appreciate the pointers regarding security. Some of which are unfortunately not changeable by my part of the application... :-( – jrn Aug 19 '19 at 13:00