Вот некоторый код C # (я немного изменил его, чтобы изменить некоторые жестко закодированные значения в нем):
public static string Decrypt(string InputFile)
{
string outstr = null;
if ((InputFile != null))
{
if (File.Exists(InputFile))
{
FileStream fsIn = null;
CryptoStream cstream = null;
try
{
byte[] _b = { 94, 120, 102, 204, 199, 246, 243, 104, 185, 115, 76, 48, 220, 182, 112, 101 };
fsIn = File.Open(InputFile, FileMode.Open, System.IO.FileAccess.Read);
SymmetricAlgorithm symm = new RijndaelManaged();
PasswordDeriveBytes Key = new PasswordDeriveBytes(System.Environment.MachineName, System.Text.Encoding.Default.GetBytes("G:MFX62rlABW:IUYAX(i"));
ICryptoTransform transform = symm.CreateDecryptor(Key.GetBytes(24), _b);
cstream = new CryptoStream(fsIn, transform, CryptoStreamMode.Read);
StreamReader sr = new StreamReader(cstream);
char[] buff = new char[1000];
sr.Read(buff, 0, 1000);
outstr = new string(buff);
}
finally
{
if (cstream != null)
{
cstream.Close();
}
if (fsIn != null)
{
fsIn.Close();
}
}
}
}
return outstr;
}
Мне нужно придумать функцию, чтобы сделать то же самое в PHP. Имейте в виду, я не писал код C # и не могу его изменить, поэтому, даже если он плохой, я застрял с ним. Я искал повсюду и нашел кусочки вокруг, но пока что ничего не работает. Все примеры, которые я нашел, используют mcrypt, который в наши дни кажется неодобрительным, но я, вероятно, застрял, используя его. Затем я нашел следующий пост, в котором есть полезная информация: Переписать код шифрования Rijndael 256 C # в PHP
Похоже, класс PasswordDeriveBytes является ключом к этому. Я создал следующий код PHP, чтобы попытаться расшифровать:
function PBKDF1($pass,$salt,$count,$dklen) {
$t = $pass.$salt;
//echo 'S||P: '.bin2hex($t).'<br/>';
$t = sha1($t, true);
//echo 'T1:' . bin2hex($t) . '<br/>';
for($i=2; $i <= $count; $i++) {
$t = sha1($t, true);
//echo 'T'.$i.':' . bin2hex($t) . '<br/>';
}
$t = substr($t,0,$dklen);
return $t;
}
$input = 'Ry5WdjGS8rpA9eA+iQ3aPw==';
$key = "win7x64";
$salt = implode(unpack('C*', "G:MFX62rlABW:IUYAX(i"));
$salt = pack("H*", $salt);
$it = 1000;
$keyLen = 16;
$key = PBKDF1($key, $salt, $it, $keyLen);
$key = bin2hex(substr($key, 0, 8));
$iv = bin2hex(substr($key, 8, 8));
echo trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($input), MCRYPT_MODE_CBC, $iv));
Вы заметите, что для того, что я считаю System.Environment.MachineName, я сейчас установил фиксированное значение, которое является именем компьютера, на котором я работаю, поэтому должно быть эквивалентно тому, что делает код C #. Кроме того, я заметил, что использование MCRYPT_RIJNDAEL_256 не работает, он выдает ошибку «Параметр IV должен быть таким же, как и размер блока». Если я использую MCRYPT_RIJNDAEL_128, я не получаю эту ошибку, но дешифрование по-прежнему не удается. Я предполагаю, что мне не хватает части для байтового массива _b, который используется функцией CreateDecryptor, я понятия не имею, куда он должен вписываться. Любая помощь приветствуется.
ОБНОВИТЬ
Это решение, которое стало возможным благодаря ответу, помеченному как правильный. Обратите внимание, что код для функции PBKDF1 не мой, он был связан в ответе.
function PBKDF1($pass, $salt, $count, $cb) {
static $base;
static $extra;
static $extracount= 0;
static $hashno;
static $state = 0;
if ($state == 0)
{
$hashno = 0;
$state = 1;
$key = $pass . $salt;
$base = sha1($key, true);
for($i = 2; $i < $count; $i++)
{
$base = sha1($base, true);
}
}
$result = "";
if ($extracount > 0)
{
$rlen = strlen($extra) - $extracount;
if ($rlen >= $cb)
{
$result = substr($extra, $extracount, $cb);
if ($rlen > $cb)
{
$extracount += $cb;
}
else
{
$extra = null;
$extracount = 0;
}
return $result;
}
$result = substr($extra, $rlen, $rlen);
}
$current = "";
$clen = 0;
$remain = $cb - strlen($result);
while ($remain > $clen)
{
if ($hashno == 0)
{
$current = sha1($base, true);
}
else if ($hashno < 1000)
{
$n = sprintf("%d", $hashno);
$tmp = $n . $base;
$current .= sha1($tmp, true);
}
$hashno++;
$clen = strlen($current);
}
// $current now holds at least as many bytes as we need
$result .= substr($current, 0, $remain);
// Save any left over bytes for any future requests
if ($clen > $remain)
{
$extra = $current;
$extracount = $remain;
}
return $result;
}
$input = 'base 64 encoded string to decrypt here';
$key = strtoupper(gethostname());
$salt = 'G:MFX62rlABW:IUYAX(i';
$it = 100;
$keyLen = 24;
$key = PBKDF1($key, $salt, $it, $keyLen);
$iv = implode(array_map('chr', [94, 120, 102, 204, 199, 246, 243, 104, 185, 115, 76, 48, 220, 182, 112, 101]));
_b
является статическим значением, которое используется в качестве IV (CreateDecryptor
принимает ключ и IV параметр). Поскольку его длина составляет 16 байт, это означает, что вы используете Rijndael-128 или более широко известный AES.
Key.GetBytes(24)
предполагает, что получен 24-байтовый ключ, а не 16-байтовый ключ.
Удостоверься что
System.Text.Encoding.Default
эквивалентно implode(unpack('C*', ...
,PasswordDeriveBytes
это 1000,PasswordDeriveBytes
это SHA-1bin2hex
).Других решений пока нет …