最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java對(duì)稱與非對(duì)稱加密算法原理詳細(xì)講解

 更新時(shí)間:2022年11月07日 08:39:37   作者:OlaiolaiO  
對(duì)稱加密算法指加密和解密使用相同密鑰的加密算法。對(duì)稱加密算法用來對(duì)敏感數(shù)據(jù)等信息進(jìn)行加密,非對(duì)稱加密算法指加密和解密使用不同密鑰的加密算法,也稱為公私鑰加密

一、對(duì)稱加密算法

1.概述

對(duì)稱加密算法就是傳統(tǒng)的用一個(gè)密碼進(jìn)行加密和解密。例如,我們常用的 WinZIP 和 WinRAR 對(duì)壓縮包 的加密和解密,就是使用對(duì)稱加密算法。

從程序的角度看,所謂加密,就是這樣一個(gè)函數(shù):

它接收密碼和明文,然后輸出密文: secret = encrypt(key, message);

而解密則相反,它接收密碼和密文,然后輸出明文: plain = decrypt(key, secret)。

2.常用的對(duì)稱加密算法

密鑰長(zhǎng)度直接決定加密強(qiáng)度,而工作模式和填充模式可以看成是對(duì)稱加密算法的參 數(shù)和格式選擇。Java標(biāo)準(zhǔn)庫提供的算法實(shí)現(xiàn)并不包括所有的工作模式和所有填充模式,但是通常我們只需要挑選常用的使用就可以了。

注意:DES 算法由于密鑰過短,現(xiàn)在已經(jīng)不安全了

3.AES加密

AES 算法是目前應(yīng)用最廣泛的加密算法。比較常見的工作模式是 ECB 和 CBC。

①ECB模式

import java.security.*;
import java.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.*;
public class Main {
    public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, world!";
        System.out.println("Message(原始信息): " + message);
        // 128位密鑰 = 16 bytes Key:
        byte[] key = "1234567890abcdef".getBytes();
        // 加密:
        byte[] data = message.getBytes();
        byte[] encrypted = encrypt(key, data);
        System.out.println("Encrypted(加密內(nèi)容): " + 
        					Base64.getEncoder().encodeToString(encrypted));
        // 解密:
        byte[] decrypted = decrypt(key, encrypted);
        System.out.println("Decrypted(解密內(nèi)容): " + new String(decrypted));
    }
    // 加密:
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
    	// 創(chuàng)建密碼對(duì)象,需要傳入算法/工作模式/填充模式
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        // 根據(jù)key的字節(jié)內(nèi)容,"恢復(fù)"秘鑰對(duì)象
        SecretKey keySpec = new SecretKeySpec(key, "AES");
        // 初始化秘鑰:設(shè)置加密模式ENCRYPT_MODE
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        // 根據(jù)原始內(nèi)容(字節(jié)),進(jìn)行加密
        return cipher.doFinal(input);
    }
    // 解密:
    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
    	// 創(chuàng)建密碼對(duì)象,需要傳入算法/工作模式/填充模式
    	Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    	// 根據(jù)key的字節(jié)內(nèi)容,"恢復(fù)"秘鑰對(duì)象
        SecretKey keySpec = new SecretKeySpec(key, "AES");
        // 初始化秘鑰:設(shè)置解密模式DECRYPT_MODE
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        // 根據(jù)原始內(nèi)容(字節(jié)),進(jìn)行解密
        return cipher.doFinal(input);
    }
}

②CBC模式

ECB 模式是最簡(jiǎn)單的 AES 加密模式,它只需要一個(gè)固定長(zhǎng)度的密鑰,固定的明文會(huì)生成固定的密文, 這種一對(duì)一的加密方式會(huì)導(dǎo)致安全性降低,更好的方式是通過 CBC 模式,它需要一個(gè)隨機(jī)數(shù)作為 IV 參 數(shù),這樣對(duì)于同一份明文,每次生成的密文都不同:

package com.apesource.demo04;
import java.security.*;
import java.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.*;
public class Main {
	public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, world!";
        System.out.println("Message(原始信息): " + message);
        // 256位密鑰 = 32 bytes Key:
        byte[] key = "1234567890abcdef1234567890abcdef".getBytes();
        // 加密:
        byte[] data = message.getBytes();
        byte[] encrypted = encrypt(key, data);
        System.out.println("Encrypted(加密內(nèi)容): " + 
				Base64.getEncoder().encodeToString(encrypted));
        // 解密:
        byte[] decrypted = decrypt(key, encrypted);
        System.out.println("Decrypted(解密內(nèi)容): " + new String(decrypted));
    }
    // 加密:
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        // 設(shè)置算法/工作模式CBC/填充
    	Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    	// 恢復(fù)秘鑰對(duì)象
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        // CBC模式需要生成一個(gè)16 bytes的initialization vector:
        SecureRandom sr = SecureRandom.getInstanceStrong();
        byte[] iv = sr.generateSeed(16); // 生成16個(gè)字節(jié)的隨機(jī)數(shù)
        System.out.println(Arrays.toString(iv));
        IvParameterSpec ivps = new IvParameterSpec(iv); // 隨機(jī)數(shù)封裝成IvParameterSpec參數(shù)對(duì)象
        // 初始化秘鑰:操作模式、秘鑰、IV參數(shù)
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps);
        // 加密
        byte[] data = cipher.doFinal(input);
        // IV不需要保密,把IV和密文一起返回:
        return join(iv, data);
    }
    // 解密:
    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        // 把input分割成IV和密文:
        byte[] iv = new byte[16];
        byte[] data = new byte[input.length - 16];
        System.arraycopy(input, 0, iv, 0, 16); // IV
        System.arraycopy(input, 16, data, 0, data.length); //密文
        System.out.println(Arrays.toString(iv));
        // 解密:
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 密碼對(duì)象
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES"); // 恢復(fù)秘鑰
        IvParameterSpec ivps = new IvParameterSpec(iv); // 恢復(fù)IV
        // 初始化秘鑰:操作模式、秘鑰、IV參數(shù)
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps);
        // 解密操作
        return cipher.doFinal(data);
    }
    // 合并數(shù)組
    public static byte[] join(byte[] bs1, byte[] bs2) {
        byte[] r = new byte[bs1.length + bs2.length];
        System.arraycopy(bs1, 0, r, 0, bs1.length);
        System.arraycopy(bs2, 0, r, bs1.length, bs2.length);
        return r;
    }
}

在 CBC 模式下,需要一個(gè)隨機(jī)生成的 16 字節(jié)IV參數(shù),必須使用 SecureRandom 生 成。因?yàn)槎嗔艘粋€(gè) IvParameterSpec 實(shí)例,因此,初始化方法需要調(diào)用 Cipher 的一個(gè) 重載方法并傳入 IvParameterSpec 。 觀察輸出,可以發(fā)現(xiàn)每次生成的 IV 不同,密文也不同。

二、秘鑰交換算法

使用Java實(shí)現(xiàn)DH算法:

import java.math.BigInteger;
import java.security.GeneralSecurityException;
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 javax.crypto.KeyAgreement;
public class Main04 {
	public static void main(String[] args) {
        // Bob和Alice:
        Person bob = new Person("Bob");
        Person alice = new Person("Alice");
        // 各自生成KeyPair: 公鑰+私鑰
        bob.generateKeyPair();
        alice.generateKeyPair();
        // 雙方交換各自的PublicKey(公鑰):
        // Bob根據(jù)Alice的PublicKey生成自己的本地密鑰(共享公鑰):
        bob.generateSecretKey(alice.publicKey.getEncoded());
        // Alice根據(jù)Bob的PublicKey生成自己的本地密鑰(共享公鑰):
        alice.generateSecretKey(bob.publicKey.getEncoded());
        // 檢查雙方的本地密鑰是否相同:
        bob.printKeys();
        alice.printKeys();
        // 雙方的SecretKey相同,后續(xù)通信將使用SecretKey作為密鑰進(jìn)行AES加解密...
    }
}
// 用戶類
class Person {
    public final String name; // 姓名
    // 密鑰
    public PublicKey publicKey; // 公鑰
    private PrivateKey privateKey; // 私鑰
    private byte[] secretKey; // 本地秘鑰(共享密鑰)
    // 構(gòu)造方法
    public Person(String name) {
        this.name = name;
    }
    // 生成本地KeyPair:(公鑰+私鑰)
    public void generateKeyPair() {
        try {
        	// 創(chuàng)建DH算法的“秘鑰對(duì)”生成器
            KeyPairGenerator kpGen = KeyPairGenerator.getInstance("DH");
            kpGen.initialize(512);
            // 生成一個(gè)"密鑰對(duì)"
            KeyPair kp = kpGen.generateKeyPair();
            this.privateKey = kp.getPrivate(); // 私鑰
            this.publicKey = kp.getPublic(); // 公鑰
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
    }
    // 按照 "對(duì)方的公鑰" => 生成"共享密鑰"
    public void generateSecretKey(byte[] receivedPubKeyBytes) {
        try {
            // 從byte[]恢復(fù)PublicKey:
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(receivedPubKeyBytes);
            // 根據(jù)DH算法獲取KeyFactory
            KeyFactory kf = KeyFactory.getInstance("DH");
            // 通過KeyFactory創(chuàng)建公鑰
            PublicKey receivedPublicKey = kf.generatePublic(keySpec);
            // 生成本地密鑰(共享公鑰)
            KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
            keyAgreement.init(this.privateKey); // 初始化"自己的PrivateKey"
            keyAgreement.doPhase(receivedPublicKey, true); // 根據(jù)"對(duì)方的PublicKey"
            // 生成SecretKey本地密鑰(共享公鑰)
            this.secretKey = keyAgreement.generateSecret();
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
    }
    public void printKeys() {
        System.out.printf("Name: %s\n", this.name);
        System.out.printf("Private key: %x\n", new BigInteger(1, this.privateKey.getEncoded()));
        System.out.printf("Public key: %x\n", new BigInteger(1, this.publicKey.getEncoded()));
        System.out.printf("Secret key: %x\n", new BigInteger(1, this.secretKey));
    }
}

DH 算法是一種密鑰交換協(xié)議,通信雙方通過不安全的信道協(xié)商密鑰,然后進(jìn)行對(duì)稱加密傳輸。

三、非對(duì)稱加密算法

1.概述

從 DH 算法我們可以看到,公鑰-私鑰組成的密鑰對(duì)是非常有用的加密方式,因?yàn)楣€是可以公開的,而私鑰是完全保密的,由此奠定了非對(duì)稱加密的基礎(chǔ)。

非對(duì)稱加密:加密和解密使用的不是相同的密鑰,只有同一個(gè)公鑰-私鑰對(duì)才能正常加解密。

例如:小明要加密一個(gè)文件發(fā)送給小紅,他應(yīng)該首先向小紅索取她的公鑰,然后, 他用小紅的公鑰加密,把加密文件發(fā)送給小紅,此文件只能由小紅的私鑰解開,因?yàn)樾?紅的私鑰在她自己手里,所以,除了小紅,沒有任何人能解開此文件。

2.RSA算法

非對(duì)稱加密的典型算法就是 RSA 算法,它是由Ron Rivest,Adi Shamir,Leonard Adleman這三個(gè)人 一起發(fā)明的,所以用他們?nèi)齻€(gè)人的姓氏首字母縮寫表示。

import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import javax.crypto.Cipher;
// RSA
public class Main {
	public static void main(String[] args) throws Exception {
		// 明文:
		byte[] plain = "Hello, encrypt use RSA".getBytes("UTF-8");
		// 創(chuàng)建公鑰/私鑰對(duì):
		Human alice = new Human("Alice");
		// 用Alice的公鑰加密:
		// 獲取Alice的公鑰,并輸出
		byte[] pk = alice.getPublicKey();
		System.out.println(String.format("public key(公鑰): %x", new BigInteger(1, pk)));
		// 使用公鑰加密
		byte[] encrypted = alice.encrypt(plain);
		System.out.println(String.format("encrypted(加密): %x", new BigInteger(1, encrypted)));
		// 用Alice的私鑰解密:
		// 獲取Alice的私鑰,并輸出
		byte[] sk = alice.getPrivateKey();
		System.out.println(String.format("private key(私鑰): %x", new BigInteger(1, sk)));
		// 使用私鑰解密
		byte[] decrypted = alice.decrypt(encrypted);
		System.out.println("decrypted(解密): " + new String(decrypted, "UTF-8"));
	}
}
// 用戶類
class Human {
	// 姓名
	String name;
	// 私鑰:
	PrivateKey sk;
	// 公鑰:
	PublicKey pk;
	// 構(gòu)造方法
	public Human(String name) throws GeneralSecurityException {
		// 初始化姓名
		this.name = name;
		// 生成公鑰/私鑰對(duì):
		KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
		kpGen.initialize(1024);
		KeyPair kp = kpGen.generateKeyPair();
		this.sk = kp.getPrivate();
		this.pk = kp.getPublic();
	}
	// 把私鑰導(dǎo)出為字節(jié)
	public byte[] getPrivateKey() {
		return this.sk.getEncoded();
	}
	// 把公鑰導(dǎo)出為字節(jié)
	public byte[] getPublicKey() {
		return this.pk.getEncoded();
	}
	// 用公鑰加密:
	public byte[] encrypt(byte[] message) throws GeneralSecurityException {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.ENCRYPT_MODE, this.pk); // 使用公鑰進(jìn)行初始化
		return cipher.doFinal(message);
	}
	// 用私鑰解密:
	public byte[] decrypt(byte[] input) throws GeneralSecurityException {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, this.sk); // 使用私鑰進(jìn)行初始化
		return cipher.doFinal(input);
	}
}

RSA 算法的密鑰有 256 / 512 / 1024 / 2048 / 4096 等不同的長(zhǎng)度。長(zhǎng)度越長(zhǎng),密碼強(qiáng)度越大,當(dāng)然計(jì)算速度也越慢。

3.非對(duì)稱加密算法的優(yōu)缺點(diǎn)

非對(duì)稱加密的優(yōu)點(diǎn):對(duì)稱加密需要協(xié)商密鑰,而非對(duì)稱加密可以安全地公開各自的 公鑰,在N個(gè)人之間通信的時(shí)候:使用非對(duì)稱加密只需要N個(gè)密鑰對(duì),每個(gè)人只管理自己的密鑰對(duì)。而使用對(duì)稱加密需要?jiǎng)t需要N*(N-1)/2個(gè)密鑰,因此每個(gè)人需要管理N-1個(gè)密鑰,密鑰管理難度大,而且非常容易泄漏。

非對(duì)稱加密的缺點(diǎn):運(yùn)算速度非常慢,比對(duì)稱加密要慢很多。

所以,在實(shí)際應(yīng)用的時(shí)候,非對(duì)稱加密總是和對(duì)稱加密一起使用。

四、總結(jié)

  • 對(duì)稱加密算法使用同一個(gè)密鑰進(jìn)行加密和解密,常用算法有 DES、AES 和 IDEA 等;
  • 對(duì)稱加密算法密鑰長(zhǎng)度由算法設(shè)計(jì)決定, AES 的密鑰長(zhǎng)度是 128 / 192 / 256 位;
  • 使用對(duì)稱加密算法需要指定算法名稱、工作模式和填充模式。
  • DH算法是一種密鑰交換協(xié)議,通信雙方通過不安全的信道協(xié)商密鑰,進(jìn)行對(duì)稱加密傳輸;
  • 非對(duì)稱加密就是加密和解密使用的不是相同的密鑰,只有同一個(gè)公鑰-私鑰對(duì)才能正常加解密。

到此這篇關(guān)于Java對(duì)稱與非對(duì)稱加密算法實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)Java對(duì)稱與非對(duì)稱加密算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java使用Redis的方法實(shí)例分析

    Java使用Redis的方法實(shí)例分析

    這篇文章主要介紹了Java使用Redis的方法,接合實(shí)例形式分析了相關(guān)redis驅(qū)動(dòng)包安裝、java連接redis服務(wù)器、數(shù)據(jù)存儲(chǔ)、讀取等相關(guān)操作技巧,需要的朋友可以參考下
    2018-05-05
  • Java實(shí)現(xiàn)Huffman編碼的示例代碼

    Java實(shí)現(xiàn)Huffman編碼的示例代碼

    Huffman編碼是一種編碼方式,本文主要介紹了Java實(shí)現(xiàn)Huffman編碼的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-08-08
  • 用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的布隆過濾器

    用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的布隆過濾器

    這篇文章主要介紹了用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的布隆過濾器,布隆過濾器是1970年由布隆提出的,它實(shí)際上是一個(gè)很長(zhǎng)的二進(jìn)制向量和一系列隨機(jī)映射函數(shù),布隆過濾器可以用于檢索一個(gè)元素是否在一個(gè)集合中,需要的朋友可以參考下
    2023-12-12
  • java對(duì)接微信小程序詳細(xì)流程(登錄&獲取用戶信息)

    java對(duì)接微信小程序詳細(xì)流程(登錄&獲取用戶信息)

    這篇文章主要給大家介紹了關(guān)于java對(duì)接微信小程序(登錄&獲取用戶信息)的相關(guān)資料,我們?cè)陂_發(fā)微信小程序時(shí)經(jīng)常需要獲取用戶微信用戶名以及頭像信息,微信提供了專門的接口API用于返回這些信息,需要的朋友可以參考下
    2023-08-08
  • Java基礎(chǔ)知識(shí)之Java語言概述

    Java基礎(chǔ)知識(shí)之Java語言概述

    這篇文章主要介紹了Java基礎(chǔ)知識(shí)之Java語言概述,本文介紹了Java語言相關(guān)的基礎(chǔ)知識(shí)、歷史介紹、主要應(yīng)用方向等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • java8 List<Object>去掉重復(fù)對(duì)象的幾種方法

    java8 List<Object>去掉重復(fù)對(duì)象的幾種方法

    本文主要介紹了java8 List<Object>去掉重復(fù)對(duì)象的幾種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • SpringBoot接口接收json參數(shù)解析

    SpringBoot接口接收json參數(shù)解析

    這篇文章主要介紹了SpringBoot接口接收json參數(shù)解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • spring scheduled單線程和多線程使用過程中的大坑

    spring scheduled單線程和多線程使用過程中的大坑

    本文主要介紹了spring scheduled單線程和多線程使用過程中的大坑,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • SpringBoot中使用MongoDB的連接池配置

    SpringBoot中使用MongoDB的連接池配置

    由于MongoDB的客戶端本身就是一個(gè)連接池,因此,我們只需要配置客戶端即可,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Java實(shí)現(xiàn)權(quán)重隨機(jī)算法詳解

    Java實(shí)現(xiàn)權(quán)重隨機(jī)算法詳解

    平時(shí),經(jīng)常會(huì)遇到權(quán)重隨機(jī)算法,從不同權(quán)重的N個(gè)元素中隨機(jī)選擇一個(gè),并使得總體選擇結(jié)果是按照權(quán)重分布的。本文就詳細(xì)來介紹如何實(shí)現(xiàn),感興趣的可以了解一下
    2021-07-07

最新評(píng)論

尼玛县| 瓮安县| 宁明县| 炉霍县| 通城县| 德昌县| 永登县| 庆云县| 宜宾市| 青川县| 郓城县| 宜都市| 龙口市| 临西县| 武定县| 临江市| 瓦房店市| 澄迈县| 凤阳县| 墨脱县| 新田县| 克东县| 岐山县| 仙桃市| 大连市| 吉水县| 泸溪县| 平潭县| 大理市| 班玛县| 栾城县| 林口县| 太谷县| 巨鹿县| 盐津县| 合作市| 新疆| 濮阳县| 华阴市| 内乡县| 锡林郭勒盟|