密码散列函数

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class HashTool {

    /**
     * 给密码散列函数的输入值加一些额外的数据,这些数据称之为盐
     */
    private static final String HASH_SALT = "&%5123***&&%%$$#@";

    /**
     * 密码散列函数的算法列表:其中MD5执行最快但是最不安全,SHA5执行最慢但是最安全
     */
    public enum HashAlgorithm{
        MD5("MD5"),SHA1("SHA-1"),SHA2("SHA-256"),SHA3("SHA-384"),SHA5("SHA-512");

        HashAlgorithm(String algorithmName){
            this.algorithmName = algorithmName;
        }

        private String algorithmName;
    }

    /**
     *
     * @param wantHashData 想要被密码散列函数执行的数据
     * @param whichHashAlgorithm 使用哪种密码散列函数
     * @return 返回执行了密码散列函数后的结果
     */
    public static String cryptographicHash(byte[] wantHashData, HashAlgorithm whichHashAlgorithm){

        if (wantHashData == null || wantHashData.length ==0){
            return null;
        }

        try {
            // 获取MD5的盐的字节数组类型的数据
            byte[] saltByteArray = HASH_SALT.getBytes("UTF-16");

            // 创建密码执行散列函数的参数:将想要执行散列函数的数据 与 盐数据 合并起来
            byte[] beforeHashData = new byte[wantHashData.length + saltByteArray.length];
            System.arraycopy(wantHashData, 0, beforeHashData, 0, wantHashData.length);
            System.arraycopy(saltByteArray, 0, beforeHashData, wantHashData.length, saltByteArray.length);

            // 创建密码散列函数执行工具
            MessageDigest messageDigest = MessageDigest.getInstance(whichHashAlgorithm.algorithmName);

            // 设置执行密码散列函数的数据
            messageDigest.update(beforeHashData);

            // 开始执行密码散列函数
            byte[] afterHashData = messageDigest.digest(); // 结果字节数组的长度必定是16

            // 将密码散列函数的结果字节数组中的每一个字节都转为十六进制表现形式,并拼接成一个长度为32的字符串
            StringBuilder result = new StringBuilder();
            for (byte anAfterHashData : afterHashData) {
                // Integer类的toHexString方法可以将 int类型 的数据对应的 二进制反码 转为 对应的 无符号 十六进制String类型 的数据

                // 目的:将byte字节数据对应的二进制反码数据不多不少的转为无符号的十六进制String类型的数据

                // 8位byte类型的数据只要进行运算必定会转为32位的int类型数据后在进行运算
                // 但是负数8位byte类型的数据在转为32位的int类型数据时,会将高24位都置为1,
                // 如此转换后的int类型数据的二进制反码相对于转换前的byte类型数据的二进制反码就会多出24位数据
                // 所以我们需要将高24位恒定保持位全0
                int apply1 = 0x000000FF & anAfterHashData; // 0x000000FF 对应二进制数为:00000000 ······ 00000000 11111111
                // int类型数据的对应二进制如果是 00000000 ······ 00000000(0) ~ 00000000 ······ 00001111(15)
                // 那么Integer类的toHexString方法在将其转为 十六进制String类型 数据时,其结果只会是包含一个字符的字符串
                // 如果不处理,那么拼接成最终字符串时,最终字符串的长度就无法是确定值,
                // 且我们也无法区分最终字符串中哪一个字符或哪两个字符是由一个字节转化而来的
                // 所以我们要保证每个一个字节在转为 十六进制String类型 的数据时,其转化结果的字符串必须是2个字符组成的
                // 将int类型数据的高24位恒定保持为全1
                int apply2 = apply1 | 0xFFFFFF00;
                // 将处理过的int数据转为 无符号 十六进制String类型 的数据
                String apply3 = Integer.toHexString(apply2);
                // 截取 toHexString 方法返回值字符串中的倒数2个字符,就是 byte字节数据对应的二进制反码 对应的 无符号 十六进制String类型 的数据
                String apply4 = apply3.substring(6);
                // 将最终处理结果进程拼接
                result.append(apply4);
            }
            return result.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace(); // 创建密码散列函数执行工具失败,没有该算法
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace(); // 获取盐的字节数组类型数据时失败,不支持该解码方式
        }

        return null;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值