MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由罗纳德·李维斯特设计,于1992年公开,用以替换MD4算法。这套算法的程序在 RFC 1321 中被加以规范。来源
罗纳德·李维斯特 (英语:Ronald Linn Rivest,1947年-)是一名美国密码学家。他是麻省理工学院电子工程和计算机科学部门 (EECS)计算机科学的一名教授 和麻省理工学院之计算机科学和人工智能实验室 (CSAIL)的成员。他与阿迪·萨莫尔和伦纳德·阿德曼共同发明了RSA加密算法;以及在密码学和计算机科学等领域做出许多杰出贡献而知名。RSA被广泛使用在计算机安全应用上,包括https。2002年,他与阿迪·萨莫尔和伦纳德·阿德曼一起因在公钥密码学RSA加密算法取得的杰出贡献而获得图灵奖。来源
维基百科已经包含了MD5码的伪代码,文章主要是openjdk的源代码进行分析MD5码算法。
下载OpenJDK
OpenJDK搜索及下载
Google搜索关键词 OpenJDK source bundle
进入下载页面(OpenJDK为例),http://download.java.net/openjdk/jdk8/下载 zip包
下载图中红线标注链接的zip文件编写gradle脚本
为了在Android Studio,查看OpenJDK的源代码,需要编写setting.gradle,build.gradle文件
下面是目录结构
.
|____corba
|____jdk
| | |____src
| | | |____windows
| | | | |____classes
| | | | |____native
| | | |____linux
| | | |____macosx
| | |____build.gradle
|____build.gradle
|____settings.gradle
jdk目录下的build.gradle文件内容如下,可以根据查看的代码进行变更
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion 16
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.ph0b.example"
minSdkVersion.apiLevel 15
targetSdkVersion.apiLevel 23
versionCode 4
versionName "1.0.1"
}
}
android.ndk {
moduleName "mymodule"
ldLibs.addAll(['log'])
cppFlags.add("-std=c++11")
cppFlags.add("-fexceptions")
platformVersion 15
stl 'gnustl_shared'
}
android.sources {
main {
java {
source {
srcDirs [ 'src/share/classes/sun' ]//"src/windows/classes"
}
}
jni {
source {
// srcDir "src/windows/native"
}
}
}
}
}
}
MD5实现
- 类图
2. 重要类分析(MD5.java,DigestBase.java,ByteArrayAccess.java)
MD5.java(位于jdk/src/share/classes/sun/security/provider/MD5.java)的implCompress方法,进行非线性函数计算
/**
* This is where the functions come together as the generic MD5
* transformation operation. It consumes sixteen
* bytes from the buffer, beginning at the specified offset.
*/
void implCompress(byte[] buf, int ofs) {
b2iLittle64(buf, ofs, x);//转化为64字节,存放在x中
...
...
...
}
MD5.java的implDigest方法,长度填充,输出结果到out字节数组
/**
* Perform the final computations, any buffered bytes are added
* to the digest, the count is added to the digest, and the resulting
* digest is stored.
*/
void implDigest(byte[] out, int ofs) {
long bitsProcessed = bytesProcessed << 3;//java计算时大小的单位为kb,md5需要转化为bit的单位
int index = (int)bytesProcessed & 0x3f;//对(2**8-1)=256,求余,单位为byte.{如果转为bit(左移3位),是对2的9次方(512)求余}
int padLen = (index < 56) ? (56 - index) : (120 - index);//如果byte小于56byte,(56*8=448bit),需要填充的bit,(56-index)*8bit.否则是120-index,即(120*8-index*8)bit,其值小于等于512(128*8-56*8=64*8=512)
engineUpdate(padding, 0, padLen);//填充
i2bLittle4((int)bitsProcessed, buffer, 56);//long共8个字节,先取前4个字节
i2bLittle4((int)(bitsProcessed >>> 32), buffer, 60);//long共8个字节,再取后4个字节
implCompress(buffer, 0);//最后一次,编码
i2bLittle(state, 0, out, ofs, 16);//数据放在out数组中,含有16个字节,即128bit
}