目录
1. 哈希
1.1 哈希的概念
哈希(Hash)又称散列,是一种将任意长度的数据映射为固定长度的数据的方法。哈希函数(Hash Function)是用来实现哈希的算法,它将输入数据映射为哈希值(Hash Value)或哈希码(Hash Code),通常是一个固定长度(如32位、64位等)的整数(16进制)。
哈希值(Hash Value),也称为散列值、摘要或指纹,是将任意长度的二进制数据通过哈希算法(Hash Function)转换成固定长度的唯一值的过程。哈希值通常用于数据的完整性验证、密码存储和比较、数据分片和负载均衡等场景。
哈希算法是一种将任意长度的输入消息转换成固定长度输出消息的算法,通常用于实现散列函数。常见的哈希算法有MD5、SHA-1、SHA-256等。哈希值具有以下特点:
-
唯一性:对于不同的输入数据,哈希算法生成的哈希值是唯一的。
-
固定长度:哈希算法生成的哈希值长度是固定的。例如,MD5算法生成的哈希值长度为128位,SHA-1算法生成的哈希值长度为160位。
-
不可逆性:由哈希值无法推算出原始输入数据的内容,也就是说,哈希值不包含原始数据的信息。
-
抗碰撞性:由于哈希算法的输出空间相对输入空间较小,因此存在多组输入数据对应同一个哈希值的情况,这被称为“碰撞”。好的哈希算法应该具有较高的抗碰撞性,即在输入空间中难以找到两个相同的哈希值。
1.2 哈希的特点
-
输入数据相同,输出的哈希值也相同。
-
输入数据不同,输出的哈希值也不同。
-
哈希函数执行速度快,适合处理大量数据。(如何理解,哈希值是16进制整数,可作索引)
1.3 哈希的应用
-
数据加密:哈希函数可以将明文数据转换为密文数据,用于数据加密和安全存储。
-
数据校验:哈希函数可以用于数据校验,例如,在文件传输中,可以使用哈希函数计算文件的哈希值,然后将哈希值传输给对方,对方接收到文件后再次计算哈希值,如果两个哈希值相同,则说明文件传输正确无误。
-
数据索引:哈希函数可以用于数据索引,例如,在哈希表中,可以使用哈希函数将键转换为对应的索引,从而快速访问数据。
需要注意的是,哈希函数虽然可以将任意长度的数据映射为固定长度的哈希值,但是由于哈希函数的输出空间是有限的,因此不可避免地存在哈希冲突(即不同的输入数据映射为相同的哈希值)。因此,在使用哈希函数时,需要考虑哈希冲突的问题,并采取相应的解决措施,例如使用开放地址法、链式法等哈希碰撞解决方法。
1.4 哈希算法
1.4.1 MD5
以下是一个使用MD5算法计算字符串哈希值的Java示例代码:
package com.zhaoxi.test;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@SpringBootTest
public class MD5Test {
String input = "Hello, world!";
// 创建MessageDigest对象并指定哈希算法为MD5
MessageDigest md;
@Test
void toMD5(){
try {
md = MessageDigest.getInstance("MD5");
// 计算字符串的哈希值
byte[] mdBytes = md.digest(input.getBytes());
// 将字节数组转换成十六进制字符串
BigInteger number = new BigInteger(1, mdBytes);
String hash = number.toString(16);
// 输出哈希值
System.out.println("Input string: " + input);
System.out.println("MD5 hash value: " + hash);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}
输出结果
Input string: Hello, world!
MD5 hash value: 6cd3556deb0da54bca060b4c39479839
在这个示例中,我们使用了Java的MessageDigest类来计算字符串的MD5哈希值。具体步骤包括:
-
创建MessageDigest对象并指定哈希算法为MD5。
-
将待计算哈希值的字符串转换成字节数组,然后调用digest方法计算哈希值。
-
将字节数组转换成十六进制字符串,用于可视化输出。
-
输出原始字符串和哈希值。
1.4.2 SHA-1
@Test
void toSHA_1(){
String input = "Hello, world!";
try {
// 创建MessageDigest对象并指定哈希算法为SHA-1
MessageDigest md = MessageDigest.getInstance("SHA-1");
// 计算字符串的哈希值
byte[] mdBytes = md.digest(input.getBytes());
// 将字节数组转换成十六进制字符串
BigInteger number = new BigInteger(1, mdBytes);
String hash = number.toString(16);
// 输出哈希值
System.out.println("Input string: " + input);
System.out.println("SHA-1 hash value: " + hash);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
输出结果如下:
Input string: Hello, world!
SHA-1 hash value: 943a702d06f34599aee1f8da8ef9f7296031d699
1.4.3 SHA-256
与以上类似,修改MessageDigest.getInstance("SHA-256");
相比之下MD5算法比较不安全,所以建议使用后面两种。如果使用MD5建议在加一定盐(salt),并且一般封装成单独工具类使用