Можно ли использовать SHA1-хэш пароля в качестве соли при получении ключа шифрования и IV из строки пароля?

Я использую Rfc2898DeriveBytes для безопасного генерирования ключа шифрования и вектора инициализации из предоставленного пользователем строкового пароля для использования с симметричным шифрованием (например, AesManaged).

Я принимаю SHA1 хэш пароля в качестве параметра соли для Rfc2898DeriveBytes, Это нормально? Если нет, то откуда мне взять соль? Мне понадобится та же соль при расшифровке, верно? Поэтому я должен хранить его где-нибудь в незашифрованном виде - без обеспечения. Если мне нужно надежно хранить его, тогда он просто становится еще одним "паролем", не так ли?

void SecureDeriveKeyAndIvFromPassword(string password, int iterations, 
    int keySize, int ivSize, out byte[] key, out byte[] iv)
{
    // Generate the salt from password:

    byte[] salt = (new SHA1Managed()).ComputeHash(Encoding.UTF8.GetBytes(password));

    // Derive key and IV bytes from password:

    Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(password, salt, iterations);

    key = derivedBytes.GetBytes(keySize);
    iv = derivedBytes.GetBytes(ivSize);
}

Я видел использование постоянной (жестко запрограммированной) соли, и я видел людей, жалующихся на это. Я думал, что получение соли из пароля будет лучшей идеей, но я не уверен, что это оптимальное решение.

Вкратце, у меня есть файл, который необходимо зашифровать, и ввод пароля пользователем. Как правильно использовать Rfc2898DeriveBytes получить безопасный ключ шифрования и IV?

Благодарю.

РЕДАКТИРОВАТЬ:

Спасибо за ваши ответы. Теперь я понимаю, что основная (может быть, только?) Цель соли - сделать генерацию радужных таблиц невозможной - вы не можете предварительно сгенерировать хеш "P@$$w0rd", потому что он будет иметь разные хеш-функции для каждого возможного соленость. Я прекрасно понимаю это, НО... Это действительно имеет отношение к симметричному шифрованию? Я нигде не храню хэш, верно? Таким образом, даже если у злоумышленника есть радужная таблица для всех возможных комбинаций паролей, он не может многое сделать, верно?

Итак, мой вопрос сейчас таков: есть ли преимущество использования случайной соли в каждой операции шифрования по сравнению с использованием соли, полученной из пароля (или даже жестко запрограммированной), при использовании с симметричными алгоритмами шифрования (такими как AesManaged of .NET)?

5 ответов

Решение

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

Идея заключается в том, что злоумышленник не может использовать готовую радужную таблицу для получения паролей. Он должен был бы создать такую ​​радужную таблицу для каждого пароля отдельно, и это не имеет смысла. Проще брутфорс, пока не найдется совпадение.

В MSDN есть пример, где соль получается из случайного источника операционной системы. Это лучшее, что вы можете сделать, чтобы получить безопасную соль, не извлекайте ее из своего пароля.

Соль предназначена для защиты от многоцелевых атак, заставляя каждую цель вести себя по-разному. Радужные таблицы - это всего лишь одно конкретное воплощение многоцелевых атак, где вычислительные усилия затрачиваются до того, как вы получите цели.

Бывают ситуации, когда применимы многоцелевые атаки, но не радужные таблицы.

Один из примеров этого: предположим, что вы используете аутентифицированную схему шифрования с семантической безопасностью, такую ​​как AES-GCM с уникальными одноразовыми номерами. Теперь вы получили миллион различных сообщений, зашифрованных с использованием другого пароля.

Если вы не используете соль, чтобы проверить, применяется ли пароль к какому-либо из них, злоумышленнику потребуется одна операция KDF и один миллион операций дешифрования. Если вы используете соль, злоумышленнику потребуется один миллион операций KDF и один миллион операций дешифрования. Поскольку KDF медленнее по сравнению с расшифровкой, атака на первую схему намного быстрее, чем атака на вторую схему.

Людям не нравятся жестко запрограммированные соли, так как они доступны всем разработчикам проекта (и, возможно, публике в случае проектов с открытым исходным кодом или реверс-инжиниринга). Затем злоумышленники могут вычислить радужные таблицы для вашей конкретной соли и начать атаковать вашу систему.

Хороший выбор солевой ценности - это то, что:

  • Доступно каждый раз, когда вы проверяете пароль
  • Не меняется между проверками пароля
  • Отличается для каждого (или большинства) вычислений пароля

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

Я действительно не знаю, что это Rfc2898DeriveBytes но я могу сказать вам следующее: соль не должна быть обеспечена. Итак, вы сказали, что видели людей, жалующихся на жестко заданные, постоянные значения для соли, и тех, кто сказал, что это правильно. Соль должна быть случайной величиной, а не постоянной, в противном случае ее цель побеждена.

Вы понимаете, для чего используется соль? Вы явно не Использование хэша в качестве соли - плохая идея, потому что пароль X всегда будет иметь значение с тем же значением Y, опять же, в ущерб своей цели.

Другие уже объяснили назначение соли и почему это может быть публичная информация.

Еще одна часть ответа на ваш вопрос: не извлекайте соль из самого пароля. Это было бы очень похоже на грубую ошибку в программировании, которая в итоге выявила миллионы паролей после взлома Эшли Мэдисон.

Проблема в том, что когда вы используете пароль для генерации соли, вы, по сути, делаете пароль доступным во второй и гораздо более легкой для взлома форме. Атакующий может полностью игнорировать вывод PBKDF2 и просто обратить вспять саму соль. Это защищено только SHA1, который уже сломан.

В Эшли Мэдисон ошибка была похожа. Пароли хранились в основной базе данных с использованием bcrypt и считались безопасными. Но затем кто-то обнаружил, что пароли для многих учетных записей фактически хранились дважды, а вторая копия была защищена только с помощью MD5.

Другие вопросы по тегам