概述

消息摘要算法包括

MD(Message Digest,消息摘要算法)

SHA(Secure Hash Algorithm,安全散列算法)

MAC(Message AuthenticationCode,消息认证码算法)

共3大系列,常用于验证数据的完整性,是数字签名算法的核心算法。

MD5和SHA1分别是MD、SHA算法系列中最有代表性的算法。

如今,MD5已被发现有许多漏洞,从而不再安全。SHA算法比MD算法的摘要长度更长,也更加安全。

算法实现

MD5、SHA的范例

JDK中使用MD5和SHA这两种消息摘要的方式基本一致,步骤如下:

(1)            初始化MessageDigest对象

(2)            更新要计算的内容

(3)            生成摘要

package com.zoo.lion.security;

import org.apache.commons.codec.binary.Hex;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @Author: xf
 * @Date: 2019/6/3 13:28
 * @Version 1.0
 */
public class Md5Coder {
    public enum Algorithm {
        md5("md5"), SHA("SHA"), sha256("SHA-256"), sha384("SHA-384"), sha512("SHA-512");
        private String algorithm;

        Algorithm(String algorithm) {
            this.algorithm = algorithm;
        }

        public String getAlgorithm() {
            return algorithm;
        }

    }

    public static void main(String[] args) {

        String md5 = md5("123456");
        System.out.println("MD5摘要: " + md5);

        String sha = sha("123456");
        System.out.println("sha摘要: " + sha);
    }

    public static String md5(String msg) {
        try {
            //编码
            byte[] encrypt = encrypt(msg, Algorithm.md5.getAlgorithm());
//            //(自己实现转换)
//            //字节数组转换为字符
//            char[] str = byteArrayToHexString(encrypt);
//            return new String(str);// 换后的结果转换为字符串
            return Hex.encodeHexString(encrypt);//利用org.apache.commons包转换
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String sha(String msg) {
        try {
            //编码
            byte[] encrypt = encrypt(msg, Algorithm.sha512.getAlgorithm());
            String sha = Hex.encodeHexString(encrypt);
            return sha;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * byte[]转化为16进制(有多种方法)
     *
     * @param data 要转换的byte
     * @return 16进制格式
     */
    private static char[] byteArrayToHexString(byte[] data) {
        // 用来将字节转换成16进制表示的字符
        char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        // 用字节表示就是 16 个字节 进制需要 32 个字符
        char[] str = new char[16 * 2];// 每个字节用 16 进制表示的话,使用两个字符, 所以表示成 16
        // 表示转换结果中对应的字符位置
        int index = 0;
        // // 遍历字节数组,通过位运算(位运算效率高),转换成字符放到字符数组中去 ,从第一个字节开始,对 MD5 的每一个字节转换成 16进制
        for (byte b : data) {
            // 进制字符的转换
            str[index++] = hexDigits[b >>> 4 & 0xf];// 取字节中高 4 位的数字转换,// >>>
            // 为逻辑右移,将符号位一起右移
            str[index++] = hexDigits[b & 0xf];// 取字节中低 4 位的数字转换
        }
        return str;
    }

    //编码
    private static byte[] encrypt(String msg, String algorithm) throws NoSuchAlgorithmException {
        // 拿到一个MD5转换器(如果想要SHA1参数换成”SHA1”)
        MessageDigest md5Digest = MessageDigest.getInstance(algorithm);
        // 更新要计算的内容
        md5Digest.update(msg.getBytes());
        // 完成哈希计算,得到摘要,结果是一个 128 位的长整数
        return md5Digest.digest();
    }


}

Hmac的范例

package com.zoo.lion.security;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * @Author: xf
 * @Date: 2019/6/3 15:08
 * @Version 1.0
 */
public class HmacCoder {
    /**
     * JDK支持HmacMD5, HmacSHA1,HmacSHA256, HmacSHA384, HmacSHA512
     */
    public enum HmacTypeEn {
        HmacMD5, HmacSHA1, HmacSHA256, HmacSHA384, HmacSHA512;
    }

    public static byte[] encode(byte[] plaintext, byte[] secretKey, HmacTypeEn type) throws NoSuchAlgorithmException, InvalidKeyException {
        SecretKeySpec keySpec = new SecretKeySpec(secretKey, type.name());
        Mac mac = Mac.getInstance(keySpec.getAlgorithm());
        mac.init(keySpec);
        return mac.doFinal(plaintext);
    }

    public static void main(String[] args) throws Exception {
        String msg = "123456";
        String secretKey = "123456";
        byte[] digest = HmacCoder.encode(msg.getBytes(), secretKey.getBytes(StandardCharsets.UTF_8), HmacTypeEn.HmacSHA1);
        System.out.println("原文: " + msg);
        System.out.println("摘要: " + Hex.encodeHexString(digest));
    }
}

(完)