天天看點

非對稱加密算法---加密學習筆記(四)

介紹:

非對稱加密相對與對稱加密算法來說是進階的。

舉個雙保險的例子:

非對稱加密算法---加密學習筆記(四)

銀行的保險櫃,客戶往銀行的保險櫃存貴重東西,這個保險櫃的鑰匙會有兩把,客戶有一把,銀行有一把。如果想打開保險櫃就需要銀行的鑰匙和客戶的鑰匙一塊使用才能打開保險櫃。

公鑰,私鑰:客戶和銀行的鑰匙

公鑰:是通過非安全的通道發放的,也就是說是公開的方式

私鑰:自己儲存的。

公鑰和私鑰一般是成對出現的,使用公鑰加密的資料隻有與它對應的私鑰才能解開。

在非對稱加密算法中有一些算法是可以公鑰加密私鑰解密,私鑰加密公鑰解密都支援的,有一些算法隻支援一種方式的。

非對稱加密算法種類:

DH(Diffie-Hellman):密鑰交換算法

RSA:基于因子分解,既能用于數字加密也能用于數字簽名

Elgamal:基于離散對數

ECC(Elliptical Curve Cryptography):橢圓曲線加密

DH

對稱加密算法的弊端:

對稱加密算法中公布密鑰這個步驟會有問題,發送密鑰的時候可能會出現洩露密鑰的情況。一旦密鑰被洩露,那麼所有的資料就很容易被破解掉。

但是DH(密鑰交換算法)是通過建構本地密鑰來解決密鑰容易在傳遞中洩露的問題的。

非對稱加密算法---加密學習筆記(四)

初始化發送方密鑰涉及的三個類:

1. KeyPairGenerator(通過KeyPairGenerator來得到KeyPair類的對象)

//建立KeyPairGenerator對象
KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance("DH");//"DH"指定算法的名稱
           

2 KeyPair(得到密鑰對,包括公鑰和私鑰)

3. PublicKey:公鑰

初始化接收方密鑰涉及到的類:

1. KeyFactory:作用是生成密鑰(包括公鑰和私鑰)

generatePublic()方法用來生成公鑰

generatePrivate()方法用來生成私鑰

2 X509EncodedKeySpec:根據ASN.1标準進行密鑰編碼

3. DHPublicKey:是PublicKey的某種具體的形式

4. DHParameterSpec:随從着DH算法來使用的參數的集合

5. KeyPairGenerator:通過KeyPairGenerator來得到KeyPair類的對象

6. PrivateKey:私鑰

密鑰建構涉及的類

  1. KeyAgreement:提供密鑰一緻性(或密鑰交換)協定的功能
//生成實作指定密鑰一緻算法的KeyAgreement對象
static keyAgreement getInstance(String algorithm)
           
//為來自指定提供程式的指定密鑰一緻算法生成一個KeyAgreement對象
static keyAgreement getInstance(String algorithm,Provider provider)
           

2 SecretKey:生成一個分組的秘密密鑰,同時提供了相應的類型安全的操作

3. KeyFactory

4. X509EncodedKeySpec

5. PublicKey

加解密涉及到的類:

Cipher

例子

package com.timliu.security.asymmetric_encryption;

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.Base64;

public class DHTest {
    public static final String src = "hello world";

    public static void main(String[] args) {
        jdkDH();
    }

    // jdk實作:
    public static void jdkDH() {
        try {
            /*
             * 發送方的操作
             */
            // 初始化發送方密鑰
            KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator
                    .getInstance("DH");
            senderKeyPairGenerator.initialize();//設定長度
            KeyPair senderKeyPair = senderKeyPairGenerator.generateKeyPair();//生成keypair
            // 儲存了發送方公鑰的位元組數組,發送給接收方(發送方式:網絡、檔案。。。)
            byte[] senderPublicKeyEnc = senderKeyPair.getPublic().getEncoded();

            /*
             * 接收方的操作
             */
            // 初始化接收方密鑰
            KeyFactory receiverKeyFactory = KeyFactory.getInstance("DH");
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(senderPublicKeyEnc);
            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[] receiverPublicKeyEnc = receiverKeypair.getPublic().getEncoded();

            // 密鑰建構
            KeyAgreement receiverKeyAgreement = KeyAgreement.getInstance("DH");
            receiverKeyAgreement.init(receiverPrivateKey);
            receiverKeyAgreement.doPhase(receiverPublicKey, true);
            //生成接收方的本地密鑰
            SecretKey receiverDesKey = receiverKeyAgreement.generateSecret("DES");

            /*
             * 發送方的操作
             */
            KeyFactory senderKeyFactory = KeyFactory.getInstance("DH");
            x509EncodedKeySpec = new X509EncodedKeySpec(receiverPublicKeyEnc);
            PublicKey senderPublicKey = senderKeyFactory.generatePublic(x509EncodedKeySpec);
            KeyAgreement senderKeyAgreement = KeyAgreement.getInstance("DH");
            senderKeyAgreement.init(senderKeyPair.getPrivate());
            senderKeyAgreement.doPhase(senderPublicKey, true);
            //生成發送方的本地密鑰
            SecretKey senderDesKey = senderKeyAgreement.generateSecret("DES");

            if(Objects.equals(receiverDesKey, senderDesKey)){
                System.out.println("發送方和接收方密鑰相同。");
            }else{
                System.out.println("發送方和接收方密鑰不相同");
            }

            // 加密
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, senderDesKey);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("bc dh encrypt:"+ Base64.encodeBase64String(result));

            // 解密
            cipher.init(Cipher.DECRYPT_MODE, receiverDesKey);
            result = cipher.doFinal(result);
            System.out.println("bc dh decrypt:" + new String(result));

        } catch (Exception e) {

            e.printStackTrace();
        }

    }

}
           

運作結果:

非對稱加密算法---加密學習筆記(四)

DH算法的應用場景

非對稱加密算法---加密學習筆記(四)
非對稱加密算法---加密學習筆記(四)

RSA

唯一廣泛接受并實作的非對稱加密的算法。

可以實作資料加密和數字簽名。

提供了:

1. 公鑰加密,私鑰解密

2. 私鑰加密,公鑰解密

非對稱加密算法---加密學習筆記(四)

例子:

package com.timliu.security.asymmetric_encryption;

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.Base64;

public class RSATest {
    public static final String src = "hello world";

    public static void main(String[] args) {
        jdkRSA();

    }

    // jdk實作:
    public static void jdkRSA() {
        try {
            // 初始化發送方密鑰
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize();
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
            System.out.println("Public Key:"+ Base64.encodeBase64String(rsaPublicKey.getEncoded()));
            System.out.println("Private Key:"+ Base64.encodeBase64String(rsaPrivateKey.getEncoded()));

            // 私鑰加密、公鑰解密 ---- 加密
            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[] result = cipher.doFinal(src.getBytes());
            System.out.println("私鑰加密、公鑰解密 ---- 加密:"+ Base64.encodeBase64String(result));

            // 私鑰加密、公鑰解密 ---- 解密
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
            keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            result = cipher.doFinal(result);
            System.out.println("私鑰加密、公鑰解密 ---- 解密:" + new String(result));

            // 公鑰加密、私鑰解密 ---- 加密
            X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
            KeyFactory keyFactory2 = KeyFactory.getInstance("RSA");
            PublicKey publicKey2 = keyFactory2.generatePublic(x509EncodedKeySpec2);
            Cipher cipher2 = Cipher.getInstance("RSA");
            cipher2.init(Cipher.ENCRYPT_MODE, publicKey2);
            byte[] result2 = cipher2.doFinal(src.getBytes());
            System.out.println("公鑰加密、私鑰解密 ---- 加密:"+ Base64.encodeBase64String(result2));

            // 公鑰加密、私鑰解密 ---- 解密
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
            KeyFactory keyFactory5 = KeyFactory.getInstance("RSA");
            PrivateKey privateKey5 = keyFactory5.generatePrivate(pkcs8EncodedKeySpec5);
            Cipher cipher5 = Cipher.getInstance("RSA");
            cipher5.init(Cipher.DECRYPT_MODE, privateKey5);
            byte[] result5 = cipher5.doFinal(result2);
            System.out.println("公鑰加密、私鑰解密 ---- 解密:" + new String(result5));

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

    }

}
           

運作結果:

Public Key:
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAOz8ggiZp7ly13XoE9CtW3OlXQjVbrXc8zZCdKhFagXSSFcUvGqKbdfZuvjAjET7Vec7GurqLX14w99KnxFAbD8CAwEAAQ==
Private Key:
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA7PyCCJmnuXLXdegT0K1bc6VdCNVutdzzNkJ0qEVqBdJIVxS8aopt19m6+MCMRPtV5zsa6uotfXjD30qfEUBsPwIDAQABAkAjp4nYyWVWnVSVRKlWh/5uU76/iXzyl59v1me+uVLONR7XjkQyz7Kq3uh33276FAxZtHFlabphCpZf0aqpUFuBAiEA9lAF2lMjx379oTtRJhs75iw11z7f+hpaxaUN+JMa1RECIQD2TpWxJfF20bRyDCi0U2sl2ElqdxjZe0pAAiebgr3sTwIgbEChQeHWUMBUMf9C2++ONMvrYc1FXMMmb8TpzfzBBzECIQCOB4y8JRQTHyO9bBOAwGWV4h2bneefaT/MnzF1tDOOcwIhALs3oH3XIAPBU2bFBaGqBTO//XIUoE8CfyOfPA3fvusC
私鑰加密、公鑰解密 ---- 加密:
cIvL/HQH8gMBpD5qi99B4Cql/qZiNFc7eHfnua9qlQLGfQ436wNV9tzCQg+n7cR+/mDlAUSAvegwvk/0FD/Jmw==
私鑰加密、公鑰解密 ---- 解密:hello world
公鑰加密、私鑰解密 ---- 加密:
rvG7tdyCbU5B4fbT2xrFPkH8tUUsepkpZwGALi56/CCpVWOyvGq/aqBS4dQJKxjwH0t0pfWzt+iw3fJe3qTwGg==
公鑰加密、私鑰解密 ---- 解密:hello world
           

RSA應用場景:

非對稱加密算法---加密學習筆記(四)
非對稱加密算法---加密學習筆記(四)

ElGamal

提供公鑰加密算法。

基于離散對數。

JDK沒有提供ElGamal算法的實作,是Bouncy Castle提供的。

非對稱加密算法---加密學習筆記(四)

例子:

package com.timliu.security.asymmetric_encryption;

import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;
import javax.crypto.spec.DHParameterSpec;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class ElGamalTest {

    public static final String src = "hello world";

    public static void main(String[] args) {
        BCElgamal();
    }

    /**
     * 
     * 對于:“Illegal key size or default
     * parameters”異常,是因為美國的出口限制,Sun通過權限檔案(local_policy
     * .jar、US_export_policy.jar)做了相應限制。是以存在一些問題: Java 6
     * 無政策限制檔案:http://www.oracle
     * .com/technetwork/java/javase/downloads/jce-6-download-429243.html Java 7
     * 無政策限制檔案
     * :http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download
     * -432124.html 我的時java7,自己安裝的。
     * /Library/Java/JavaVirtualMachines/jdk1.7.0_71
     * .jdk/Contents/Home/jre/lib/security目錄下
     * ,對應覆寫local_policy.jar和US_export_policy.jar兩個檔案。
     * 
     * 切換到%JDK_Home%\jre\lib\security目錄下,對應覆寫local_policy.jar和US_export_policy.
     * jar兩個檔案。同時,你可能有必要在%JRE_Home%\lib\security目錄下,也需要對應覆寫這兩個檔案。
     */

    // BC實作:“私鑰解密、公鑰加密” , 對于:“私鑰加密、公鑰解密”有問題,因為Elgamal不支援
    public static void BCElgamal() {
        try {
            // 加入對BouncyCastle支援
            Security.addProvider(new BouncyCastleProvider());

            // 初始化發送方密鑰
            AlgorithmParameterGenerator algorithmParameterGenerator = AlgorithmParameterGenerator
                    .getInstance("Elgamal");
            // 初始化參數生成器
            algorithmParameterGenerator.init();
            // 生成算法參數
            AlgorithmParameters algorithmParameters = algorithmParameterGenerator
                    .generateParameters();
            // 建構參數材料
            DHParameterSpec dhParameterSpec = (DHParameterSpec) algorithmParameters
                    .getParameterSpec(DHParameterSpec.class);
            // 執行個體化密鑰生成器
            KeyPairGenerator keyPairGenerator = KeyPairGenerator
                    .getInstance("Elgamal");
            // 初始化密鑰對生成器
            keyPairGenerator.initialize(dhParameterSpec, new SecureRandom());
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            // 公鑰
            PublicKey elGamalPublicKey = keyPair.getPublic();
            // 私鑰
            PrivateKey elGamalPrivateKey = keyPair.getPrivate();
            System.out.println("Public Key:"
                    + Base64.encodeBase64String(elGamalPublicKey.getEncoded()));
            System.out
                    .println("Private Key:"
                            + Base64.encodeBase64String(elGamalPrivateKey
                                    .getEncoded()));

            // 私鑰解密、公鑰加密 ---- 加密
            // 初始化公鑰
            // 密鑰材料轉換
            X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(
                    elGamalPublicKey.getEncoded());
            // 執行個體化密鑰工廠
            KeyFactory keyFactory2 = KeyFactory.getInstance("Elgamal");
            // 産生公鑰
            PublicKey publicKey2 = keyFactory2
                    .generatePublic(x509EncodedKeySpec2);
            // 資料加密
            // Cipher cipher2 = Cipher.getInstance("Elgamal");
            Cipher cipher2 = Cipher.getInstance(keyFactory2.getAlgorithm());
            cipher2.init(Cipher.ENCRYPT_MODE, publicKey2);
            byte[] result2 = cipher2.doFinal(src.getBytes());
            System.out.println("私鑰加密、公鑰解密 ---- 加密:"
                    + Base64.encodeBase64String(result2));

            // 私鑰解密、公鑰加密 ---- 解密
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(
                    elGamalPrivateKey.getEncoded());
            KeyFactory keyFactory5 = KeyFactory.getInstance("Elgamal");
            PrivateKey privateKey5 = keyFactory5
                    .generatePrivate(pkcs8EncodedKeySpec5);
            // Cipher cipher5 = Cipher.getInstance("Elgamal");
            Cipher cipher5 = Cipher.getInstance(keyFactory5.getAlgorithm());
            cipher5.init(Cipher.DECRYPT_MODE, privateKey5);
            byte[] result5 = cipher5.doFinal(result2);
            System.out.println("Elgamal 私鑰加密、公鑰解密 ---- 解密:"
                    + new String(result5));

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

    }

}
           

運作結果:

非對稱加密算法---加密學習筆記(四)

應用場景:

非對稱加密算法---加密學習筆記(四)

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>

版權聲明:本文為部落客原創文章,未經部落客允許不得轉載。