📅  最后修改于: 2023-12-03 15:15:59.619000             🧑  作者: Mango
在软件开发中,保护用户密码是至关重要的任务。一种常见的方法是对用户密码进行哈希(Hash)处理。哈希函数将输入的密码转换为固定长度的二进制字符串,使得用户密码不可逆地转换为哈希值,从而保护用户密码不被直接暴露。
在 Java 中,标准库提供了多个哈希函数算法类,如 MessageDigest
和 SecureRandom
。本文将介绍如何使用这些类来实现密码哈希。
MessageDigest
是一个抽象类,用于将任意长度的消息转换为固定长度的哈希值。以下代码演示如何使用 MessageDigest
将字符串密码转换为 SHA-256 哈希值:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class PasswordHasher {
public static String hashPassword(String password, String salt) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256"); // 选择 SHA-256 算法
digest.update(salt.getBytes()); // 添加盐值
byte[] hashedBytes = digest.digest(password.getBytes()); // 哈希密码
return bytesToHex(hashedBytes); // 返回十六进制字符串
}
private static String bytesToHex(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b : bytes) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
}
hashPassword()
方法接收两个参数:用户密码和盐值。盐值是一个随机字符串,用于增加哈希值的随机性和复杂度。在实现时,我们将密码和盐值拼接后再进行哈希处理。最后,将哈希值转换为十六进制字符串并返回。
使用时,可以直接调用 PasswordHasher.hashPassword(password, salt)
来获得哈希值。
在上述示例中,盐值需要手动输入。但实际上,盐值应当是一个随机字符串。此时,可以使用 SecureRandom
类来生成随机盐值:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class PasswordHasher {
private static final int SALT_LENGTH = 16; // 盐值长度
public static String hashPassword(String password) throws NoSuchAlgorithmException {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[SALT_LENGTH];
random.nextBytes(salt); // 生成随机盐值
MessageDigest digest = MessageDigest.getInstance("SHA-256"); // 选择 SHA-256 算法
digest.update(salt); // 添加盐值
byte[] hashedBytes = digest.digest(password.getBytes()); // 哈希密码
return bytesToHex(hashedBytes) + ":" + bytesToHex(salt); // 返回哈希值和盐值
}
private static String bytesToHex(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b : bytes) {
builder.append(String.format("%02x", b));
}
return builder.toString();
}
}
在此示例中,我们利用 SecureRandom
类生成一个随机的盐值,并在哈希计算时添加到密码中。在返回值中,我们将哈希值和盐值以冒号分隔,方便后续校验操作。
对于已经哈希过的密码,我们可以使用 MessageDigest
的 isEqual()
方法来判断用户输入的明文密码是否正确:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class PasswordValidator {
public static boolean validatePassword(String password, String hashedPasswordWithSalt) throws NoSuchAlgorithmException {
String[] parts = hashedPasswordWithSalt.split(":");
byte[] hashedBytes = hexToBytes(parts[0]);
byte[] salt = hexToBytes(parts[1]);
MessageDigest digest = MessageDigest.getInstance("SHA-256"); // 选择 SHA-256 算法
digest.update(salt); // 添加盐值
byte[] hashedBytesToMatch = digest.digest(password.getBytes()); // 哈希输入的密码
return MessageDigest.isEqual(hashedBytes, hashedBytesToMatch); // 比较哈希值是否相等
}
private static byte[] hexToBytes(String hex) {
byte[] bytes = new byte[hex.length() / 2];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
}
return bytes;
}
}
validatePassword()
方法接收两个参数:用户输入的明文密码和已经哈希过的密码(包含哈希值和盐值)。在校验时,我们提取出盐值和哈希值,并对用户输入的明文密码进行哈希计算。最后,比较计算出的哈希值和已有哈希值是否相等即可得到验证结果。
Java 提供了丰富的哈希函数库,包括 MessageDigest
、SecureRandom
等类,可以方便地实现密码哈希和校验。在保护用户密码安全时,使用哈希函数是一种常见而有效的方法。