将 BCrypt 与 char[] 一起使用
Using BCrypt with a char[]
大约几个小时前,我在 Stack Overflow 上查询了有关如何将 char[] 转换为 MD5 哈希的方法。提供了一个解决方案,但被认为是不安全的 - 正如几个人所概述的:
Neil Smithline 建议我使用 BCrypt,但我无法将它与 char[] 一起使用。
我使用 char[] 来存储从登录表单检索到的密码的原因是 .getPassword()
仅支持 char[]。
char[] passwordChars = passwordInputField.getPassword();
String hashed = BCrypt.hashpw(passwordChars, BCrypt.gensalt(12));
目前,我正在尝试使用上面的代码生成散列,但由于变量 passwordCars 是 char[] 类型,BCrypt.haspw()
不支持它
现在我不使用常规字符串的唯一原因是它无法从内存中清除。
我现在的问题是 - 是否可以通过某种方式将 char[] 与 BCrypt 一起使用?
提前致谢!
我发现的两个 Java bcrypt impls 都将字符串作为输入。正如您所知,将密码放入字符串中会使您容易受到内存攻击。
您可以使用 PBKDF2 和 bcrypt。两者都被认为是一流的。有 PBKDF2 Java 个代码示例 here and here。两者都允许将 char[]
传递给函数。
回答评论中的一个隐含问题,您不使用 MD5 或任何哈希的原因是它们太快了。使用它们可以使用特殊硬件暴力破解密码。 Bcrypt 和 PBKDF2 的设计速度很慢。
即使您打算使用散列(我不建议这样做),您也必须对其加盐。反转未加盐的密码哈希是微不足道的(参见 this tool)。
关于密码存储的 CrackStation's reference 是一个很好的通用参考。
因此,根据 https://github.com/jeremyh/jBCrypt 中介绍的实现,您需要更改 hashpw
和 checkpw
方法以接受 char[]
而不是 String
可能最难的部分在hashpw
...
try {
passwordb = (password + (minor >= 'a' ? "[=10=]0" : "")).getBytes("UTF-8");
} catch (UnsupportedEncodingException uee) {
throw new AssertionError("UTF-8 is not supported");
}
最简单的解决方案是将 char[]
换回到 String
,但我们正在努力避免这种情况。相反,根据 Converting char[] to byte[] 的最高分答案,我们可以做一些更像...
char[] expanded = password;
if (minor >= 'a') {
expanded = Arrays.copyOf(expanded, expanded.length + 1);
expanded[expanded.length - 1] = '[=11=]0';
}
CharBuffer charBuffer = CharBuffer.wrap(expanded);
ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
passwordb = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
checkpw
方法实际上不需要任何修改(参数除外),因为它使用hashpw
方法来检查结果。
那么,测试...
// We want the same salt for comparison
String salt = BCrypt.gensalt(12);
String original = BCrypt.hashpw("Testing", salt);
System.out.println(original);
String hash = BCrypt.hashpw("Testing".toCharArray(), salt);
System.out.println(hash);
System.out.println(BCrypt.checkpw("Testing", hash));
System.out.println(BCrypt.checkpw("Testing".toCharArray(), hash));
输出...
a$KclXlnca78yhcrg1/mNrRepLYqeJE//SRhrh1X3UM7YUQMjY4x8gy
a$KclXlnca78yhcrg1/mNrRepLYqeJE//SRhrh1X3UM7YUQMjY4x8gy
true
true
现在,如果您有一个 GitHub 帐户,您实际上可以克隆原始存储库,进行建议的更改并生成拉取请求。我个人很想摆脱需要 String
的 checkpw
和 hashpw
方法
我还找到了 PDKDF2 的 this 实现,它使用 String
,但随后立即将其转换为 char[]
... 所以,这很容易改变。 ..
对您的问题的简短回答:是,可以在 Java.
中将 char[]
s 与 BCrypt 一起使用
Bouncy Castle crypto packages for Java在 1.52 版本(2015 年 3 月)中添加了 BCrypt 密码哈希算法(使用字符串格式和 OpenBSD 上参考实现的 Base64 编码),并且它只支持char[]
个密码。
生成 BCrypt 字符串的相关方法可以在 org.bouncycastle.crypto.generators.OpenBSDBCrypt class 中找到,并具有以下签名:
String generate(char[] password,
byte[] salt,
int cost)
如果您想在源代码中验证 char[]
被保留而不被转换成字符串,相关的 class 是 OpenBSDBcrypt, Strings and BCrypt.
大约几个小时前,我在 Stack Overflow 上查询了有关如何将 char[] 转换为 MD5 哈希的方法。提供了一个解决方案,但被认为是不安全的 - 正如几个人所概述的:
Neil Smithline 建议我使用 BCrypt,但我无法将它与 char[] 一起使用。
我使用 char[] 来存储从登录表单检索到的密码的原因是 .getPassword()
仅支持 char[]。
char[] passwordChars = passwordInputField.getPassword();
String hashed = BCrypt.hashpw(passwordChars, BCrypt.gensalt(12));
目前,我正在尝试使用上面的代码生成散列,但由于变量 passwordCars 是 char[] 类型,BCrypt.haspw()
现在我不使用常规字符串的唯一原因是它无法从内存中清除。
我现在的问题是 - 是否可以通过某种方式将 char[] 与 BCrypt 一起使用?
提前致谢!
我发现的两个 Java bcrypt impls 都将字符串作为输入。正如您所知,将密码放入字符串中会使您容易受到内存攻击。
您可以使用 PBKDF2 和 bcrypt。两者都被认为是一流的。有 PBKDF2 Java 个代码示例 here and here。两者都允许将 char[]
传递给函数。
回答评论中的一个隐含问题,您不使用 MD5 或任何哈希的原因是它们太快了。使用它们可以使用特殊硬件暴力破解密码。 Bcrypt 和 PBKDF2 的设计速度很慢。
即使您打算使用散列(我不建议这样做),您也必须对其加盐。反转未加盐的密码哈希是微不足道的(参见 this tool)。
关于密码存储的 CrackStation's reference 是一个很好的通用参考。
因此,根据 https://github.com/jeremyh/jBCrypt 中介绍的实现,您需要更改 hashpw
和 checkpw
方法以接受 char[]
而不是 String
可能最难的部分在hashpw
...
try {
passwordb = (password + (minor >= 'a' ? "[=10=]0" : "")).getBytes("UTF-8");
} catch (UnsupportedEncodingException uee) {
throw new AssertionError("UTF-8 is not supported");
}
最简单的解决方案是将 char[]
换回到 String
,但我们正在努力避免这种情况。相反,根据 Converting char[] to byte[] 的最高分答案,我们可以做一些更像...
char[] expanded = password;
if (minor >= 'a') {
expanded = Arrays.copyOf(expanded, expanded.length + 1);
expanded[expanded.length - 1] = '[=11=]0';
}
CharBuffer charBuffer = CharBuffer.wrap(expanded);
ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
passwordb = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
checkpw
方法实际上不需要任何修改(参数除外),因为它使用hashpw
方法来检查结果。
那么,测试...
// We want the same salt for comparison
String salt = BCrypt.gensalt(12);
String original = BCrypt.hashpw("Testing", salt);
System.out.println(original);
String hash = BCrypt.hashpw("Testing".toCharArray(), salt);
System.out.println(hash);
System.out.println(BCrypt.checkpw("Testing", hash));
System.out.println(BCrypt.checkpw("Testing".toCharArray(), hash));
输出...
a$KclXlnca78yhcrg1/mNrRepLYqeJE//SRhrh1X3UM7YUQMjY4x8gy
a$KclXlnca78yhcrg1/mNrRepLYqeJE//SRhrh1X3UM7YUQMjY4x8gy
true
true
现在,如果您有一个 GitHub 帐户,您实际上可以克隆原始存储库,进行建议的更改并生成拉取请求。我个人很想摆脱需要 String
checkpw
和 hashpw
方法
我还找到了 PDKDF2 的 this 实现,它使用 String
,但随后立即将其转换为 char[]
... 所以,这很容易改变。 ..
对您的问题的简短回答:是,可以在 Java.
中将char[]
s 与 BCrypt 一起使用
Bouncy Castle crypto packages for Java在 1.52 版本(2015 年 3 月)中添加了 BCrypt 密码哈希算法(使用字符串格式和 OpenBSD 上参考实现的 Base64 编码),并且它只支持char[]
个密码。
生成 BCrypt 字符串的相关方法可以在 org.bouncycastle.crypto.generators.OpenBSDBCrypt class 中找到,并具有以下签名:
String generate(char[] password,
byte[] salt,
int cost)
如果您想在源代码中验证 char[]
被保留而不被转换成字符串,相关的 class 是 OpenBSDBcrypt, Strings and BCrypt.