天天看點

高等資料加密--非對稱加密算法分類DH(密鑰交換算法)RSA算法ElGamal算法

非對稱加密算法與對稱加密算法的主要差別在于非對稱加密算法用于加密和解密的密鑰不同,一個公開,稱為公鑰;一個保密,稱為私鑰。是以,非對稱密碼算法也稱為雙鑰和公鑰加密算法。

非對稱加密算法解決了對稱加密算法密鑰配置設定問題,并極大的提高了算法的安全性。多種B2C或B2B應用均使用非對稱加密算法作為資料加密的核心算法。解決了對稱加密算法的密鑰存儲問題。

分類

非對稱加密算法源于DH算法,其後主要分為兩類:

1. 基于因子分解難題:

RSA算法(可用于數字加密和數字簽名)

2. 基于離散對數難題:

DSA算法(數字簽名算法)、ECC算法(橢圓曲線加密)算法以曲線方程式為基礎産生密鑰(傳統使用大質數的積産生),可以做到更快、更小,并且更有效。

DH(密鑰交換算法)

DH算法是一個密鑰協商算法、僅能用于密鑰配置設定,再通過這個密鑰對資料進行加密和解密處理。

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class DH {
    //非對稱加密密鑰算法
    public static final String KEY_ALGORITHM = "DH";
    //本地密鑰算法,即對稱加密算法
    public static final String SECRET_ALGORITHM = "AES";
    /**
     * 密鑰長度
     * DH算法預設密鑰長度為1024
     * 密鑰長度必須是64的倍數,其範圍在512位到1024位之間
     */
    private static final int KEY_SIZE = 512;
    //公鑰
    public static final String PUBLIC_KEY = "DHPublicKey";
    //私鑰
    public static final String PRIVATE_KEY = "DHPrivateKey";

    /**
     * 初始化甲方密鑰
     * @return
     * @throws Exception
     */
    public static Map<String,Object> initKey() throws Exception {
        //執行個體化密鑰生成器
        KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //初始化密鑰生成器
        keyPairGenerator.initialize(KEY_SIZE);
        //生成密鑰對
        KeyPair keyPair=keyPairGenerator.generateKeyPair();
        //甲方公鑰
        DHPublicKey publicKey=(DHPublicKey) keyPair.getPublic();
        //甲方私鑰
        DHPrivateKey privateKey=(DHPrivateKey) keyPair.getPrivate();
        //将密鑰存儲在map中
        Map<String,Object> keyMap=new HashMap<String,Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 生成乙方密鑰
     * @param key 甲方公鑰
     * @return
     * @throws Exception
     */
    public static Map<String,Object> initKey(byte[] key) throws Exception {
        //解析甲方的公鑰
        //轉換公鑰的材料
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
        //執行個體化密鑰工廠
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
        //産生公鑰
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
        //由甲方的公鑰構造乙方密鑰
        DHParameterSpec dhParamSpec=((DHPublicKey)pubKey).getParams();
        //執行個體化密鑰生成器
        KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
        //初始化密鑰生成器
        keyPairGenerator.initialize(dhParamSpec);
        //産生密鑰對
        KeyPair keyPair=keyPairGenerator.genKeyPair();
        //乙方公鑰
        DHPublicKey publicKey=(DHPublicKey)keyPair.getPublic();
        //乙方私鑰
        DHPrivateKey privateKey=(DHPrivateKey)keyPair.getPrivate();
        //将密鑰存儲在Map中
        Map<String,Object> keyMap=new HashMap<String,Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 加密
     * @param data 待加密資料
     * @param key 密鑰
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data,byte[] key) throws Exception {
        //還原秘密密鑰
        SecretKey secretKey = new SecretKeySpec(key,SECRET_ALGORITHM);
        //建立加解密對象
        Cipher cipher = Cipher.getInstance(SECRET_ALGORITHM);
        //初始化為加密模式
        cipher.init(Cipher.ENCRYPT_MODE,secretKey);
        //加密
        return cipher.doFinal(data);
    }

    /**
     *解密
     * @param data 待解密資料
     * @param key 密鑰
     * @return 解密資料
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data,byte[] key) throws Exception {
        //還原秘密密鑰
        SecretKey secretKey = new SecretKeySpec(key,SECRET_ALGORITHM);
        //建立加解密對象
        Cipher cipher = Cipher.getInstance(SECRET_ALGORITHM);
        //初始化為解密模式
        cipher.init(Cipher.DECRYPT_MODE,secretKey);
        //解密
        return cipher.doFinal(data);
    }

    /**
     * 生成本地密鑰
     * @param publicKey 公鑰
     * @param privateKey 私鑰
     * @return 本地密鑰
     * @throws Exception
     */
    public static byte[] getSecretKey(byte[] publicKey,byte[] privateKey) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        //執行個體化密鑰工廠
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
        //初始化公鑰
        //密鑰材料轉換
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(publicKey);
        //産生公鑰
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
        //初始化私鑰
        //密鑰材料轉換
        PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(privateKey);
        //産生私鑰
        PrivateKey priKey=keyFactory.generatePrivate(pkcs8KeySpec);
        //執行個體化
        KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm());
        //初始化
        keyAgree.init(priKey);
        keyAgree.doPhase(pubKey, true);
        //生成本地密鑰
        SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM);
        return secretKey.getEncode();
    }

    /**
     * 擷取密鑰
     * @param keys 存儲密鑰的map對象
     * @param keyType 密鑰類型
     * @return
     * @throws Exception
     */
    public  static  byte[] getKey(Map<String,Object> keys,String keyType) throws Exception {
        Key key = (Key) keys.get(keyType);
        return key.getEncoded();
    }

    /**
     * 轉換為Base64String
     * @param data 待加密資料
     * @return
     */
    public static String toBase64String(byte[] data){
        return Base64.encodeBase64String(data);
    }
    
    @Test
    public void test() throws Exception {
         //生成甲方密鑰對
        Map<String,Object> keys = DH.initKey();
        //甲方公鑰
        byte[] pubKey1 = DH.getKey(keys,DH.PUBLIC_KEY);
        //甲方私鑰
        byte[] priKey1 = DH.getKey(keys, DH.PRIVATE_KEY);
        System.out.println("甲方公鑰:"+DH.toBase64String(pubKey1));
        System.out.println("甲方私鑰:"+DH.toBase64String(priKey1));

        //生成乙方密鑰對
        Map<String,Object> keys1 = DH.initKey(pubKey1);
        //乙方公鑰
        byte[] pubKey2 = DH.getKey(keys1,DH.PUBLIC_KEY);
        //乙方私鑰
        byte[] priKey2 = DH.getKey(keys1, DH.PRIVATE_KEY);
        System.out.println("乙方公鑰:"+DH.toBase64String(pubKey2));
        System.out.println("乙方私鑰:"+DH.toBase64String(priKey2));
        //甲方本地密鑰
        byte[] secret1 = DH.getSecretKey(pubKey2,priKey1);
        //乙方本地密鑰
        byte[] secret2 = DH.getSecretKey(pubKey1,priKey2);
        System.out.println("甲方本地密鑰:"+DH.toBase64String(secret1));
        System.out.println("乙方本地密鑰:"+DH.toBase64String(secret2));

        String text1 = "算法怎麼沒用";
        byte[] data = DH.encrypt(text1.getBytes("utf-8"),secret1);
        System.out.println(DH.toBase64String(DH.decrypt(data,secret2)));
    }
    
    //輸出結果
    甲方公鑰:MIHgMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANEAAJBAJXzgB2MZ/GD3nfiwsfXy45+VAHYRuoYvzWbUCUtba+M82ec2VYK/t/dr5NH89KitK5WKD6TvpBwGui5OY8WjOM=
    甲方私鑰:MIHSAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQzAjEAtG2dpvIXfNObwStWvopwppUmekkDtfUPX3Pg+xpiL0DoiVIFVQvP/UTijB+laO64
    乙方公鑰:MIHgMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANEAAJBANpVJymcJssw3O8xcSeWZyPmjBBoPwHMJOln0eOsW+FFyKHzNO9GIysuMkE1GrEVqA0b6uQ+gRmku4/8oA183i0=
    乙方私鑰:MIHSAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQzAjEAvBjOMSA4FKWc1d6JPy2wEXT7f5Kpu9WuJbmwL7DGa+b39pScBVCebXf3lJy1+yBW
    甲方本地密鑰:Oe6gr0aq4fVIeO5/yUVcnPVLlv1jYcmG4ntEm3fAMBcn6CrpM4OnJX3DX4vxaYR9GVIOWhL8CEA+Z6Z7hP3Vpg==
    乙方本地密鑰:Oe6gr0aq4fVIeO5/yUVcnPVLlv1jYcmG4ntEm3fAMBcn6CrpM4OnJX3DX4vxaYR9GVIOWhL8CEA+Z6Z7hP3Vpg==
    算法怎麼沒用
           

RSA算法

RSA算法可以用來資料加密和數字簽名,使用一套密鑰對,公鑰長度遠小于私鑰長度,并遵循"公鑰加密,私鑰解密"和"私鑰加密,公鑰解密"這兩項原則。

package algorithm;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class RSADecoder {
    //公鑰
    public static final String PUBLIC_KEY = "PublicKey";
    //私鑰
    public static final String PRIVATE_KEY = "PrivateKey";
    //非對稱加密密鑰算法
    public static final String KEY_ALGORITHM = "RSA";
    //密鑰長度
    private static final int KEY_SIZE = 512;

    /**
     * 私鑰解密
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data,byte[] key) throws  Exception {
        PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(encodedKeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE,privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 公鑰加密
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data,byte[] key) throws Exception {
        X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(encodedKeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE,publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 私鑰加密
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data,byte[] key) throws Exception {
        PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(encodedKeySpec);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE,privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 公鑰加密
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception {
        X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(encodedKeySpec);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        return cipher.doFinal(data);
    }

    /**
     * 生成密鑰
     * @return
     * @throws Exception
     */
    public static Map<String,Object> initKey() throws Exception {
        //執行個體化密鑰生成器
        KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //初始化密鑰生成器
        keyPairGenerator.initialize(KEY_SIZE);
        //生成密鑰對
        KeyPair keyPair=keyPairGenerator.generateKeyPair();
        PublicKey publicKey= keyPair.getPublic();
        PrivateKey privateKey= keyPair.getPrivate();
        Map<String,Object> keyMap=new HashMap<String,Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

    /**
     * 擷取密鑰
     * @param keys
     * @param keyType
     * @return
     * @throws Exception
     */
    public  static  byte[] getKey(Map<String,Object> keys,String keyType) throws Exception {
        Key key = (Key) keys.get(keyType);
        return key.getEncoded();
    }
}

@Test
public void test() throws Exception {
    Map<String, Object> stringObjectMap = RSADecoder.initKey();
        byte[] pubKey = RSADecoder.getKey(stringObjectMap,RSADecoder.PUBLIC_KEY);
        byte[] priKey = RSADecoder.getKey(stringObjectMap,RSADecoder.PRIVATE_KEY);

        System.out.println("公鑰:"+Base64.encodeBase64String(pubKey));
        System.out.println("私鑰:"+Base64.encodeBase64String(priKey));

        //公鑰加密,私鑰解密
        String str = "公鑰加密,私鑰解密";
        byte[] data = RSADecoder.encryptByPublicKey(str.getBytes("utf-8"),pubKey);
        System.out.println(new String(RSADecoder.decryptByPrivateKey(data,priKey),"utf-8"));
        //私鑰加密,公鑰解密
        str = "私鑰加密,公鑰解密";
        data = RSADecoder.encryptByPrivateKey(str.getBytes("utf-8"),priKey);
        System.out.println(new String(RSADecoder.decryptByPublicKey(data,pubKey),"utf-8"));
}

//輸出結果
公鑰:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI/0dZZmoODkEFXqFnrjAlY1OdKjO2G1tHorC3trUU7zMKuAtlOO3yzdO5sFqpnaHQInOfYYcAalbxosUNjqjL8CAwEAAQ==
私鑰:MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAj/R1lmag4OQQVeoWeuMCVjU50qM7YbW0eisLe2tRTvMwq4C2U47fLN07mwWqmdodAic59hhwBqVvGixQ2OqMvwIDAQABAkAqA2e6IHO9jvIxkONEtDI/ZMNedWNkTfrBWQS93YFab/ETsyv14EUuEjzobMuvDvKnSUZOQ/kGh6c4oozvrEn5AiEAz5S26Rjv12SUjlLdV7/n65f2mVfRY8G4tZf4W8TSD/MCIQCxiHGarRfnDal/pWw4Z/UkM5HlYRFYtpMNvrq9/9sPBQIgHWCjnkucLfSbHaVWlAOh0/LWwI7wIFkbRf/y8zHgtMcCIBwmnp0ARYIF0JLFEFwBYAXVh5Tvx2hhyv+q9sGaCIphAiAcSXumoKYNBzEUFROwQNnSeWre4wGWP5V96+7AuDhqNQ==
公鑰加密,私鑰解密
私鑰加密,公鑰解密
           

ElGamal算法

ElGamal算法是一種基于離散對數問題的非對稱加密算法,該算法既可以用于加密,又可以用于數字簽名,是除了RSA算法最具有代表性的公鑰加密算法之一。遵循"公鑰加密,私鑰解密"的部分。

//簡單的實作
        Security.addProvider(new BouncyCastleProvider());
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ElGamal");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        //加密
        Cipher cipher = Cipher.getInstance(keyPairGenerator.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        byte[] data = cipher.doFinal("公鑰加密,私鑰解密".getBytes("utf-8"));
        System.out.println("加密後資料:"+new String(data,"utf-8"));
        Cipher cipher1 = Cipher.getInstance(keyPairGenerator.getAlgorithm());
        cipher1.init(Cipher.DECRYPT_MODE,privateKey);
        System.out.println("解密後資料:"+new String(cipher1.doFinal(data),"utf-8"));
        
        //輸出結果
        加密後資料:???'??|$L?*a????BC?#C?!r=????B=??K??????VQ??J;??FE?s^?????5????!Ok?p??
5?c?vj*&6BM???F"??O?;K?|???`?Eo?,??????;>?????U?+?m?u?a&??'?	Y2??N?`????b?l7??O'????/??l???f;o?a[???????????&??
        解密後資料:公鑰加密,私鑰解密