MD5是什么?及其它的特点

比较官方的解释大家可以百度,这里我说一下自己的理解。

一.作用:一般用于互联网一种数据的唯一性标识。

二.实体:本身是一个128位的0/1比特。一般被表示为16进制的字符串。4个比特位组成一个16进制字符,因此常常能见到的是(128/4=)32个16进制字符组成的字符串   4951 dd1c bff8 cbbe 4cd4 475c a939 fc8b,当然它实质是一种消息摘要算法

三.特点:

1.完全相同的一段数据,不论时间地点(加密算法相同的条件)加密出的32位的字符串完全相同。

2.加密过程本身就是一个有损的加密过程。因此几乎不能还原出原始数据。安全

补充:一般还原出原始数据都是使用碰撞的方式来还原。意思大概和穷举的意思一样,有足够多的原始数据量,世界上的所有数据用 1~n来表示,把1~n都用MD5计算一遍得1x~nx(x表示计算后得的数)。把1~n当成键值对,把1x~nx放入键值对当得到一个MD5字符串,通过值去找键,就知道是什么数据了。因为你本来就拥有数据,因此才能找到数据。但当你没有原始数据时,想通过128比特的玩意去恢复大于128比特的数据本身就是玩笑,数据量都不一样,至于原理有兴趣的朋友可以研究研究信息论。不想研究的可以回想回想之前学的香农公式。再从这一点去研究。又有大的世界。

3.散列能力巨强。安全

MD5工具类代码:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;

public class MD5Utils {
	public static String getStringMD5(String str) {
		try {
			MessageDigest digest = MessageDigest.getInstance("MD5");
			return new String(encode(digest.digest(str.getBytes())));
		} catch (Exception e) {
			throw new RuntimeException("md5 digest fail:", e);
		}
	}

	public static String getFileMD5(File file) {
		FileInputStream in = null;
		try {
			MessageDigest digest = MessageDigest.getInstance("MD5");
			if (!file.isFile()) {
				throw new RuntimeException("md5 digest fail: file not exists!");
			}
			byte buffer[] = new byte[1024];
			int len;
			in = new FileInputStream(file);
			while ((len = in.read(buffer, 0, 1024)) != -1) {
				digest.update(buffer, 0, len);
			}
			return new String(encode(digest.digest()));
		} catch (Exception e) {
			throw new RuntimeException("md5 digest fail:", e);
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
				}
			}
		}
	}

	private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

	public static char[] encode(byte[] bytes) {
		final int nBytes = bytes.length;
		char[] result = new char[2 * nBytes];

		int j = 0;
		for (int i = 0; i < nBytes; i++) {
			// Char for top 4 bits
			result[j++] = HEX[(0xF0 & bytes[i]) >>> 4];
			// Bottom 4
			result[j++] = HEX[(0x0F & bytes[i])];
		}

		return result;
	}

}

当以上代码加密文件时。即使文件名不同,只要文件内容相同,加密出的MD5完全一致:

测试:

加密一个图片:

 

import java.io.File;
import utils.MD5Utils;

public class MD5Test {
	public static void main(String[] args) {
		//MD5第一次运算 4951dd1cbff8cbbe4cd4475ca939fc8b
		System.out.println(
				MD5Utils.getFileMD5(
						new File("C:\\Users\\anxiaopei\\Desktop\\index.jpg")
						)
				);
		//MD5第二次运算
		System.out.println(
				MD5Utils.getFileMD5(
						new File("C:\\Users\\anxiaopei\\Desktop\\index.jpg")
						)
				);
		//MD5第三次运算
		System.out.println(
				MD5Utils.getFileMD5(
						new File("C:\\Users\\anxiaopei\\Desktop\\index文件名真的不同!.jpg")
						)
				);
		//MD5第四次运算
		System.out.println(
				MD5Utils.getFileMD5(
						new File("C:\\Users\\anxiaopei\\Desktop\\index文件名真的不同!.jpg")
						)
				);
		//1的MD5数为
		System.out.println(
				MD5Utils.getStringMD5(
						"1"
						)
				);
	}
}

结果:

对字符串1的加密,大家使用我的代码在你的机器上做了MD5运算后一定也能得到 c4ca4238a0b923820dcc509a6f75849b

第一次与第二次加密证明了,对相同的文件 不同的时间加密的出相同的MD5

第三四次加密与前两次相同证明在,文件的副本,哪怕文件名不一样,只要文件内容相同,加密的MD5也是相同的。

现在我们来做一个有趣的事。

把图片以记事本打开 更改其中一个字符。再次加密图片(改了一个字符,图片也会打不开,不要使用重要图片做测试),这次我们更改文件的副本里的一个字符。删掉添加更改都可以,随意。这次我就只改一个字符,把最后一个字符“ ? ”删掉。

删掉“?”后我的副本都不能预览了。

 用MD5运算后,可以看到第二行与第三行结果完全不一样,证明了它散列的能力。巨强!可以说百分之零点几的的差别也会导致MD5完全不一样。因此再不考虑碰撞的可能性下,只要两个数据的MD5相同,那我们可以认为这两个数据完全相同。

补充:什么是碰撞?:https://blog.csdn.net/qq_29519041/article/details/84404223

 

说了这么多知道了它唯一标识的能力很强。

既然他的唯一标识能力这么强。

那有个使用场景就是,用来作为文件的唯一标识。比如文件上传时,哪怕你的文件名不一样,经过MD5一下,服务器对比一下存在服务器的文件的MD5码表。就知道你上传的这个文件是否服务器已经存在,qq的秒传也是使用这个方法(我猜的)发现服务器有这个文件后,直接把服务器那个文件传给你要传的人。如果你是上传文件给服务器,那你也得到一个访问服务器那个文件的权限。因为服务器知道你上传的文件就是服务器存着的那个文件,这就是秒传的精髓。当然具体实现消息摘要算法的方式也许会不一样。也许是md其他什么的。

 

  • 16
    点赞
  • 74
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值