一、使用场景
-
检测文件是否被篡改:
在文件上传到服务器的时候,我们希望能够获得文件的指纹以确定文件没有被篡改过 -
不存储重复文件信息:
在文件上传到服务器的时候,为了节省服务器的存储空间,我们可以对文件指纹进行比对,存在的指纹文件,无需再次保存到文件服务器
二、加密算法
-
常用哈希算法:
MD4
1990 年,输出 128 位(已经不安全)MD5
1991 年,输出 128 位(已经不安全)SHA-0
1993 年 输出 160 位(发布之后很快就被 NSA 撤回,是 SHA-1 的前身)SHA-1
1995 年,输出 160 位(已经不安全)SHA-2
包括:SHA-224
、SHA-256
、SHA-384
、SHA-512
,分别输出 224、256、384、512 位(目前安全)
-
哈希算法特点:
- 正像快速:原始数据可以快速计算出哈希值
- 逆向困难:通过哈希值基本不可能推导出原始数据
- 输入敏感:原始数据只要有一点变动,得到的哈希值差别很大
- 冲突避免:很难找到不同的原始数据得到相同的哈希值
三、源码演示
-
获取目标文件
/** * 读取本地文件到比特数组 * * @param file 文件对象 * @return byte[] 文件数组 */ public static byte[] readRandomAccess(File file) throws IOException { // 1、使用 RandomAccessFile 打开文件管道 FileChannel channel = new RandomAccessFile(file, "r").getChannel(); int fileSize = (int) channel.size(); try { // 2、创建 MappedByteBuffer,并使用 NIO 管道进行数据映射,加载数据到物理内存 //load(): 将此缓冲区的内容加载到物理内存中。此方法尽最大努力确保当它返回时,缓冲区的内容驻留在物理内存中。调用此方法可能会导致出现一些页面错误和I/O操作。 MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize).load(); //remaining() 返回当前位置和限制之间的元素数。此缓冲区中剩余的元素数 byte[] result = new byte[fileSize]; if (buffer.remaining() > 0) { // 3、读取数据到 byte 数组中 buffer.get(result, 0, fileSize); } buffer.clear(); return result; } finally { closeChannel(channel); } } private static void closeChannel(FileChannel channel) { try { channel.close(); } catch (IOException e) { e.printStackTrace(); } }
-
采用 MD5 哈希
/** * 生成文件 MD5 指纹 * * @param fileData 文件内容比特数组 * @return java.lang.String 文件内容 MD5 指纹 */ public static String generateFileMd5Hash(byte[] fileData) { return DigestUtils.md5Hex(fileData); }
P.S
DigestUtils.md5Hex
有很多重载,可以根据实际情况选择 -
采用 SHA 哈希
/** * 生成文件 SHA 指纹 * * @param fileData 文件内容比特数组 * @return java.lang.String 文件内容 SHA 指纹 */ public static String generateFileSha256Hash(byte[] fileData) { return DigestUtils.sha256Hex(fileData); }
P.S
DigestUtils.sha256Hex
有很多重载,可以根据实际情况选择 -
演示结果
public static void main(String[] args) throws IOException { File file = new File("/Users/rambo/Desktop/1.txt"); byte[] bytes = readRandomAccess(file); String md5Hash = generateFileMd5Hash(bytes); String shaHash = generateFileSha256Hash(bytes); System.out.println("MD5 指纹:" + md5Hash); System.out.println("SHA 指纹:" + shaHash); }
MD5 指纹:0615ce4d9d3c12bf493bab656dd65dd0 SHA 指纹:b1f63d223f7c733b62243d7f55961ab4ad38d92ec413a03c7bed51288aa22323