Java 加密解密之消息摘要算法(MD5 SHA MAC)

Java加密解密系列

Java 加密解密基礎
Java byte數組與十六進制字符串互轉
Java BASE64加密解密
Java 加密解密之消息摘要算法(MD5 SHA MAC)
Java 加密解密之對稱加密算法DES
Java 加密解密之對稱加密算法DESede
Java 加密解密之對稱加密算法AES
Java 加密解密之對稱加密算法PBE

Java 加密解密之消息摘要算法(MD5 SHA MAC)

消息摘要

消息摘要(Message Digest)又稱爲數字摘要(Digital Digest)。它是一個唯一對應一個消息或文本的固定長度的值,它由一個單向Hash加密函數對消息進行作用而產生。如果消息在途中改變了,則接收者通過對收到消息的新產生的摘要與原摘要比較,就可知道消息是否被改變了。因此消息摘要保證了消息的完整性。消息摘要採用單向Hash 函數將需加密 的明文”摘要”成一串128bit的密文,這一串密文亦稱爲數字指紋(Finger Print),它有固定的長度,且不同的明文摘要成密文,其結果總是不同的,而同樣的明文其摘要必定一致 。這樣這串摘要便可成爲驗證明文是否是”真身”的”指紋”了。

HASH函數的抗衝突性使得如果一段明文稍有變化,哪怕只更改該段落的一個字母,通過哈希算法作用後都將產生不同的值。而HASH算法的單向性使得要找到到哈希值相同的兩個不 同的輸入消息,在計算上是不可能的。所以數據的哈希值,即消息摘要,可以檢驗數據的完整性。哈希函數的這種對不同的輸入能夠生成不同的值的特性使得無法找到兩個具有相同哈希值的輸入。因此,如果兩個文檔經哈希轉換後成爲相同的值,就可以肯定它們是同一文檔。 所以,當希望有效地比較兩個數據塊時,就可以比較它們的哈希值。例如,可以通過比較郵件發送前和發送後的哈希值來驗證該郵件在傳遞時是否修改。

消息摘要算法

消息摘要算法的主要特徵是加密過程不需要密鑰,並且經過加密的數據無法被解密,只有輸入相同的明文數據經過相同的消息摘要算法才能得到相同的密文。消息摘要算法不存在 密鑰的管理與分發問題,適合於分佈式網絡相同上使用。由於其加密計算的工作量相當可觀,所以以前的這種算法通常只用於數據量有限的情況下的加密,例如計算機的口令就是 用不可逆加密算法加密的。近年來,隨着計算機相同性能的飛速改善,加密速度不再成爲限制這種加密技術發展的桎梏,因而消息摘要算法應用的領域不斷增加。

消息摘要算法的特點:
① 無論輸入的消息有多長,計算出來的消息摘要的長度總是固定的。
② 消息摘要看起來是“隨機的”。這些比特看上去是胡亂的雜湊在一起的。
③ 一般地,只要輸入的消息不同,對其進行摘要以後產生的摘要消息也必不相同;但相同的輸入必會產生相同的輸出。
④ 消息摘要函數是無陷門的單向函數,即只能進行正向的信息摘要,而無法從摘要中恢復出任何的消息,甚至根本就找不到任何與原信息相關的信息。
⑤ 好的摘要算法,無法找到兩條消息,是它們的摘要相同。

現有的消息摘要算法:
消息摘要算法包含MD、SHA和MAC三大系列,常用於驗證數據的完整性,是數據簽名算法的核心算法。
MAC與MD和SHA不同,MAC是含有密鑰的散列函數算法,我們也常把MAC稱爲HMAC。

JDK對消息摘要算法的支持
JDK6支持MD2/MD5/SHA/SHA256/SHA384/SHA512/HmacMD5/HmacSHA1/ HmacSHA256/HmacSHA384/HmacSHA512

使用到 十六進制工具類Hex.java 見: java byte數組與十六進制字符串互轉

MD和SHA系列的java實現:
DigestUtils.java

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

/** 
 * reference apache commons <a 
 * href="http://commons.apache.org/codec/">http://commons.apache.org/codec/</a> 
 *  
 * support MD2/MD5/SHA/SHA256/SHA384/SHA512 
 * @author Aub 
 *  
 */  
public class DigestUtils {  

    /** 
     * 根據給定摘要算法創建一個消息摘要實例 
     *  
     * @param algorithm 
     *            摘要算法名 
     * @return 消息摘要實例 
     * @see MessageDigest#getInstance(String) 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    static MessageDigest getDigest(String algorithm) {  
        try {  
            return MessageDigest.getInstance(algorithm);  
        } catch (NoSuchAlgorithmException e) {  
            throw new RuntimeException(e.getMessage());  
        }  
    }  

    /** 
     * 獲取 MD5 消息摘要實例 
     *  
     * @return MD5 消息摘要實例 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    private static MessageDigest getMd5Digest() {  
        return getDigest("MD5");  
    }  

    /** 
     * 獲取 SHA-1 消息摘要實例 
     *  
     * @return SHA-1 消息摘要實例 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    private static MessageDigest getShaDigest() {  
        return getDigest("SHA");  
    }  

    /** 
     * 獲取 SHA-256 消息摘要實例 
     *  
     * @return SHA-256 消息摘要實例 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    private static MessageDigest getSha256Digest() {  
        return getDigest("SHA-256");  
    }  

    /** 
     * 獲取 SHA-384 消息摘要實例 
     *  
     * @return SHA-384 消息摘要實例 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    private static MessageDigest getSha384Digest() {  
        return getDigest("SHA-384");  
    }  

    /** 
     * 獲取 SHA-512 消息摘要實例 
     *  
     * @return SHA-512 消息摘要實例 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    private static MessageDigest getSha512Digest() {  
        return getDigest("SHA-512");  
    }  

    /** 
     * 使用MD5消息摘要算法計算消息摘要 
     *  
     * @param data 
     *            做消息摘要的數據 
     * @return 消息摘要(長度爲16的字節數組) 
     */  
    public static byte[] encodeMD5(byte[] data) {  
        return getMd5Digest().digest(data);  
    }  

    /** 
     * 使用MD5消息摘要算法計算消息摘要 
     *  
     * @param data 
     *            做消息摘要的數據 
     * @return 消息摘要(長度爲32的十六進制字符串) 
     */  
    public static String encodeMD5Hex(byte[] data) {  
        return Hex.encodeHexStr(encodeMD5(data));  
    }  

    /** 
     * 使用SHA-1消息摘要算法計算消息摘要 
     *  
     * @param data 
     *            做消息摘要的數據 
     * @return SHA-1消息摘要(長度爲20的字節數組) 
     */  
    public static byte[] encodeSHA(byte[] data) {  
        return getShaDigest().digest(data);  
    }  

    /** 
     * 使用SHA-1消息摘要算法計算消息摘要 
     *  
     * @param data 
     *            做消息摘要的數據 
     * @return SHA-1消息摘要(長度爲40的十六進制字符串) 
     */  
    public static String encodeSHAHex(byte[] data) {  
        return Hex.encodeHexStr(getShaDigest().digest(data));  
    }  

    /** 
     * 使用SHA-256消息摘要算法計算消息摘要 
     *  
     * @param data 
     *            做消息摘要的數據 
     * @return SHA-256消息摘要(長度爲32的字節數組) 
     */  
    public static byte[] encodeSHA256(byte[] data) {  
        return getSha256Digest().digest(data);  
    }  

    /** 
     * 使用SHA-256消息摘要算法計算消息摘要 
     *  
     * @param data 
     *            做消息摘要的數據 
     * @return SHA-256消息摘要(長度爲64的十六進制字符串) 
     */  
    public static String encodeSHA256Hex(byte[] data) {  
        return Hex.encodeHexStr(encodeSHA256(data));  
    }  

    /** 
     * 使用SHA-384消息摘要算法計算消息摘要 
     *  
     * @param data 
     *            做消息摘要的數據 
     * @return SHA-384消息摘要(長度爲43的字節數組) 
     */  
    public static byte[] encodeSHA384(byte[] data) {  
        return getSha384Digest().digest(data);  
    }  

    /** 
     * 使用SHA-384消息摘要算法計算消息摘要 
     *  
     * @param data 
     *            做消息摘要的數據 
     * @return SHA-384消息摘要(長度爲86的十六進制字符串) 
     */  
    public static String encodeSHA384Hex(byte[] data) {  
        return Hex.encodeHexStr(encodeSHA384(data));  
    }  

    /** 
     * 使用SHA-512消息摘要算法計算消息摘要 
     *  
     * @param data 
     *            做消息摘要的數據 
     * @return SHA-512消息摘要(長度爲64的字節數組) 
     */  
    public static byte[] encodeSHA512(byte[] data) {  
        return getSha512Digest().digest(data);  
    }  

    /** 
     * 使用SHA-512消息摘要算法計算消息摘要 
     *  
     * @param data 
     *            做消息摘要的數據 
     * @return SHA-512消息摘要(長度爲128的十六進制字符串) 
     */  
    public static String encodeSHA512Hex(byte[] data) {  
        return Hex.encodeHexStr(encodeSHA512(data));  
    }  
}  

參考 org.apache.commons.codec.digest.DigestUtils
下載地址: http://commons.apache.org/codec/download_codec.cgi

MAC系列的java實現
Hmac.java

import java.security.InvalidKeyException;  
import java.security.Key;  
import java.security.NoSuchAlgorithmException;  

import javax.crypto.KeyGenerator;  
import javax.crypto.Mac;  
import javax.crypto.SecretKey;  
import javax.crypto.spec.SecretKeySpec;  

/** 
 * Hmac<br/> 
 * algorithm HmacMD5/HmacSHA/HmacSHA256/HmacSHA384/HmacSHA512 
 * @author Aub 
 */  
public class Hmac {  

    /** 
     * 根據給定密鑰生成算法創建密鑰 
     *  
     * @param algorithm 
     *            密鑰算法 
     * @return 密鑰 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    private static byte[] getHmacKey(String algorithm){  
        //初始化KeyGenerator  
        KeyGenerator keyGenerator = null;  
        try {  
            keyGenerator = KeyGenerator.getInstance(algorithm);  
        } catch (NoSuchAlgorithmException e) {  
            throw new RuntimeException(e.getMessage());  
        }  
        //產生密鑰  
        SecretKey secretKey = keyGenerator.generateKey();  
        //獲得密鑰  
        return secretKey.getEncoded();  
    }  

    /** 
     * 獲取 HmaMD5的密鑰 
     *  
     * @return  HmaMD5的密鑰 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    public static byte[] getHmaMD5key(){  
        return getHmacKey("HmacMD5");  
    }  

    /** 
     * 獲取 HmaSHA的密鑰 
     *  
     * @return  HmaSHA的密鑰 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    public static byte[] getHmaSHAkey(){  
        return getHmacKey("HmacSHA1");  
    }  

    /** 
     * 獲取 HmaSHA256的密鑰 
     *  
     * @return  HmaSHA256的密鑰 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    public static byte[] getHmaSHA256key(){  
        return getHmacKey("HmacSHA256");  
    }  

    /** 
     * 獲取 HmaSHA384的密鑰 
     *  
     * @return  HmaSHA384的密鑰 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    public static byte[] getHmaSHA384key(){  
        return getHmacKey("HmacSHA384");  
    }  

    /** 
     * 獲取 HmaSHA512的密鑰 
     *  
     * @return  HmaSHA384的密鑰 
     * @throws RuntimeException 
     *             當 {@link java.security.NoSuchAlgorithmException} 發生時 
     */  
    public static byte[] getHmaSHA512key(){  
        return getHmacKey("HmacSHA512");  
    }  

    /** 
     * 轉換密鑰 
     *  
     * @param key   二進制密鑰 
     * @param algorithm 密鑰算法 
     * @return 密鑰 
     */  
    private static Key toKey(byte[] key,String algorithm){  
        //生成密鑰  
        return new SecretKeySpec(key, algorithm);  
    }  

    /** 
     * 使用HmacMD5消息摘要算法計算消息摘要 
     *  
     * @param data 做消息摘要的數據 
     * @param key 密鑰 
     * @return 消息摘要(長度爲16的字節數組) 
     */  
    public static byte[] encodeHmacMD5(byte[] data, Key key){  
        Mac mac = null;  
        try {  
            mac = Mac.getInstance("HmacMD5");  
            mac.init(key);  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
            return new byte[0];  
        }catch (InvalidKeyException e) {  
            e.printStackTrace();  
            return new byte[0];  
        }  
        return mac.doFinal(data);  
    }  

    /** 
     * 使用HmacMD5消息摘要算法計算消息摘要 
     *  
     * @param data 做消息摘要的數據 
     * @param key 密鑰 
     * @return 消息摘要(長度爲16的字節數組) 
     */  
    public static byte[] encodeHmacMD5(byte[] data, byte[] key){  
        Key k = toKey(key, "HmacMD5");  
        return encodeHmacMD5(data, k);  
    }  

    /** 
     * 使用HmacSHA消息摘要算法計算消息摘要 
     *  
     * @param data 做消息摘要的數據 
     * @param key 密鑰 
     * @return 消息摘要(長度爲16的字節數組) 
     */  
    public static byte[] encodeHmacSHA(byte[] data, Key key){  
        Mac mac = null;  
        try {  
            mac = Mac.getInstance("HmacSHA1");  
            mac.init(key);  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
            return new byte[0];  
        }catch (InvalidKeyException e) {  
            e.printStackTrace();  
            return new byte[0];  
        }  
        return mac.doFinal(data);  
    }  

    /** 
     * 使用HmacSHA消息摘要算法計算消息摘要 
     *  
     * @param data 做消息摘要的數據 
     * @param key 密鑰 
     * @return 消息摘要(長度爲16的字節數組) 
     */  
    public static byte[] encodeHmacSHA(byte[] data, byte[] key){  
        Key k = toKey(key, "HmacSHA1");  
        return encodeHmacSHA(data, k);  
    }  

    /** 
     * 使用HmacSHA256消息摘要算法計算消息摘要 
     *  
     * @param data 做消息摘要的數據 
     * @param key 密鑰 
     * @return 消息摘要(長度爲16的字節數組) 
     */  
    public static byte[] encodeHmacSHA256(byte[] data, Key key){  
        Mac mac = null;  
        try {  
            mac = Mac.getInstance("HmacSHA256");  
            mac.init(key);  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
            return new byte[0];  
        }catch (InvalidKeyException e) {  
            e.printStackTrace();  
            return new byte[0];  
        }  
        return mac.doFinal(data);  
    }  

    /** 
     * 使用HmacSHA256消息摘要算法計算消息摘要 
     *  
     * @param data 做消息摘要的數據 
     * @param key 密鑰 
     * @return 消息摘要(長度爲16的字節數組) 
     */  
    public static byte[] encodeHmacSHA256(byte[] data, byte[] key){  
        Key k = toKey(key, "HmacSHA256");  
        return encodeHmacSHA256(data, k);  
    }  


    /** 
     * 使用HmacSHA384消息摘要算法計算消息摘要 
     *  
     * @param data 做消息摘要的數據 
     * @param key 密鑰 
     * @return 消息摘要(長度爲16的字節數組) 
     */  
    public static byte[] encodeHmacSHA384(byte[] data, Key key){  
        Mac mac = null;  
        try {  
            mac = Mac.getInstance("HmacSHA384");  
            mac.init(key);  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
            return new byte[0];  
        }catch (InvalidKeyException e) {  
            e.printStackTrace();  
            return new byte[0];  
        }  
        return mac.doFinal(data);  
    }  

    /** 
     * 使用HmacSHA384消息摘要算法計算消息摘要 
     *  
     * @param data 做消息摘要的數據 
     * @param key 密鑰 
     * @return 消息摘要(長度爲16的字節數組) 
     */  
    public static byte[] encodeHmacSHA384(byte[] data, byte[] key){  
        Key k = toKey(key, "HmacSHA384");  
        return encodeHmacSHA384(data, k);  
    }  



    /** 
     * 使用HmacSHA512消息摘要算法計算消息摘要 
     *  
     * @param data 做消息摘要的數據 
     * @param key 密鑰 
     * @return 消息摘要(長度爲16的字節數組) 
     */  
    public static byte[] encodeHmacSHA512(byte[] data, Key key){  
        Mac mac = null;  
        try {  
            mac = Mac.getInstance("HmacSHA512");  
            mac.init(key);  
        } catch (NoSuchAlgorithmException e) {  
            e.printStackTrace();  
            return new byte[0];  
        }catch (InvalidKeyException e) {  
            e.printStackTrace();  
            return new byte[0];  
        }  
        return mac.doFinal(data);  
    }  

    /** 
     * 使用HmacSHA512消息摘要算法計算消息摘要 
     *  
     * @param data 做消息摘要的數據 
     * @param key 密鑰 
     * @return 消息摘要(長度爲16的字節數組) 
     */  
    public static byte[] encodeHmacSHA512(byte[] data, byte[] key){  
        Key k = toKey(key, "HmacSHA512");  
        return encodeHmacSHA512(data, k);  
    }  


    private static String  showByteArray(byte[] data){  
        if(null == data){  
            return null;  
        }  
        StringBuilder sb = new StringBuilder("{");  
        for(byte b:data){  
            sb.append(b).append(",");  
        }  
        sb.deleteCharAt(sb.length()-1);  
        sb.append("}");  
        return sb.toString();  
    }  

    public static void main(String[] args) {  
//      byte[] key = getHmaMD5key();  
//      byte[] key = getHmaSHAkey();  
//      byte[] key = getHmaSHA256key();  
//      byte[] key = getHmaSHA384key();  
        byte[] key = getHmaSHA512key();  


        System.out.println("加密密鑰: byte[]:"+showByteArray(key).length());  

        String data = "Mac數據";  
        System.out.println("加密前數據: string:"+data);  
        System.out.println("加密前數據: byte[]:"+showByteArray(data.getBytes()));  
        System.out.println();  
//      byte[] encodeData = encodeHmacMD5(data.getBytes(), key);  
//      byte[] encodeData = encodeHmacSHA(data.getBytes(), key);  
//      byte[] encodeData = encodeHmacSHA256(data.getBytes(), key);  
//      byte[] encodeData = encodeHmacSHA384(data.getBytes(), key);  
        byte[] encodeData = encodeHmacSHA512(data.getBytes(), key);  
        System.out.println("加密後數據: byte[]:"+showByteArray(encodeData).length());  
        System.out.println("加密後數據: byte[]:"+encodeData.length);  
        System.out.println("加密後數據: hexStr:"+Hex.encodeHexStr(encodeData));  
        System.out.println();  
    }  
}  
發佈了63 篇原創文章 · 獲贊 134 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章