JAVA中的MD5加密,常见问题处理

平常使用MD5加密时,自己封装处理时,常见有2个问题:

1、转换为字符串时,高位的0被舍去;

2、出现负数时会有多个连续的F;

这是因为MessageDigest返回的结果是无符号数的byte数组,所以一个byte表示2位的十六进制数时,高位可能为0,而且在JAVA中byte默认是按有符号数的来读取的,转换时会出现负数。

public class MD5Utils {
    
    private static final char[] chs =
            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    
    public static String getMD5(String str) {
        MessageDigest messageDigest;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException();
        }
        byte[] bys = messageDigest.digest(str.getBytes());
        StringBuilder sb = new StringBuilder(32);
        int index;
        for (byte b : bys) {
            index = b & 0xff;//将负数byte按无符号数读取
            sb.append(chs[index >> 4]);//16进制数的高位
            sb.append(chs[index % 16]);//16进制数的低位
        }
        return sb.toString();//返回的结果为32位的16进制数字符串
    }
}

其中,因为MessageDigest返回的结果是用无符号数来表示的,而在JAVA中默认是采用最高位来表示正负的,所以使用了位运算的方式来截取该无符号数:

		   index = b & 0xff;

等价于:

			   index = b;
			   if(index < 0 ){
				   index += 256;
			   }

 

一个byte可以表示2位的16进制数,采用Integer.toHexString(index)转换时,若小于16会只有1位16进制数。继续使用位运算+查表法来获取16进制数:

		       sb.append(chs[ index >> 4]);
		       sb.append(chs[ index % 16]);

等价于:

               if(index < 16){
                   sb.append('0');
               }
               sb.append(Integer.toHexString(index));

因为没有使用Integer的toHexString(index)和toString(int i, int radix)方法,而是自己重新实现了,所以效率有所提高。

点赞