MD5算法分析及其java代码实现
上一篇博文深入分析了java JDK中的java.util.HashMap类,其实哈希表在日常生活中用的十分广泛,从到数据存储,文件加密,数字签名。本篇博文主要介绍利用散列实现MD5加密算法。
对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
在MD5算法中,首先需要对信息进行填充,使其位长对512求余的结果等于448。因此,信息的位长(Bits Length)将被扩展至N*512+448,N为一个非负整数,N可以是零。填充的方法如下,在信息的后面填充一个1和剩余的0,直到满足上面的条件时才停止用0对信息的填充。然后,在这个结果后面附加一个以64位二进制表示的填充前信息长度。经过这两步的处理,现在的信息的位长=N*512+448+64=(N+1)*512,
即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。
如下图:
MD5初始的128位值为初试链接变量,为4组8位16进制数。分别为:
A=0x67452301
B=0xefcdab89
C=0x98badcfe
D=0x98badcfe
在java中用数组封装:
private long[] state = new long[4]; // state (ABCD) state[0] = 0x67452301L; state[1] = 0xefcdab89L; state[2] = 0x98badcfeL; state[3] = 0x10325476L;
基本处理思想:初始为128个bit 信息,将128bit 初始信息与分割后的512bit 数据经过4组16次hash循环算法,得到128bit 的新信息,依次循环,直到与最后一组512 bit的数据hash算法后,就得到的整个文件的MD5值。
MD5主循环有四轮,每轮循环都很相似。第一轮进行16次操作。每次操作对a、b、c和d中的其中三个作一次非线性函数运算,然后将所得结果加上第四个变量,文本的一个子分组和一个常数。再将所得结果向左环移一个不定的数,并加上a、b、c或d中之一。最后用该结果取代a、b、c或d中之一。
四个非线性函数:
F(X,Y,Z) =(X&Y)|((~X)&Z)
G(X,Y,Z) =(X&Z)|(Y&(~Z))
H(X,Y,Z) =X^Y^Z
I(X,Y,Z)=Y^(X|(~Z))
将其用java代码实现:
/** * F, G, H ,I 是4个基本的MD5函数 把它们封装成private方法,名字保持一致。 * * @param x * @param y * @param z * @return */ private long F(long x, long y, long z) { return (x & y) | ((~x) & z); } private long G(long x, long y, long z) { return (x & z) | (y & (~z)); } private long H(long x, long y, long z) { return x ^ y ^ z; } private long I(long x, long y, long z) { return y ^ (x | (~z)); }
进一步位运算: FF, GG, HH和II
FF(a,b,c,d,Mj,s,ti)表示 a = b + ((a + F(b,c,d) + Mj + ti) << s)
GG(a,b,c,d,Mj,s,ti)表示 a = b + ((a + G(b,c,d) + Mj + ti) << s)
HH(a,b,c,d,Mj,s,ti)表示 a = b + ((a + H(b,c,d) + Mj + ti) << s)
Ⅱ(a,b,c,d,Mj,s,ti)表示 a = b + ((a + I(b,c,d) + Mj + ti) << s)
Mj表示消息的第j个子分组(从0到15),常数ti是2^32*abs(sin(i))的整数部分,i取值从1到64
作用如下图:
java代码实现:
/** * FF,GG,HH和II将调用F,G,H,I进行近一步变换 FF, GG, HH和II * * @param a * @param b * @param c * @param d * @param Mj : 第j个子分组 * @param s : 左移位数 * @param ac : 2^32 * abs(sin(i))的整数部分,i取值从1到64,单位是弧度。 * @return */ private long FF(long a, long b, long c, long d, long Mj, long s, long ac) { a += F(b, c, d) + Mj + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; } private long GG(long a, long b, long c, long d, long Mj, long s, long ac) { a += G(b, c, d) + Mj + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; } private long HH(long a, long b, long c, long d, long Mj, long s, long ac) { a += H(b, c, d) + Mj + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; } private long II(long a, long b, long c, long d, long Mj, long s, long ac) { a += I(b, c, d) + Mj + ac; a = ((int) a << s) | ((int) a >>> (32 - s)); a += b; return a; }
循环哈希算法
第一轮 FF(a,b,c,d,M0,7,0xd76aa478) FF(d,a,b,c,M1,12,0xe8c7b756) FF(c,d,a,b,M2,17,0x242070db) FF(b,c,d,a,M3,22,0xc1bdceee) FF(a,b,c,d,M4,7,0xf57c0faf) FF(d,a,b,c,M5,12,0x4787c62a) FF(c,d,a,b,M6,17,0xa8304613) FF(b,c,d,a,M7,22,0xfd469501) FF(a,b,c,d,M8,7,0x698098d8) FF(d,a,b,c,M9,12,0x8b44f7af) FF(c,d,a,b,M10,17,0xffff5bb1) FF(b,c,d,a,M11,22,0x895cd7be) FF(a,b,c,d,M12,7,0x6b901122) FF(d,a,b,c,M13,12,0xfd987193) FF(c,d,a,b,M14,17,0xa679438e) FF(b,c,d,a,M15,22,0x49b40821) 第二轮 GG(a,b,c,d,M1,5,0xf61e2562) GG(d,a,b,c,M6,9,0xc040b340) GG(c,d,a,b,M11,14,0x265e5a51) GG(b,c,d,a,M0,20,0xe9b6c7aa) GG(a,b,c,d,M5,5,0xd62f105d) GG(d,a,b,c,M10,9,0x02441453) GG(c,d,a,b,M15,14,0xd8a1e681) GG(b,c,d,a,M4,20,0xe7d3fbc8) GG(a,b,c,d,M9,5,0x21e1cde6) GG(d,a,b,c,M14,9,0xc33707d6) GG(c,d,a,b,M3,14,0xf4d50d87) GG(b,c,d,a,M8,20,0x455a14ed) GG(a,b,c,d,M13,5,0xa9e3e905) GG(d,a,b,c,M2,9,0xfcefa3f8) GG(c,d,a,b,M7,14,0x676f02d9) GG(b,c,d,a,M12,20,0x8d2a4c8a) 第三轮 HH(a,b,c,d,M5,4,0xfffa3942) HH(d,a,b,c,M8,11,0x8771f681) HH(c,d,a,b,M11,16,0x6d9d6122) HH(b,c,d,a,M14,23,0xfde5380c) HH(a,b,c,d,M1,4,0xa4beea44) HH(d,a,b,c,M4,11,0x4bdecfa9) HH(c,d,a,b,M7,16,0xf6bb4b60) HH(b,c,d,a,M10,23,0xbebfbc70) HH(a,b,c,d,M13,4,0x289b7ec6) HH(d,a,b,c,M0,11,0xeaa127fa) HH(c,d,a,b,M3,16,0xd4ef3085) HH(b,c,d,a,M6,23,0x04881d05) HH(a,b,c,d,M9,4,0xd9d4d039) HH(d,a,b,c,M12,11,0xe6db99e5) HH(c,d,a,b,M15,16,0x1fa27cf8) HH(b,c,d,a,M2,23,0xc4ac5665) 第四轮 Ⅱ(a,b,c,d,M0,6,0xf4292244) Ⅱ(d,a,b,c,M7,10,0x432aff97) Ⅱ(c,d,a,b,M14,15,0xab9423a7) Ⅱ(b,c,d,a,M5,21,0xfc93a039) Ⅱ(a,b,c,d,M12,6,0x655b59c3) Ⅱ(d,a,b,c,M3,10,0x8f0ccc92) Ⅱ(c,d,a,b,M10,15,0xffeff47d) Ⅱ(b,c,d,a,M1,21,0x85845dd1) Ⅱ(a,b,c,d,M8,6,0x6fa87e4f) Ⅱ(d,a,b,c,M15,10,0xfe2ce6e0) Ⅱ(c,d,a,b,M6,15,0xa3014314) Ⅱ(b,c,d,a,M13,21,0x4e0811a1) Ⅱ(a,b,c,d,M4,6,0xf7537e82) Ⅱ(d,a,b,c,M11,10,0xbd3af235) Ⅱ(c,d,a,b,M2,15,0x2ad7d2bb) Ⅱ(b,c,d,a,M9,21,0xeb86d391)
为了方便期间,我们定义一个所用到的s用4 * 4的矩形来存储。
上面的部分用java代码实现:
/** * MD5核心变换程序,有md5Update调用 * @param block 分块的原始字节 */ private void md5Transform(byte block[]) { long a = state[0], b = state[1], c = state[2], d = state[3]; long[] x = new long[16]; Decode(x, block, 64);//把long类型(64bit)按顺序拆成byte数组 /* Round 1 */ a = FF(a, b, c, d, x[0], S11, 0xd76aa478L); /* 1 */ d = FF(d, a, b, c, x[1], S12, 0xe8c7b756L); /* 2 */ c = FF(c, d, a, b, x[2], S13, 0x242070dbL); /* 3 */ b = FF(b, c, d, a, x[3], S14, 0xc1bdceeeL); /* 4 */ a = FF(a, b, c, d, x[4], S11, 0xf57c0fafL); /* 5 */ d = FF(d, a, b, c, x[5], S12, 0x4787c62aL); /* 6 */ c = FF(c, d, a, b, x[6], S13, 0xa8304613L); /* 7 */ b = FF(b, c, d, a, x[7], S14, 0xfd469501L); /* 8 */ a = FF(a, b, c, d, x[8], S11, 0x698098d8L); /* 9 */ d = FF(d, a, b, c, x[9], S12, 0x8b44f7afL); /* 10 */ c = FF(c, d, a, b, x[10], S13, 0xffff5bb1L); /* 11 */ b = FF(b, c, d, a, x[11], S14, 0x895cd7beL); /* 12 */ a = FF(a, b, c, d, x[12], S11, 0x6b901122L); /* 13 */ d = FF(d, a, b, c, x[13], S12, 0xfd987193L); /* 14 */ c = FF(c, d, a, b, x[14], S13, 0xa679438eL); /* 15 */ b = FF(b, c, d, a, x[15], S14, 0x49b40821L); /* 16 */ /* Round 2 */ a = GG(a, b, c, d, x[1], S21, 0xf61e2562L); /* 17 */ d = GG(d, a, b, c, x[6], S22, 0xc040b340L); /* 18 */ c = GG(c, d, a, b, x[11], S23, 0x265e5a51L); /* 19 */ b = GG(b, c, d, a, x[0], S24, 0xe9b6c7aaL); /* 20 */ a = GG(a, b, c, d, x[5], S21, 0xd62f105dL); /* 21 */ d = GG(d, a, b, c, x[10], S22, 0x2441453L); /* 22 */ c = GG(c, d, a, b, x[15], S23, 0xd8a1e681L); /* 23 */ b = GG(b, c, d, a, x[4], S24, 0xe7d3fbc8L); /* 24 */ a = GG(a, b, c, d, x[9], S21, 0x21e1cde6L); /* 25 */ d = GG(d, a, b, c, x[14], S22, 0xc33707d6L); /* 26 */ c = GG(c, d, a, b, x[3], S23, 0xf4d50d87L); /* 27 */ b = GG(b, c, d, a, x[8], S24, 0x455a14edL); /* 28 */ a = GG(a, b, c, d, x[13], S21, 0xa9e3e905L); /* 29 */ d = GG(d, a, b, c, x[2], S22, 0xfcefa3f8L); /* 30 */ c = GG(c, d, a, b, x[7], S23, 0x676f02d9L); /* 31 */ b = GG(b, c, d, a, x[12], S24, 0x8d2a4c8aL); /* 32 */ /* Round 3 */ a = HH(a, b, c, d, x[5], S31, 0xfffa3942L); /* 33 */ d = HH(d, a, b, c, x[8], S32, 0x8771f681L); /* 34 */ c = HH(c, d, a, b, x[11], S33, 0x6d9d6122L); /* 35 */ b = HH(b, c, d, a, x[14], S34, 0xfde5380cL); /* 36 */ a = HH(a, b, c, d, x[1], S31, 0xa4beea44L); /* 37 */ d = HH(d, a, b, c, x[4], S32, 0x4bdecfa9L); /* 38 */ c = HH(c, d, a, b, x[7], S33, 0xf6bb4b60L); /* 39 */ b = HH(b, c, d, a, x[10], S34, 0xbebfbc70L); /* 40 */ a = HH(a, b, c, d, x[13], S31, 0x289b7ec6L); /* 41 */ d = HH(d, a, b, c, x[0], S32, 0xeaa127faL); /* 42 */ c = HH(c, d, a, b, x[3], S33, 0xd4ef3085L); /* 43 */ b = HH(b, c, d, a, x[6], S34, 0x4881d05L); /* 44 */ a = HH(a, b, c, d, x[9], S31, 0xd9d4d039L); /* 45 */ d = HH(d, a, b, c, x[12], S32, 0xe6db99e5L); /* 46 */ c = HH(c, d, a, b, x[15], S33, 0x1fa27cf8L); /* 47 */ b = HH(b, c, d, a, x[2], S34, 0xc4ac5665L); /* 48 */ /* Round 4 */ a = II(a, b, c, d, x[0], S41, 0xf4292244L); /* 49 */ d = II(d, a, b, c, x[7], S42, 0x432aff97L); /* 50 */ c = II(c, d, a, b, x[14], S43, 0xab9423a7L); /* 51 */ b = II(b, c, d, a, x[5], S44, 0xfc93a039L); /* 52 */ a = II(a, b, c, d, x[12], S41, 0x655b59c3L); /* 53 */ d = II(d, a, b, c, x[3], S42, 0x8f0ccc92L); /* 54 */ c = II(c, d, a, b, x[10], S43, 0xffeff47dL); /* 55 */ b = II(b, c, d, a, x[1], S44, 0x85845dd1L); /* 56 */ a = II(a, b, c, d, x[8], S41, 0x6fa87e4fL); /* 57 */ d = II(d, a, b, c, x[15], S42, 0xfe2ce6e0L); /* 58 */ c = II(c, d, a, b, x[6], S43, 0xa3014314L); /* 59 */ b = II(b, c, d, a, x[13], S44, 0x4e0811a1L); /* 60 */ a = II(a, b, c, d, x[4], S41, 0xf7537e82L); /* 61 */ d = II(d, a, b, c, x[11], S42, 0xbd3af235L); /* 62 */ c = II(c, d, a, b, x[2], S43, 0x2ad7d2bbL); /* 63 */ b = II(b, c, d, a, x[9], S44, 0xeb86d391L); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; }
经过以上hash算法,就可以得到文件的MD5值了、、、
为了验证程序的正确性:提供几个常见字符串的MD5值:
空文的散列为:MD5("") = d41d8cd98f00b204e9800998ecf8427e
MD5("abc") = 900150983cd24fb0d6963f7d28e17f72
参考资料:http://www.ietf.org/rfc/rfc1321.txt
对数据结构还不是特别熟悉,希望大家多多支持和指正。
相关推荐
### MD5算法在Java中的实现 #### 一、概述 MD5(Message-Digest Algorithm 5)是一种...通过以上分析,我们可以了解到MD5算法的基本原理以及如何在Java中实现它。同时,也指出了在实际应用中需要注意的一些关键点。
通过上述分析,我们可以看到,给定的Java代码提供了一种简单而有效的方法来实现MD5哈希算法。它不仅展示了如何利用Java标准库中的`MessageDigest`类来计算MD5值,还展示了如何处理字节和十六进制之间的转换,以及...
根据提供的标题、描述以及部分上下文内容,我们可以推断出这份文档主要涉及的是关于MD5算法在Java中的实现。下面将详细阐述与标题和描述相关的MD5算法知识点,并结合给出的部分内容进行分析。 ### MD5算法简介 MD5...
通过对上述代码的分析,我们可以清楚地了解到如何在Java中实现文件的MD5加密功能。这种方法不仅可以用于验证文件的一致性,还可以用于简单场景下的数据校验。尽管MD5存在一定的安全风险,但在非敏感信息处理方面仍然...
通过上述分析,我们可以了解到MD5算法的基本原理以及如何使用Java语言来实现它。虽然MD5算法在安全性方面存在问题,但其仍然是理解散列算法工作原理的重要案例之一。在实际应用中,选择合适的散列算法是非常重要的,...
上述代码提供了一种使用Java语言实现MD5加密的基本框架。通过了解这些基础知识,开发者可以更好地理解MD5算法的工作原理以及如何在实际项目中运用该算法来提高数据的安全性和完整性。需要注意的是,虽然MD5算法在...
在Java中,可以通过`java.security.MessageDigest`类来实现MD5算法。 #### 二、MD5加密原理 MD5算法将任意长度的消息压缩成一个固定长度(通常是128位)的散列值。该散列值具有以下特点: 1. **不可逆性**:从...
MD5(Message-Digest Algorithm 5)是一种广泛使用的哈希函数,由计算机科学家伦纳德·里德·莫里斯...实验三可能包含的是一个实际的MD5算法实现代码,通过分析和运行这个代码,你可以更深入地理解MD5的内部工作机制。
根据提供的部分Java代码片段,我们可以看出这是一个简单的MD5算法实现类`MD5`,其主要功能包括初始化MD5上下文、更新散列值、计算最终的MD5值并将其转换为十六进制字符串表示形式。 1. **初始化MD5上下文 (`md5Init...
在给定的代码片段中,我们可以通过以下几个步骤来理解如何在Java中实现MD5加密: 1. **导入必要的包**: ```java import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; ``` 2...
MD5加密技术在Java中的应用与实现 MD5(Message-Digest Algorithm 5)是一种广泛使用的散列算法,主要用于确保数据的完整性和安全性。在Java编程语言中,MD5加密常用于密码保护、数据校验等场景,通过将原始字符串...
为了实现MD5算法,在Java中主要依赖`java.security.MessageDigest`类。以下是对给定代码片段的理解与分析: #### 实现细节 1. **导入必要的包** ```java import java.security.MessageDigest; ``` 2. **创建...
通过上述分析可以看出,在Java中实现MD5加密主要涉及将数据转换为字节数组、计算MD5散列值以及验证散列值的正确性等步骤。虽然MD5在安全性方面存在一定的局限性,但在某些对安全性要求不高的应用场景中,仍然可以...
MD5码,全称为Message-Digest Algorithm 5,是一种广泛使用的哈希函数,可以将任意长度的数据转换为固定...同时,通过阅读和分析源码,可以深入理解Java的IO操作和安全相关API的使用,以及MD5算法在实际应用中的实现。
通过上述分析,我们了解了MD5算法的基本原理及其实现方式,并学习了如何在Java中使用加盐散列技术增强密码的安全性。这种方式在实际应用中非常有用,尤其是在需要保护用户隐私和数据安全的场合。
在Java编程语言中,MD5(Message-Digest Algorithm 5)是一种广泛使用的哈希函数,它将任意长度的数据转化为固定长度的输出,通常为32...通过实际操作和分析这些代码,你将能够更好地掌握如何在实际项目中实现MD5加密。
### JAVA MD5加密算法 #### 一、简介 在计算机科学领域中,MD5(Message-Digest Algorithm 5)是一种广泛使用的散列函数,能够将任意长度的数据转换为一个固定长度(通常是128位)的十六进制数字字符串。这种转换...
通过上述分析可知,该程序通过MD5算法实现了字符串的加密及验证功能。这对于保护敏感信息(如密码)的安全性具有重要意义。同时,了解和掌握MD5加密的基本原理及其在Java中的实现方式对于开发者来说是非常有用的技能...
为了解决MD5算法的不足,特别是针对短明文摘要加密不安全的问题,本文探讨了基于MD5算法的加盐消息摘要Java实现方法。 消息摘要本质上是一种单向散列函数,它能够将任意长度的数据映射为固定长度的字符串,通常用于...
这段代码主要实现了MD5加密算法,并且是为J2ME(Java 2 Micro Edition)环境设计的。接下来,我们将详细探讨以下几点: 1. **MD5算法简介**:MD5(Message-Digest Algorithm 5)是一种广泛使用的散列函数,它可以将...