.NET: разница между PasswordDeriveBytes и Rfc2898DeriveBytes
Я пытаюсь понять какой-то C#-код, который мне вручают, который имеет дело с криптографией и специально использует PasswordDeriveBytes
от System.Security.Cryptography
,
В документах.NET написано, что PasswordDeriveBytes
использует "расширение алгоритма PBKDF1", которое позже в документе указано как "стандарт PKCS#5 v2.0", то есть PBKDF2 (насколько я могу судить). Тем не менее, везде в сети, которую я нашел (в том числе здесь, в Stack Exchange), все говорят: "используйте Rfc2898DeriveBytes, потому что Password* устарел и использует PBKDF1". Но единственное отличие в документах на http://msdn.microsoft.com/ видимому, заключается в том, что Rfc*-версия конкретно упоминает PBKDF2, где Password* говорит "расширение PBKDF1" и "PKCS#5 v 2.0".
Итак, может кто-нибудь сказать мне, в чем разница между этими двумя классами (если таковые имеются) и почему я должен использовать один, а не другой для получения ключа пароля PBKDF2?
Теперь другой код, который работает с теми же данными, явно использует PBKDF2 и работает, так что можно предположить, что это действительно так. PasswordDeriveBytes
также использует PBKDF2, или что PBKDF2 просто совместим с PBKDF1 при определенных обстоятельствах, но я хочу точно знать, что это не какой-то побочный эффект какой-то случайной вещи, и что все просто волшебным образом работает (и в конечном итоге, вероятно, волшебно и эффектно сломается) и никто не понимает почему.
4 ответа
Если вы создаете экземпляр PasswordDeriveBytes
и сделать один звонок в GetBytes
метод, передающий значение, которое меньше выходного размера базового алгоритма дайджеста, затем возвращает значение из алгоритма PBKDF1.
Если вы сделаете два вызова GetBytes для одного и того же объекта, вы можете столкнуться с ошибкой подсчета в реализации.
PBKDF1 описывается только для вывода до размера алгоритма хеширования (например, 20 байтов для SHA-1), но класс PasswordDeriveBytes создал формулу для поддержки до 1000 раз превышающего размер вывода хеш-функции. Таким образом, большая ценность, производимая этим классом, не может быть легко достижима на другой платформе.
Если вы создаете экземпляр Rfc2898DeriveBytes
Вы получаете потоковую реализацию алгоритма PBKDF2. Наиболее очевидное отличие PBKDF2 от PBKDF1 заключается в том, что PBKDF2 позволяет генерировать произвольный объем данных (ограничение (2^32-1)*hashOutputSize
; или для SHA-1 (85 899 345 900 байт). PBKDF2 также использует более сложную конструкцию (в частности, HMAC поверх прямого дайджеста), чтобы затруднить восстановление входного пароля из выходного значения.
"Потоковое" в реализации заключается в том, что объединение GetBytes(5)
а также GetBytes(3)
такой же как GetBytes(8)
, В отличие от PasswordDeriveBytes, это правильно работает в Rfc2898DeriveBytes.
PBKDF1 изначально был создан для генерации ключей DES, опубликованных в PKCS #5 v1.5 в 1993 году. PBKDF2 был опубликован в PKCS #5 v2.0 (который был переиздан как RFC2898) в 1999 году. Слайд-колоду, которую можно найти по адресу ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-5v2/pkcs5v2-0.pdf (но, похоже, возникают проблемы, так что ftp://ftp.dfn-cert.de/pub/pca/docs/PKCS/ftp.rsa.com/99workshop/pkcs5_v2.0.ppt может понадобиться) дополнительно суммирует различия. (Слайд-колода была написана RSA Security, создателями PBKDF1 и PBKDF2, и они - люди, которые рекомендуют PBKDF2 вместо PBKDF1).
Я думаю, что отличный ответ на это можно найти здесь:
C# PasswordDeriveBytes Confusion
Но подведем итог:
Внедрение Microsoft оригинальной PKCS#5 (также известной как PBKDF1) включает небезопасные расширения для предоставления большего количества байтов, чем может предоставить хеш-функция (см. Отчеты об ошибках здесь и здесь).
Даже если это не было ошибкой, вам следует избегать незарегистрированных, проприетарных расширений стандартов (или вы никогда не сможете расшифровать свои данные в будущем - по крайней мере, за пределами Windows).
Я настоятельно рекомендую вам использовать более новый Rfc2898DeriveBytes, который реализует PBKDF2 (PKCS#5 v2), который доступен с.NET 2.0.
Вот сообщение в блоге, детализирующее различия:
http://blogs.msdn.com/b/shawnfa/archive/2004/04/14/generating-a-key-from-a-password.aspx
PBKDF2 может использоваться для генерации ключей любой длины, что очень полезно для шифрования на основе паролей (он может генерировать ключи любой длины, как того требует симметричный шифр), но означает меньше для безопасного хранения паролей. Он также применяет соль, используя HMAC вместо конкатенации, как PBKDF1, которая обладает лучшими защитными свойствами в случае слабых солей.
PKCS#5 v2.0 определяет PBKDF1 и PBKDF2, первый по причинам обратной совместимости, а также рекомендует использовать PBKDF2 для новых приложений. Я понятия не имею, почему последний лучше первого, но два класса.NET, похоже, используют разные, но совместимые алгоритмы. (Возможно, потому что обменивается только полученный ключ, а не входы + KDF.)