0%

MessageDigest 使用注意,并发问题

MessageDigest 使用注意,并发问题

Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。该算法的文件号为RFC 1321(R.Rivest,MIT Laboratory for Computer Science and RSA Data Security Inc. April 1992)。

产生错误原因

因为这些常用的工具类之前都写好了,用的时候没有多想就直接Copy过来了,请求是并发的,刚刚开始的时候,并发请求较少(1-2)个,没有出现什么问题,后来请求3-4个同时发的时候,服务端偶尔抛出MD5值验证错误的信息,后来翻看了MD5工具类之后才发现,原来这个类写的方式并不支持并发,MessageDigest被声明为成员变量,多线程环境下会共享同一个MessageDigest对象

MessageDigest源码

1
2
3
4
5
6
7
8
9
/**
* Updates the digest using the specified array of bytes.
*
* @param input the array of bytes.
*/
public void update(byte[] input) {
engineUpdate(input, 0, input.length);
state = IN_PROGRESS;
}

调用了engineUpdate方法,此方法进行一个更新操作。

1
Updates the digest using the specified array of bytes, starting at the specified offset.

然后state属性的状态就被改变了,表明当前计算正在处理过程中。

state默认属性

1
private int state = INITIAL;

然后需要调用MessageDigest.digest()方法计算哈希值

1
2
3
4
5
6
7
8
9
10
11
12
/**
* Completes the hash computation by performing final operations
* such as padding. The digest is reset after this call is made.
*
* @return the array of bytes for the resulting hash value.
*/
public byte[] digest() {
/* Resetting is the responsibility of implementors. */
byte[] result = engineDigest();
state = INITIAL;
return result;
}

到这里已经完成了MD5值的计算,state属性恢复初始状态,如果想要重用MessageDigest对象,还需要调用MessageDigest.reset()方法进行重置,以免这次计算数据会对下一次的计算造成影响,从而导致计算结果错误。

而我所遇到的问题就是,在MessageDigest在多线程的环境下,Thread-1的计算还没有完成的情况下,Thread-2又开始使用该MessageDigest对象进行下一次的计算,Thread-2修改了MessageDigest的状态,Thread-1使用被修改过后的MessageDigest进行计算,从而导致了计算结果错误。

解决方法

pom.xml

1
2
3
4
5
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
1
2
3
byte[] md5Value = DigestUtils.md5(date);

String md5Value = DigestUtils.md5Hex(date);