MD5算法java实现源码

流程

  1. 处理需要加密的字符串:
    1. 以byte[]的形式获取,此时,每个字符为一个字节,占8位
    2. 当此时获得的字节流对512位,也就是64个字节取余,结果不为448,即56个字节时,使用1000……0的二进制位进行补位,直到取余结果为448,;而当结果为448时,也需要补位,补512位;(如果是字节补位则为128,0,0……)
    3. 此时如果想要按照每512为一块划分还缺少64位,这64位为最开始得到的字符串占用的位数,也就是字符串长度*8(因为每个字符8位,所以一共是8*长度,并将这个结果转化为64位二进制)
  2. 每512(64字节)位分为一块,其中,每64位(4字节)分为一组,每块共16组
  3. 对每块的16组进行循环操作
    1. 一共进行4*16次循环,4次外循环,每次使用不用的函数,分别为FF GG HH II ,16次内循环则是对每块的16组进行的操作
    2. 此时需要注意,16个组被处理的顺序是不同的
  4. 将得到的结果恢复为16进制输出

函数解释

  1. changeToBytes——将当前的字符串转换并完成补位,得到字节流
  2. changeToLongGroups——将当前的字节流进行块和组的划分,得到二维数组
  3. recycle——每轮要进行的循环操作
  4. funcPoint——通过外循环序号的判断运行不同的函数
  5. changeK——通过内循环序号决定当前处理的是哪一组
  6. offSigned——字节是有符号位的,去除符号位,转为数据位
  7. F G H I FF GG HH II:预先定义的函数加密方法

源码

public class MD5 {
	static final String hexs[]={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
    private static final long A=0x67452301L;
    private static final long B=0xefcdab89L;
    private static final long C=0x98badcfeL;
	private static final long D=0x10325476L;
	private static long[] res = {A, B, C, D};
	private static long[] deal = {A, B, C, D};
	private static final int s[][] = {
		{7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22},
		{5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20}, 
		{4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23}, 
		{6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21}
	};
	private static final long T[] = {
		0xd76aa478L, 0xe8c7b756L, 0x242070dbL, 0xc1bdceeeL, 0xf57c0fafL, 0x4787c62aL, 0xa8304613L, 0xfd469501L, 0x698098d8L, 0x8b44f7afL, 0xffff5bb1L, 0x895cd7beL, 0x6b901122L, 0xfd987193L, 0xa679438eL, 0x49b40821L,
		0xf61e2562L, 0xc040b340L, 0x265e5a51L, 0xe9b6c7aaL, 0xd62f105dL, 0x02441453L, 0xd8a1e681L, 0xe7d3fbc8L, 0x21e1cde6L, 0xc33707d6L, 0xf4d50d87L, 0x455a14edL, 0xa9e3e905L, 0xfcefa3f8L, 0x676f02d9L, 0x8d2a4c8aL,
		0xfffa3942L, 0x8771f681L, 0x6d9d6122L, 0xfde5380cL, 0xa4beea44L, 0x4bdecfa9L, 0xf6bb4b60L, 0xbebfbc70L, 0x289b7ec6L, 0xeaa127faL, 0xd4ef3085L, 0x04881d05L, 0xd9d4d039L, 0xe6db99e5L, 0x1fa27cf8L, 0xc4ac5665L,
		0xf4292244L, 0x432aff97L, 0xab9423a7L, 0xfc93a039L, 0x655b59c3L, 0x8f0ccc92L, 0xffeff47dL, 0x85845dd1L, 0x6fa87e4fL, 0xfe2ce6e0L, 0xa3014314L, 0x4e0811a1L, 0xf7537e82L, 0xbd3af235L, 0x2ad7d2bbL, 0xeb86d391L};
	public static void main(String []args){
        MD5 md=new MD5();
		String test = "123456";
		byte[] allBytes = changeToBytes(test);
		long[][] groups = changeToLongGroups(allBytes);
		///System.out.println(groups.length);
		for(int t = 0; t < groups.length; ++t){
			recycle(groups[t]);
			
			String resStr="";
        	long temp=0;
       		for(int i=0;i<4;i++){
            	for(int j=0;j<4;j++){
					temp=res[i]&0x0FL;
					String a=hexs[(int)(temp)];
					res[i]=res[i]>>4;
					temp=res[i]&0x0FL;
					resStr+=hexs[(int)(temp)]+a;
					res[i]=res[i]>>4;
				}
			}
			System.out.println(resStr+"\n");
		}
    }
	
	private static byte[] changeToBytes(String str) {
		int K = str.length() * 8;
		int P = K % 512;
		P = P < 448 ? 448-P : 512-P+448;
	    byte[] allBytes = new byte[K/8+P/8+8];
	    for(int i = 0; i < K/8; ++i) 
	    	allBytes[i] = str.getBytes()[i];
	    for(int i = 0; i < P/8; ++i) 
			allBytes[K/8 + i] = (i == 0) ? (byte)128 : (byte)0;
			
		long len=(long)(K/8<<3);
            for(int i=0;i<8;i++){
                allBytes[K/8 + P/8 +i]=(byte)(len&0xFFL);
                len=len>>8;
        }
	    // if(K >= 64) 
	    // 	for(int i = 0; i < 8; ++i)	
	    // 		allBytes[K/8+P/8+i] = allBytes[K/8-8+i];
	    // else {
	    // 	for(int i = 0; i < 8; ++i) {
	    // 		if((i+K/8) < 8) allBytes[K/8+P/8+i] = 0 & 0xff;
	    // 		else allBytes[K/8+P/8+i] = allBytes[i+K/8-8];
	    // 	}
		// }
		
	    return allBytes;
	}
	
	private static long[][] changeToLongGroups(byte[] allBytes) {
	
		int groupNum = allBytes.length / 64;
		
		long[][] res = new long[groupNum][16];
		for(int i = 0; i < groupNum; ++i) {
			for(int j=0; j<16; ++j){
	            res[i][j] = (offSigned(allBytes[64*i + j*4])) |
					(offSigned(allBytes[64*i + j*4 + 1])) << 8|
					(offSigned(allBytes[64*i + j*4 + 2])) << 16|
					(offSigned(allBytes[64*i + j*4 + 3])) << 24;
				
	        }
		}
		
		return res;
	}

	
	private static void recycle(long[] group){
		// System.out.println("1");
		for(int i = 0; i < 4; ++i){
			for(int j = 0; j < 16; ++j){
				int k = changeK(i, j);
				if(j%4 == 0)
					deal[0] = funcPoint(deal[0], deal[1], deal[2], deal[3], group[k], s[i][j], T[i*16+j], i);
				else if(j%4 == 1)
					deal[3] = funcPoint(deal[3], deal[0], deal[1], deal[2], group[k], s[i][j], T[i*16+j], i);
				else if(j%4 == 2)
					deal[2] = funcPoint(deal[2], deal[3], deal[0], deal[1], group[k], s[i][j], T[i*16+j], i);
				else
					deal[1] = funcPoint(deal[1], deal[2], deal[3], deal[0], group[k], s[i][j], T[i*16+j], i);
				
			}
				
		}

        res[0] = (deal[0] + res[0]) & 0xFFFFFFFFL;
		res[1] = (deal[1] + res[1]) & 0xFFFFFFFFL;
		res[2] = (deal[2] + res[2]) & 0xFFFFFFFFL;
		res[3] = (deal[3] + res[3]) & 0xFFFFFFFFL;
	}

	private static long funcPoint(long a, long b, long c, long d, long Mj, long s, long ti, int choose){
		if(choose == 0)
			return FF(a, b, c, d, Mj, s, ti);
		else if(choose == 1)
			return GG(a, b, c, d, Mj, s, ti);
		else if(choose == 2)
			return HH(a, b, c, d, Mj, s, ti);
		else
			return II(a, b, c, d, Mj, s, ti);
	}

	public static long offSigned(byte bytes){
        return bytes < 0 ? bytes & 0x7F + 128 : bytes;
    }
	
	private static long F(long X, long Y, long Z) {
		return (X & Y) | ((~X) & Z);
	}
	private static long G(long X, long Y, long Z) {
		return (X & Z) | (Y & (~Z));
	}
	private static long H(long X, long Y, long Z) {
		return X^Y^Z;
	}
	private static long I(long X, long Y, long Z) {
		return Y ^ (X | (~Z));
	}
	private static long FF(long a, long b, long c, long d, long Mj, long s, long ti) {
		a += (F(b, c, d) & 0xFFFFFFFFL) + Mj + ti;
        a = ((a&0xFFFFFFFFL)<< s) | ((a&0xFFFFFFFFL) >> (32 - s));
        a += b;
		return (a & 0xFFFFFFFFL);
	}
	private static long GG(long a, long b, long c, long d, long Mj, long s, long ti) {
		a += (G(b, c, d) & 0xFFFFFFFFL) + Mj + ti;
        a = ((a&0xFFFFFFFFL)<< s) | ((a&0xFFFFFFFFL) >> (32 - s));
        a += b;
		return (a & 0xFFFFFFFFL);
	}
	private static long HH(long a, long b, long c, long d, long Mj, long s, long ti) {
		a += (H(b, c, d) & 0xFFFFFFFFL) + Mj + ti;
        a = ((a&0xFFFFFFFFL)<< s) | ((a&0xFFFFFFFFL) >> (32 - s));
        a += b;
		return (a & 0xFFFFFFFFL);
	}
	private static long II(long a, long b, long c, long d, long Mj, long s, long ti) {
		a += (I(b, c, d) & 0xFFFFFFFFL) + Mj + ti;
        a = ((a&0xFFFFFFFFL)<< s) | ((a&0xFFFFFFFFL) >> (32 - s));
        a += b;
		return (a & 0xFFFFFFFFL);
	}

	private static int changeK(int i, int j){
		int k = 0;
		switch(i){
			case 0:
				k = j;
				break;
			case 1:
				k = (1 + 5 * j) % 16;
				break;
			case 2:
				k = (5 + 3 * j) % 16;
				break;
			default:
				k = (7 * j) % 16;
				break;
		}
		return k;
	}

}

 

  • 1
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 5

打赏作者

Suata

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值