哈希(Hash)是一种将任意长度的输入数据映射为固定输出长度的算法。
其特点有
哈希,hash的译文是弄乱的意思,中文润色后也叫散列。
哈希算法,本质就是一种单向散列函数。虽然存在碰撞问题,但该函数的初衷就是不可逆,故依然是单向的。
哈希的应用场景有
要考虑彩虹表攻击
因为哈希算法相同的输入一定得到相同的输出,所以在某种程度上,将预先计算好的key与对应的hash value存起来作为对照表,就成了彩虹表。
那么如何抵御彩虹表呢?可以对每个key生成时额外添加随机值,这种方法称之为:加盐(salt)
因为加盐是对每个加密的内容中添加额外的随机数,以确保加密内容的更加安全,这个随机性带来更强的安全形的同时也带来了加密内容的随机性,随机到的不同的盐值,加密后的结果天差地别,所以,牢记
salt
是之后对该加密内容进行验证的关键所在!
常见的hash算法归类,散列值长度越高,安全性越高。
算法名称 | 散列值bit长度(byte) | 备注 |
---|---|---|
MD5 | 128(16) | |
SHA-1 | 160(20) | |
SHA-224 | 224(28) | |
SHA-256 | 256(32) | |
SHA-384 | 384(48) | |
SHA-512 | 512(64) | |
SHA-512/224 | 224(28) | 由SHA-512算法生成的散列值,截取前224 |
SHA-512/256 | 256(32) | 由SHA-512算法生成的散列值,截取前256 |
SHA3-224 | 224(28) | |
SHA3-256 | 256(32) | |
SHA3-384 | 384(48) | |
SHA3-512 | 512(64) |
简单实现其工具类
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.util.Set;
/**
* 哈希工具类
*
* @author chenchuancheng
* @since 2023/08/28 21:01
*/
public class HashUtils {
private static final String MD5 = "MD5";
private static final String SHA_1 = "SHA-1";
private static final String SHA_224 = "SHA-224";
private static final String SHA_256 = "SHA-256";
private static final String SHA_384 = "SHA-384";
private static final String SHA_512 = "SHA-512";
private static final String SHA3_224 = "SHA3-224";
private static final String SHA3_256 = "SHA3-256";
private static final String SHA3_384 = "SHA3-384";
private static final String SHA3_512 = "SHA3-512";
private static final String SHA3_512_224 = "SHA3-512/224";
private static final String SHA3_512_256 = "SHA3-512/256";
/**
* 列举出jdk可用的hash算法
*/
private static void listJDKAvailableAlgorithms() {
// 获取所有已注册的安全提供程序
Provider[] providers = Security.getProviders();
for (Provider provider : providers) {
System.out.println("Provider: " + provider.getName());
Set<Object> keys = provider.keySet();
for (Object key : keys) {
System.out.println(" Algorithm: " + provider.get(key));
}
}
}
/**
* 摘要十六进制字符串
*
* @param algorithm 算法
* @param dataToHash 需要散列的数据
* @param salt 盐, 相当于在dataToHash后面直接追加了salt
* @return {@link String}
* @throws NoSuchAlgorithmException 没有这样算法异常
*/
public static String digestHexString(String algorithm, String dataToHash, String salt) throws NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
byte[] dataToHashBytes = dataToHash.getBytes(StandardCharsets.UTF_8);
messageDigest.update(dataToHashBytes);
if (!(salt == null || salt.isEmpty())) {
byte[] saltBytes = salt.getBytes(StandardCharsets.UTF_8);
//相当于在原内容dataToHashBytes上,追加了saltBytes
messageDigest.update(saltBytes);
}
byte[] digest = messageDigest.digest();
// 将哈希值转换为十六进制字符串
StringBuilder hexStringBuilder = new StringBuilder();
for (byte b : digest) {
// String hexString = Integer.toHexString(b & 0xff);
// hexStringBuilder.append(hexString);//这个做法转换出来的,比如0f,只会显示为f,并不会补0
/**
* 将byte转换为十六进制字符串
* 0-结果不足指定宽度时,用0填充
* 2-宽度为2
* @see https://stackoverflow.com/questions/2817752/java-code-to-convert-byte-to-hexadecimal
*/
String hexString = String.format("%02x", b);
hexStringBuilder.append(hexString);
}
return hexStringBuilder.toString();
}
public static String digestHexStringByMD5(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(MD5, dataToHash, salt);
}
public static String digestHexStringByMD5(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(MD5, dataToHash, null);
}
public static String digestHexStringBySHA1(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(SHA_1, dataToHash, salt);
}
public static String digestHexStringBySHA1(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(SHA_1, dataToHash, null);
}
public static String digestHexStringBySHA224(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(SHA_224, dataToHash, salt);
}
public static String digestHexStringBySHA224(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(SHA_224, dataToHash, null);
}
public static String digestHexStringBySHA256(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(SHA_256, dataToHash, salt);
}
public static String digestHexStringBySHA256(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(SHA_256, dataToHash, null);
}
public static String digestHexStringBySHA384(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(SHA_384, dataToHash, salt);
}
public static String digestHexStringBySHA384(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(SHA_384, dataToHash, null);
}
public static String digestHexStringBySHA512(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(SHA_512, dataToHash, salt);
}
public static String digestHexStringBySHA512(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(SHA_512, dataToHash, null);
}
public static String digestHexStringBySHA3_224(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(SHA3_224, dataToHash, salt);
}
public static String digestHexStringBySHA3_224(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(SHA3_224, dataToHash, null);
}
public static String digestHexStringBySHA3_256(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(SHA3_256, dataToHash, salt);
}
public static String digestHexStringBySHA3_256(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(SHA3_256, dataToHash, null);
}
public static String digestHexStringBySHA3_384(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(SHA3_384, dataToHash, salt);
}
public static String digestHexStringBySHA3_384(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(SHA3_384, dataToHash, null);
}
public static String digestHexStringBySHA3_512(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(SHA3_512, dataToHash, salt);
}
public static String digestHexStringBySHA3_512(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(SHA3_512, dataToHash, null);
}
public static String digestHexStringBySHA3_512_224(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(SHA3_512_224, dataToHash, salt);
}
public static String digestHexStringBySHA3_512_224(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(SHA3_512_224, dataToHash, null);
}
public static String digestHexStringBySHA3_512_256(String dataToHash, String salt) throws NoSuchAlgorithmException {
return digestHexString(SHA3_512_256, dataToHash, salt);
}
public static String digestHexStringBySHA3_512_256(String dataToHash) throws NoSuchAlgorithmException {
return digestHexString(SHA3_512_256, dataToHash, null);
}
}
什么是哈希算法? - 知乎
什么是哈希算法? - 知乎
java - 一文搞懂单向散列加密:MD5、SHA-1、SHA-2、SHA-3 - 个人文章 - SegmentFault 思否
哈希(Hash)算法以及应用场景 - 知乎
哈希算法总结(含哈希算法工具类的封装)_猿究院杨树林的博客-CSDN博客
文件上传下载系列——如何实现文件秒传_秒传格式_夏诗曼CharmaineXia的博客-CSDN博客
tps://zhuanlan.zhihu.com/p/572831003)
哈希算法总结(含哈希算法工具类的封装)_猿究院杨树林的博客-CSDN博客
文件上传下载系列——如何实现文件秒传_秒传格式_夏诗曼CharmaineXia的博客-CSDN博客