1. 程式人生 > >java訊息摘要演算法加密

java訊息摘要演算法加密

訊息摘要演算法加密

  •  訊息摘要演算法主要分為3類:MD(Message Digest)、SHA(Secure Hash Algorithm)、MAC(Message Authentication Code),以上3類演算法的主要作用是驗證資料的完整性——是數字簽名的核心演算法。

訊息摘要演算法——MD

  • MD演算法家族有3類MD2、MD4、MD5,MD家族生成的都是128位的資訊摘要。
演算法 摘要長度 實現方
MD2 128 JDK
MD4 128 Bouncy
MD5 128 JDK
  • 資訊摘要演算法由於使用的是一種單向函式,所以理論上是不可破解的(山東大學的王曉雲教授已經破解了MD5和SHA,所以訊息摘要是可以偽造的,只不過難度比較大)。所有MD演算法進行摘要的結果都是128為位(32位16進位制的數字,因為1位16進位制數代表4位二進位制數)

以下是Java中實現的各種MD加密:

package md;

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

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.MD2Digest;
import
org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.jce.provider.BouncyCastleProvider; public class JavaMD { private static String src = "object-oriented"; // 需要加密的原始字串 public static void main(String[] args) throws NoSuchAlgorithmException { System.out.println("原始字串:"
+ src + "\n"); jdkMD5(); bouncyCastleMD5(); commonsCodecMD5(); System.out.println(); jdkMD2(); bouncyCastleMD2(); commonsCodecMD2(); System.out.println(); bouncyCastleMD4(); } /** jdk實現MD5加密 */ public static void jdkMD5() throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] md5Bytes = md.digest(src.getBytes()); System.out.println("JDK MD5:" + Hex.encodeHexString(md5Bytes));//利用第三方包將byte陣列轉化為16進位制字串 } /** jdk實現MD2加密 */ public static void jdkMD2() throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("md2"); byte[] md5Bytes = md.digest(src.getBytes()); System.out.println("JDK MD2:" + Hex.encodeHexString(md5Bytes)); } /** Bouncy Castle實現MD4加密 */ public static void bouncyCastleMD4() throws NoSuchAlgorithmException{ /*通過這種方式給JDK動態新增一個provider,就可以通過這種方式獲得JDK本身不支援的MD4了*/ Security.addProvider(new BouncyCastleProvider()); MessageDigest md = MessageDigest.getInstance("md4"); byte[] md4Bytes = md.digest(src.getBytes()); System.out.println("bc MD4:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes)); } /** Bouncy Castle實現MD5加密 */ public static void bouncyCastleMD5(){ Digest digest = new MD5Digest(); digest.update(src.getBytes(), 0, src.getBytes().length); byte[]md5Bytes = new byte[digest.getDigestSize()]; digest.doFinal(md5Bytes, 0); System.out.println("bc MD5:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md5Bytes)); } /** Bouncy Castle實現MD2加密 */ public static void bouncyCastleMD2(){ Digest digest = new MD2Digest(); digest.update(src.getBytes(), 0, src.getBytes().length); byte[]md2Bytes = new byte[digest.getDigestSize()]; digest.doFinal(md2Bytes, 0); System.out.println("bc MD2:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md2Bytes)); } /** Commons Codec 實現MD5加密*/ public static void commonsCodecMD5() { System.out.println("cc MD5:\t" + DigestUtils.md5Hex(src.getBytes())); } /** Commons Codec 實現MD2加密*/ public static void commonsCodecMD2() { System.out.println("cc MD2:\t" + DigestUtils.md2Hex(src.getBytes())); } }

以上程式的執行結果:
這裡寫圖片描述

  • JDK本身提供了MD2和MD5的實現,apache的Commons Codec在JDK的基礎上進行了改良,使用Commons Codec提供介面進行MD2和MD5加密將會簡單很多。JDK本省並沒有提供MD4演算法的實現,但是我們可以通過動態新增provider的方式讓jdk支援MD4,見以下程式碼:
/* 通過這種方式給JDK動態新增一個provider,就可以通過這種方式獲得JDK本身不支援的MD4了 */
Security.addProvider(new BouncyCastleProvider());

MessageDigest md = MessageDigest.getInstance("md4");

byte[] md4Bytes = md.digest(src.getBytes());
System.out.println("bc MD4:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes));
  • Bouncy Castle提供了MD2、MD4和MD5的實現,對訊息摘要演算法的支援比較完善,但是API還是沒有Apache的Commons Codec友善。因此,如果我們要進行MD2和MD4實現,最好選用Commons Codec。

MD演算法的應用

這裡寫圖片描述

  • 註冊時:
      應用程式伺服器將使用者提交的密碼進行MD5即:資料庫中存放的使用者名稱是明文,而密碼是密文(16進位制字串)摘要演算法,得到32位的16進位制字串(密文)。把使用者名稱(明文)和密碼(密文)進行資訊持久化儲存到資料庫中,返回註冊結果。

  • 登入時:
      應用程式伺服器同樣對密碼進行MD5摘要,然後將使用者提交的使用者名稱和密碼的摘要資訊和資料庫中儲存的資訊進行比對,返回登入結果。

訊息摘要演算法——SHA

安全雜湊演算法,固定長度的摘要資訊。被認為是MD5的繼承者。是一個系列,包括SHA-1、SHA-2(SHA-224、SHA-256、SHA-384、SHA-512),也就是除了SHA-1,其他的4種都被稱為是SHA-2。每種演算法的摘要長度和實現方如下:
這裡寫圖片描述

  • SHA演算法的實現和MD演算法的實現大同小異,也是JDK提供了預設的幾種實現,apache的Commons Codec在JDK的基礎上進行了優化,使其更好用,而Bouncy Castle是JDK的拓展,提供了JDK和Commons Codec沒有的SHA-224的實現。
package sha;

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

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;

public class JavaSHA {

    private static String src = "object-oriente"; // 需要加密的原始字串

    public static void main(String[] args) throws NoSuchAlgorithmException {

        System.out.println("原始字串:" + src);

        jdkSHA1();
        bouncyCastleSHA1();
        commonsCodecSAH1();
        System.out.println();

        bouncyCastleSHA224();
        System.out.println();
        jdkSHA256();

        bouncyCastleSHA256();
    }

    /** JDK實現sha-1 */
    public static void jdkSHA1() throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("sha");// sha1演算法傳入引數為sha
        byte[] sha1Bytes = md.digest(src.getBytes());
        System.out.println("JDK SHA-1:\t" + Hex.encodeHexString(sha1Bytes));
    }

    /** JDK實現sha-256 */
    public static void jdkSHA256() throws NoSuchAlgorithmException{
        MessageDigest md = MessageDigest.getInstance("sha-256");
        md.update(src.getBytes());
        System.out.println("JDK SHA-256:\t" + org.bouncycastle.util.encoders.Hex.toHexString(md.digest()));
    }

    /** Bouncy Castle實現sha-1 */
    public static void bouncyCastleSHA1(){

        Digest digest = new SHA1Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[]sha1Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(sha1Bytes, 0);
        System.out.println("bc SHA-1:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha1Bytes));
    }

    /** Bouncy Castle實現sha-224 */
    public static void bouncyCastleSHA224(){

        Digest digest = new SHA224Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[]sha224Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(sha224Bytes, 0);
        System.out.println("bc SHA-224:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha224Bytes));
    }

    /** Bouncy Castle實現sha-256 */
    public static void bouncyCastleSHA256() {
        Digest digest = new SHA256Digest();
        digest.update(src.getBytes(), 0, src.getBytes().length);
        byte[] sha256Bytes = new byte[digest.getDigestSize()];
        digest.doFinal(sha256Bytes, 0);
        System.out.println("bc SHA-256:\t" + org.bouncycastle.util.encoders.Hex.toHexString(sha256Bytes));
    }

    /** Commons Codec實現sha-1 */
    public static void commonsCodecSAH1(){

        System.out.println("cc SHA-1:\t" + DigestUtils.sha1Hex(src.getBytes()));

        /* 採用下面的方式更加方便 */
//        System.out.println("cc SHA-1:\t" + DigestUtils.sha1Hex(src));

    }
}

執行結果:
這裡寫圖片描述

SHA演算法的應用

 在瀏覽器的證書管理器中證書:WEB證書一般採用SHA演算法。
 這裡寫圖片描述

訊息摘要演算法是為了防止訊息在傳輸過程中的篡改。
這裡寫圖片描述

我們在很多網站上都可以用QQ賬號一鍵登入,通常騰訊會給每一個接入方一個key,可能會約定一個訊息傳送的格式(例如:http://**?msg=12Hsad74mj&&timestamp=1309488734),其中msg=摘要資訊+key+時間戳。

訊息摘要演算法——MAC

MAC(Message Authentication Code),相容了MD和SHA的特性,並且在它們的基礎上加入了金鑰。因此MAC也稱為HMAC(keyed-Hash Message Authentication Code)含有金鑰的雜湊函式演算法。

  • MD系列:HmacMD2、HmacMD4、HmacMD5
  • SHA系列:HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512

例如:常用的Linux客戶端SecurityCRT。MAC的演算法的提供者如下:
這裡寫圖片描述

Commons Codec中並沒有提供Hmac演算法的實現。

下面的程式以JDK本身和Bouncy Castle實現了HmacMD5,如果需要實現其他的加密只需要改變相關的引數即可:

package hmac;

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

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

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;


public class JavaHmac {

    private static String src = "object-oriente"; // 需要加密的原始字串

    public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, DecoderException {

        System.out.println("原始字串:" + src + "\n");
        jdkHmacMD5();
        bouncyCastleHmacMD5();
    }

    public static void jdkHmacMD5() throws NoSuchAlgorithmException, InvalidKeyException, DecoderException{

        //1.得到金鑰
        KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5"); 
        SecretKey secretKey = keyGenerator.generateKey();//生成金鑰
//        byte[] key = secretKey.getEncoded();//獲得金鑰
        byte[] key = Hex.decodeHex("aabbccddee".toCharArray());

        //2.還原金鑰
        SecretKey restoreSecretKey = new SecretKeySpec(key, "hmacMD5");

        //3.資訊摘要
        Mac mac = Mac.getInstance(restoreSecretKey.getAlgorithm());//例項化mac
        mac.init(restoreSecretKey);//初始化mac
        byte[] hmacMD5Bytes = mac.doFinal(src.getBytes());//執行摘要

        System.out.println("jdkHmacMD5:\t" + Hex.encodeHexString(hmacMD5Bytes));
    }

    public static void bouncyCastleHmacMD5() {

        HMac hmac = new HMac(new MD5Digest());
        //生成金鑰的時候以aabbccddee為基準
        hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex.decode("aabbccddee")));
        hmac.update(src.getBytes(), 0, src.getBytes().length);

        // 執行摘要
        byte[]hmacMDdBytes = new byte[hmac.getMacSize()];
        hmac.doFinal(hmacMDdBytes, 0);

        System.out.println("bcHmacMD5:\t"+org.bouncycastle.util.encoders.Hex.toHexString(hmacMDdBytes));
    }

}

執行結果:
這裡寫圖片描述

HMAC演算法的應用:
這裡寫圖片描述