c # — эквивалент openssl для TripleDESCryptoServiceProvider

У меня есть код 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 # неизменяем. Должен быть openssl, так как я использую php.

1

Решение

Есть несколько вещей:

  1. Опечатка. В вашем C # вы шифруете «abcdegf», в вашем OpenSSL вы используете «abcdefg» (обратите внимание на порядок f а также g).

  2. echo добавляет новую строку к тому, что он выводит. использование echo -n чтобы получить тот же результат, что и ваш код (убедитесь, что ваш echo на самом деле имеет -n вариант или использовать printf при шифровании).

  3. Вы хотите опция командной строки -K скорее, чем -k. -k указывает пароль который вводится через функцию KDF, вы хотите указать ключ напрямую.

  4. Ваш код C # использует байты ASCII ключа и строки IV. Командная строка OpenSSL интерпретирует их как шестнадцатеричные строки. То, что вы хотите использовать в командной строке 41424344454630313233343536373839 для ключа (шестнадцатеричное кодирование байтов, составляющих «ABCDEF0123456789») и 4142434445463031 для IV (шестнадцатеричное кодирование «ABCDEF01»).

  5. Ваш ключ длиной 16 байт. Это означает, что Код C # использует «2 ключа» 3DES. В OpenSSL вам нужно явно указать это des-ede-cbc (обратите внимание на отсутствие 3).

Таким образом, комбинируя все это, для репликации того, что делает ваш код C #, вам нужно что-то вроде этого:

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

Другие решения

Других решений пока нет …