如何生成MD5哈希?


Answers:


602

你需要java.security.MessageDigest

致电MessageDigest.getInstance("MD5")以获取MessageDigest您可以使用的MD5实例。

通过执行以下操作之一来计算哈希:

  • 将整个输入作为a byte[]并使用进行一次运算来计算哈希md.digest(bytes)
  • 订阅MessageDigest一个byte[]通过调用一次块md.update(bytes)。添加完输入字节后,请使用计算哈希值 md.digest()

byte[]返回的md.digest()是MD5哈希值。


144
这里没有提到的一件事,让我惊讶。MessageDigest类不是线程安全的。如果它们将被不同的线程使用,则只需创建一个新线程,而不是尝试重用它们。
mjuarez

39
它使用多种方法来改变其内部状态。缺乏线程安全性怎么会令人惊讶?
孟买

90
@Bombe:为什么我们应该期望必须了解MessageDigest的内部状态?
Dan Barowy 2014年

28
@DanBarowy好,您正在对其进行突变(即,调用不返回值但导致其他方法返回不同值的方法),因此在证明不这样做之前,您应始终假定这样做并非线程安全的。
孟买

3
@Traubenfuchs MessageDigest允许您分块输入数据。用静态方法是不可能的。尽管您可以争辩说,当您一次可以传递所有数据时,为方便起见它们应该添加一个。
user253751

690

MessageDigest班可为您提供的MD5摘要的一个实例。

使用字符串和crypto类时,请务必始终指定要使用字节表示形式的编码。如果仅使用string.getBytes()它,则将使用平台默认值。(并非所有平台都使用相同的默认值)

import java.security.*;

..

byte[] bytesOfMessage = yourString.getBytes("UTF-8");

MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(bytesOfMessage);

如果您有大量数据,请查看.update(byte[])可以重复调用的方法。然后调用.digest()以获得结果哈希。


“ LATIN1”!=“ ASCII”(或“ US-ASCII”)。ASCII是7位字符集,Latin1是8位字符集。他们不一样。
孟买

8
(见joelonsoftware.com/articles/Unicode.html为更好的理由和解释)
Piskvor离开大楼

14
如果需要将结果字节转换为十六进制字符串,则本主题也很有用。
周末

1
那么你如何将这个摘要转换为字符串,以便我们可以将其插入mysql中?
汉弗莱

2
更好的是,尽可能使用yourString.getBytes(StandardCharsets.UTF_8)。这样可以防止处理UnsupportedEncodingException
Hummeling Engineering BV

267

如果您实际上希望答案以字符串而不是字节数组的形式返回,则始终可以执行以下操作:

String plaintext = "your text here";
MessageDigest m = MessageDigest.getInstance("MD5");
m.reset();
m.update(plaintext.getBytes());
byte[] digest = m.digest();
BigInteger bigInt = new BigInteger(1,digest);
String hashtext = bigInt.toString(16);
// Now we need to zero pad it if you actually want the full 32 chars.
while(hashtext.length() < 32 ){
  hashtext = "0"+hashtext;
}

12
@BalusC:否,BigInteger.toString方法将以指定的基数返回完整数字。0x0606将被打印为606,只是省略了尾随的零,
Spidey

11
次要nitpick:在调用getInstance之后,不需要m.reset()。更重要的是:“您的文字在这里”需要双引号。
David Leppik

从Java 11开始,您可以使用hashtext = "0".repeat(32 - hashtext.length()) + hashtext代替while,因此编辑器不会警告您正在循环内进行字符串连接。
汤姆(Tom),

代替m.update(plaintext.getBytes()); 我建议指定编码。例如m.update(plaintext.getBytes(“ UTF-8”)); getBytes()不保证编码,并且可能因系统而异,这可能导致同一String的系统之间的MD5结果不同。
user1819780

256

您可能还需要查看apache commons编解码器项目的DigestUtils类,该类提供了非常方便的方法来创建MD5或SHA摘要。


2
特别地,以字符串形式返回字节数据的“安全”编码表示的方法。
罗布

4
但是,没有一种简单的方法就可以将DigestUtils类添加到您的项目中,而又不增加大量的库,也不需要移植“每手”类,这至少需要两个以上的类。
iuiz 2011年

在Maven仓库中也找不到它。rr
sparkyspider11年

5
除非我发疯,否则应该在中央Maven存储库中:groupId = commons-codecartifactId = commons-codec version = 1.5
Nick Spacek

160

发现了这一点:

public String MD5(String md5) {
   try {
        java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
        byte[] array = md.digest(md5.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) {
    }
    return null;
}

在下面的网站上,我对此一无所知,但是它是可行的解决方案!对我来说,许多其他代码无法正常工作,我最终在哈希中缺少0。这似乎与PHP相同。来源:http : //m2tec.be/blog/2010/02/03/java-md5-hex-0093


15
您应该指定要在中使用的编码getBytes(),否则您的代码将在不同的平台/用户设置上获得不同的结果。
圣保罗Ebermann

@PaŭloEbermann执行MessageDigest.getInstance(“ MD5”); 不够?我尝试在getBytes()中添加“ MD5”,但返回错误
Blaze Tama 2014年

2
@BlazeTama“ MD5”不是一种编码,它是一种消息摘要算法(不是在新应用程序中应使用的一种算法)。编码是一种算法对,它将字节转换为字符串,并将字符串转换为字节。一个示例是“ UTF-8”,“ US-ASCII”,“ ISO-8859-1”,“ UTF-16BE”等。请使用与计算该字符串的哈希值的其他各方相同的编码,否则您将获得不同的结果。
圣保罗Ebermann

6
有关字符集的示例...(使用UTF-8,在我看来这是最好和最兼容的)...byte[] array = md.digest(md5.getBytes(Charset.forName("UTF-8")));
理查德(Richard

由于它不是我的解决方案,并且我自己没有测试所有方案,因此我将其保持不变,尽管我认为指定编码等可能是一个好主意。
dac2009年

88

这是我的用法:

final MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.reset();
messageDigest.update(string.getBytes(Charset.forName("UTF8")));
final byte[] resultByte = messageDigest.digest();
final String result = new String(Hex.encodeHex(resultByte));

十六进制在哪里:org.apache.commons.codec.binary.Hex来自Apache Commons项目


14
如果你使用Apache共享编解码器,反正你可以使用:commons.apache.org/codec/api-release/org/apache/commons/codec/...
squiddle

13
我将最后一行替换为:String result = Hex.encodeHexString(resultByte);
蓝蓝的

84

我刚刚下载了commons-codec.jar,并获得了像md5这样的完美php。这是手册

只需将其导入您的项目并使用

String Url = "your_url";

System.out.println( DigestUtils.md5Hex( Url ) );

就在那里。


1
该方法提供与MySQL函数md5(str)相同的返回值。许多其他答案的确返回了其他值。
rwitzel

1
这在Android上无法正常运行,因为Android捆绑了commons-codec 1.2,您需要使用此解决方法:stackoverflow.com/a/9284092/2413303
EpicPandaForce 2015年

76

我发现这是最清晰,最简洁的方法:

MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(StandardCharsets.UTF_8.encode(string));
return String.format("%032x", new BigInteger(1, md5.digest()));

3
大。它不会陷入削减前导零的陷阱。
马库斯·普谢伊特(Marus Pscheidt),2016年

2
请注意,如果您使用的API级别<19,则这不适用于Android,但您只需要使用md5.update(string.getBytes(“ UTF-8”))更改第二行即可;不过,这将添加另一个受检查的异常来处理……
Fran Marzoa

34

发现此解决方案从MD5散列取回String表示形式方面更为简洁。

import java.security.*;
import java.math.*;

public class MD5 {
    public static void main(String args[]) throws Exception{
        String s="This is a test";
        MessageDigest m=MessageDigest.getInstance("MD5");
        m.update(s.getBytes(),0,s.length());
        System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16));
    }
}

代码是从这里提取的。


2
为什么这个答案为-1,而另一个简短且描述性较小的答案却为+146?
Nilzor

4
很高兴使用BigInteger获得十六进制值+1
Dave.B 2013年

5
我刚刚发现,在某些情况下,它只能生成31个字符长的MD5和,而不是应该的32个字符
kovica 2013年

3
@kovica这是因为,如果我没记错的话,起始零将被截断 String.format("%032x", new BigInteger(1, hash)); 。“哈希”是哈希的byte []。
鹤山Perera

这个答案有字符集类型的错误!
戴维德罗兹(Dawid Drozd),2015年

31

另一种选择是使用番石榴散列方法

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

如果您已经在使用番石榴,则非常方便(如果没有,则应该使用)。


3
或使用以下快捷方式之一:Hashing.md5().hashString("my string").asBytes();
Kurt Alfred Kluever 2015年

4
@KurtAlfredKluever不要忘记像'Hashing.md5()。hashString(“ my string”,Charsets.UTF_8).asBytes()一样插入字符集
Justin

31

另一个实现:

import javax.xml.bind.DatatypeConverter;

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

2
我所看到的只有一种格式不使用外部库。
holmis83

除非我弄错了,否则返回的结果总是大写,这与不使用十六进制的md5对齐。甚至无法确定它是真正的md5
walshie4

2
@ walshie4没有十六进制就没有MD5(请参见ietf.org/rfc/rfc1321.txt),要使其小写,只需添加.toLower()。将结果与en.wikipedia.org/wiki/MD5中的示例进行比较,那么您将更有机会相信Javas库代码是正确的。
堆垛机

28

我有一个Class(Hash)以以下格式转换哈希中的纯文本: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


17

您可以尝试关注。在此处查看详细信息和下载代码: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();
}
}

16

Bombe的答案是正确的,但是请注意,除非您绝对必须使用MD5(例如,为实现互操作性而强加于您),否则SHA1是更好的选择,因为MD5在长期使用方面存在弱点。

我应该补充一点,SHA1也有理论上的漏洞,但没有那么严重。哈希技术的当前水平是,存在许多候选替换哈希函数,但是还没有一种方法成为替换SHA1的标准最佳实践。因此,根据您的需求,建议您将哈希算法配置为可配置的,以便将来可以替换。


您能否指出一些资源,在这里我可以阅读每种资源的相对优缺点?
Akshay

目前可能最好的方法是使用SHA1,并准备在将来替换它。您可以使用较新的函数,但尚未对其进行大量研究。您可以跟踪在线安全资源,以了解何时发生更改(例如Bruce Schneier的博客)。
frankodwyer

7
除非您希望使用密码学上安全的哈希,即不希望哈希帮助重构原始消息,也不希望聪明的攻击者创建与哈希匹配的其他消息,否则SHA1会显得过大。如果原始文件不是秘密,并且哈希没有用于安全性,那么MD5既快速又容易。例如,Google Web Toolkit在JavaScript URL中使用MD5哈希(例如foo.js?hash = 12345)。
David Leppik

12

另一个实现:Java的快速MD5实现

String hash = MD5.asHex(MD5.getHash(new File(filename)));

1
这是一个具有最小依赖性的坚固,独立的库。好东西。
2014年

我发现它非常有用。4.57GB文件花费了15357毫秒,而Java内置实现花费了19094毫秒。
bkrish

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知识真的很糟糕之前:我刚刚发现DigestInputStreamDigestOutputStream。我将编辑原始解决方案以反映我刚刚学到的内容。
kriegaex 2012年


6

对于它的价值,我偶然发现了这一点,因为我想从自然键为要安装COM组件的程序合成GUID。我想进行合成,以免管理GUID生命周期。我将使用MD5,然后使用UUID类从中获取字符串。(http://stackoverflow.com/questions/2190890/how-can-i-generate-guid-for-a-string-values/12867439引发了此问题)。

无论如何,java.util.UUID可以从MD5字节中为您提供一个不错的字符串。

return UUID.nameUUIDFromBytes(md5Bytes).toString();

实际上,它不仅接受MD5字节数组(大小== 16)。您可以传递任意长度的字节数组。它将通过MD5转换为MD5字节数组MessageDigest(请参阅nameUUIDFromBytes()源代码
Lu55

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

6

与PHP不同,您可以通过调用md5函数来对文本进行MD5哈希处理,即md5($text)在Java中,它有点复杂。我通常通过调用返回md5哈希文本的函数来实现它。这是我实现它的方法,首先md5hashing在您的主类中创建一个命名为函数,如下所示。

public static String md5hashing(String text)
    {   String hashtext = null;
        try 
        {
            String plaintext = text;
            MessageDigest m = MessageDigest.getInstance("MD5");
            m.reset();
            m.update(plaintext.getBytes());
            byte[] digest = m.digest();
            BigInteger bigInt = new BigInteger(1,digest);
            hashtext = bigInt.toString(16);
            // Now we need to zero pad it if you actually want the full 32 chars.
            while(hashtext.length() < 32 ){
              hashtext = "0"+hashtext;   
            }
        } catch (Exception e1) 
        {
            // TODO: handle exception
            JOptionPane.showMessageDialog(null,e1.getClass().getName() + ": " + e1.getMessage());   
        }
        return hashtext;     
    }

现在,请在需要时调用函数,如下所示。

String text = textFieldName.getText();
String pass = md5hashing(text);

在这里,您可以看到哈希文本附加了零,以使其与PHP中的md5哈希匹配。


5

如果您不需要最佳的安全性,那么MD5就是完美的选择,如果您正在执行类似检查文件完整性的操作,那么就不必考虑安全性了。在这种情况下,您可能需要考虑一些更简单,更快捷的方法,例如Java库也支持的Adler32。


2
是什么让您认为文件完整性不是安全问题?
Jeremy Huiskamp 2011年

5

这是您从mysql的md5函数或php的md5函数等获得的确切md5。这是我使用的一个(您可以根据需要进行更改)

public static String md5( String input ) {
    try {
        java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
        byte[] array = md.digest(input.getBytes( "UTF-8" ));
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < array.length; i++) {
            sb.append( String.format( "%02x", array[i]));
        }
        return sb.toString();
    } catch ( NoSuchAlgorithmException | UnsupportedEncodingException e) {
        return null;            
    }

}

4

尝试这个:

public static String getHashMD5(String string) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        BigInteger bi = new BigInteger(1, md.digest(string.getBytes()));
        return bi.toString(16);
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(MD5Utils.class
                .getName()).log(Level.SEVERE, null, ex);

        return "";
    }
}

2
这可能是最糟糕的解决方案,因为它会去除前导零。
Jannick

4
import java.security.MessageDigest

val digest = MessageDigest.getInstance("MD5")

//Quick MD5 of text
val text = "MD5 this text!"
val md5hash1 = digest.digest(text.getBytes).map("%02x".format(_)).mkString

//MD5 of text with updates
digest.update("MD5 ".getBytes())
digest.update("this ".getBytes())
digest.update("text!".getBytes())
val md5hash2 = digest.digest().map(0xFF & _).map("%02x".format(_)).mkString

//Output
println(md5hash1 + " should be the same as " + md5hash2)

1
这是科特林语言吗?
Isuru

3
@Isuru看起来像Scala
gildor '17

4

您可以通过使用包中的类中的方法为给定的文本生成MD5哈希。以下是完整的代码段,MessageDigestjava.security

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.xml.bind.DatatypeConverter;

public class MD5HashGenerator 
{

   public static void main(String args[]) throws NoSuchAlgorithmException
   {
       String stringToHash = "MyJavaCode"; 
       MessageDigest messageDigest = MessageDigest.getInstance("MD5");
       messageDigest.update(stringToHash.getBytes());
       byte[] digiest = messageDigest.digest();
       String hashedOutput = DatatypeConverter.printHexBinary(digiest);
       System.out.println(hashedOutput);
   }
}

MD5函数的输出是由32个十六进制数字表示的128位哈希。

如果您使用的是MySQL之类的数据库,则也可以采用更简单的方式进行。查询Select MD5(“text here”)将返回括号中文本的MD5哈希值。


2

这就是我来到这里的一个方便的scala函数,该函数返回MD5哈希的字符串:

def md5(text: String) : String = java.security.MessageDigest.getInstance("MD5").digest(text.getBytes()).map(0xFF & _).map { "%02x".format(_) }.foldLeft(""){_ + _}

0
 import java.math.BigInteger;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;

/**
* MD5 encryption
*
* @author Hongten
*
*/
public class MD5 {

 public static void main(String[] args) {
     System.out.println(MD5.getMD5("123456"));
 }

 /**
  * Use md5 encoded code value
  *
  * @param sInput
  * clearly
  * @ return md5 encrypted password
  */
 public static String getMD5(String sInput) {

     String algorithm = "";
     if (sInput == null) {
         return "null";
     }
     try {
         algorithm = System.getProperty("MD5.algorithm", "MD5");
     } catch (SecurityException se) {
     }
     MessageDigest md = null;
     try {
         md = MessageDigest.getInstance(algorithm);
     } catch (NoSuchAlgorithmException e) {
         e.printStackTrace();
     }
     byte buffer[] = sInput.getBytes();

     for (int count = 0; count < sInput.length(); count++) {
         md.update(buffer, 0, count);
     }
     byte bDigest[] = md.digest();
     BigInteger bi = new BigInteger(bDigest);
     return (bi.toString(16));
 }
}

关于Codingkit的文章。检出:http : //codingkit.com/a/JAVA/2013/1020/2216.html

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.