2.Java 加解密技术系列之 MD5
Java 加解密技术系列之 MD5
- 序
- 背景
- 正文
- 结束语
序
BASE64,也简单的提了一下编码的原理。这篇文章继续加解密的系列,当然也是介绍比较基础的加密方式 — — MD5,MD5 属于单向加密算法,是不可逆的加密方式,也就是说,采用了 MD5 加密方式加密之后,就不能对加密的结果进行解密,得到原有的字符串,这是不可以的。
背景
中,MD5 用到的还是很广泛的。在说 MD5 之前,首先来了解一下单向加密算法都有哪些。当然,MD5 是其中之一,除此之外还有,SHA,HMAC
等这几种算法。不过,今天这篇文章,我们只介绍 MD5,至于 SHA 和 HMAC 在后续的文章中会陆续的介绍。
正文
“Message Digest Algorithm
5”,中文名“消息摘要算法第五版”,它是计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。严格来说,它是一种摘要算法,是确保信息完
整性的。不过,在某种意义上来说,也可以算作一种加密算法。
- MD5 的作用是让大容量信息在用数字签名软件签署私人密钥前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的十六进制数字串)。
其实在我们生活中是很常用的,似乎你并没有注意到,当你下载了一个镜像之后,你会发现下载页面还提供了一组 MD5 值,那么这组 MD5
值是用来做什么的呢?了解了 MD5 的作用之后,你就不难想到,MD5 是用来验证文件的一致性的,当你下载好镜像之后,你需要对该镜像做一次 MD5
的校验,得到的 MD5 值与下载页面提供的 MD5 值进行对比,以此来验证该镜像是否被篡改。
算法中,首先需要对信息进行填充,使其位长对 512 求余的结果等于 448,并且填充必须进行,即使其位长对 512 求余的结果等于
448。因此,信息的位长(Bits Length)将被扩展至 N * 512 + 448,N 为一个非负整数,N 可以是零。
循环有四轮,每轮循环都很相似。第一轮进行 16 次操作。每次操作对 a、b、c 和 d
中的其中三个作一次非线性函数运算,然后将所得结果加上第四个变量,文本的一个子分组和一个常数。再将所得结果向左环移一个不定的数,并加上 a、b、c
或 d 中之一。最后用该结果取代 a、b、c
或 d 中之一。
代码
public class MD5 {
/**
* 单例
*/
private static MD5 instance;
/**
* 四个链接变量
*/
private final int A = 0x67452301;
private final int B = 0xefcdab89;
private final int C = 0x98badcfe;
private final int D = 0x10325476;
/**
* ABCD的临时变量
*/
private int Atemp;
private int Btemp;
private int Ctemp;
private int Dtemp;
/**
* 常量ti
* 公式:floor(abs(sin(i+1))×(2pow32)
*/
private final int[] K = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 0x698098d8,
0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193,
0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, 0x265e5a51,
0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905,
0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681,
0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60,
0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244,
0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314,
0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
};
/**
* 向左位移数,计算方法未知
*/
private 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 MD5() {
}
/**
* 单例模式
* @return
*/
public static MD5 getInstance() {
if (instance == null) {
instance = new MD5();
}
return instance;
}
/**
* 初始化函数
*/
private void init() {
Atemp = A;
Btemp = B;
Ctemp = C;
Dtemp = D;
}
/**
* 移动一定位数
* @param a
* @param s
* @return
*/
private int shift(int a, int s) {
return (a << s) | (a >>> (32 - s)); // 右移的时候,高位一定要补零,而不是补充符号位
}
/**
* 主循环
* @param M
*/
private void mainLoop(int[] M) {
int F;
int g;
int a = Atemp;
int b = Btemp;
int c = Ctemp;
int d = Dtemp;
for (int i = 0; i < 64; i++) {
if (i < 16) {
F = (b & c) | ((~b) & d);
g = i;
}else if (i < 32) {
F = (d & b) | ((~d) & c);
g = (5 * i + 1) % 16;
}else if (i < 48) {
F = b ^ c ^ d;
g = (3 * i + 5) % 16;
} else {
F = c ^ (b | (~d));
g = (7 * i) % 16;
}
int tmp = d;
d = c;
c = b;
b = b + shift(a + F + K[i] + M[g], s[i]);
a = tmp;
}
Atemp += a;
Btemp += b;
Ctemp += c;
Dtemp += d;
}
/**
* 填充函数
* 处理后应满足bits≡448(mod512),字节就是bytes≡56(mode64)
* 填充方式为先加一个0,其它位补零
* 最后加上64位的原来长度
* @param str
* @return
*/
private int[] add(String str) {
int num = ((str.length() + 8) / 64) + 1; // 以512位,64个字节为一组
int[] strByte = new int[num * 16]; // 64/4=16,所以有16个整数
for (int i = 0; i < num * 16; i++) {
// 全部初始化为0
strByte[i] = 0;
}
int j;
for (j = 0; j < str.length(); j++) {
strByte[j >> 2] |= str.charAt(j) << ((j % 4) * 8); // 一个整数存储四个字节,小端序
}
strByte[j >> 2] |= 0x80 << ((j % 4) * 8); // 尾部添加1
// 添加原长度,长度指位的长度,所以要乘8,然后是小端序,所以放在倒数第二个,这里长度只用了32位
strByte[num * 16 - 2] = str.length() * 8;
return strByte;
}
/**
* 调用函数
* @param source 原始字符串
* @return
*/
public String getMD5(String source) {
// 初始化
init();
int[] strByte = add(source);
for (int i = 0; i < strByte.length / 16; i += 16) {
int[] num = new int[16];
for (int j = 0; j < 16; j++) {
num[j] = strByte[i * 16 + j];
}
mainLoop(num);
}
return changeHex(Atemp) + changeHex(Btemp) + changeHex(Ctemp) + changeHex(Dtemp);
}
/**
* 整数变成16进制字符串
* @param a 整数
* @return
*/
private String changeHex(int a) {
String str="";
String tmp = "";
for(int i=0;i<4;i++) {
tmp = Integer.toHexString(((a >> i * 8) % (1 << 8)) & 0xff);
if (tmp.length() < 2) {
tmp = "0" + tmp;
}
str += tmp;
}
return str;
}
/**
* 测试方法
* @param args
*/
public static void main(String[] args) {
String str = MD5.getInstance().getMD5("");
String str1 = MD5.getInstance().getMD5("123");
System.out.println(str);
System.out.println("d41d8cd98f00b204e9800998ecf8427e");
System.out.println(str1);
System.out.println("202cb962ac59075b964b07152d234b70");
}
}
结束语
MD5,但你从来没有注意过,到底什么才是 MD5。也或许你知道什么是 MD5,但或许你并不了解 MD5
是作何用的。那么,从今天起,从你读完这篇博客起,我相信,以后再见到 MD5 的时候,你肯定会对它印象深刻,再下载文件的时候,也会对它进行 MD5
的一致性校验。那么,我就可以说,我的这篇文章还是起到了一丁点的作用。
2.Java 加解密技术系列之 MD5的更多相关文章
- Java 加解密技术系列文章
Java 加解密技术系列之 总结 Java 加解密技术系列之 DH Java 加解密技术系列之 RSA Java 加解密技术系列之 PBE Java 加解密技术系列之 AES Java 加解密技术系列 ...
- 7.java 加解密技术系列之 AES
java 加解密技术系列之 AES 序 概念 原理 应用 代码实现 结束语 序 这篇文章继续介绍对称加密算法,至于今天的主角,不用说,也是个厉害的角色 — — AES.AES 的出现,就是为了来替代原 ...
- 5.Java 加解密技术系列之 DES
Java 加解密技术系列之 DES 序 背景 概念 基本原理 主要流程 分组模式 代码实现 结束语 序 前 几篇文章讲的都是单向加密算法,其中涉及到了 BASE64.MD5.SHA.HMAC 等几个比 ...
- 4.Java 加解密技术系列之 HMAC
Java 加解密技术系列之 HMAC 序 背景 正文 代码 结束语 序 上一篇文章中简单的介绍了第二种单向加密算法 — —SHA,同时也给出了 SHA-1 的 Java 代码.有这方面需求的童鞋可以去 ...
- 3.Java 加解密技术系列之 SHA
Java 加解密技术系列之 SHA 序 背景 正文 SHA-1 与 MD5 的比较 代码实现 结束语 序 上一篇文章中介绍了基本的单向加密算法 — — MD5,也大致的说了说它实现的原理.这篇文章继续 ...
- 11.Java 加解密技术系列之 总结
Java 加解密技术系列之 总结 序 背景 分类 常用算法 原理 关于代码 结束语 序 上一篇文章中简单的介绍了第二种非对称加密算法 — — DH,这种算法也经常被叫做密钥交换协议,它主要是针对密钥的 ...
- 10.Java 加解密技术系列之 DH
Java 加解密技术系列之 DH 序 概念 原理 代码实现 结果 结束语 序 上一篇文章中简单的介绍了一种非对称加密算法 — — RSA,今天这篇文章,继续介绍另一种非对称加密算法 — — DH.当然 ...
- 9.Java 加解密技术系列之 RSA
Java 加解密技术系列之 RSA 序 概念 工作流程 RSA 代码实现 加解密结果 结束语 序 距 离上一次写博客感觉已经很长时间了,先吐槽一下,这个月以来,公司一直在加班,又是发版.上线,又是新项 ...
- 8.Java 加解密技术系列之 PBE
Java 加解密技术系列之 PBE 序 概念 原理 代码实现 结束语 序 前 边的几篇文章,已经讲了几个对称加密的算法了,今天这篇文章再介绍最后一种对称加密算法 — — PBE,这种加密算法,对我的认 ...
随机推荐
- HTML5基础学习
分享一下html5的一些基础,小白上路! 一.html5基本结构 <!DOCTYPE html> ↑声明文档类型为HTML5文件. 文档声明,在HTML文档必不可少.且必须放在文档第一行 ...
- 修改Gradle 和Maven本地仓库的位置 方法
关于Maven的配置: 用过Maven的兄弟应该知道Maven可以通过配置 conf文件夹下面的settings.xml文件来修改maven下载的包,默认是下在c盘的用户文件夹下的.m2中,日积月累. ...
- Node.js基本开发流程
创建一个hello world: 1.打开一个文本编辑器,在其中输入console.log("hello world"),并保存为hello.js; 注意:输入中文如果编码不是ut ...
- 使用PCA + KNN对MNIST数据集进行手写数字识别
首先引入需要的包 %matplotlib inline import numpy as np import scipy as sp import pandas as pd import matplot ...
- [No0000E9]Microsoft Help Viewer 2.3绿色版
今天没事,提取了一下2017的Microsoft Help Viewer 2.3绿色版,自测没发现什么问题,有问题请后补. 下载地址:http://files.cnblogs.com/files/Ch ...
- STM32F4XX与STM32F0XX编程差别
//普通管脚初始化 /*****************************************************************************STM32F0***** ...
- 热爱H5
我不去想是否能够功成名就既然选择了前端便只顾埋头于无声 我不去想能否赢得掌声既然钟情于IT就勇敢得踏步前行 我不去想前行的路上会不会日暮穷途既然目标是未来留给现在的只能是汗水 我不去想所谓的成功是不是 ...
- 基于vue2.0前端组件库element中 el-form表单 自定义验证填坑
eleme写的基于vue2.0的前端组件库: http://element.eleme.io 我在平时使用过程中,遇到的问题. 自定义表单验证出坑: 1: validate/resetFields 未 ...
- [原创]一种基于Python爬虫和Lucene检索的垂直搜索引擎的实现方法介绍
声明:本文首发在博客园晨星落羽,Shulin_Cao和lvmememe首页,转载请注明出处. 前言 2016.5到2017.5,我们三人(lvmememe,Shulin_Cao,晨星落羽)共同完成了一 ...
- 前端工作日常爬坑之——单页面微信开发Jssdk相关,以及jssdk图片直传自己服务器的实现。
日常爬坑 遇到的情况大致说明: 项目基于Vue2全家桶实现,vue-router控制前端路由,路由模式是History(主要是领导追求太高,觉得hash带#号太丑,然后遇到了小坑...),主要是服务于 ...