PHP эквивалент C # SHA1 Unicode-хэширования - PullRequest
0 голосов
/ 17 октября 2019

У меня работает приложение C # с аутентификацией пользователя. Я шифрую пароли с помощью класса SHA1Managed, используя Encoding.Unicode. Сейчас мы разрабатываем новое веб-приложение на PHP, и кажется, что метод PHP sha1 использует ASCII, поэтому зашифрованные пароли немного отличаются.

Я не могу изменить свой код C #, так как он работает на нескольких разных серверах, и все пароли пользователей уже зашифрованы. Это нельзя изменить, поскольку это будет означать, что все пользователи будут спрашивать их пароли (что невозможно).

Я ознакомился со следующими решениями, однако не могу решить с ними свою проблему:

  1. C # SHA-1 против PHP SHA-1 ... Различные результаты? В этом они предлагают использовать ASCIIEncoding. Однако, как я уже говорил ранее, это нельзя изменить.
  2. SHA1: различные результаты для PHP и C # и Создание хеша PHP UTF-16 SHA1 для соответствия методу C # они используют кодировку base64, и это несовместимо с моей кодировкой C # (я думаю)
  3. php эквивалентно следующему коду шифрования sha1 c # этот код также использует ASCIIEncoding.

Это мой код C #, который НЕ МОЖЕТ быть изменен:

byte[] msgBytes = Encoding.Unicode.GetBytes(data);
SHA1Managed sha1 = new SHA1Managed();
byte[] hashBytes = sha1.ComputeHash(msgBytes);

StringBuilder hashRet = new StringBuilder("");
foreach (byte b in hashBytes)
    hashRet.AppendFormat("{0:X}", b);

return hashRet.ToString();

Это код PHP, реализованный до сих пор:

$str=mb_convert_encoding($password.$SALT, 'UTF-16LE');
$result=strtoupper(sha1($str));

Результат, полученный для строки примера "1981 "в C # D4CEDCADB729F37C30EBF41BC8F2929AF526AD3

В PHP я получаю: D4CEDCADB729F37C30EBF41BC8F29209AF526AD3

Как можно видеть, единственная разница между каждым из 0 - это 0 символов. Это происходит во всех строках, но 0 появляется в разных местах.

РЕДАКТИРОВАТЬ

Как указано https://stackoverflow.com/users/1839439/dharman, результаты не могут быть воспроизведены точно так, какмоя строка имеет сольОднако результаты должны отличаться даже без соли.

РЕШЕНИЕ Пользователь дал предложение, которое решило мою проблему. К сожалению, он удалил ответ, прежде чем я смог опубликовать, что он работал. Проблема в C #, когда я анализирую байты в строку в StringBuilder. Формат: {0: X}, и любой начальный 0 в байте игнорируется. Например, 01 будет проанализирован как 1, 0D будет проанализирован как D.

Поэтому мне пришлось перебирать пары результатов, полученных в PHP, и удалять там начальные нули.

Окончательный код в PHP выглядит следующим образом:

$str=mb_convert_encoding($password.$SALT, 'UTF-16LE');
$result=strtoupper(sha1($str));
$array = str_split($result, 2);
foreach ($array as &$valor) {
    $valor = ltrim($valor, '0');
}
unset($valor);
$result = implode($array);

1 Ответ

2 голосов
/ 17 октября 2019

Вам не понравится мой ответ, но вот он.
Прежде всего, проблема не в PHP, PHP прост и работает правильно. У вас есть серьезная ошибка в вашем коде C #. Это нужно исправить так или иначе как можно скорее.

Это нельзя изменить, поскольку это будет означать, что все пользователи будут запрашивать их пароли (что невозможно).

К сожалению, именно это и должно произойти. Вы можете сделать это, не вызывая массовой паники. Я предполагаю, что у вашей БД есть какой-то способ узнать, был ли пароль сброшен администраторами;если нет, то вам нужно добавить такой столбец (желательно типа timestamp). В следующий раз, когда пользователь входит в систему, он должен предоставить свой пароль, потому что вы сбросили их все, поэтому возьмите этот пароль и перефразируйте его правильно и сохраните новый хэш в базе данных. Было бы разумно использовать новый столбец для нового хэша или хотя бы иметь способ определения исправленных хэшей. Столбец должен быть как минимум VARCHAR (60), но лучше всего иметь его VARCHAR (255), который должен вместить все популярные хеши.

Конечно, SHA1 не подходит для хеширования паролей, даже если используются соли. Так как вам все равно нужно перефразировать все пароли, хорошей идеей будет переключиться на bcrypt или аналогичную функцию безопасного хеширования.

Поскольку в вашем исходном приложении появилась эта ошибка, вам потребуются некоторые обходные пути. Поддержка ошибочного поведения в новом приложении не кажется хорошей идеей, поэтому я бы посоветовал не искать обходных путей в PHP. Конечно, вы можете попытаться изменить пароли так же, как вы предложили в вопросе, но это просто перетаскивание той же самой ошибки в новое приложение, не исправляя ее вообще.

Прежде чем начать что-либо делать, вы должны проанализировать, сколько ваших паролей повреждено в базе данных. Правильная длина хэша SHA1 должна быть 40 символов. Если вы можете найти количество паролей, которое меньше 40, вы узнаете, какие и сколько паролей необходимо исправить.

Исправить пароли будет сложно, но определенно стоит.

Примечание по кодировке символов:
PHP большую часть времени использует кодировку UTF-8. Это наиболее распространенная кодировка, используемая в сети, и я бы рекомендовал использовать ее для ваших строк. Когда дело доходит до хеширования, не имеет значения, в какой кодировке находится строка, потому что хэши рассчитываются в байтах. По этой причине вы преобразуете свою строку C # в байты в UTF-16 с Encoding.Unicode.GetBytes(data).

...