在 Java 中使用 PBKDF2 进行密码验证

Posted

技术标签:

【中文标题】在 Java 中使用 PBKDF2 进行密码验证【英文标题】:Password Verification with PBKDF2 in Java 【发布时间】:2011-01-23 10:47:47 【问题描述】:

我正在用 Java 进行基于密码的文件加密;我使用 AES 作为底层加密算法,PBKDF2WithHmacSHA1 使用以下代码从盐和密码组合中派生密钥(我从本网站的另一张慷慨的海报中获得)。

SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec ks = new PBEKeySpec(password,salt,1024,128);
SecretKey s = f.generateSecret(ks);
Key k = new SecretKeySpec(s.getEncoded(),"AES");

我共享盐,用户在每一端输入他们的密码,加密和解密工作正常:-) 我的问题是我希望能够在开始之前验证用户输入的密码是否正确(可能很长)解密过程。我知道 PBKD 规范包含一个可选的 2 字节验证值,但我不确定如何使用上述方法生成该值。 Java 是否为此提供支持,或者如果不提供支持,那将是一个安全的替代方案吗?

感谢您的宝贵时间。

【问题讨论】:

【参考方案1】:

根据定义,没有安全的“快速检查”机制。使用 PBKDF2 或相关技术的全部目的是使密码检查变慢,以阻止密码破解程序。如果你添加了一个快速检查系统,密码破解者将能够非常快速地批量猜出密码。

【讨论】:

您好,感谢您的回答。我的印象是 PBKDF2 及其重复组合盐和密码以派生密钥的目的是使从纯文本密码计算密钥的过程变得昂贵,因此使字典式攻击更加困难。就像我说的 PBKDF2 规范包括一个可选的密码验证值,我只是不知道如何在 java 实现中得到它。 我同意在密钥派生过程完成后允许快速检查使得暴力攻击更容易,因为攻击者实际上不需要解密任何东西来检查那里的密钥,但我会认为大搜索无论如何,256 位 AES 密钥的空间使得纯暴力攻击令人望而却步? @pinkynobrain:快速检查的问题在于它大大缩小了密钥空间:您可以快速找出快速检查成功的所有密码。因此,用于暴力破解 AES 的密钥要少得多。【参考方案2】:

计算某种密码验证标签并将其与加密的文件数据一起存储,以便您首先检查它。这可能类似于固定(短)字符串的 PBMAC。当然,这需要是一个不可逆的函数,这样破解者就无法确定密码,也不能计算得太快,从而混淆暴力攻击。

您是否考虑过是否(以及如何)检测整个文件是否已正确解密?您可能应该研究 PBES2 和 PBMAC 的某种组合,而不是直接使用 AES。

【讨论】:

您好,感谢您的快速回复以及您对 PBES2 和 PMAC 的建议,我一定会调查的。我曾想过使用固定字符串方法,但担心它会打开已知纯文本攻击的过程。相反,我想使用密钥本身的安全散列,如果散列函数确实是不可逆的,那么这将不提供密钥本身的任何信息,但仍然允许我检查密钥是否相同。您认为这是一个好方法吗? 确实,某种验证必然会产生某种已知的明文。然而,PB* 函数的使用使工作函数变得更加困难,与简单的单个哈希相比,它有效地乘以迭代次数。【参考方案3】:

嘿,感谢疯狂的苏格兰人和克里斯的帮助。经过一番挖掘后,我决定使用Dr Gladmans file encryption page 中描述的方法进行密码验证和消息验证。我相信这种基于 PBKDF2 和 MAC 的方法使得导出密码的验证值足够昂贵以使其安全。再次感谢,我希望这个解决方案对其他人有所帮助。

【讨论】:

以上是关于在 Java 中使用 PBKDF2 进行密码验证的主要内容,如果未能解决你的问题,请参考以下文章

PBKDF2适合登录密码验证吗?

使用Pbkdf2加密加密和验证使用Salt的哈希密码

如何在 Ktor 中散列和验证密码?

是否有使用 PBKDF2 作为密码哈希的标准?

Java - 使用 HMACSHA256 作为 PRF 的 PBKDF2

crypto.pbkdf2 是异步的,如何将其视为同步?