MD5简介:

MD5的全称:Message-Digest Algorithm 5(信息-摘要算法5)

MD5的加密方式是一种哈希加密。一些主流的编程语言都已经实现了MD5的加密,所以如果你的程序或是系统涉及到在多种语言之间的校验,那么MD5可以是备选之一。不过因为MD5是采用哈希函数来进行的加密,所以它无关密钥,也就是说在确定了明文的情况下,MD5就可以加密。不过MD5是不可逆的,只能加密,不能解密。

MD5加密字符串:

public class Md5Util {

// 标准的构造函数,调用md5Init函数进行初始化工作

public Md5Util() {

md5Init();

return;

}

// RFC1321中定义的标准4*4矩阵的常量定义。

static final int S11 = 7, S12 = 12, S13 = 17, S14 = 22;

static final int S21 = 5, S22 = 9, S23 = 14, S24 = 20;

static final int S31 = 4, S32 = 11, S33 = 16, S34 = 23;

static final int S41 = 6, S42 = 10, S43 = 15, S44 = 21;

// 按RFC1321标准定义不可变byte型数组PADDING

static final byte[] PADDING = { -128, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

// MD5计算过程中的3组核心数据,采用数组形式存放

private long[] state = new long[4]; // 计算状态(分别对应a b c d)

private byte[] buffer = new byte[64]; // 分配64个字节私有缓冲区

private long[] count = new long[2]; // 位个数

// 最新一次计算结果的16进制ASCII字符串表示,代表了16个字符串形式的MD5值

public String resultStr;

// 最新一次计算结果的2进制数组表示,一共16个字节,代表了128bit形式的MD5值

public byte[] digest = new byte[16];

/**

* 获得两次MD5加密的字符串

*

* @param str

* @return

*/

public String getTwiceMD5ofString(String str) {

return getMD5ofStr(getMD5ofStr(str));

}

/**

* MD5_Encoding类提供的主要的接口函数getMD5ofStr,用来进行数据加密变换。

*

* 调用其可对任意字符串进行加密运算,并以字符串形式返回加密结果。

*

* @param in

* @return

*/

public String getMD5ofStr(String in) {

md5Init(); // 初始化

md5Update(in.getBytes(), in.length());// 调用MD5的主计算过程

md5Final(); // 输出结果到digest数组中

for (int i = 0; i < 16; i++) {

resultStr += byteToHEX(digest[i]); // 将digest数组中的每个byte型数据转为16进制形式的字符串

}

return resultStr;

}

// md5初始化函数.初始化核心变量.

private void md5Init() {

state[0] = 0x67452301L; // 定义state为RFC1321中定义的标准幻数

state[1] = 0xefcdab89L; // 定义state为RFC1321中定义的标准幻数

state[2] = 0x98badcfeL; // 定义state为RFC1321中定义的标准幻数

state[3] = 0x10325476L; // 定义state为RFC1321中定义的标准幻数

count[0] = count[1] = 0L; // 初始化为0

resultStr = "";// 初始化resultStr字符串为空

for (int i = 0; i < 16; i++) {

digest[i] = 0;// 初始化digest数组元素为0

}

return;

}

// 定义F G H I 为4个基数 ,即为4个基本的MD5函数,进行简单的位运算

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调用F,G,H,I函数进行进一步变换

private long FF(long a, long b, long c, long d, long x, long s, long ac) {

a += F(b, c, d) + x + ac;

a = ((int) a << s) | ((int) a >>> (32 - s)); // 这里long型数据右移时使用无符号右移运算符>>>

a += b;

return a;

}

private long GG(long a, long b, long c, long d, long x, long s, long ac) {

a += G(b, c, d) + x + ac;

a = ((int) a << s) | ((int) a >>> (32 - s)); // 这里long型数据右移时使用无符号右移运算符>>>

a += b;

return a;

}

private long HH(long a, long b, long c, long d, long x, long s, long ac) {

a += H(b, c, d) + x + ac;

a = ((int) a << s) | ((int) a >>> (32 - s));// 这里long型数据右移时使用无符号右移运算符>>>

a += b;

return a;

}

private long II(long a, long b, long c, long d, long x, long s, long ac) {

a += I(b, c, d) + x + ac;

a = ((int) a << s) | ((int) a >>> (32 - s));// 这里long型数据右移时使用无符号右移运算符>>>

a += b;

return a;

}

// MD5的主计算过程,input是需要变换的二进制字节串,inputlen是长度

private void md5Update(byte[] input, int inputLen) {

int i = 0, index, partLen;

byte[] block = new byte[64]; // 分配64个字节缓冲区

// 根据count计算index值。这里long型数据右移时使用无符号右移运算符>>>

index = (int) (count[0] >>> 3) & 0x3F;

if ((count[0] += (inputLen << 3)) < (inputLen << 3)) {

count[1]++;

}

count[1] += (inputLen >>> 29); // 这里int型数据右移时使用无符号右移运算符>>>

partLen = 64 - index; // 计算partLen值

if (inputLen >= partLen) {

md5Memcpy(buffer, input, index, 0, partLen);

md5Transform(buffer);

for (i = partLen; i + 63 < inputLen; i += 64) {

md5Memcpy(block, input, 0, i, 64);

md5Transform(block);

}

index = 0;

} else {

i = 0;

}

md5Memcpy(buffer, input, index, i, inputLen - i);

}

// 整理和填写输出结果,结果放到数组digest中。

private void md5Final() {

byte[] bits = new byte[8];

int index, padLen;

Encode(bits, count, 8);

index = (int) (count[0] >>> 3) & 0x3f; // 这里long型数据右移时使用无符号右移运算符>>>

padLen = (index < 56) ? (56 - index) : (120 - index);

md5Update(PADDING, padLen);

md5Update(bits, 8);

Encode(digest, state, 16);

}

// byte数组的块拷贝函数,将input数组中的起始位置为inpos,长度len的数据拷贝到output数组起始位置outpos处。

private void md5Memcpy(byte[] output, byte[] input, int outpos, int inpos, int len) {

int i;

for (i = 0; i < len; i++) {

output[outpos + i] = input[inpos + i];

}

}

// MD5核心变换计算程序,由md5Update函数调用,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);

// 进行4级级联运算

// 第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 */

// 第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 */

// 第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 */

// 第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],state[1],state[2],state[3]

state[0] += a;

state[1] += b;

state[2] += c;

state[3] += d;

}

// 把byte型数据转换为无符号long型数据

private static long byteToul(byte b) {

return b > 0 ? b : (b & 0x7F + 128);

}

// 把byte类型的数据转换成十六进制ASCII字符表示

private static String byteToHEX(byte in) {

char[] DigitStr = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

char[] out = new char[2];

out[0] = DigitStr[(in >> 4) & 0x0F]; // 取高4位

out[1] = DigitStr[in & 0x0F]; // 取低4位

String s = new String(out);

return s;

}

// 将long型数组按顺序拆成byte型数组,长度为len

private void Encode(byte[] output, long[] input, int len) {

int i, j;

for (i = 0, j = 0; j < len; i++, j += 4) {

output[j] = (byte) (input[i] & 0xffL);

output[j + 1] = (byte) ((input[i] >>> 8) & 0xffL);

output[j + 2] = (byte) ((input[i] >>> 16) & 0xffL);

output[j + 3] = (byte) ((input[i] >>> 24) & 0xffL);

}

}

// 将byte型数组按顺序合成long型数组,长度为len

private void Decode(long[] output, byte[] input, int len) {

int i, j;

for (i = 0, j = 0; j < len; i++, j += 4) {

output[i] = byteToul(input[j]) | (byteToul(input[j + 1]) << 8) | (byteToul(input[j + 2]) << 16) | (byteToul(input[j + 3]) << 24);

}

return;

}

}

通过上面的代码,我们就就可以使用MD5加密校验数据了。

MD5加密文件:

在讲解MD5加密文件之前,我想问一个问题:MD5加密文件是不是就是加密文件中的内容,而文件名称或是结构无关呢?

下面我们来做一个小实验:

1.我们新建一个文件a.txt,内容为"Hello MD5!",保存退出

2.另外复制三份文件,分别命名为:b.txt,c.dat,d.txt

3.b.txt和c.dat与a.txt唯一不同的是名称;d.txt中将内容修改为"Hello MD5."

4.分别加密这4份文件:

public static void main(String[] args) {

String value = "";

File file = new File("F:/Temp/zip/c.dat");

value = Md5Util.getMd5ByFile(file);

System.out.println(value);

file = new File("F:/Temp/zip/b.txt");

value = Md5Util.getMd5ByFile(file);

System.out.println(value);

file = new File("F:/Temp/zip/a.txt");

value = Md5Util.getMd5ByFile(file);

System.out.println(value);

file = new File("F:/Temp/zip/d.txt");

value = Md5Util.getMd5ByFile(file);

System.out.println(value);

}

5.加密结果如下:

281d077ae77948c2c8533c01eeffd2d5

281d077ae77948c2c8533c01eeffd2d5

281d077ae77948c2c8533c01eeffd2d5

f146f3d71763ec95d9d6c1873927514c

说明加密文件的实质就是加密文件中的内容,与其他因素无关。

那么你可能就会问一个问题,这样的话,那么我们在加密文件的时候是不是就是把文件中的内容全部读到内存中,然后再把这个内存中的数据进行MD5加密呢?答案是正确的。不过这里有一个问题,需要我们解决:上面的例子只是一个很小的文件,那么如果我的文件很大呢?我们要怎么解决加密大文件下的效率问题?

使用Java中普通的文件读写已经不行了,那么是不是有更好的办法呢?答案是肯定的,那就是内存映射。Java已经提供了相应的接口,在良好的封装机制下,代码量就减少了很多了。如下过程:

/**

* 加密文件 2015年7月1日 上午12:06:37

*/

public static String getMd5ByFile(File file) {

String value = null;

FileInputStream in = null;

try {

in = new FileInputStream(file);

} catch (FileNotFoundException e1) {

e1.printStackTrace();

}

try {

MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());

MessageDigest md5 = MessageDigest.getInstance("MD5");

md5.update(byteBuffer);

BigInteger bi = new BigInteger(1, md5.digest());

value = bi.toString(16);

} catch (Exception e) {

e.printStackTrace();

} finally {

if (null != in) {

try {

in.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

return value;

}

说明:

文章中的使用的代码来源于实验楼。

md5加密校验 java_Java实现MD5加密和文件校验相关推荐

  1. android sha1校验工具,【原创实用】文件校验工具V1.2.1:支持MD5 SHA1 SHA256

    前言:这个程序其实我很早以前(大概上上周?)就已经完成了 但是没有发布,因为我还想不断打磨打磨. 先别走,结尾还有彩蛋 现如今相较第一个版本,已经进行如下改动: 解决clear之后后台线程依然未停止的 ...

  2. md5校验 java_java生成MD5校验码

    在Java中,java.security.MessageDigest (rt.jar中)已经定义了 MD5 的计算,所以我们只需要简单地调用即可得到 MD5 的128 位整数.然后将此 128 位计 ...

  3. Java实现MD5加密和文件校验

    MD5简介: MD5的全称:Message-Digest Algorithm 5(信息-摘要算法5) MD5的加密方式是一种哈希加密.一些主流的编程语言都已经实现了MD5的加密,所以如果你的程序或是系 ...

  4. md5碰撞Java_java现在MD5加密不安全了吗?

    泻药, 首先,md5 和Java无关,md5是一种摘要算法(和加密有区别),Java是一种编程语言,你可以说可以用Java实现一个md5摘要函数. 其次,重申md5不是加密,而是摘要, 加密只有可以解 ...

  5. Java使用MD5加盐对密码进行加密处理,附注册和登录加密解密处理

    前言 在开发的时候,有一些敏感信息是不能直接通过明白直接保存到数据库的.最经典的就是密码了.如果直接把密码以明文的形式入库,不仅会泄露用户的隐私,对系统也是极其的不厉,这样做是非常危险的. 那么我们就 ...

  6. php md5加密(并小写),PHP常见加密函数用法示例【crypt与md5】

    本文实例讲述了PHP常见加密函数用法.分享给大家供大家参考,具体如下: 1.crypt()函数 crypt()函数用于返回使用DES.Blowfish或MD5算法加密过后的字符串,crypt(str, ...

  7. 使用crypto模块实现md5加密功能(解决中文加密前后端不一致的问题)

    使用crypto模块实现md5加密功能(解决中文加密前后端不一致的问题) 参考文章: (1)使用crypto模块实现md5加密功能(解决中文加密前后端不一致的问题) (2)https://www.cn ...

  8. openssl算法 —— 利用openssl进行BASE64编码解码、md5/sha1摘要、AES/DES3加密解密

    openssl 加密字符串的方法: 一.利用openssl命令进行BASE64编码解码(base64 encode/decode): 1. BASE64编码命令 对字符串'abc'进行base64编码 ...

  9. openssl md5算法 —— Linux下(字符串加密、文件加密)

    理解openssl md5: OpenSSL 是一个安全套接字层密码库,囊括主要的密码算法.常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用. OpenSSL被曝出现 ...

最新文章

  1. CRF算法中辅助概念 团 极大团 最大团
  2. c:if test=/c:if 使用
  3. 超越Android:探索Kotlin的应用领域
  4. nginx 1.16 配置反向代理,http,https,ssl
  5. 【registry】Reader schema missing default value for field: age
  6. PS:oracle恢复删除的数据
  7. 小鹏汽车面试经验分享
  8. js模块化编程发展历程
  9. 泰克示波器入门级TBS1102C+电流探头TCP2020方案
  10. ArcGIS jsAPI 本地部署字体符号乱码
  11. 微信小程序页面回到顶端的方式
  12. HOJ 1568 Fibonacci(对数,数列通项公式)
  13. 校园网免认证软件无为WiFi卡DNS解决教程
  14. 歌剧《猫》的经典唱段《memory》中英文对照
  15. 程序员才懂的58张图片,哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈
  16. 阿尔茨海默最新研究进展(2022年12月)
  17. 日语输入法键盘假名对应表
  18. thymeleaf数据回显,单选回填,下拉回填,时间框回填
  19. 有趣好玩实用的网站 保证闻所未闻
  20. WordPress能承载多大的数据?文章十万百万能承载吗?

热门文章

  1. 首次曝光:大厂都是这样过1024的,看的我酸了
  2. 干货来袭!3天0基础Python实战项目快速学会人工智能必学数学基础全套(含源码)(第3天)概率分析篇:条件概率、全概率与贝叶斯公式
  3. 删除文件夹时,报错“错误ox80070091:目录不是空的”,该如何解决?
  4. The following packages have unmet dependencies
  5. win7+opencv+V2015环境搭建
  6. Butter Knife[黄油刀]配置
  7. [Java练习] 学生查询系统
  8. SpyNote V5.0图形化工具远程控制Android手机教程(图文教程+演示视频)
  9. Arcgis教程:如何批量统计网格内的线段长度。
  10. Stream流、方法引用知识梳理