📜  java 哈希密码 - Java (1)

📅  最后修改于: 2023-12-03 15:15:59.619000             🧑  作者: Mango

Java 哈希密码

在软件开发中,保护用户密码是至关重要的任务。一种常见的方法是对用户密码进行哈希(Hash)处理。哈希函数将输入的密码转换为固定长度的二进制字符串,使得用户密码不可逆地转换为哈希值,从而保护用户密码不被直接暴露。

在 Java 中,标准库提供了多个哈希函数算法类,如 MessageDigestSecureRandom。本文将介绍如何使用这些类来实现密码哈希。

使用 MessageDigest 实现密码哈希

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 生成盐值

在上述示例中,盐值需要手动输入。但实际上,盐值应当是一个随机字符串。此时,可以使用 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 类生成一个随机的盐值,并在哈希计算时添加到密码中。在返回值中,我们将哈希值和盐值以冒号分隔,方便后续校验操作。

验证密码

对于已经哈希过的密码,我们可以使用 MessageDigestisEqual() 方法来判断用户输入的明文密码是否正确:

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 提供了丰富的哈希函数库,包括 MessageDigestSecureRandom 等类,可以方便地实现密码哈希和校验。在保护用户密码安全时,使用哈希函数是一种常见而有效的方法。