zoukankan      html  css  js  c++  java
  • 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加密与解密的艺术

  • 相关阅读:
    P3225 [HNOI2012]矿场搭建 题解
    CodeForces
    poj-3723
    codeforces -1214 E
    POJ-1741 树上分治--点分治(算法太奇妙了)
    洛谷p1345---最小割的奇妙运用
    洛谷p2149----两个终点和两个起点,最短路最大交汇长度!!!
    BerOS File Suggestion(字符串匹配map)
    Garbage Disposal(模拟垃圾装垃圾口袋)
    第八周组队赛
  • 原文地址:https://www.cnblogs.com/seve/p/13984749.html
Copyright © 2011-2022 走看看