Хэшированные пароли отображаются странно

#c#

#c#

Вопрос:

Я столкнулся с любопытным поведением при попытке хэшировать строковый пароль, а затем отобразить хэш в консоли.

Мой код:

     static void Main(string[] args)
    {
        string password = "password";

        ConvertPasswordToHash(password);

    }

    private static void ConvertPasswordToHash(string password)
    {
        using (HashAlgorithm sha = SHA256.Create())
        {
            byte[] result = sha.ComputeHash(Encoding.UTF8.GetBytes(password));

            string hashText = Encoding.UTF8.GetString(result);

            Console.WriteLine(hashText);

            StringBuilder sb = new StringBuilder();

            foreach (var item in result)
            {
                sb.Append((char)item);
            }

            Console.WriteLine(sb);
        }
    }
  

Проблема двоякая:

  1. hashTest и sb содержат разные значения (оба задолго до вывода составляют 32 символа), и 2) Выходные данные консоли еще более странные. Они не имеют длины 32 символа, а во-вторых, выходные данные немного отличаются:

введите описание изображения здесь

При проверке строк перед их выводом я заметил, что hashText содержит, например, u0004, который может быть каким-либо символом юникода, в то время как sb вообще не содержит его (то есть до вывода значений в консоль).

Мои вопросы:

  1. Какой способ является правильным способом получения строки символов из предоставленного массива байтов?
  2. Почему выходные данные консоли отличаются, но лишь незначительно? Не похоже, что это ошибка использования неправильной кодировки.
  3. Как мне вывести правильный хэш (32 символа) в консоль? Я попытался добавить ‘@’ перед строками, чтобы отменить любые возможные возвраты каретки и т.д… Практически без какого-либо результата.

Возможно, я упускаю что-то очевидное. Спасибо.

Комментарии:

1. Вы могли бы попробовать кодирование результата в base64. Имейте в виду, что хэш — это число, а не текст

2. Немного не по теме, но использование SHA256 для паролей — плохая практика. Вместо этого используйте правильную функцию хэширования паролей.

3. Почему вы пытаетесь кому-либо показывать хэши паролей? То, что хэш более безопасен, чем обычный текстовый пароль, не означает, что вы должны быть более либеральными в показе его другим.

4. @Servy конечно, я не хочу делать это на производстве. Я не чувствовал необходимости указывать. Я просто играл с хэшами и наткнулся на это.

5. Подойдет любой алгоритм, специально разработанный для хранения паролей. В .NET есть встроенная реализация PBKDF2, bcrypt — еще одна распространенная, или более новые альтернативы, такие как Argon2, например. Любой хэш общего назначения, такой как MD5, SHA1, любой SHA2 или SHA3, плох для паролей, потому что они быстрые . Посмотрите здесь для получения дополнительной информации: security.stackexchange.com/questions/211 /…

Ответ №1:

Правильная логика должна быть следующей:

 private static void ConvertPasswordToHash(string password)
{
    using (HashAlgorithm sha = SHA256.Create())
    {
        byte[] result = sha.ComputeHash(Encoding.UTF8.GetBytes(password));

        StringBuilder sb = new StringBuilder();

        foreach (var item in result)
        {
            sb.Append(item.ToString("x2"));
        }

        Console.WriteLine(sb);
    }
}
  

ToString("x2") форматирует строку в виде двух шестнадцатеричных символов.

Живой пример:https://dotnetfiddle.net/QkREkX

Другой способ — просто представить ваш byte[] массив в виде базовой строки 64, не StringBuilder требуется.

 byte[] result = sha.ComputeHash(Encoding.UTF8.GetBytes(password));
Console.WriteLine(Convert.ToBase64String(result));