openssl等效于TripleDESCryptoServiceProvider

时间:2017-05-05 12:07:53

标签: c# php encryption openssl 3des

我有一些C#代码用于使用TripleDES进行加密和解密。我把它简化为一个最小的发布示例。

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);
    }
}

这是有效的(从某种意义上说,它可以用相同的密钥和iv加密它加密的内容)。但是,我一直未能在openssl中提出相应的内容。最近我尝试过的事情:

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

C#代码产生了x9iWzVc4FfU=的非常不同的结果。同样,如果我将x9iWzVc4FfU=提供给反向openssl命令,则barfs。

我把头发拉出来。 c#代码是不可更改的。当我使用php时,需要开放。

1 个答案:

答案 0 :(得分:2)

有一些事情:

  1. 一个错字。在您的C#中,您正在加密&#34; abcdegf&#34;,在您使用的OpenSSL中&#34; abcdefg&#34; (请注意fg)的顺序。

  2. echo为其输出内容添加换行符。使用echo -n获得与您的代码相同的结果(检查您的echo实际上是否有-n选项,或在加密时使用printf

  3. 您想要command line option -K rather than -k-k指定通过KDF函数发送的密码,您希望直接指定密钥。

  4. 您的C#代码使用密钥和IV字符串的ASCII字节。 OpenSSL命令行将它们解释为十六进制编码字符串。您希望在命令行上使用41424344454630313233343536373839作为密钥(构成“ABCDEF0123456789”的字节的十六进制编码)和4142434445463031作为IV(“ABCDEF01”的十六进制编码)。

  5. 您的密钥长度为16个字节。这意味着C# code is using “2 key” 3DES。在OpenSSL中,您需要使用des-ede-cbc明确指定(请注意缺少3)。

  6. 所以结合所有这些,复制你的C#代码你需要这样的东西:

    $ echo -n abcdegf | openssl enc -e -des-ede-cbc -a -K 41424344454630313233343536373839 -iv 4142434445463031
    x9iWzVc4FfU=