分类
Java Security

Java中的MD5散列

译者注

原文

https://www.baeldung.com/java-md5

Demo

https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-security-2

一、前言

MD5广泛应用在密码散列中,它提供128位的散列。
在本文中,我们将会学习不同的方法,使用多种Java库来实现MD5散列

二、使用MessageDigest

java.security.MessageDigest类中提供了散列功能。
我们需要把你想使用的算法作为参数,来实例化一个对象:

MessageDigest.getInstance(String Algorithm)

然后使用update()方法来更新消息的内容:

public void update(byte [] input)

如果你想读取一个长文件,上面这个方法,可以被多次调用,最终我们需要使用digest()方法来生成一个散列代码:

public byte[] digest()

下面的案例展示了如何给一个密码生成散列,并且验证它:

@Test
public void givenPassword_whenHashing_thenVerifying() 
  throws NoSuchAlgorithmException {
    String hash = "35454B055CC325EA1AF2126E27707052";
    String password = "ILoveJava";

    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(password.getBytes());
    byte[] digest = md.digest();
    String myHash = DatatypeConverter
      .printHexBinary(digest).toUpperCase();
    assertThat(myHash.equals(hash)).isTrue();
}

相似的,我们也可以检查文件的校验和:

@Test
public void givenFile_generatingChecksum_thenVerifying() 
  throws NoSuchAlgorithmException, IOException {
    String filename = "src/test/resources/test_md5.txt";
    String checksum = "5EB63BBBE01EEED093CB22BB8F5ACDC3";

    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(Files.readAllBytes(Paths.get(filename)));
    byte[] digest = md.digest();
    String myChecksum = DatatypeConverter
      .printHexBinary(digest).toUpperCase();
    assertThat(myChecksum.equals(checksum)).isTrue();
}

我们需要注意的是,这个MessageDigest线程不安全的。因此,我们需要在每个线程中使用新的实例。

3. 使用Apache Commons

阿帕奇的org.apache.commons.codec.digest.DigestUtils类也提供了相似的功能,而且使用起来很简单。
下面给出一个生成密码散列和校验的例子:

@Test
public void givenPassword_whenHashingUsingCommons_thenVerifying()  {
    String hash = "35454B055CC325EA1AF2126E27707052";
    String password = "ILoveJava";

    String md5Hex = DigestUtils
      .md5Hex(password).toUpperCase();
    assertThat(md5Hex.equals(hash)).isTrue();
}

4. 使用Guava

下面的例子是另一个生成MD5校验和的方法,使用com.google.common.io.Files.hash类:

@Test
public void givenFile_whenChecksumUsingGuava_thenVerifying() 
  throws IOException {
    String filename = "src/test/resources/test_md5.txt";
    String checksum = "5EB63BBBE01EEED093CB22BB8F5ACDC3";

    HashCode hash = com.google.common.io.Files
      .hash(new File(filename), Hashing.md5());
    String myChecksum = hash.toString()
      .toUpperCase();

    assertThat(myChecksum.equals(checksum)).isTrue();
}

需要注意的是,Hashing.md5是被反对的,然而,正如官方文档所说,原因是建议用户不要使用MD5去生成安全信息。
这意味着我们仍然可以使用它,如果我们需要整合使用MD5的传统项目。除此之外,我们最好去考虑更安全的方案,例如使用SHA-256
(译者注:MD5已经被破解了,因此它不再安全了)

5、 总结

本文中我们学习了使用不同的方式,调用Java API或第三方API,来实现MD5的散列。
实际使用时,我们需要根据项目的需要和项目的依赖关系来选择具体的方案。

和往常一样,你可以在Github上找到本文的示例代码。