bcrypt против pbkdf2 для шифрования закрытых ключей

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

Первоначально я использовал pbkdf2 для хеширования пароля перед шифрованием закрытого ключа, но, поскольку я также использую bcrypted пароль, могу ли я использовать вместо него bcrypted?

Согласно https://medium.com/@mpreziuso/password-hashing-pbkdf2-scrypt-bcrypt-1ef4bb9c19b3#.sj4jcbynx ответ не только да, но и bcrypt даже лучше, поскольку он более устойчив к GPU-ASIC. Что-то мне не хватает?


person pupeno    schedule 12.11.2016    source источник
comment
В ПРОЕКТЕ NIST Special Publication 800-63B Digital Authentication Guideline предлагается использовать PBKDF2 для получения пароля.   -  person zaph    schedule 12.11.2016
comment
Непонятно, что ты делаешь. 1. Где используется bcrypt. 2. Если вы отправляете зашифрованный пароль, у вас не будет пароля для расшифровки ключа EC. 3. Пошагово переформулируйте вопрос в порядке выполнения: 1. сделать так, 2. сделать это, 3. и т. Д.   -  person zaph    schedule 12.11.2016
comment
Насколько я могу понять это, вы спрашиваете, можете ли вы отправить ключ, используемый для шифрования некоторого открытого текста, вместе с зашифрованным текстом, полученным из него. Не совсем безопасно.   -  person eh9    schedule 15.11.2016
comment
какова цель отправки зашифрованного пароля на сервер? Без вашего исходного пароля сервер не может расшифровать зашифрованный закрытый ключ даже с зашифрованным паролем. Сервер может использовать только зашифрованный пароль для проверки правильности введенного пароля. Однако с исходным паролем вы можете расшифровать закрытый ключ без зашифрованного пароля. Почему утечка засасывает важную информацию на сервер?   -  person Yuan Wen    schedule 22.09.2020


Ответы (1)


Вы не должны использовать хеш-вывод bcrypt в качестве ключа шифрования; он не предназначен для использования в качестве ключевого материала:

  • BCrypt не является функцией получения ключа
  • BCrypt - это функция хранения паролей.

У вас есть закрытый ключ с эллиптической кривой, который вы хотите зашифровать с помощью пароля пользователя. Конечно, вы не хотите использовать пароль напрямую - вы хотите использовать пароль для получения ключа шифрования. Для этого вы можете использовать:

  • PBKDF2
  • зашифровать

Это обе функции получения ключа (например, функция получения ключа на основе пароля). Их цель - сгенерировать ключ шифрования по паролю. Они созданы быть «сложными».

Вы кормите оба этих алгоритма:

  • пароль
  • параметры стоимости
  • поваренная соль
  • желаемое количество байтов (например, 32 ==> 32 байта ==> 256 бит)

и он возвращает вам 256-битный ключ, который вы можете использовать в качестве ключа шифрования для AES-256.

Затем вы хотите сделать резервную копию ключа пользователя

Я так понимаю, вы хотите:

  • хранить зашифрованный закрытый ключ эллиптической кривой на вашем сервере
  • хранить хэш их пароля на своем сервере

И ваш вопрос был таков: поскольку вы уже пропустили их пароль через «функцию хеширования», не можете ли вы просто использовать этот хеш в качестве сохраненного пароля?

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

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

  • pbkdf2 (функция получения ключа, использованная в хранилище паролей)
  • bcrypt (лучше, чем pbkdf2)
  • scrypt (функция получения ключа, используемая в хранилище паролей; лучше, чем bcrypt)
  • argon2 (лучше, чем scrypt)

Вы должны отдельно запустить пароль пользователя с помощью одного из этих алгоритмов хранения паролей. Если у вас есть доступ к bcrypt; используйте это поверх pbkdf2. Если у вас есть скрипт, используйте его для обоих:

  • получение ключа шифрования
  • хеширование пароля

Безопасность вашей системы зависит (в дополнение к секретности пароля) от вычислительного расстояния между паролем пользователя и ключом шифрования, защищающим его закрытый ключ:

"hunter2"  --PBKDF2--> Key material
"hunter2"  ---------bcrypt-------> Key material
"hunter2"  ----------------scrypt----------> Key material

Вы хотите, чтобы между паролем и ключом было как можно большее расстояние.

Не рекомендуемый чит

Если вы действительно отчаянно пытаетесь сэкономить циклы процессора (и избежать двойного вычисления scrypt), технически вы можете взять:

Key Material ---SHA2---> "hashed password"

И назовите хэш ключа шифрования своим «хешированным паролем» и сохраните его. Вычисление одного SHA2 незначительно. Это приемлемо, потому что единственный способ использовать это злоумышленник - это попытаться угадать все возможные 256-битные ключи шифрования - это проблема, которую они не могут решить в первую очередь. Невозможно подобрать 256-битный ключ. И если бы они попытались перебрать его, дополнительная хешированная версия им не помогла, так как они могли бы просто проверить свою попытку, пытаясь расшифровать закрытый ключ.

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

Подводить итоги

  • сгенерировать пару ключей EC
  • encryptionKey = scryptDeriveBytes (пароль, соль, стоимость, 32)
  • encryptedPrivateKey = AES256 (privateKey, encryptionKey)
  • passwordHash = scryptHashPassword (пароль, соль, стоимость)

и загрузить

  • encryptedPrivateKey
  • хэш паролей
person Ian Boyd    schedule 16.11.2016
comment
Да ... Конечно, я не хочу использовать один и тот же хеш для шифрования закрытого ключа и аутентификации. Вскоре после того, как я разместил этот вопрос и записал этот дизайн, у меня был большой момент. Дох! - person pupeno; 17.11.2016
comment
Я думаю, что ответ можно было бы сделать немного более ясным, если бы он подчеркивал, что вам нужно использовать разные соли для encryptionKey и passwordHash. - person Freek; 18.10.2019
comment
вы можете получить 64-байтовый ключ encryptionKey, используя первые 32 байта в качестве ключа aes256; хеширование (оставшиеся 32 байта + зашифрованный текст) как passwordHash. encryptionKey = scryptDeriveBytes (пароль, соль, стоимость, 64); encryptedPrivateKey = AES256 (privateKey, encryptionKey [0,31]); passwordHash = sha3 (encryptionKey [32,63] + encryptedPrivateKey). Это может быть намного безопаснее, чем хеширование ключа encryptionKey напрямую. - person Yuan Wen; 22.09.2020