我该如何在Java中生成MD5哈希值?

1092

有没有一种方法在Java中生成字符串的MD5哈希值?


2
https://dev59.com/9XVC5IYBdhLWcg3wZwTj - Leif Gruenwoldt
46
MD5 作为一种单向安全特性可能不太安全,但仍适用于通用的校验和应用。 - rustyx
34个回答

35

另一种实现:

import javax.xml.bind.DatatypeConverter;

String hash = DatatypeConverter.printHexBinary( 
           MessageDigest.getInstance("MD5").digest("SOMESTRING".getBytes("UTF-8")));

2
我见过的唯一不使用外部库的一行代码。 - holmis83
除非我弄错了,否则这将始终返回大写字母,这与不使用十六进制的md5不匹配。甚至不确定它是否是真正的md5。 - walshie4

32

另一个选择是使用Guava哈希方法

Hasher hasher = Hashing.md5().newHasher();
hasher.putString("my string");
byte[] md5 = hasher.hash().asBytes();

如果您已经在使用Guava(如果没有,那您可能应该使用它),那么这将非常方便。


3
或者使用其中一种快捷方法: Hashing.md5().hashString("my string").asBytes(); - Kurt Alfred Kluever
4
@KurtAlfredKluever别忘了像这样插入字符集,例如'Hashing.md5().hashString("my string", Charsets.UTF_8).asBytes()'。 - Justin

29

我有一个类(哈希),可以将纯文本转换为哈希格式,如md5或sha1,类似于php函数(md5sha1):

public class Hash {
    /**
     * 
     * @param txt, text in plain format
     * @param hashType MD5 OR SHA1
     * @return hash in hashType 
     */
    public static String getHash(String txt, String hashType) {
        try {
                    java.security.MessageDigest md = java.security.MessageDigest.getInstance(hashType);
                    byte[] array = md.digest(txt.getBytes());
                    StringBuffer sb = new StringBuffer();
                    for (int i = 0; i < array.length; ++i) {
                        sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1,3));
                 }
                    return sb.toString();
            } catch (java.security.NoSuchAlgorithmException e) {
                //error action
            }
            return null;
    }

    public static String md5(String txt) {
        return Hash.getHash(txt, "MD5");
    }

    public static String sha1(String txt) {
        return Hash.getHash(txt, "SHA1");
    }
}

使用JUnit和PHP进行测试

PHP脚本:

<?php

echo 'MD5 :' . md5('Hello World') . "\n";
echo 'SHA1:' . sha1('Hello World') . "\n";

输出PHP脚本:

MD5 :b10a8db164e0754105b7a99be72e3fe5
SHA1:0a4d55a8d778e5022fab701977c5d840bbc486d0

使用示例并使用JUnit进行测试:

    public class HashTest {

    @Test
    public void test() {
        String txt = "Hello World";
        assertEquals("b10a8db164e0754105b7a99be72e3fe5", Hash.md5(txt));
        assertEquals("0a4d55a8d778e5022fab701977c5d840bbc486d0", Hash.sha1(txt));
    }

}

在 GitHub 上的代码

https://github.com/fitorec/java-hashes


正如@CedricSimon所说,这正是我在寻找的。点个赞..谢谢! - Joabe Lucena

22

我的回答并不是很具有启示性:

private String md5(String s) {
    try {
        MessageDigest m = MessageDigest.getInstance("MD5");
        m.update(s.getBytes(), 0, s.length());
        BigInteger i = new BigInteger(1,m.digest());
        return String.format("%1$032x", i);         
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return null;
}

使用String.format("%1$032X", big)可以将大写格式应用于变量。 - alex

18

顺便说一句:这种方法的性能比使用BigInteger创建十六进制字符串表示要好得多。 - James

18

你可以尝试以下方法。在此处查看详细信息并下载代码:http://jkssweetlife.com/java-hashgenerator-md5-sha-1/

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5Example {

public static void main(String[] args) throws Exception {

    final String inputString = "Hello MD5";

    System.out.println("MD5 hex for '" + inputString + "' :");
    System.out.println(getMD5Hex(inputString));
}

public static String getMD5Hex(final String inputString) throws NoSuchAlgorithmException {

    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(inputString.getBytes());

    byte[] digest = md.digest();

    return convertByteToHex(digest);
}

private static String convertByteToHex(byte[] byteData) {

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < byteData.length; i++) {
        sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
    }

    return sb.toString();
}
}

15

Bombe的回答是正确的,但请注意,除非你绝对必须使用MD5(例如强制要求你为了互操作性而使用),否则更好的选择是SHA1,因为MD5在长期使用中存在弱点。

我应该补充说明,SHA1也具有理论上的漏洞,但没有那么严重。目前哈希算法的最新技术是有一些备选哈希函数,但还没有出现作为替代SHA1的标准最佳实践的函数。因此,根据你的需求,你最好将哈希算法设置为可配置的,以便在未来可以替换它。


你能给我指一些资源吗,让我可以了解每个方案的优缺点吗? - Akshay
目前最好的做法可能是使用SHA1,并准备在未来进行替换。您可以使用更新的功能,但它们尚未经过大量研究。您可以跟踪在线安全资源以了解何时发生更改-例如Bruce Schneier的博客。 - frankodwyer
8
除非您需要一个密码安全的哈希函数,否则使用SHA1就过于复杂了。也就是说,您不希望哈希值有助于重建原始消息,也不希望聪明的攻击者创建另一条与哈希值匹配的消息。如果原始信息不是秘密且哈希值不用于安全目的,则MD5很快且易于使用。例如,Google Web Toolkit在JavaScript URL中使用MD5哈希(例如foo.js?hash=12345)。 - David Leppik

13

1
这是一个具有最小依赖关系的稳定独立库。非常不错。 - Ajax
我发现这非常有用。对于一个4.57GB的文件,它只需要15357毫秒,而Java内置实现则需要19094毫秒。 - bkrish
这非常有用。我在使用MessageDigest.getInstance("MD5")时遇到了问题。 - Arundale Ramanathan

11

我不知道是否对任何阅读此内容的人相关,但我刚遇到了这个问题:

  • 从给定的URL下载文件并且
  • 与已知值比较其MD5。

我想仅使用JRE类来完成此操作(没有使用Apache Commons或类似库)。快速搜索未显示同时执行两种任务的示例代码片段,只有每个任务单独执行的示例。因为这需要两次读取同一文件,所以我想编写一些代码将两个任务合并在一起,在下载文件时即时计算校验和。这是我的结果(如果它不是完美的Java代码,那很抱歉,但我想您仍然能够理解):

import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.security.DigestOutputStream;        // new
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

void downloadFile(String fromURL, String toFile, BigInteger md5)
    throws IOException, NoSuchAlgorithmException
{
    ReadableByteChannel in = Channels.newChannel(new URL(fromURL).openStream());
    MessageDigest md5Digest = MessageDigest.getInstance("MD5");
    WritableByteChannel out = Channels.newChannel(
        //new FileOutputStream(toFile));  // old
        new DigestOutputStream(new FileOutputStream(toFile), md5Digest));  // new
    ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);  // 1 MB

    while (in.read(buffer) != -1) {
        buffer.flip();
        //md5Digest.update(buffer.asReadOnlyBuffer());  // old
        out.write(buffer);
        buffer.clear();
    }

    BigInteger md5Actual = new BigInteger(1, md5Digest.digest()); 
    if (! md5Actual.equals(md5))
        throw new RuntimeException(
            "MD5 mismatch for file " + toFile +
            ": expected " + md5.toString(16) +
            ", got " + md5Actual.toString(16)
        );
}

1
顺便说一句,在除了我自己之外的任何人注意到我的JRE知识有多糟糕之前:我刚刚发现了DigestInputStream和DigestOutputStream。我将编辑我的原始解决方案以反映我刚刚学到的内容。 - kriegaex

9
import java.security.*;
import javax.xml.bind.*;

byte[] bytesOfMessage = yourString.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytesOfDigest = md.digest(bytesOfMessage);
String digest = DatatypeConverter.printHexBinary(bytesOfDigest).toLowerCase();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接