Хеширование строки с помощью Sha256
Я пытаюсь хэшировать строку с использованием SHA256, я использую следующий код:
using System;
using System.Security.Cryptography;
using System.Text;
public class Hash
{
public static string getHashSha256(string text)
{
byte[] bytes = Encoding.Unicode.GetBytes(text);
SHA256Managed hashstring = new SHA256Managed();
byte[] hash = hashstring.ComputeHash(bytes);
string hashString = string.Empty;
foreach (byte x in hash)
{
hashString += String.Format("{0:x2}", x);
}
return hashString;
}
}
Однако этот код дает значительно разные результаты по сравнению с моими друзьями php, а также онлайн-генераторами (такими как Этот генератор)
Кто-нибудь знает, что такое ошибка? Разные базы?
Ответы
Ответ 1
Encoding.Unicode
- это вводящее в заблуждение имя Microsoft для UTF-16 (двухуровневая кодировка, используемая в мире Windows по историческим причинам, но не используемая кем-либо еще). http://msdn.microsoft.com/en-us/library/system.text.encoding.unicode.aspx
Если вы проверите свой массив bytes
, вы увидите, что каждый второй байт 0x00
(из-за кодирования с двойным расширением).
Вместо этого вы должны использовать Encoding.UTF8.GetBytes
.
Но также вы увидите разные результаты в зависимости от того, считаете ли вы завершающий байт '\0'
частью данных, которые вы хешируете. Хеширование двух байтов "Hi"
даст другой результат из хэширования трех байтов "Hi"
. Вам придется решить, что вы хотите сделать. (Предположительно, вы хотите делать то, что делает ваш PHP-код вашего друга.)
Для текста ASCII Encoding.UTF8
определенно будет подходящим. Если вы нацелены на идеальную совместимость с кодом вашего друга, даже на входах, отличных от ASCII, вам лучше попробовать несколько тестовых примеров с не-ASCII-символами, такими как é
и 家
, и посмотреть, соответствуют ли ваши результаты вверх. Если нет, вам нужно выяснить, какая кодировка используется вашим другом; это может быть одна из 8-разрядных "кодовых страниц", которые раньше были популярны до изобретения Unicode. (Опять же, я думаю, что Windows является основной причиной того, что кому-то все еще нужно беспокоиться о "кодовых страницах".)
Ответ 2
У меня также была эта проблема с другим стилем реализации, но я забыл, где я ее получил, так как это было 2 года назад.
static string sha256(string randomString)
{
var crypt = new SHA256Managed();
string hash = String.Empty;
byte[] crypto = crypt.ComputeHash(Encoding.ASCII.GetBytes(randomString));
foreach (byte theByte in crypto)
{
hash += theByte.ToString("x2");
}
return hash;
}
Когда я по какой-то причине ввожу что-то вроде abcdefghi2013
, это дает разные результаты и приводит к ошибкам в моем модуле входа в систему.
Затем я попытался изменить код так же, как это было предложено Quuxplusone, и изменил кодировку с ASCII
на UTF8
, после чего он наконец заработает!
static string sha256(string randomString)
{
var crypt = new System.Security.Cryptography.SHA256Managed();
var hash = new System.Text.StringBuilder();
byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(randomString));
foreach (byte theByte in crypto)
{
hash.Append(theByte.ToString("x2"));
}
return hash.ToString();
}
Еще раз спасибо Quuxplusone за прекрасный и подробный ответ! :)
Ответ 3
В версии PHP вы можете отправить "true" в последнем параметре, но по умолчанию "false". Следующий алгоритм эквивалентен хэш-функции PHP по умолчанию при передаче 'sha256' в качестве первого параметра:
public static string GetSha256FromString(string strData)
{
var message = Encoding.ASCII.GetBytes(strData);
SHA256Managed hashString = new SHA256Managed();
string hex = "";
var hashValue = hashString.ComputeHash(message);
foreach (byte x in hashValue)
{
hex += String.Format("{0:x2}", x);
}
return hex;
}
Ответ 4
public string EncryptPassword(string password, string saltorusername)
{
using (var sha256 = SHA256.Create())
{
var saltedPassword = string.Format("{0}{1}", salt, password);
byte[] saltedPasswordAsBytes = Encoding.UTF8.GetBytes(saltedPassword);
return Convert.ToBase64String(sha256.ComputeHash(saltedPasswordAsBytes));
}
}
Ответ 5
Вы должны солить свой пароль, прежде чем вы его сделаете:
private const string _salt = "P&0myWHq";
private static string CalculateHashedPassword(string clearpwd)
{
using (var sha = SHA256.Create())
{
var computedHash = sha.ComputeHash(Encoding.Unicode.GetBytes(clearpwd+_salt));
return Convert.ToBase64String(computedHash);
}
}