JAVA加密算法- 非對稱加密算法(DH,RSA)的詳細(xì)介紹
非對稱密碼概念
1、與對稱加密算法的主要差別在于,加密和解密的密鑰不相同,一個(gè)公開(公鑰),一個(gè)保密(私鑰)。主要解決了對稱加密算法密鑰分配管理的問題,提高了算法安全性。
2、非對稱加密算法的加密、解密的效率比較低。在算法設(shè)計(jì)上,非對稱加密算法對待加密的數(shù)據(jù)長度有著苛刻的要求。例如RSA算法要求待加密的數(shù)據(jù)不得大于53個(gè)字節(jié)。
3、非對稱加密算法主要用于 交換對稱加密算法的密鑰,而非數(shù)據(jù)交換
4、java6提供實(shí)現(xiàn)了DH和RSA兩種算法。Bouncy Castle提供了E1Gamal算法支持。除了上述三種算法還有一個(gè)ECC算法,目前沒有相關(guān)的開源組件提供支持
需要兩個(gè)密鑰進(jìn)行加密或解密,分為公鑰和私鑰
特點(diǎn):安全性高,速度慢
用途
【密鑰交換(DH)】
雙方在沒有確定共同密鑰的情況下,生成密鑰,不提供加密工作,加解密還需要其他對稱加密算法實(shí)現(xiàn)
DH算法示例
import javax.crypto.KeyAgreement;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
//1 生成源密鑰
//2 把源公鑰交給目標(biāo),目標(biāo)通過源公鑰,生成目標(biāo)公鑰和私鑰
//3 把目標(biāo)公鑰交給源
//4 雙方使用對方的公鑰和和自己的私鑰,生成本地密鑰
//5 如果雙方生成本地密鑰相同則完成密鑰交換
public class DHUtil {
public static final String PUBLIC_KEY = "DH_Public_Key";
public static final String PRIVATE_KEY = "DH_Private_key";
/**
* 生成源密鑰對
* @return
* @throws Exception
*/
public static Map<String,Object> initSourceKey() throws Exception{
//創(chuàng)建KeyPairGenerator的實(shí)例,選用DH算法
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH");
//初始化密鑰長度,默認(rèn)1024,可選范圍512-65536 & 64的倍數(shù)
keyPairGenerator.initialize(1024);
//生成密鑰對
KeyPair keyPair = keyPairGenerator.generateKeyPair();
DHPublicKey dhPublicKey = (DHPublicKey) keyPair.getPublic();
DHPrivateKey dhPrivateKey = (DHPrivateKey) keyPair.getPrivate();
//將密鑰對放入Map
Map<String,Object> keyMap = new HashMap<String, Object>();
keyMap.put(PUBLIC_KEY, dhPublicKey);
keyMap.put(PRIVATE_KEY, dhPrivateKey);
return keyMap;
}
/**
* 通過源公鑰 生成 目標(biāo)密鑰對
* @param sourcePublicKey
* @return
* @throws Exception
*/
public static Map<String,Object> initTargetKey(byte[] sourcePublicKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("DH");
//通過源公鑰,生成keySpec,使用KeyFactory生成源PublicKey相關(guān)信息
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(sourcePublicKey);
DHPublicKey sourcePublic = (DHPublicKey) keyFactory.generatePublic(keySpec);
DHParameterSpec dhPublicKeyParams = sourcePublic.getParams();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH");
keyPairGenerator.initialize(dhPublicKeyParams);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
DHPublicKey dhPublicKey = (DHPublicKey) keyPair.getPublic();
DHPrivateKey dhPrivateKey = (DHPrivateKey) keyPair.getPrivate();
//將密鑰對放入Map
Map<String,Object> keyMap = new HashMap<String, Object>();
keyMap.put(PUBLIC_KEY, dhPublicKey);
keyMap.put(PRIVATE_KEY, dhPrivateKey);
return keyMap;
}
/**
* 使用一方的公鑰和另一方的私鑰,生成本地密鑰
* @return
*/
public static byte[] generateLocalSecretKey(byte[] aPublicKey, byte[] bPrivateKey) throws Exception{
KeyFactory keyFactory = KeyFactory.getInstance("DH");
//通過A公鑰,生成keySpec,使用KeyFactory生成A PublicKey相關(guān)信息
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(aPublicKey);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
//通過B私鑰,生成B PrivateKey相關(guān)信息
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(bPrivateKey);
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
//通過KeyAgreement對A的PublicKey和B的PrivateKey進(jìn)行加密
KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
keyAgreement.init(privateKey);
keyAgreement.doPhase(publicKey,true);
return keyAgreement.generateSecret("AES").getEncoded();//算法使用對稱加密算法(DES,DESede,AES)
//return keyAgreement.generateSecret(); // 也可以不選擇算法,使用默認(rèn)方法計(jì)算
}
//獲取公鑰字節(jié)數(shù)組
public static byte[] getPublicKey(Map<String,Object> map){
return ((DHPublicKey) map.get(PUBLIC_KEY)).getEncoded();
}
//獲取私鑰字節(jié)數(shù)組
public static byte[] getPrivateKey(Map<String,Object> map){
return ((DHPrivateKey) map.get(PRIVATE_KEY)).getEncoded();
}
public static void main(String[] args) throws Exception {
byte[] source_public_key;
byte[] source_private_key;
byte[] source_local_key;
byte[] target_public_key;
byte[] target_private_key;
byte[] target_local_key;
Map<String, Object> sourceKey = initSourceKey();
source_public_key = getPublicKey(sourceKey);
source_private_key = getPrivateKey(sourceKey);
System.out.println("源公鑰:"+BytesToHex.fromBytesToHex(source_public_key));
System.out.println("源私鑰:"+BytesToHex.fromBytesToHex(source_private_key));
Map<String, Object> targetKey = initTargetKey(getPublicKey(sourceKey));
target_public_key = getPublicKey(targetKey);
target_private_key = getPrivateKey(targetKey);
System.out.println("目標(biāo)公鑰:"+BytesToHex.fromBytesToHex(target_public_key));
System.out.println("目標(biāo)私鑰:"+BytesToHex.fromBytesToHex(target_private_key));
source_local_key = generateLocalSecretKey(target_public_key, source_private_key);
target_local_key = generateLocalSecretKey(source_public_key, target_private_key);
System.out.println("源本地密鑰:"+BytesToHex.fromBytesToHex(source_local_key));
System.out.println("目標(biāo)本地密鑰:"+BytesToHex.fromBytesToHex(target_local_key));
}
}
【加密/解密(RSA)】【數(shù)字簽名(RSA)】
RSA算法晚于DH算法,這五個(gè)字母全都是人名首字母.DH算法是第一個(gè)非對稱密碼體系.
RSA算法運(yùn)算速度慢,不適宜加密大量數(shù)據(jù).一種解決方案是,將RSA跟對稱加密方式混合使用,將數(shù)據(jù)使用對稱加密方式加密,對稱加密的密鑰使用RSA算法加密,因?yàn)槊荑€很短,所以時(shí)間費(fèi)不了太多.實(shí)際上,對稱加密方式唯一的弊端就是密鑰不好傳遞,對稱加密方式也很難破解.
RSA的適用情景一:
(1)服務(wù)器生成一個(gè)公鑰和一個(gè)私鑰,把公鑰公開了.
(2)客戶端使用公鑰把數(shù)據(jù)進(jìn)行加密,上交服務(wù)器.別人是沒法理解加密后的數(shù)據(jù)的.
(3)服務(wù)器使用私鑰將數(shù)據(jù)解密,查看用戶提交的數(shù)據(jù).
這種情景下,公鑰像是一個(gè)信箱,每個(gè)人都可以往這個(gè)信箱里面放信,但是這個(gè)信箱里面的信只有掌握信箱鑰匙的人才能開箱查看.
RSA適用情景二:
(1)皇上生成一個(gè)公鑰和一個(gè)密鑰,把公鑰公開了.
(2)皇上發(fā)布了一封詔書,昭告天下.詔書右下角有兩串?dāng)?shù)字,第一串?dāng)?shù)字是一個(gè)隨機(jī)串,第二串?dāng)?shù)字是用私鑰加密第一串?dāng)?shù)字所得的結(jié)果.
(3)有人不相信這詔書是皇上寫的,就把第二串?dāng)?shù)字使用公鑰解密,解密之后發(fā)現(xiàn)跟第一串?dāng)?shù)字一樣,說明確實(shí)是皇上寫的,因?yàn)橐话闳藳]有密鑰,也就沒法加密那些能夠用公鑰解密的數(shù)據(jù).
這種情境下,公鑰用于解密,私鑰用于加密,這可以用于發(fā)布公告時(shí),證明這個(gè)公告確實(shí)是某個(gè)人發(fā)的.相當(dāng)于簽名.
實(shí)際上,簽名沒有必要特別長,一般情況下,簽名是定長的,要想定長,可以使用MessageDigest算法,如MD5和SHA系列.所以就有了多種簽名算法,如MD5withRSA等.
RSA 加密/解密 示例
import javax.crypto.Cipher;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
import java.util.Map;
/**
* RSA加密工具
*/
public class RSAUtil {
public static final String PUBLIC_KEY = "RSA_Public_Key";
public static final String PRIVATE_KEY = "RSA_Private_Key";
/**
* 初始化密鑰
* @return
* @throws Exception
*/
public static Map<String,Object> initKey() throws Exception{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);//512-65536 & 64的倍數(shù)
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String,Object> keyMap = new HashMap<String, Object>();
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
public static RSAPublicKey getPublicKey(Map<String,Object> keyMap) {
return (RSAPublicKey) keyMap.get(PUBLIC_KEY);
}
public static RSAPrivateKey getPrivateKey(Map<String,Object> keyMap){
return (RSAPrivateKey) keyMap.get(PRIVATE_KEY);
}
/**
* 使用公鑰對數(shù)據(jù)進(jìn)行加密
* @param data
* @param publicKey
* @return
* @throws Exception
*/
public static byte[] encrypt(byte[] data, RSAPublicKey publicKey) throws Exception{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE,publicKey);
return cipher.doFinal(data);
}
/**
* 使用私鑰解密
* @param data
* @param privateKey
* @return
* @throws Exception
*/
public static byte[] decrypt(byte[] data, RSAPrivateKey privateKey) throws Exception{
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE,privateKey);
return cipher.doFinal(data);
}
public static void main(String[] args) throws Exception {
String data = "周杰倫-東風(fēng)破";
Map<String, Object> keyMap = initKey();
byte[] miwen = encrypt(data.getBytes(),getPublicKey(keyMap));
System.out.println("加密后的內(nèi)容:"+BytesToHex.fromBytesToHex(miwen));
byte[] plain = decrypt(miwen, getPrivateKey(keyMap));
System.out.println("解密后的內(nèi)容:"+new String(plain));
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
macOS中搭建Java8開發(fā)環(huán)境(基于Intel?x86?64-bit)
這篇文章主要介紹了macOS中搭建Java8開發(fā)環(huán)境(基于Intel?x86?64-bit)?的相關(guān)資料,需要的朋友可以參考下2022-12-12
Java 在volatile內(nèi)部調(diào)用接口的方法
在Java中,volatile?關(guān)鍵字通常用于確保變量的可見性和有序性,而不是用來修飾接口或方法調(diào)用的,這篇文章主要介紹了Java 在volatile內(nèi)部調(diào)用接口的方法,需要的朋友可以參考下2024-07-07
Java類的繼承實(shí)例詳解(動力節(jié)點(diǎn)Java學(xué)院整理)
在Java開發(fā)中,我們常常用到繼承這一概念,可以說繼承是Java這類面向?qū)ο缶幊陶Z言的基石,今天小編一起和大家一起學(xué)習(xí)java類的繼承2017-04-04
Java實(shí)現(xiàn)多個(gè)數(shù)組間的排列組合
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)多個(gè)數(shù)組間的排列組合,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02
SpringBoot整合Swagger Api自動生成文檔的實(shí)現(xiàn)
本文主要介紹了SpringBoot整合Swagger Api自動生成文檔的實(shí),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
Java基于TCP協(xié)議socket網(wǎng)絡(luò)編程的文件傳送的實(shí)現(xiàn)
這篇文章主要介紹了Java基于TCP協(xié)議socket網(wǎng)絡(luò)編程的文件傳送的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
SpringBoot利用MDC機(jī)制過濾單次請求的所有日志
在服務(wù)出現(xiàn)故障時(shí),我們經(jīng)常需要獲取一次請求流程里的所有日志進(jìn)行定位 ,如何將一次數(shù)據(jù)上報(bào)請求中包含的所有業(yè)務(wù)日志快速過濾出來,就是本文要介紹的,需要的朋友可以參考下2024-04-04

