Немного про хэши
Хэширование — это процесс преобразования некоторых входных данных любой длины в массив байтов фиксированной длины.
Хэш представляет собой одностороннюю функцию преобразования, результат работы которой нельзя реверсировать для получения исходных входных данных. Очень часто используется для хранения паролей. Даже если злоумышленник получит хэш, то получить сам пароль не получится. Длина хэша определяется алгоритмом хэширования.
В .NET можно найти следующие алгоритмы хэширования (наследующие абстрактный класс HashAlgorithm):
- MD5 — длина 128 битов
- SHA (Secure Hash Algorithm) — такого класса нет, но есть SHA1 (160 битов), SHA256, SHA384, SHA512
- KeydHashAlgorithm (известные как Message Authentication Code). Представителями является класс алгоритмов HMAC и MACTripleDES
В .NET, если не нужен хэш, основанный на ключе, то, при прочих равных условиях на сегодняшний день, лучше всего использовать алгоритм SHA512. MD5 несколько устарел и может быть скомпрометирован. SHA512 работает очень быстро (уступает только SHA1). Вообще-то всё семейство SHA работает быстро. Самый медленный MACTripleDES. Семейство HMAC работает примерно в два-четыре раза медленнее, чем SHA.
Хэши на основе ключа могут использоваться для защиты данных от модификаций. Запросы посылаемые на сервер с клиента могут проверяться на предмет модификаций. Если данные, передаваемые на сервер были модифицированы, то хэши не совпадут. При защите строковых запросов нельзя использовать простой хэш, без ключа. Потому что, тогда злоумышленник просто переберёт все возможные алгоритмы хэширования, найдёт нужный, модифицирует аргументы в строке запроса и подставит нужный хэш и тогда, серверу ничего не останется, как отвечать на корректно сформированный запрос. Для такой защиты вполне может подойти HMACSHA1 в качестве алгоритма хэширования, основанного на ключе. Разумеется, в полный рост встаёт и проблема хранения секретного ключа.
public static byte[] ComputeHmacsha1(byte[] data, byte[] key)
{
using (var hmac = new HMACSHA1(key))
{
return hmac.ComputeHash(data);
}
}
Чтобы у злоумышленника оставалось меньше возможностей на сбор входных данных и соответствующих им хэшей для последующего перебора с целью поиска ключа, можно добавить соль.
Соль — это некий рандомизированный дополнительный «ключ», который добавляет энтропии к шифрованию. Соль можно передавать в открытом виде. Соль можно сгенерировать и ассоциировать с текущей сессией пользователя. Таким образом, соль будет меняться каждую сессию и результаты хэширования для одних и тех же запросов будут разные. Соль также добавляют при хэшировании паролей, чтобы усложнить перебор по словарю, особенно если, например, у злоумышленника есть доступ к значениям хэшей. Для генерации соли лучше использовать криптоустойчивый генератор типа RNGCryptoServiceProvider.
Соль можно сгенерировать следующим образом:
string salt = GenSalt(32);
string GenSalt(int length)
{
RNGCryptoServiceProvider p = new RNGCryptoServiceProvider();
var salt = new byte[length];
p.GetBytes(salt);
return Convert.ToBase64String(salt);
}