Java加密与解密之消息摘要算法

概述

消息摘要算法又称为散列算法,其核心在于散列函数的单向性。即通过散列函数可获得对应的散列值,但不可通过该散列值反推其原始信息。这是消息摘要算法的安全性的根本所在。消息摘要算法主要分为三大类:MD(MessageDigest,消息摘要算法)SHA(Secure HashAlgorithm,安全散列算法)MAC(MessageAuthentication Code,消息认证码算法)。MD5、SHA和HMAC分别是三大类消息摘要算法中的代表。

MD5和SHA

1.MD5算法是典型的消息摘要算法,其前身有MD2、MD3和MD4算法,它由MD4、MD3、MD2算法改进而来,1996年后该算法被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA。

2.SHA家族的五个算法,分别是SHA-1、SHA-224、SHA-256、SHA-384,和SHA-512。SHA与MD算法不同之处主要在于摘要长度,SHA算法的摘要长度更长,安全性更高。

MD5和SHA在实现代码上大部分是一致的,只是指定的算法不一样。

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

public class MdaUtil {
	
	/**
     * MD5/SHA消息摘要
     * @param content 数据
     * @param algorithm 消息摘要算法
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String messageDigestAlgorithm(String content, String algorithm) throws NoSuchAlgorithmException {
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        byte[] result = messageDigest.digest(content.getBytes());
        StringBuilder sb = new StringBuilder();
        for(byte b : result){
            //转16进制
            String a = Integer.toHexString(b & 0xff);
            //长度为1时在最高位补0
            if(a.length() == 1){
                a = "0" + a;
            }
            sb.append(a);
        }
        return sb.toString();
    }

    public static void main(String[] args) throws NoSuchAlgorithmException {
        System.out.println(messageDigestAlgorithm("消息摘要算法", "md5"));//b7c58f860f1add7de092b1f2931a3eb9
        System.out.println(messageDigestAlgorithm("消息摘要算法", "sha"));//ff0e2136bc6df62bbe0d9b6ad9d028852312aad5
    }
}

HMAC

HMAC算法结合了MD5和SHA算法的优势,并加入密钥的支持,是一种更为安全的消息摘要算法。

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class HmacUtil {

    /**
     * 生成base64编码后的密钥
     * @param algorithm 摘要算法
     * @return
     * @throws Exception
     */
    public static String generateKey(String algorithm) throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
        SecretKey secretKey = keyGenerator.generateKey();
        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
    }

    /**
     * HMAC消息摘要
     * @param algorithm 摘要算法
     * @param key 密钥
     * @param data 数据
     * @return
     * @throws Exception
     */
    public static String hmac(String algorithm, String key, String data) throws Exception {
        SecretKey secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), algorithm);
        Mac mac = Mac.getInstance(algorithm);
        mac.init(secretKey);
        return Base64.getEncoder().encodeToString(mac.doFinal(data.getBytes()));
    }

    public static void main(String[] args) throws Exception {
        String algorithm = "HmacMD5";
        String data = "消息摘要算法";
        String key = generateKey(algorithm);
        System.out.println("Base64编码后的密钥:" + key);
        System.out.println("Base64编码后的HMAC消息摘要:" + hmac(algorithm, key, data));
    }
}

文件完整性验证

以tomcat为例,在官网上可以看到tomcat安装包以及它对应的经过消息摘要算法处理的后的值:

下载文件,通过计算文件的消息摘要值来验证文件的完整性,如果文件是完整的则计算出来的值和官网上的值是相同的。

import java.io.FileInputStream;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;

public class FileVerificationUtil {

    /**
     * 文件消息摘要验证
     *
     * @param digestData  原摘要数据
     * @param algorithm   摘要算法
     * @param inputStream 待验证文件
     * @return
     * @throws Exception
     */
    public static boolean fileVerification(String digestData, String algorithm, InputStream inputStream) throws Exception {
        DigestInputStream digestInputStream = new DigestInputStream(inputStream, MessageDigest.getInstance(algorithm));
        int bufferSize = 1024;
        byte[] buffer = new byte[bufferSize];
        int read = digestInputStream.read(buffer, 0, bufferSize);
        while (read > -1) {
            read = digestInputStream.read(buffer, 0, bufferSize);
        }
        digestInputStream.close();
        MessageDigest messageDigest = digestInputStream.getMessageDigest();
        byte[] result = messageDigest.digest();
        StringBuilder sb = new StringBuilder();
        for (byte b : result) {
            //转16进制
            String a = Integer.toHexString(b & 0xff);
            //长度为1时在最高位补0
            if (a.length() == 1) {
                a = "0" + a;
            }
            sb.append(a);
        }
        return sb.toString().equals(digestData);
    }

    public static void main(String[] args) throws Exception {
        String digestData = "8ee33ad87e40659e501517d8ac9915ee0b19ee0fa590feb80c85f0d93c6dfe2658cdc73d2a2545ace52b7896e8a96ba6a025dda8254d6c5d9cea563c1f9e4d77";
        String algorithm = "sha-512";
        System.out.println(fileVerification(digestData, algorithm, new FileInputStream("F:\\chrome_download\\apache-tomcat-10.0.0-M9-windows-x64.zip")));//true
    }
}

参考:Java加密与解密的艺术

posted @ 2020-11-16 14:06  布禾  阅读(551)  评论(0编辑  收藏  举报