术 | Hash摘要实现

340 阅读2分钟

这是我参与更文挑战的第9天,活动详情查看: 更文挑战。终于第九天了,达到了这次活动的第一个节点,存货用的差不多了,要开始动手肝了,是时候展现真实的实力了。

专栏内上一篇文章有讲到常见的加密算法,包括非对称加密对称加密、以及特殊的加密Hash摘要。这篇文章是实践篇,来讲如何用Java开发语言实现Hash,具体实现的有MD5Message Digest version 5)和SHASecure Hash Algorithm)。

一、回顾

在动手之前,先来回顾一下什么是Hash摘要

Hash摘要也被称为加密散列函数,它以任意大小的数据作为输入(消息)并产生固定长度的散列值。

Hash摘要最重要的特性之一是,生成具有给定散列(安全单向)的消息,并且是不可逆的。Hash摘要经常用于检查数据完整性,例如根据其已知的散列值检查下载文件的完整性;还有一个更为见的用法是在数据库中加密用户的密码。

二、实践步骤

Java语言给我们提供了丰富的类库,其中MessageDigest类能帮助我们实现MD5,HASH算法。

生成Hash的步骤分为两种情况。

2.1 内容较少

MessageDigest digest = MessageDigest.getInstance(algorithm);
byte[] inputBytes = ${dynamic message} // 待加密的内容
byte[] hashBytes = digest.digest(inputBytes);

2.2 内容较多(文件)

MessageDigest digest = MessageDigest.getInstance(algorithm);
byte[] inputBytes = ${dynamic message}// 待加密的内容
digest.update(inputBytes);
byte[] hashedBytes = digest.digest();

三、例子

Hash摘要工具类如下:

public interface DigestUtils {

    static String SHA256(byte[] bytes) throws NoSuchAlgorithmException {
        return digest(bytes, AlgorithmType.SHA256);
    }
    static String SHA512(byte[] bytes) throws NoSuchAlgorithmException {
        return digest(bytes, AlgorithmType.SHA512);
    }

    static String MD5(byte[] bytes) throws NoSuchAlgorithmException {
        return digest(bytes, AlgorithmType.MD5);
    }

    static String SHA1(byte[] bytes) throws NoSuchAlgorithmException {
        return digest(bytes, AlgorithmType.SHA1);
    }

    /**
     * 将待加密的内容和算法名称作为输入,并返回计算出的哈希值的十六进制形式
     * @param aByte 待加密的内容
     * @param algorithm 算法名称
     * @return 哈希值的十六进制形式
     * @throws NoSuchAlgorithmException  没有找到加密算法异常
     */
    static String digest(byte[] aByte, @NotNull String algorithm) throws NoSuchAlgorithmException {
        final MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        final byte[] digest = messageDigest.digest(aByte);
        return ArraysStringConverter.convertByteArrayToHexString(digest);
    }

    interface AlgorithmType {
        String SHA1 = "SHA-1";
        String MD5 = "MD5";
        String SHA256 = "SHA-256";
        String SHA512 = "SHA-512";
    }
}

在工具内有用到将字节数组转成十六进制的字符串的方法,具体实现如下

public interface ArraysStringConverter {
    /**
     * 转换字节数组到16进制的字符串
     *
     * @param arrayBytes 字节数组
     * @return 16进制的字符串
     */
    static String convertByteArrayToHexString(byte[] arrayBytes) {
        StringBuilder stringBuffer = new StringBuilder();
        for (byte arrayByte : arrayBytes) {
            stringBuffer.append(Integer.toString((arrayByte & 0xff) + 0x100, 16)
                .substring(1));
        }
        return stringBuffer.toString();
    }
}

Main函数测试方法就不列举出来,已经在生产环境中使用了。Hash一个文件的代码就不给出来,无法就是把文件的按照指定的长度读出来,不断进行digest.update(),参照实践步骤的内容较多(文件)的步骤进行即可。

四、源码地址

附上Github的源代码地址 training.platform.training.java.crypto.digest