使用带有char []的BCrypt

时间:2015-05-31 21:46:22

标签: java security hash char bcrypt

几个小时前,我在Stack Overflow上询问了如何将char []转换为MD5哈希的方法。提供了一个解决方案,但被认为是不安全的 - 正如一些人所概述的那样:Generating an MD5 Hash with a char[]

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?

提前致谢!

3 个答案:

答案 0 :(得分:4)

因此,根据https://github.com/jeremyh/jBCrypt中提供的实施,您需要更改hashpwcheckpw方法以接受char[]而不是String

可能最困难的部分是hashpw ......

    try {
        passwordb = (password + (minor >= 'a' ? "\000" : "")).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] = '\000';
    }

    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));

...输出

$2a$12$KclXlnca78yhcrg1/mNrRepLYqeJE//SRhrh1X3UM7YUQMjY4x8gy
$2a$12$KclXlnca78yhcrg1/mNrRepLYqeJE//SRhrh1X3UM7YUQMjY4x8gy
true
true

现在,如果您有一个GitHub帐户,您实际上可以克隆原始仓库,进行建议的更改并生成拉取请求。我个人想要摆脱需要checkpw的{​​{1}}和hashpw方法

我还发现了this PDKDF2的实现,它使用了String,但随后迅速将其转换为String ...所以,这非常简单地改变......

答案 1 :(得分:1)

我发现的两个Java impel都是以字符串作为输入。您似乎知道,将密码放入字符串会让您受到内存攻击。

您可以使用PBKDF2以及bcrypt。两者都被认为是一流的。有PBKDF2 Java代码示例herehere。两者都允许将char[]传递给函数。

要回答评论中的隐含问题,您不使用MD5或任何哈希的原因是它们太快了。可以使用特殊硬件强制执行密码。 Bcrypt和PBKDF2设计得很慢。

即使您要使用哈希(我建议反对),您也必须加盐。反转未加密的密码哈希值很简单(参见this tool)。

密码存储上的CrackStation's reference是一个很好的一般参考。

答案 2 :(得分:0)

对您的问题的简短回答:,可以在Java中使用char[]和BCrypt。

Bouncy Castle crypto packages for Java在版本1.52(2015年3月)中添加了BCrypt密码哈希算法(使用String格式和OpenBSD上参考实现的Base64编码),它只支持{{1}密码

生成BCrypt字符串的相关方法可以在org.bouncycastle.crypto.generators.OpenBSDBCrypt类中找到,并具有以下签名:

char[]

如果您想在源代码中验证String generate(char[] password, byte[] salt, int cost) 是否保留而未转换为字符串,则相关的类为OpenBSDBcryptStrings和{{3} }。