2

I have some C# code for encrypting and decrypting using TripleDES. I've reduced it to a minimal example for posting.

using System;
using System.Security;
using System.Security.Cryptography;
using System.IO;
using System.Text;

class TDes
{
    static void Main() {
        string key = "ABCDEF0123456789";
        string iv = "ABCDEF01";

        TDes tdes = new TDes(key, iv);

        string dataToDecrypt = "x9iWzVc4FfU=";
        string decrypted = tdes.Decrypt(dataToDecrypt,key);
        Console.WriteLine(decrypted);

        string dataToEncrypt = "abcdegf";
        string encrypted = tdes.Encrypt(dataToEncrypt, key);
        Console.WriteLine(encrypted);
    }

    public TripleDESCryptoServiceProvider TdesProvider;

    public TDes(string Key, string IV)
    {
        TdesProvider = new TripleDESCryptoServiceProvider();
        TdesProvider.Key = System.Text.ASCIIEncoding.ASCII.GetBytes(Key);
        TdesProvider.IV = System.Text.ASCIIEncoding.ASCII.GetBytes(IV);
    }

    public string Decrypt(string Source, string Key)
    {
        long lLen;
        int nRead, nReadTotal;
        byte[] buf = new byte[3];
        byte[] decData;
        byte[] encData;
        System.IO.MemoryStream sin;
        System.IO.MemoryStream sout;
        CryptoStream decStream;

        encData = System.Convert.FromBase64String(Source);
        sin = new MemoryStream(encData);
        sout = new MemoryStream();

        decStream = new CryptoStream(sin,
            TdesProvider.CreateDecryptor(),
            CryptoStreamMode.Read);

        lLen = sin.Length;
        nReadTotal = 0;
        while (nReadTotal < lLen)
        {
            nRead = decStream.Read(buf, 0, buf.Length);
            if (0 == nRead) break;

            sout.Write(buf, 0, nRead);
            nReadTotal += nRead;
        }
        decStream.Close();

        decData = sout.ToArray();

        ASCIIEncoding ascEnc = new ASCIIEncoding();
        return ascEnc.GetString(decData);
    }

    public string Encrypt(string Source, string Key)
    {
        long lLen;
        int nRead, nReadTotal;
        byte[] buf = new byte[3];
        byte[] srcData;
        byte[] encData;
        System.IO.MemoryStream sin;
        System.IO.MemoryStream sout;
        CryptoStream encStream;

        srcData = System.Text.ASCIIEncoding.ASCII.GetBytes(Source);
        sin = new MemoryStream();
        sin.Write(srcData,0,srcData.Length);
        sin.Position = 0;
        sout = new MemoryStream();

        encStream = new CryptoStream(sout,
            TdesProvider.CreateEncryptor(),
            CryptoStreamMode.Write);
        lLen = sin.Length;
        nReadTotal = 0;
        while (nReadTotal < lLen)
        {
            nRead = sin.Read(buf, 0, buf.Length);
            encStream.Write(buf, 0, nRead);
            nReadTotal += nRead;
        }
        encStream.Close();

        encData = sout.ToArray();
        return System.Convert.ToBase64String(encData);
    }
}

This works(in the sense that it can decrypt what it encrypts with the same key and iv). However, I have been failing to come up with the equivalent in openssl. Most recent thing I've tried:

echo abcdefg | openssl enc -e -des-ede3-cbc -a -k ABCDEF0123456789 -iv ABCDEF01
U2FsdGVkX1+o9K0itpYTEqGfyMjN8gARTYIDB2ZHg1U=

The C# code produced a VERY different result of x9iWzVc4FfU= Likewise if I feed x9iWzVc4FfU= into the inverse openssl command it barfs.

I'm pulling my hair out on this. The c# code is unchangeable. Needs to be openssl as I'm using php.

Cruncher
  • 7,641
  • 1
  • 31
  • 65
  • 2
    Do not use 3DES for new work, it has has been superseded by AES. Further in this question two-key 3DES is being used which is very insecure having only a 112-bit key and is only four times stronger than DES. For existing work it is best to make a large effort to update to AES. – zaph May 05 '17 at 13:47
  • I'm aware of this @zaph. Thank you, but I have no control over it. Just have to shoehorn to fit it at this point. – Cruncher May 05 '17 at 14:24
  • 1
    Please show your C-based OpenSSL code. Otherwise, this question merely asks for all the code or a tutorial. – jww May 05 '17 at 15:24
  • Yeah, security is not really that important, there usually seems to be a reason to ignore it, right? Will we still have 2-key 3DES in 2050, probably still with the same excuse. Why this code may be cited as the reason not to update the other side code, a never ending cycle! The solution, simply add a version tag and both the legacy and secure version, then both sides can be updates separately in time and eventually there will be secure encryption. It only takes a 1-byte version indicator. It is versioning that allows HTTP/SSL/TLS to be updated and backward compatible. – zaph May 05 '17 at 16:15
  • @zaph Did you misread my comment? I said that I do *not* have control over it. – Cruncher May 05 '17 at 16:54
  • @jww I showed the openssl command that I was trying. Once I have a working ssl command, it was not hard at all to write the php. I provided that. I don't know what you're talking about. The accepted answer is precisely what I was looking for. – Cruncher May 05 '17 at 16:55
  • I read the comment and offered a compatibility suggestion. I am abhorred that a developer would continue such lacking security practices. It is not substantially different that a structural engineer being asked to use sub-standard materials, what would he do? But I guess the difference is the structural engineer is a professional, we are just code monkeys? Sad! Finally, unless one is an indentured servant, there is a choice: No. – zaph May 05 '17 at 17:21
  • @zaph I'm with you in general. I really am. But I do not have a choice in the matter. Also, where the encryption is being used, is somewhere that is not really necessary. It's encrypted just in transit within an already secure connection. I didn't design the system(or have any jurisdiction over the code that goes into it), I'm just working with it. Sometimes you just have requirements to work within – Cruncher May 05 '17 at 18:05
  • I understand and it seems the encryption is not needed. In my case I would refuse and quit if necessary, been there and done that. YMMV but you do gain respect. – zaph May 05 '17 at 18:21

1 Answers1

3

There’s a few things:

  1. A typo. In your C# you are encrypting "abcdegf", in your OpenSSL you are using "abcdefg" (note the order of f and g).

  2. echo adds a newline to what it outputs. Use echo -n to get the same result as your code (check that your echo actually has the -n option, or use printf when encrypting).

  3. You want the command line option -K rather than -k. -k specifies a password which is put through a KDF function, you want to specify the key directly.

  4. Your C# code uses the ASCII bytes of the key and IV strings. The OpenSSL command line interprets them as hex encoded strings. What you want to use on the command line is 41424344454630313233343536373839 for the key (the hex encoding of the bytes making up “ABCDEF0123456789”) and 4142434445463031 for the IV (the hex encoding of “ABCDEF01”).

  5. Your key is 16 bytes long. This means that the C# code is using “2 key” 3DES. In OpenSSL you need to specify this explicitly with des-ede-cbc (note the lack of 3).

So combining all these, to replicate what your C# code does you need something like this:

$ echo -n abcdegf | openssl enc -e -des-ede-cbc -a -K 41424344454630313233343536373839 -iv 4142434445463031
x9iWzVc4FfU=
matt
  • 78,533
  • 8
  • 163
  • 197
  • Oh my god thank you. I'm in transit right now, but I'll try this out as soon as I get to a computer – Cruncher May 05 '17 at 12:46
  • And lol, of course the last thing I try while putting together a question would have a typo... I definitely tried it many times without typos – Cruncher May 05 '17 at 12:51
  • I got this working in php. Only change I actually had to make was the algorithm name. Thanks again – Cruncher May 05 '17 at 14:26