Java中的MD5生成31个字符的哈希值

14

我正在使用以下代码块生成MD5哈希:

public static String encode(String data) throws Exception {

    /* Check the validity of data */
    if (data == null || data.isEmpty()) {
        throw new IllegalArgumentException("Null value provided for "
                + "MD5 Encoding");
    }

    /* Get the instances for a given digest scheme MD5 or SHA */
    MessageDigest m = MessageDigest.getInstance("MD5");

    /* Generate the digest. Pass in the text as bytes, length to the
     * bytes(offset) to be hashed; for full string pass 0 to text.length()
     */
    m.update(data.getBytes(), 0, data.length());

    /* Get the String representation of hash bytes, create a big integer
     * out of bytes then convert it into hex value (16 as input to
     * toString method)
     */
    String digest = new BigInteger(1, m.digest()).toString(16);

    return digest;
}

当我使用字符串数据[12, B006GQIIEM, MH-ANT2000]运行上述代码段时,输出是一个31个字符的哈希值 - 268d43a823933c9dafaa4ac0e756d6a

MD5哈希函数存在问题还是上述代码存在问题?


1
我刚在这里发现,哈希值开头有一个被省略了的0。我在这里尝试了在线MD5生成器,也得到了相同的结果0268d43a823933c9dafaa4ac0e756d6a。当哈希值长度不是32位时,我需要每次都在开头加上一个0吗? - divinedragon
你的输入是 [12,B006GQIIEM,MH-ANT2000] 吗? - Bhavik Ambani
是的。大括号是输入的一部分。 - divinedragon
那么为什么我使用你上面提到的代码却得到了32位编码的文本呢? - Bhavik Ambani
请检查这个 - [12,B006GQIIEM,MH-ANT2000]。实际上,在 MH-ANT2000 之前有一个额外的空格。总共有两个空格。 - divinedragon
显示剩余3条评论
4个回答

8
你的代码唯一的问题是当MSB小于0x10时,结果哈希字符串只有31个字节,而不是32个字节,缺少前导零。
按照以下方式创建MD5字符串:
            byte messageDigest[] = m.digest();

            hexString = new StringBuffer();
            for (int i=0;i<messageDigest.length;i++) {
                String hex=Integer.toHexString(0xFF & messageDigest[i]);
                if(hex.length()==1)
                    hexString.append('0');

                hexString.append(hex);
            }

所以只需要加上额外的 0。如果哈希长度为31,我需要在前面加上一个 0。就是这样对吗? - divinedragon
@divinedragon 不需要添加额外的“0”。您需要检查每个字符的长度,并在该特定位置附加“0”。可以在字符串中间添加“0”。您可以看到代码中我正在检查每个字符串的长度并附加“0”。 - rizzz86
2
@rizzz86:抱歉,但您的评论是误导性的,因为它与OP的代码无关,而与您的代码有关。他使用了.toString(16),这会生成正确的十六进制表示形式,它不会忘记在十六进制字符串中添加零 - 它只会丢弃前导零。因此,OP可能会在前面加上尽可能多的零以获得一个32字节的字符串。 - zb226
这段代码 for(byte b : digest){ sb.append(String.format("%02x", b&0xff)); } 和你的有什么不同...?哪一个更好..? - Kanagavelu Sugumar

8
你可以试一下这个方法:
...
String digest = String.format("%032x", new BigInteger(1, m.digest()));

注意:它应该是"%032x",而不是"%32x"


你的版本返回了完全不同的哈希值 - d41d8cd98f00b204e9800998ecf8427e - divinedragon
谢谢。但是我从接触Java的那一天起就一直在使用它。 - user1521536
@divinedragon 在我这里工作。我复制了你的代码,然后用这行代替了它。 - djeikyb

3

以下是我使用MD5哈希的方法。从字符串计算MD5哈希并返回32字节的十六进制表示。

import java.io.UnsupportedEncodingException; 
import java.security.MessageDigest; 
import java.security.NoSuchAlgorithmException; 

public class MySimpleMD5 { 

private static String convertToHex(byte[] data) { 
    StringBuffer buf = new StringBuffer();
    for (int i = 0; i < data.length; i++) { 
        int halfbyte = (data[i] >>> 4) & 0x0F;
        int two_halfs = 0;
        do { 
            if ((0 <= halfbyte) && (halfbyte <= 9)) 
                buf.append((char) ('0' + halfbyte));
            else 
                buf.append((char) ('a' + (halfbyte - 10)));
            halfbyte = data[i] & 0x0F;
        } while(two_halfs++ < 1);
    } 
    return buf.toString();
} 

public static String MD5(String text) 
throws NoSuchAlgorithmException, UnsupportedEncodingException  { 
    MessageDigest md;
    md = MessageDigest.getInstance("MD5");
    byte[] md5hash = new byte[32];
    md.update(text.getBytes("iso-8859-1"), 0, text.length());
    md5hash = md.digest();
    return convertToHex(md5hash);
 } 
} 

你的版本运行正确。之前的代码有什么问题吗? - divinedragon
很好的答案,但是我认为这并不满足提问者的要求。 - Bhavik Ambani

0

你也可以尝试这个:

private static String getMd5Hash(String input) throws NoSuchAlgorithmException {
    MessageDigest m = MessageDigest.getInstance("MD5");

    byte[] data = m.digest(EncodingUtils.getBytes(input, "UTF8"));

    StringBuilder sBuilder = new StringBuilder();

    for (int i = 0; i < data.length; i++) {

        for (byte b : data) {
            if(b == 0x00){
                sBuilder.append("00");
            } else if ((b & 0x0F) == b) {
                sBuilder.append("0");
                break;
            } else {
                break;
            }
        }

        BigInteger bigInt = new BigInteger(1, data);
        sBuilder.append(bigInt.toString(16));
    }

    // Return the hexadecimal string.
    return sBuilder.toString().substring(0, 32);
}

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