encryption — расшифровывает строку, зашифрованную в C # с помощью класса RijndaelManaged, используя переполнение стека

Вот некоторый код 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]));

0

Решение

_b является статическим значением, которое используется в качестве IV (CreateDecryptor принимает ключ и IV параметр). Поскольку его длина составляет 16 байт, это означает, что вы используете Rijndael-128 или более широко известный AES.

Key.GetBytes(24) предполагает, что получен 24-байтовый ключ, а не 16-байтовый ключ.

Удостоверься что

  • System.Text.Encoding.Default эквивалентно implode(unpack('C*', ...,
  • Значение по умолчанию для итераций PasswordDeriveBytes это 1000,
  • Значение по умолчанию для хэша PasswordDeriveBytes это SHA-1

Проблемы с безопасностью:

  • PBKDF1 устарел, а PBKDF2 не намного лучше. Используйте современные алгоритмы получения ключей, такие как Argon2 или scrypt.
  • IV должен быть выбран случайным образом для обеспечения семантической безопасности. Он не должен быть секретным, поэтому его можно отправить вместе с зашифрованным текстом.
  • Растяжение ключа путем его кодирования в шестнадцатеричный код не обеспечивает никакой безопасности (не используйте bin2hex).
  • Зашифрованный текст не аутентифицирован, что означает, что вы не можете обнаружить (злонамеренное) манипулирование зашифрованными сообщениями. Используйте шифрование-затем-MAC.
1

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

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

По вопросам рекламы [email protected]