【问题标题】:bcrypt vs pbkdf2 for encrypting private keysbcrypt vs pbkdf2 用于加密私钥
【发布时间】:2017-03-26 19:18:54
【问题描述】:

我正在构建一个应用程序,其中在客户端使用密码来加密椭圆曲线密钥对的私钥。然后密码被bcrypted并发送到服务器(连同加密的私钥)和公钥。

最初,我在加密私钥之前使用 pbkdf2 对密码进行哈希处理,但由于我也在对密码进行 bcrypt,我可以使用 bcrypted 来代替吗?

根据https://medium.com/@mpreziuso/password-hashing-pbkdf2-scrypt-bcrypt-1ef4bb9c19b3#.sj4jcbynx 的答案不仅是肯定的,而且 bcrypt 甚至更好,因为它更具 GPU-ASIC 弹性。我有什么遗漏吗?

【问题讨论】:

  • DRAFT NIST 特别出版物 800-63B 数字认证指南建议将 PBKDF2 用于密码派生。
  • 不清楚你在做什么。 1.bcrypt在哪里使用。 2. 如果您发送的是 bcrypted 密码,您将没有解密 EC 密钥的密码。 3.按执行顺序一步步修改问题:1.做这个,2.做这个,3.等等..
  • 在我能理解的范围内,您是在询问是否可以将用于加密某些明文的密钥与从中派生的密文一起发送。不完全安全。
  • 向服务器端发送 bcypted 密码的目的是什么?如果没有您的原始密码,即使使用 bcypted 密码,服务器也无法解密加密的私钥。服务器只能使用 bcypted 密码来验证输入密码的正确性。但是,使用原始密码,您可以在没有 bcypted 密码的情况下解密私钥。为什么要向服务器泄露重要信息?

标签: encryption cryptography bcrypt pbkdf2


【解决方案1】:

您不应该使用 bcrypt 哈希输出作为加密密钥;它不是关键材料:

  • BCrypt 不是密钥派生函数
  • BCrypt 是一个密码存储功能

您有一个椭圆曲线私钥,您想使用用户密码对其进行加密。当然,您不想直接使用密码——您想使用密码导出加密密钥。为此,您可以使用:

  • PBKDF2
  • 加密

这些都是密钥派生函数(例如基于密码的密钥派生函数)。它们的目的是在给定密码的情况下生成加密密钥。它们被设计为“硬”

您同时提供这两种算法:

  • 密码
  • 成本参数
  • 所需的字节数(例如 32 ==> 32 字节 ==> 256 位)

它会返回一个 256 位密钥,您可以将其用作 AES-256 的加密密钥。

然后您要备份用户的密钥

我猜你想:

  • 将加密的椭圆曲线私钥存储在您的服务器上
  • 在您的服务器上存储他们密码的哈希

而您的问题是:既然您已经通过“散列函数”运行了他们的密码,您不能只使用该散列作为他们存储的密码吗?

不!该哈希也是保护其私钥的加密密钥。您不希望该私钥在任何地方传输。你不希望它存在于任何地方。使用完该 32 字节加密密钥后,应立即从内存中擦除它。

如果您还希望存储用户密码的散列,您应该使用通常用于密码存储的算法:

  • pbkdf2(一种密钥派生函数被滥用到密码存储中)
  • bcrypt(优于 pbkdf2)
  • scrypt(一种被滥用到密码存储中的密钥派生函数;优于 bcrypt)
  • argon2(优于 scrypt)

您应该通过这些密码存储算法之一单独运行用户密码。如果您可以访问 bcrypt;在 pbkdf2 上使用它。如果您有 scrypt,请同时使用它:

  • 加密密钥的派生
  • 密码散列

您系统的安全性来自(除了密码的保密性)用户密码和保护其私钥的加密密钥之间的计算距离:

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

您希望密码和密钥之间的距离尽可能远。

不推荐作弊

如果您真的很想节省 CPU 周期(并避免计算 scrypt 两次),从技术上讲,您可以采取:

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

并将加密密钥的散列称为“散列密码”并将其存储。单个 SHA2 的计算可以忽略不计。这是可以接受的,因为攻击者可以使用它的唯一方法是尝试猜测每个可能的 256 位加密密钥 - 这是他们首先无法解决的问题。没有办法暴力破解 256 位密钥。如果他们试图暴力破解,额外的哈希版本对他们没有帮助,因为他们可以通过尝试解密私钥来测试他们的尝试。

但这不太理想,因为您存储的是加密密钥的(转换后的)版本。您希望尽可能少地存储该密钥(以及它的任何转换版本)。

总结一下

  • 生成 EC 密钥对
  • encryptionKey = scryptDeriveBytes(password, salt, cost, 32)
  • encryptedPrivateKey = AES256(privateKey, encryptionKey)
  • passwordHash = scryptHashPassword(密码、盐、成本)

并上传

  • 加密的PrivateKey
  • 密码哈希

【讨论】:

  • 是的...当然我不想使用相同的哈希来加密私钥和身份验证。在发布这个问题并写下这个设计后不久,我有一个很大的“doh”时刻。哇!
  • 我认为如果它强调你需要为加密密钥和密码哈希使用不同的盐,答案可能会更清楚一点。
  • 可以导出64字节的encryptionKey,使用前32字节作为aes256的key;散列(剩余的 32 字节 + 密文)作为密码哈希。 encryptionKey = scryptDeriveBytes(密码,盐,成本,64); encryptedPrivateKey = AES256(privateKey, encryptionKey[0,31]); passwordHash = sha3(encryptionKey[32,63]+ encryptedPrivateKey)。这比直接散列加密密钥要安全得多
猜你喜欢
  • 2012-11-26
  • 2011-07-24
  • 1970-01-01
  • 1970-01-01
  • 2012-07-09
  • 1970-01-01
  • 2015-10-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多