MD5加密详解

MD5全称:message-digest algorithm 5 

翻译过来就是:信息 摘要 算法 5

1.特点

  • 1.长度固定:

    不管多长的字符串,加密后长度都是一样长 

    作用:方便平时信息的统计和管理

    详解:经过MD5加密生成一个固定长度为128bit的串。因为12801的二进制串表达不友好,因此转化为了16进制,128/4 = 32位的16进制。将32位去掉前8位和后8位得到的是16位。因此会有MD532 16位加密说法

  • 2.易计算:

    字符串和文件加密的过程是容易的

    作用开发者很容易理解和做出加密工具

  • 3.细微性

    一个文件,不管多大,小到几k,大到几G,只要改变里面某个字符,那么都会导致MD5值改变. 

    作用:很多软件和应用在网站提供下载资源,其中包含了对文件的MD5,用户下载后只需要用工具测一下下载好的文件,通过对比就知道该文件是否有过更改变动.

  • 4.不可逆性

    你明明知道密文和加密方式,你却无法反向计算出原密码

    作用:基于这个特点,很多安全的加密方式都是用到.大大提高了数据的安全性

    不可逆的原因:摘要是部分内容,因此由MD5的密文和加密方式会得到很多明文,而无法确定明文。

    一个原始数据,只对应一个md5值;但是一个md5值,可能对应多个原始数据。

    补充:MD5常用于字符串和文件的加密

2.撞库

  • 关于撞库破解:

    这是概率极低的破解方法,原理就是:

    1.建立一个大型的数据库,把日常的各个语句,通过MD5加密成为密文,不断的积累大量的句子,放在一个庞大的数据库里.

    2.比如一个人拿到了别人的密文,想去查询真实的密码,就需要那这个密文去到提供这个数据库的公司网站去查询.

    这就是撞库的概念.

3.关于MD5加盐:

比如我的银行密码是"12345"

1.得到的MD5:827ccb0eea8a706c4c34a16891f84e7b

2.一个人截取到这个密文,那么通过撞库肯定容易撞出12345.

3.我们要做的就是加盐,银行密码还是"12345",然后我把银行密码加上我特定的字符串才计算MD5 
所以密码还是那个密码,但是变成求"12345密码加密987"MD5,然后再得到MD5,那么这个MD5起码可以确认那个数据库不会有.

4.MD5工具的制作

我们一般加密都是加密字符串或者文件,所以我们的工具就有加密字符串和文件的两种方法,两个方法同名,通过重载完成

1.加密字符串

逻辑思维:

  • 1.获取信息摘要对象:md5

    通过信息摘要单例的构造函数获取:

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

  • 2.信息摘要对象是对字节数组进行摘要,所以先获取字符串的字节数组.
  • byte[] bytes = str.getBytes();
  • 3.信息摘要对象对字节数组进行摘要,得到摘要字节数组:
  • byte[] digest = md5.digest(bytes);
  • 4.摘要数组中的每一个字节转换成16进制,并拼在一起就得到了MD5. (PS,有些转换过来得到的是前面6f的情况,:ffffff82,这是因为前面有641,所以提前把这61111先变成0就好了,然后再转16进制就没有f
    (
    其实也可以在后面续把f去掉)

2.加密文件

方法传入的是文件对象 : file

  • 1.因为是文件不是方法,所以不是像刚才那样通过摘要获取字符串.
  • 2.使用到另一个方法即可:就是信息摘要对象更新:md5.update(byte[] input)方法,用法是通过读取流,不断的更新从流中读到的"信息数组".
  • 3.然后通过"信息摘要对象"获取摘要,不用参数:md5.digest(),此时返回的数组就已经是包含内容的摘要数组

以下是详细代码:

public class MD5Tool {

public static void main(String[] args) throws Exception {

/*--------------字符串--------------*/

String str = "12345";

String md1 = getMD5(str);

System.out.println(md1);//827ccb0eea8a706c4c34a16891f84e7b

 

/*--------------文件--------------*/

File file = new File("D:\\1.mp3");

String md2 = getMD5(file);

System.out.println(md2);//9068aaead9a5b75e6a54395d8183ec9

}

/**

* 逻辑:

*

* 1.获取md5对象,通过"信息摘要"获取实例构造("MD5").

* 2.md5对象对("字符串的"字节形式"-得到的数组)进行摘要",那么会返回一个"摘要的字节数组"

* 3.摘要字节数组中的"每个二进制值"字节形式,"转成十六进制形式",然后再把这些值给拼接起来,就是MD5值了

* (PS:为了便于阅读,把多余的fff去掉,并且单个字符前加个0)

*

*/

//加密字符串

public static String getMD5(String str) throws Exception {

String MD5 = "";

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

byte[] bytes = str.getBytes();

byte[] digest = md5.digest(bytes);

for (int i = 0; i < digest.length; i++) {

//摘要字节数组中各个字节的"十六进制"形式.

int j = digest[i];

j = j & 0x000000ff; //去掉符号

String s1 = Integer.toHexString(j);

 

if (s1.length() == 1) {

s1 = "0" + s1; //统一格式

}

MD5 += s1;

}

return MD5;

}

//或者

 

 

//重载,所以用户传入"字符串"或者"文件"都可以解决.

public static String MD5(String str) {

String MD5 = "";

MessageDigest md5 = null;

try {

md5 = MessageDigest.getInstance("MD5");

byte[] bytes = str.getBytes();

byte[] digest = md5.digest(bytes);

for (int i = 0; i < digest.length; i++) {

//摘要字节数组中各个字节的"十六进制"形式.

int j = digest[i];

j = j & 0x000000ff;

String s1 = Integer.toHexString(j);

 

if (s1.length() == 1) {

s1 = "0" + s1;

}

MD5 += s1;

}

return MD5;

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

return "";

}

 

}

 

/**

* 处理逻辑:

* 1.现在传入的是"文件",不是字符串

* 2.所以信息摘要对象.进行摘要得到数组不能像上面获得:md5.digest(bytes),因为不是str.getBytes得到bytes

* 3.其实还是通过mdt.digest();获取到字节数组,但是前期必须要有一个方法必须是md5.update(),"信息摘要对象"要先更新

* 4."信息摘要更新"里面有(byte[] input),说明是读取流获取到的数组,所以我们就用这个方法.

* 5.所以最终的逻辑就是:

*

* 1.获取文件的读取流

* 2.不停的读取流中的"内容"放入字符串,放一部分就"更新"一部分.直到全部完毕

* 3.然后调用md5.digest();就会得到有内容的字节数组,剩下的就和上边一样了.

*/

//加密文件

public static String getMD5(File file) throws Exception {

String MD5 = "";

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

FileInputStream fis = new FileInputStream(file);

byte[] bytes = new byte[1024 * 5];

int len = -1;

while ((len=fis.read(bytes))!=-1) {

//一部分一部分更新

md5.update(bytes, 0, len);

}

byte[] digest = md5.digest();

for (int i = 0; i <digest.length; i++) {

int n = digest[i] & 0x000000ff;

String s = Integer.toHexString(n);

MD5 += s;

}

return MD5;

}

}

 

 

或者

/**

* @param urlPath wx图片url转路径

* @return 返回文件名

*/

public static String getFileName(String urlPath) {

try {

// Create MD5 Hash

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

digest.update(urlPath.getBytes());

byte messageDigest[] = digest.digest();

 

// Create Hex String

StringBuilder hexString = new StringBuilder();

for (int i = 0; i < messageDigest.length; i++)

hexString.append(Integer.toHexString(0xFF & messageDigest[i]));

return hexString.toString();

 

} catch (NoSuchAlgorithmException e) {

e.printStackTrace();

}

Random random = new Random();

StringBuilder sb = new StringBuilder("abc");

sb.append(String.valueOf(random.nextInt(100)));

sb.append(String.valueOf(random.nextInt(100)));

sb.append(String.valueOf(random.nextInt(100)));

sb.append(String.valueOf(random.nextInt(100)));

return sb.toString();

}

拓展

0xfffffff代表的含义:

  • 0x:代表16进制;
  • 一个f代表:41,(1111);
  • 所以0xffffffff代表:841
  • 1111 - 1111 - 1111 - 1111 - 1111 - 1111 - 1111 - 1111
  • 所以刚才的0xffffff82就是前面6组都是1,后面两组是
  • 1111 - 1111 - 1111 - 1111 - 1111 - 1111 - 0111 - 0010
  • 所以先与上0x000000ff,
  • 0000 - 0000 - 0000 - 0000 - 0000 - 0000 - 1111 - 1111
  • 就得到了82

上面的方法也可以写写成:

for (int i = 0; i < digest.length; i++) {

//摘要字节数组中各个字节的"十六进制"形式.

String s1 = Integer.toHexString( digest[i]);

 

//如果是8个长度的,把前面的6f去掉,只获取后面的

if (s1.length() == 8) {

s1 = s1.substring(6);

}

if (s1.length() == 1) {

s1 = "0" + s1;

}

MD5 += s1;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值