Хеширование строки с помощью 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);
    }
}