【问题标题】:Using BCrypt with a char[]将 BCrypt 与 char[] 一起使用
【发布时间】:2015-08-14 07:05:53
【问题描述】:

大约几个小时前,我在 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 一起使用?

提前致谢!

【问题讨论】:

  • 这是个坏主意,但是您需要将 char[] 转换回字符串(根据我从 api 中可以看出的内容),这似乎是一个糟糕的设计.. .
  • 那你会推荐什么? MD5 似乎不安全,而 BCrypt 似乎不适用于 char[]。
  • 找一个不使用String的实现
  • 有什么好推荐的吗?
  • 无论如何我都不是安全专家,但我所知道的关于 md5 的唯一问题是,它极有可能为两个不同的字符串生成相同的哈希值。你有更多关于它的价值的信息吗?

标签: java security hash char bcrypt


【解决方案1】:

因此,基于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 帐户,您实际上可以克隆原始存储库,进行建议的更改并生成拉取请求。我个人很想摆脱需要Stringcheckpwhashpw 方法

我还发现了 PDKDF2 的 this 实现,它使用 String,但随后立即将其转换为 char[] ...所以,这很容易改变...

【讨论】:

    【解决方案2】:

    我发现的 bcrypt 的两个 Java 实现都将字符串作为输入。如您所知,将密码放入字符串中会导致内存攻击。

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

    要回答 cmets 的一个隐含问题,您不使用 MD5 或任何散列的原因是它们太快了。使用特殊硬件的暴力破解密码成为可能。 Bcrypt 和 PBKDF2 的设计速度很慢。

    即使你要使用哈希(我不建议这样做),你也必须加盐。反转未加盐的密码哈希很简单(请参阅this tool)。

    关于密码存储的CrackStation's reference 是一个很好的通用参考。

    【讨论】:

    • 如果你不推荐使用哈希,那么你会推荐使用什么?
    • 另外,对于第二个例子,我需要修改任何源代码吗?你能提供一个使用例子吗?
    【解决方案3】:

    对您的问题的简短回答:是的,可以在 Java 中将char[]s 与 BCrypt 一起使用。

    Bouncy Castle crypto packages for Java 在版本 1.52(2015 年 3 月)中添加了 BCrypt 密码哈希算法(使用字符串格式和 OpenBSD 上的参考实现的 Base64 编码),仅支持 char[] 密码强>。

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

    String generate(char[] password,
                    byte[] salt,
                    int cost)
    

    如果您想在源代码中验证char[] 是否被保留而不被转换为字符串,则相关类为OpenBSDBcryptStringsBCrypt

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-23
      • 2017-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多