【问题标题】:Generating an MD5 Hash with a char[]使用 char[] 生成 MD5 哈希
【发布时间】:2024-01-18 04:48:01
【问题描述】:

如何转换使用此方法获得的 char[] 密码:

char[] password = passwordInputField.getPassword();

到 MD5 哈希?通常我会使用下面的方法,但 getBytes 只与字符串兼容:

MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes());
String hashedPass = new BigInteger(1, md.digest()).toString(16);

【问题讨论】:

  • 不确定您的应用程序是什么,但 MD5 通常不再用于安全目的。
  • 那么你推荐使用什么?
  • 假设您希望在登录时进行密码存储和验证,bcrypt 就是今天的standard。有关 Java 实现,请参阅 this question

标签: java security hash md5 message-digest


【解决方案1】:

注意: MD5 哈希算法不应该用于密码存储,因为它的哈希值很容易被破解。不过,为了简单起见,我将使用它。

快速/简单/不安全的解决方法是将 char 数组转换为字符串。但是,这是不安全的,因为字符串是不可变的,无法从内存中清除。

String password = new String(passwordInputField.getPassword());

MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes());
String hashedPass = new BigInteger(1, md.digest()).toString(16);

更安全的解决方案:将 char[] 转换为 byte[],然后从内存中清除数组。

private byte[] toBytes(char[] chars) {
    CharBuffer charBuffer = CharBuffer.wrap(chars);
    ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
    byte[] bytes = Arrays.copyOfRange(byteBuffer.array(),
            byteBuffer.position(), byteBuffer.limit());
    Arrays.fill(charBuffer.array(), '\u0000'); // clear sensitive data
    Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
    return bytes;
}

char[] passChars = passwordInputField.getPassword();
byte[] passBytes = toBytes(passChars);

MessageDigest md = MessageDigest.getInstance("MD5");
md.update(passBytes);
String hashedPass = new BigInteger(1, md.digest()).toString(16);

Arrays.fill(passChars, '\u0000'); // clear sensitive data
Arrays.fill(passBytes, (byte) 0); // clear sensitive data

编辑:

使用更安全的解决方案更新了答案(此想法归功于 user2656928)。

char[] to byte[] method 归功于 andreyne

【讨论】:

  • 快速简单,是的。但是getPassword()security considerations 返回char[]。处理密码时应牢记这一点。
  • 这将违背安全原因,为什么 swing 返回密码为 char[] 而不是 String - 也就是说,字符串是不可变的,所以创建了一个就无法从内存中删除它。使用char[],您可以在完成后覆盖数据(除了允许 GC 移动对象,并且不能指望删除原始数据)。如果您关心安全性,您确实需要找到或编写一个 char[]byte[] 转换器,然后清理两个数组。
  • @RealSkeptic 你没有错,但是如果出于任何安全目的直接传输或存储该 MD5 哈希,那么整个系统的问题比分配的字符串在内存中徘徊同时。
  • @Barend 是的,当然。并且完全不加盐。
  • 感谢@Connor,尽管您似乎确实犯了一个错误。 Bytes 是 Byte: byte[] passBytes = toBytes(passChars);