1. 程式人生 > >加密演算法你要知道的事

加密演算法你要知道的事

首先大家要記住現代密碼學最重要的原則柯克霍夫原則: 
資料的安全基於金鑰而不是演算法的保密。也就是說即使密碼系統的任何細節已為人悉知,只要密匙未洩漏,它也應是安全的。

具體來說: 
系統必須可用,非數學上不可譯碼。 
系統不一定要保密,可以輕易落入敵人手中。 
密匙必須可以不經書寫的資料交換和記憶,且雙方可以改變密匙。 
系統可以用於電訊。 
系統可以轉移位置,它的功能必須不用經過幾個人之手才可達到。 
系統容易使用,不要求使用者的腦力過份操勞或有很多的規則。

一、主要的加密方式程式碼提供方 
JDK:程式碼在java安裝目錄下的jre\lib\jce.jar包裡; 
CC:Apache公司提供的org.apache.commons.codec 
主頁:

http://commons.apache.org/proper/commons-codec/ 
BC:org.bouncecastle 
主頁:http://www.bouncycastle.org/java.html 
基本常用的使用JDK就夠了。

二、Base64演算法 
1、從現在加密演算法的複雜性來看Base64這種都不好意思說自己是加密,不過對於完全不懂計算機的人來說也夠用了。採用Base64編碼具有不可讀性,即所編碼的資料不會被人用肉眼所直接看到。 
Base64編碼一般用於url的處理,或者說任何你不想讓普通人一眼就知道是啥的東西都可以用Base64編碼處理後再發布在網路上。

package com.amuro.strategy.base64;

import
java.util.Base64; import com.amuro.strategy.IStrategy; /** * Base64演算法基於64個基本字元,加密後的string中只包含這64個字元 * @author Amuro * */ public class Base64Strategy implements IStrategy { public String encode(String src) { byte[] encodeBytes = Base64.getEncoder().encode(src.getBytes()); return
new String(encodeBytes); } public String decode(String src) { byte[] decodeBytes = Base64.getDecoder().decode(src.getBytes()); return new String(decodeBytes); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

2、Base64編碼對應關係表 
這裡寫圖片描述

三、訊息摘要演算法(Message Digest) 
訊息摘要(Message Digest)又稱為數字摘要(Digital Digest)。它是一個唯一對應一個訊息或文字的固定長度的值,它由一個單向Hash加密函式對訊息進行作用而產生。HASH函式的抗衝突性使得如果一段明文稍有變化,哪怕只更改該段落的一個字母,通過雜湊演算法作用後都將產生不同的值。而HASH演算法的單向性使得要找到雜湊值相同的兩個不同的輸入訊息,在計算上是不可能的。所以資料的雜湊值,即訊息摘要,可以檢驗資料的完整性。 
用大白話來說,任何一段資料應該都和人一樣是唯一的,唯一的標識是什麼,人類的話目前就是指紋,而資料的指紋是什麼呢?沒錯,就是訊息摘要演算法產生的這一段String。比如我們在註冊網站的時候,客戶端向伺服器傳輸的,應該是我們輸入的密碼進行訊息摘要處理後的內容,這樣就算伺服器被攻破,Hack也無法知道使用者真實的密碼是什麼。不過有說現在MD5和SHA已經被攻破了,具體大家可以谷歌。 
1、MD5

package com.amuro.strategy.message_digest;

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

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

import com.amuro.strategy.IStrategy;

/**
 * 訊息摘要演算法
 * @author Amuro
 *
 */
public class MD5Strategy implements IStrategy
{

    public String encode(String src)
    {
        try
        {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] encodeBytes = md.digest(src.getBytes());

            return Hex.encodeHexString(encodeBytes);
        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public String decode(String src)
    {
        throw new RuntimeException("MD5 no decode");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

2、SHA

package com.amuro.strategy.message_digest;

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

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

import com.amuro.strategy.IStrategy;

/**
 * 安全雜湊演算法
 * @author Amuro
 *
 */
public class SHAStrategy implements IStrategy
{

    public String encode(String src)
    {
        try
        {
            MessageDigest md = MessageDigest.getInstance("SHA");
            md.update(src.getBytes());
            return Hex.encodeHexString(md.digest());
        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        return null;
    }

    public String decode(String src)
    {
        throw new RuntimeException("SHA no decode");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

四、對稱加密 
採用單鑰密碼系統的加密方法,同一個金鑰可以同時用作資訊的加密和解密,這種加密方法稱為對稱加密,也稱為單金鑰加密。而因為加密和解密都使用同一個金鑰,如何把金鑰安全地傳遞到解密者手上就成了必須要解決的問題。當然,安全性較低帶來的優點就是優計算量小、加密速度快、加密效率高。 
然並卵,現代計算機對這種級別的計算量早就不care了,安全才是最重要的。 
1、DES 
DES,全稱為“Data Encryption Standard”,中文名為“資料加密標準”,是一種使用金鑰加密的塊演算法。DES 演算法為密碼體制中的對稱密碼體制,又被稱為美國資料加密標準,是 1972 年美國 IBM 公司研製的對稱密碼體制加密演算法。 明文按 64 位進行分組,金鑰長 64 位,金鑰事實上是 56 位參與 DES 運算(第8、16、24、32、40、48、56、64 位是校驗位, 使得每個金鑰都有奇數個 1)分組後的明文組和 56 位的金鑰按位替代或交換的方法形成密文組的加密方法。

package com.amuro.strategy.des;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

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

import com.amuro.strategy.IStrategy;

/**
 * 
 * @author Amuro
 *
 */
public class DESStrategy implements IStrategy
{
    private Cipher cipher;
    private SecretKey generateKey;

    public String encode(String src)
    {
        try
        {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
            keyGenerator.init(56);//size
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] keyBytes = secretKey.getEncoded();

            DESKeySpec desKeySpec = new DESKeySpec(keyBytes);
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
            generateKey = secretKeyFactory.generateSecret(desKeySpec);

            cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, generateKey);
            byte[] resultBytes = cipher.doFinal(src.getBytes());

            return Hex.encodeHexString(resultBytes);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    public String decode(String src)
    {
        try
        {
            cipher.init(Cipher.DECRYPT_MODE, generateKey);
            byte[] result = Hex.decodeHex(src.toCharArray());
            return new String(cipher.doFinal(result));
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

2、3DES 
3DES,也就是“Triple DES”,中文名“三重資料加密演算法”,它相當於是對每個資料塊應用三次 DES 加密演算法。由於計算機運算能力的增強,原版 DES 密碼的金鑰長度變得容易被暴力破解;3DES 即是設計用來提供一種相對簡單的方法,即通過增加 DES 的金鑰長度來避免類似的攻擊,而不是設計一種全新的塊密碼演算法。

package com.amuro.strategy.des;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;

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

import com.amuro.strategy.IStrategy;

public class _3DESStrategy implements IStrategy
{
    private Cipher cipher;
    private SecretKey generateKey;

    public String encode(String src)
    {
        try
        {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
            keyGenerator.init(168);//size
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] keyBytes = secretKey.getEncoded();

            DESedeKeySpec desKeySpec = new DESedeKeySpec(keyBytes);
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DESede");
            generateKey = secretKeyFactory.generateSecret(desKeySpec);

            cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, generateKey);
            byte[] resultBytes = cipher.doFinal(src.getBytes());

            return Hex.encodeHexString(resultBytes);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    public String decode(String src)
    {
        try
        {
            cipher.init(Cipher.DECRYPT_MODE, generateKey);
            byte[] result = Hex.decodeHex(src.toCharArray());
            return new String(cipher.doFinal(result));
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

3、AES 
AES,全稱為“Advanced Encryption Standard”,中文名“高階加密標準”,在密碼學中又稱 Rijndael 加密法,是美國聯邦政府採用的一種區塊加密標準。AES 加密演算法作為新一代的資料加密標準匯聚了強安全性、高效能、高效率、易用和靈活等優點。AES 設計有三個金鑰長度:128,192,256 位。相對而言,AES 的 128 金鑰比 DES 的 56 金鑰強了 1021 倍。

package com.amuro.strategy.des;

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

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

import com.amuro.strategy.IStrategy;

public class AESStrategy implements IStrategy
{
    private Cipher cipher;
    private SecretKey generateKey;

    public String encode(String src)
    {
        try
        {
            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
            keyGenerator.init(128);//size
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] keyBytes = secretKey.getEncoded();

            generateKey = new SecretKeySpec(keyBytes, "AES");

            cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, generateKey);
            byte[] resultBytes = cipher.doFinal(src.getBytes());

            return Hex.encodeHexString(resultBytes);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    public String decode(String src)
    {
        try
        {
            cipher.init(Cipher.DECRYPT_MODE, generateKey);
            byte[] result = Hex.decodeHex(src.toCharArray());
            return new String(cipher.doFinal(result));
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

4、PBE 
PBE,全稱為“Password Base Encryption”,中文名“基於口令加密”,是一種基於密碼的加密演算法,其特點是使用口令代替了金鑰,而口令由使用者自己掌管,採用隨機數雜湊多重加密等方法保證資料的安全性。 
PBE演算法沒有金鑰的概念,把口令當做金鑰了。因為金鑰長短影響演算法安全性,還不方便記憶,這裡我們直接換成我們自己常用的口令就大大不同了,便於我們的記憶。但是單純的口令很容易被字典法給窮舉出來,所以我們這裡給口令加了點“鹽”,這個鹽和口令組合,想破解就難了。同時我們將鹽和口令合併後用訊息摘要演算法進行迭代很多次來構建金鑰初始化向量的基本材料,使破譯更加難了。

package com.amuro.strategy.pbe;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

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

import com.amuro.strategy.IStrategy;

/**
 * 基於口令的加密(password),對稱 + 訊息摘要
 * @author Amuro
 *
 */
public class PBEStrategy implements IStrategy
{
    private Cipher cipher;
    private SecretKey generateKey;
    private PBEParameterSpec pbeParameterSpec;

    public String encode(String src)
    {
        try
        {
            SecureRandom secureRandom = new SecureRandom();
            byte[] salt = secureRandom.generateSeed(8);

            String password = "amuro";
            PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBEWITHMD5andDES");
            generateKey = secretKeyFactory.generateSecret(pbeKeySpec);

            pbeParameterSpec = new PBEParameterSpec(salt, 100);
            cipher = Cipher.getInstance("PBEWITHMD5andDES");
            cipher.init(Cipher.ENCRYPT_MODE, generateKey, pbeParameterSpec);
            byte[] resultBytes = cipher.doFinal(src.getBytes());
            return Hex.encodeHexString(resultBytes);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    public String decode(String src)
    {
        try
        {
            cipher.init(Cipher.DECRYPT_MODE, generateKey, pbeParameterSpec);
            byte[] result = Hex.decodeHex(src.toCharArray());
            return new String(cipher.doFinal(result));
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

五、非對稱加密 
非對稱加密演算法需要兩個金鑰來進行加密和解密,分別是公鑰和私鑰。需要注意的一點,這個公鑰和私鑰必須是一對的,如果用公鑰對資料進行加密,那麼只有使用對應的私鑰才能解密,反之亦然。由於加密和解密使用的是兩個不同的金鑰,因此,這種演算法叫做非對稱加密演算法。 
1、RSA 
其實,在早在 1978 年的時候,RSA就已經出現了,它是第一個既能用於資料加密也能用於數字簽名的演算法。它易於理解和操作,也很流行。其原理就如上面的工作過程所述。RSA 演算法基於一個十分簡單的數論事實:將兩個大素數相乘十分容易,但是想要對其乘積進行因式分解卻極其困難,因此可以將乘積公開作為加密金鑰。

package com.amuro.strategy.asymmetric;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

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

import com.amuro.strategy.IStrategy;

public class RSAStrategy implements IStrategy
{
    private RSAPublicKey rsaPublicKey;
    private RSAPrivateKey rsaPrivateKey;

    public String encode(String src)
    {
        try
        {
            //初始化金鑰
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(512);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
            rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();

            //私鑰加密 公鑰解密
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec 
                = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] resultBytes = cipher.doFinal(src.getBytes());

            //私鑰解密 公鑰加密
//          X509EncodedKeySpec x509EncodedKeySpec =
//                  new X509EncodedKeySpec(rsaPublicKey.getEncoded());
//          KeyFactory keyFactory = KeyFactory.getInstance("RSA");
//          PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
//          Cipher cipher = Cipher.getInstance("RSA");
//          cipher.init(Cipher.ENCRYPT_MODE, publicKey);
//          byte[] resultBytes = cipher.doFinal(src.getBytes());

            return Hex.encodeHexString(resultBytes);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    public String decode(String src)
    {
        try
        {
            //私鑰加密 公鑰解密
            X509EncodedKeySpec x509EncodedKeySpec =
                    new X509EncodedKeySpec(rsaPublicKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            byte[] resultBytes = cipher.doFinal(Hex.decodeHex(src.toCharArray()));

            //私鑰解密 公鑰加密
//          PKCS8EncodedKeySpec pkcs8EncodedKeySpec 
//              = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
//          KeyFactory keyFactory = KeyFactory.getInstance("RSA");
//          PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
//          Cipher cipher = Cipher.getInstance("RSA");
//          cipher.init(Cipher.DECRYPT_MODE, privateKey);
//          byte[] resultBytes = cipher.doFinal(Hex.decodeHex(src.toCharArray()));

            return new String(resultBytes);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        return null;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

2、DH演算法 
DH,全稱為“Diffie-Hellman”,他是一種確保共享KEY安全穿越不安全網路的方法,也就是常說的金鑰一致協議。由公開金鑰密碼體制的奠基人Diffie和Hellman所提出的一種思想。簡單的說就是允許兩名使用者在公開媒體上交換資訊以生成“一致”的、可以共享的金鑰。也就是由甲方產出一對金鑰(公鑰、私鑰),乙方依照甲方公鑰產生乙方金鑰對(公鑰、私鑰)。 
以此為基線,作為資料傳輸保密基礎,同時雙方使用同一種對稱加密演算法構建本地金鑰(SecretKey)對資料加密。這樣,在互通了本地金鑰(SecretKey)演算法後,甲乙雙方公開自己的公鑰,使用對方的公鑰和剛才產生的私鑰加密資料,同時可以使用對方的公鑰和自己的私鑰對資料解密。不單單是甲乙雙方兩方,可以擴充套件為多方共享資料通訊,這樣就完成了網路互動資料的安全通訊!

package com.amuro.strategy.asymmetric;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Objects;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;

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

import com.amuro.strategy.IStrategy;

public class DHStrategy implements IStrategy
{
    private Cipher cipher;
    private SecretKey receiverSecretKey;

    public String encode(String src)
    {
        try
        {
            //初始化傳送方金鑰
            KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance("DH");
            senderKeyPairGenerator.initialize(512);
            KeyPair senderkeyPair = senderKeyPairGenerator.generateKeyPair();
            PrivateKey senderPrivateKey = senderkeyPair.getPrivate();
            byte[] senderPublicKeyBytes = senderkeyPair.getPublic().getEncoded();//傳送方的公鑰

            //初始化接收方金鑰,用傳送方的公鑰
            KeyFactory receiverKeyFactory = KeyFactory.getInstance("DH");
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(senderPublicKeyBytes);
            PublicKey receiverPublicKey = receiverKeyFactory.generatePublic(x509EncodedKeySpec);
            DHParameterSpec dhParameterSpec = 
                    ((DHPublicKey)receiverPublicKey).getParams();
            KeyPairGenerator receiverKeyPairGenerator = KeyPairGenerator.getInstance("DH");
            receiverKeyPairGenerator.initialize(dhParameterSpec);
            KeyPair receiverKeyPair = receiverKeyPairGenerator.generateKeyPair();
            PrivateKey receiverPrivateKey = receiverKeyPair.getPrivate();
            byte[] receiverPublicKeyBytes = receiverKeyPair.getPublic().getEncoded();

            KeyAgreement receiverKeyAgreement = KeyAgreement.getInstance("DH");
            receiverKeyAgreement.init(receiverPrivateKey);
            receiverKeyAgreement.doPhase(receiverPublicKey, true);
            receiverSecretKey = receiverKeyAgreement.generateSecret("DES");

            //傳送方拿到接收方的public key就可以做加密了
            KeyFactory senderKeyFactory = KeyFactory.getInstance("DH");
            x509EncodedKeySpec = new X509EncodedKeySpec(receiverPublicKeyBytes);
            PublicKey senderPublicKey = senderKeyFactory.generatePublic(x509EncodedKeySpec);
            KeyAgreement senderKeyAgreement = KeyAgreement.getInstance("DH");
            senderKeyAgreement.init(senderPrivateKey);
            senderKeyAgreement.doPhase(senderPublicKey, true);
            SecretKey senderSecretKey = senderKeyAgreement.generateSecret("DES");

            if(Objects.equals(receiverSecretKey, senderSecretKey))
            {
                cipher = Cipher.getInstance("DES");
                cipher.init(Cipher.ENCRYPT_MODE, senderSecretKey);
                byte[] result = cipher.doFinal(src.getBytes());
                return Hex.encodeHexString(result);
            }

        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return null;
    }

    public String decode(String src)
    {
        try
        {
            cipher.init(Cipher.DECRYPT_MODE, receiverSecretKey);
            byte[] result = Hex.decodeHex(src.toCharArray());
            return new String(cipher.doFinal(result));
        }
        catch(Exception e)
        {
            e.printStackTrac