Java 有人能验证使用此方法获取md5哈希的正确性吗?

Java 有人能验证使用此方法获取md5哈希的正确性吗?,java,md5,hash,Java,Md5,Hash,这些代码行背后的思想是,我们将类/模型的所有值附加到StringBuilder中,然后返回该类/模型的填充哈希(Java实现返回长度为30或31的md5哈希,因此最后一行将哈希格式化为0填充) 我可以验证这是否有效,但我感觉它在某一点上失败了(我们的应用程序失败了,我相信这是可能的原因) 有谁知道这不起作用的原因吗?是否有任何变通方法可以使此代码不易出错(例如,不需要将字符串设置为UTF-8)。一个可能的问题是: MessageDigest m=MessageDigest.get

这些代码行背后的思想是,我们将类/模型的所有值附加到StringBuilder中,然后返回该类/模型的填充哈希(Java实现返回长度为30或31的md5哈希,因此最后一行将哈希格式化为0填充)

我可以验证这是否有效,但我感觉它在某一点上失败了(我们的应用程序失败了,我相信这是可能的原因)


有谁知道这不起作用的原因吗?是否有任何变通方法可以使此代码不易出错(例如,不需要将字符串设置为UTF-8)。

一个可能的问题是:

        MessageDigest m=MessageDigest.getInstance("MD5");
        StringBuffer sb = new StringBuffer();
        if(nodeName!=null) sb.append(nodeName);
        if(nodeParentName!=null) sb.append(nodeParentName);
        if(nodeParentFieldName!=null) sb.append(nodeParentFieldName);
        if(nodeRelationName!=null) sb.append(nodeRelationName);
        if(nodeViewName!=null) sb.append(nodeViewName);
        if(treeName!=null) sb.append(treeName);
        if(nodeValue!=null && nodeValue.trim().length()>0) sb.append(nodeValue);
        if(considerParentHash) sb.append(parentHash);
        m.update(sb.toString().getBytes("UTF-8"),0,sb.toString().length());
        BigInteger i = new BigInteger(1,m.digest());
        hash = String.format("%1$032X", i);
正如Robbing Green所说,
UTF-8
编码可以产生一个比原始字符串长的
字节[]
(当字符串包含非ASCII字符时,它会完全这样做)。在本例中,您只对字符串的开头进行哈希运算

最好这样写:

m.update(sb.toString().getBytes("UTF-8"),0,sb.toString().length());

当然,如果您的字符串中有非ASCII字符,这不会导致异常,只是另一个散列,而不是其他情况下产生的散列。您应该尝试将故障归结为SSCCE,就像lesmana建议的那样。

一个可能的问题是:

        MessageDigest m=MessageDigest.getInstance("MD5");
        StringBuffer sb = new StringBuffer();
        if(nodeName!=null) sb.append(nodeName);
        if(nodeParentName!=null) sb.append(nodeParentName);
        if(nodeParentFieldName!=null) sb.append(nodeParentFieldName);
        if(nodeRelationName!=null) sb.append(nodeRelationName);
        if(nodeViewName!=null) sb.append(nodeViewName);
        if(treeName!=null) sb.append(treeName);
        if(nodeValue!=null && nodeValue.trim().length()>0) sb.append(nodeValue);
        if(considerParentHash) sb.append(parentHash);
        m.update(sb.toString().getBytes("UTF-8"),0,sb.toString().length());
        BigInteger i = new BigInteger(1,m.digest());
        hash = String.format("%1$032X", i);
正如Robbing Green所说,
UTF-8
编码可以产生一个比原始字符串长的
字节[]
(当字符串包含非ASCII字符时,它会完全这样做)。在本例中,您只对字符串的开头进行哈希运算

最好这样写:

m.update(sb.toString().getBytes("UTF-8"),0,sb.toString().length());

当然,如果您的字符串中有非ASCII字符,这不会导致异常,只是另一个散列,而不是其他情况下产生的散列。你应该像lesmana推荐的那样,尝试将失败归结为SSCCE。

你的代码中有一些奇怪的东西

字符的UTF-8编码可以使用多个字节。因此,您不应该使用字符串长度作为
update()
调用的最终参数,而应该使用
getBytes()
实际返回的字节数组的长度。按照帕罗的建议,使用
update()
方法,该方法将单个
字节[]
作为参数

MD5的输出是一个16字节的序列,具有相当任意的值。如果将其解释为整数(这就是调用
biginger()
),则将得到一个小于2160的数值,可能要小得多。当转换回十六进制数字时,您可能会得到32、31、30。。。或少于30个字符。您对
%032X”
格式字符串的使用留下了足够多的零,所以您的代码可以工作,但它是一种间接的(MD5的输出从一开始就不是整数)

您可以使用原始连接来组装散列输入元素。这可能会引发一些问题。例如,如果
modeName
是“
foo
”,
modeParentName
是“
barqux
”,那么MD5输入将以“
foobarqux
”的UTF-8编码开始。如果
modeName
为“
foobar
”,
modeParentName
为“
qux
”,则MD5输入也将以“
foobarqux
”开头。您不知道为什么要使用散列函数,但通常,当您使用散列函数时,它是为了拥有某个数据段的唯一跟踪;两个不同的数据元素应该产生不同的散列输入

处理
nodeValue
时,调用
trim()
,这意味着该字符串可以以空格开头和/或结尾,您不希望将该空格包含在哈希输入中,但您确实包含了它,因为您附加了
nodeValue
而不是
nodeValue.trim()

如果您试图做的事情与安全性有任何关系,那么您不应该使用MD5,因为它在加密方面是不可靠的。改用SHA-256


散列XML元素通常通过规范化(处理空白、属性顺序、文本表示等)完成。请参阅关于使用Java规范化XML数据的主题。

代码中有一些奇怪的东西

字符的UTF-8编码可以使用多个字节。因此,您不应该使用字符串长度作为
update()
调用的最终参数,而应该使用
getBytes()
实际返回的字节数组的长度。按照帕罗的建议,使用
update()
方法,该方法将单个
字节[]
作为参数

MD5的输出是一个16字节的序列,具有相当任意的值。如果将其解释为整数(这就是调用
biginger()
),则将得到一个小于2160的数值,可能要小得多。当转换回十六进制数字时,您可能会得到32、31、30。。。或少于30个字符。您对
%032X”
格式字符串的使用留下了足够多的零,所以您的代码可以工作,但它是一种间接的(MD5的输出从一开始就不是整数)

您可以使用原始连接来组装散列输入元素。这可能会引发一些问题。例如,如果
modeName
是“
foo
”,
modeParentName
是“
barqux
”,那么MD5输入将以“
foobarqux
”的UTF-8编码开始。如果
modeName
为“
foobar
”,
modeParentName
为“
qux
”,则MD5输入也将以“
foobarqux
”开头。您不知道为什么要使用散列函数,但通常,当您使用散列函数时,它是为了拥有某个数据段的唯一跟踪;两个不同的数据元素应该产生不同的散列输入

处理
nodeValue
时,调用
trim()
,这意味着该字符串可以以空格开头和/或结尾,而不希望包含该whitepac