Содержание
.NET предоставляет следующие классы, реализующие алгоритмы хэширования: SHA256, SHA384, SHA512, а также MD5 и SHA1. Но алгоритмы MD5 и SHA-1 были признаны небезопасными и сейчас рекомендуется алгоритм SHA-2, который включает в себя алгоритмы SHA256, SHA384 и SHA512. Рассмотрим как использовать эти алгоритмы в C#
Общее описание классов C# для использования алгоритмов хэширования
Несмотря на то, что в C# (что логично) для работы с различными алгоритмами хэширования используются также и различные классы, все они работают, по сути, по одному сценарию, который можно описать следующим образом:
- С использованием метода Create соответствующего класса создается объект (экземпляр) этого класса.
- Входное сообщение, например, строка преобразуется в массив байтов
- Массив байтов передается в метод
ComputeHash
, который и вычисляет дайджест сообщения по заданному алгоритму и возвращает также массив байтов - Если необходимо преобразовать полученный массив в строку, то можно использовать, например, метод
Convert.ToHexString()
.
Кроме этого, различные варианты метода ComputeHash
могут принимать в качестве входного сообщения потоки (Stream) или же вычислять хэш для заданной части массива байтов.
Алгоритм MD5
MD5 (от англ. Message Digest 5) — это128-битный алгоритм хеширования, разработанный профессором Рональдом Л. Ривестом из Массачусетского технологического института в 1991 году. Алгоритм предназначен для создания «отпечатков» или, как их ещё называют дайджестов сообщения произвольной длины и последующей проверки их подлинности. Несмотря на то, что алгоритм признан небезопасным, он до сих пор довольно часто встречается.
Рассмотрим работу с этим алгоритмом хэширования в C# на подробном примере:
using System.Security.Cryptography; using System.Text; namespace HashFunctions { internal class Program { static void Main(string[] args) { string input = "Hello, World"; //входное сообщение string output; //дайджест сообщения (хэш) MD5 MD5Hash = MD5.Create(); //создаем объект для работы с MD5 byte[] inputBytes = Encoding.ASCII.GetBytes(input); //преобразуем строку в массив байтов byte[] hash = MD5Hash.ComputeHash(inputBytes); //получаем хэш в виде массива байтов output = Convert.ToHexString(hash); //преобразуем хэш из массива в строку, состоящую из шестнадцатеричных символов в верхнем регистре Console.WriteLine(output); } } }
Для того, чтобы получить хэш MD5 в C# необходимо преобразовать входную строку в массив байтов и, затем, передать её в метод ComputeHash
, созданного объекта типа MD5
. Для преобразования полученного массива байтов мы используем метод ToHexString
из класса Convert
. В результате, вместо сообщения «Hello, world» мы получим в консоли следующий хэш:
Следует отметить, что вне зависимости от того, какое сообщение (массив байтов) мы хэшируем, всё равно мы будем получать на выходе строку, состоящую из 32 символов (16 байт или 16*8 = 128 бит). Например, вот так выглядит хэш пустой строки (""
)
Алгоритмы SHA256, SHA384 и SHA512
Этот алгоритм входит в семейство алгоритмов SHA-2. Общее описание алгоритма, данное в Википедии, следующее: исходное сообщение после дополнения разбивается на блоки, каждый блок — на 16 слов. Алгоритм пропускает каждый блок сообщения через цикл с 64 (SHA256) или 80 (SHA512) итерациями (раундами). На каждой итерации 2 слова преобразуются, функцию преобразования задают остальные слова. Результаты обработки каждого блока складываются, сумма является значением хеш-функции. Тем не менее, инициализация внутреннего состояния производится результатом обработки предыдущего блока. Поэтому независимо обрабатывать блоки и складывать результаты нельзя.
Этот алгоритм может использоваться для проверки подлинности сообщения. Даже малейшее изменение исходного сообщения приводит к тому, что хэш значительно изменяется. Например, вычислим хэш двух строк, которые различаются всего одним символом. Метод, в котором получаем хэш SHA256:
public static string CreateSHA256(string input) { using SHA256 hash = SHA256.Create(); return Convert.ToHexString(hash.ComputeHash(Encoding.ASCII.GetBytes(input))); }
Console.WriteLine(Hash.CreateSHA256("Hello, world")); Console.WriteLine(Hash.CreateSHA256("Hello. world"));
Результат вычислений:
Аналогичным образом действуют и алгоритмы SHA384 и SHA512, но, соответственно хэш получится в два раза больше, например, ниже представлены результаты вычисления хэша для строки «Привет, мир» с использованием алгоритма SHA256 и SHA512:
SHA512: 39B5FA93892703D4C95BC8C16D42599B988B83602AB1775849FC3C424D46F40B791484A9E518DF027ACBA901ED3739CBFE7D40BF7FBB0117E6B6047457C7F864
Алгоритмы хэширования и русские символы
Довольно часто, в начале работы с различными хэш-алгоритмами можно столкнуться с такой проблемой — хэш, созданный вами в C# не совпадает с тем хэшем, который вы получили, например, от какого-либо онлайн-сервиса. В большинстве случаев, проблема кроется в кодировке текста. Например, вернемся к алгоритму SHA256. Как было сказано выше, малейшее изменение сообщения должно привести к значительной смене результата. Возьмем два русских слова — «кот» и «код» и попробуем вычислить их хэш с помощью следующего метода:
public static string CreateSHA256(string input) { using SHA256 hash = SHA256.Create(); return Convert.ToHexString(hash.ComputeHash(Encoding.ASCII.GetBytes(input))); }
В результате получим неверное значение хэшей. Более того, изменение одного символа вообще никак не затронуло значение хэша:
A03B221C6C6EAE7122CA51695D456D5222E524889136394944B2F9763B483615
Проблема кроется в кодировке символов. Мы использовали в этом примере кодировку ASCII, в то время, как должны были использовать Unicode. Для получения верного результата перепишем пример следующим образом:
public static string CreateSHA256(string input) { using SHA256 hash = SHA256.Create(); return Convert.ToHexString(hash.ComputeHash(Encoding.UTF8.GetBytes(input))); }
Теперь хэши будут действительно сильно различаться
87FC5157A761FC742B0258FE3753A062257288F65F2C6BF74200B4829B14DF95
Почему именно UTF-8, а не UTF-16 или UTF-32? В, принципе, можно использовать и эти кодировки для русских символов, т.к. всё это Unicode, как ни крути и результат не изменится для русского текста. Но, всё же в Сети на данный момент, преобладает кодировка UTF-8 и, потому, лучше использовать именно её, чтобы с большей вероятностью получать переносимый результат, который будет принят каким-либо внешним сервисом.
Итого
В этой статье мы рассмотрели наиболее популярные алгоритмы хэширования, реализованные в .NET C#. Классы для работы с этими алгоритмами работают единообразно, поэтому получить хэш сообщения по любому алгоритму в C# достаточно просто.