java MD5 并发

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

查看MessageDigest源码

public void update(byte[] input) {
        engineUpdate(input, 0, input.length);
        state = IN_PROGRESS;
}

可以看到这里调用了engineUpdate方法,此方法进行一个更新操作。

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

state默认属性

private int state = INITIAL;

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

 

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进行计算,从而导致了计算结果错误。

解决方案有两个:

1、加锁来共享同一个MessageDigest;

public class MD5 {
private static final byte[] ToHex_ =
{ '0','1','2','3','4','5','6','7',
'8','9','a','b','c','d','e','f'
};
private MessageDigest md5_ = null;
static private MessageDigest Md5_;
static
{
try { Md5_ = MessageDigest.getInstance("MD5");} // MD5 is supported
catch ( NoSuchAlgorithmException e ) {}; // safe to swallow
};

public MD5()
{
try { md5_ = MessageDigest.getInstance("MD5");} // MD5 is supported
catch ( NoSuchAlgorithmException e ) {}; // safe to swallow
}
/**
* 
*/
public static synchronized String Digest(byte[] dataToHash)
{
Md5_.update(dataToHash, 0, dataToHash.length);
return HexStringFromBytes( Md5_.digest() );
}
/**
* Non-threadsafe MD5 digest (hashing) function
*/
public String digest(byte[] dataToHash)
{
md5_.update(dataToHash, 0, dataToHash.length);
return HexStringFromBytes( md5_.digest() );
}
private static String HexStringFromBytes(byte[] b)
{
byte [] hex_bytes = new byte[ b.length * 2 ];
int i,j=0;
for (i=0; i < b.length; i++)
{
hex_bytes[j] = ToHex_[ ( b[i] & 0xF0 ) >> 4 ] ;
hex_bytes[j+1] = ToHex_[ b[i] & 0xF ];
j+=2;
}
return new String( hex_bytes );
}
}

  

2、每次新创建一个MessageDigest;

class  MD5_test {  
   public   final   static  String MD5(String s) {  
    char  hexDigits[] = {  '0' ,  '1' ,  '2' ,  '3' ,  '4' ,  '5' ,  '6' ,  '7' ,  '8' ,  '9' ,  
      'a' ,  'b' ,  'c' ,  'd' ,  'e' ,  'f'  };  
    try  {  
   byte [] strTemp = s.getBytes();  
   MessageDigest mdTemp = MessageDigest.getInstance("MD5" );  
   mdTemp.update(strTemp);  
   byte [] md = mdTemp.digest();  
   int  j = md.length;  
   char  str[] =  new   char [j *  2 ];  
   int  k =  0 ;  
   for  ( int  i =  0 ; i < j; i++) {  
    byte  byte0 = md[i];  
    str[k++] = hexDigits[byte0 >>> 4  &  0xf ];  
    str[k++] = hexDigits[byte0 & 0xf ];  
   }  
   return   new  String(str);  
  } catch  (Exception e) {  
   return   null ;  
  }  
 }  
  
 public   static   void  main(String[] args) {  
  // MD5_Test aa = new MD5_Test();   
	 System.out.print(MD5_test.MD5("a" ));  
//  System.out.print(MD5_test.MD5("%7B%7DAHRCU" ));  
 }  
} 

  

这两种方案都可解决并发问题。

 

posted @ 2017-12-15 18:02  徐继收  阅读(981)  评论(0编辑  收藏  举报