JAVA加密算法- 非對(duì)稱(chēng)加密算法(DH,RSA)的詳細(xì)介紹
非對(duì)稱(chēng)密碼概念
1、與對(duì)稱(chēng)加密算法的主要差別在于,加密和解密的密鑰不相同,一個(gè)公開(kāi)(公鑰),一個(gè)保密(私鑰)。主要解決了對(duì)稱(chēng)加密算法密鑰分配管理的問(wèn)題,提高了算法安全性。
2、非對(duì)稱(chēng)加密算法的加密、解密的效率比較低。在算法設(shè)計(jì)上,非對(duì)稱(chēng)加密算法對(duì)待加密的數(shù)據(jù)長(zhǎng)度有著苛刻的要求。例如RSA算法要求待加密的數(shù)據(jù)不得大于53個(gè)字節(jié)。
3、非對(duì)稱(chēng)加密算法主要用于 交換對(duì)稱(chēng)加密算法的密鑰,而非數(shù)據(jù)交換
4、java6提供實(shí)現(xiàn)了DH和RSA兩種算法。Bouncy Castle提供了E1Gamal算法支持。除了上述三種算法還有一個(gè)ECC算法,目前沒(méi)有相關(guān)的開(kāi)源組件提供支持
需要兩個(gè)密鑰進(jìn)行加密或解密,分為公鑰和私鑰
特點(diǎn):安全性高,速度慢
用途
【密鑰交換(DH)】
雙方在沒(méi)有確定共同密鑰的情況下,生成密鑰,不提供加密工作,加解密還需要其他對(duì)稱(chēng)加密算法實(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)通過(guò)源公鑰,生成目標(biāo)公鑰和私鑰 //3 把目標(biāo)公鑰交給源 //4 雙方使用對(duì)方的公鑰和和自己的私鑰,生成本地密鑰 //5 如果雙方生成本地密鑰相同則完成密鑰交換 public class DHUtil { public static final String PUBLIC_KEY = "DH_Public_Key"; public static final String PRIVATE_KEY = "DH_Private_key"; /** * 生成源密鑰對(duì) * @return * @throws Exception */ public static Map<String,Object> initSourceKey() throws Exception{ //創(chuàng)建KeyPairGenerator的實(shí)例,選用DH算法 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH"); //初始化密鑰長(zhǎng)度,默認(rèn)1024,可選范圍512-65536 & 64的倍數(shù) keyPairGenerator.initialize(1024); //生成密鑰對(duì) KeyPair keyPair = keyPairGenerator.generateKeyPair(); DHPublicKey dhPublicKey = (DHPublicKey) keyPair.getPublic(); DHPrivateKey dhPrivateKey = (DHPrivateKey) keyPair.getPrivate(); //將密鑰對(duì)放入Map Map<String,Object> keyMap = new HashMap<String, Object>(); keyMap.put(PUBLIC_KEY, dhPublicKey); keyMap.put(PRIVATE_KEY, dhPrivateKey); return keyMap; } /** * 通過(guò)源公鑰 生成 目標(biāo)密鑰對(duì) * @param sourcePublicKey * @return * @throws Exception */ public static Map<String,Object> initTargetKey(byte[] sourcePublicKey) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance("DH"); //通過(guò)源公鑰,生成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(); //將密鑰對(duì)放入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"); //通過(guò)A公鑰,生成keySpec,使用KeyFactory生成A PublicKey相關(guān)信息 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(aPublicKey); PublicKey publicKey = keyFactory.generatePublic(keySpec); //通過(guò)B私鑰,生成B PrivateKey相關(guān)信息 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(bPrivateKey); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); //通過(guò)KeyAgreement對(duì)A的PublicKey和B的PrivateKey進(jìn)行加密 KeyAgreement keyAgreement = KeyAgreement.getInstance("DH"); keyAgreement.init(privateKey); keyAgreement.doPhase(publicKey,true); return keyAgreement.generateSecret("AES").getEncoded();//算法使用對(duì)稱(chēng)加密算法(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è)非對(duì)稱(chēng)密碼體系.
RSA算法運(yùn)算速度慢,不適宜加密大量數(shù)據(jù).一種解決方案是,將RSA跟對(duì)稱(chēng)加密方式混合使用,將數(shù)據(jù)使用對(duì)稱(chēng)加密方式加密,對(duì)稱(chēng)加密的密鑰使用RSA算法加密,因?yàn)槊荑€很短,所以時(shí)間費(fèi)不了太多.實(shí)際上,對(duì)稱(chēng)加密方式唯一的弊端就是密鑰不好傳遞,對(duì)稱(chēng)加密方式也很難破解.
RSA的適用情景一:
(1)服務(wù)器生成一個(gè)公鑰和一個(gè)私鑰,把公鑰公開(kāi)了.
(2)客戶(hù)端使用公鑰把數(shù)據(jù)進(jìn)行加密,上交服務(wù)器.別人是沒(méi)法理解加密后的數(shù)據(jù)的.
(3)服務(wù)器使用私鑰將數(shù)據(jù)解密,查看用戶(hù)提交的數(shù)據(jù).
這種情景下,公鑰像是一個(gè)信箱,每個(gè)人都可以往這個(gè)信箱里面放信,但是這個(gè)信箱里面的信只有掌握信箱鑰匙的人才能開(kāi)箱查看.
RSA適用情景二:
(1)皇上生成一個(gè)公鑰和一個(gè)密鑰,把公鑰公開(kāi)了.
(2)皇上發(fā)布了一封詔書(shū),昭告天下.詔書(shū)右下角有兩串?dāng)?shù)字,第一串?dāng)?shù)字是一個(gè)隨機(jī)串,第二串?dāng)?shù)字是用私鑰加密第一串?dāng)?shù)字所得的結(jié)果.
(3)有人不相信這詔書(shū)是皇上寫(xiě)的,就把第二串?dāng)?shù)字使用公鑰解密,解密之后發(fā)現(xiàn)跟第一串?dāng)?shù)字一樣,說(shuō)明確實(shí)是皇上寫(xiě)的,因?yàn)橐话闳藳](méi)有密鑰,也就沒(méi)法加密那些能夠用公鑰解密的數(shù)據(jù).
這種情境下,公鑰用于解密,私鑰用于加密,這可以用于發(fā)布公告時(shí),證明這個(gè)公告確實(shí)是某個(gè)人發(fā)的.相當(dāng)于簽名.
實(shí)際上,簽名沒(méi)有必要特別長(zhǎng),一般情況下,簽名是定長(zhǎng)的,要想定長(zhǎng),可以使用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); } /** * 使用公鑰對(duì)數(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)); } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java編程實(shí)現(xiàn)非對(duì)稱(chēng)加密的方法詳解
- java 非對(duì)稱(chēng)加密算法RSA實(shí)現(xiàn)詳解
- java 非對(duì)稱(chēng)加密算法DH實(shí)現(xiàn)詳解
- 解決JAVA非對(duì)稱(chēng)加密不同系統(tǒng)加密結(jié)果不一致的問(wèn)題
- Java 實(shí)現(xiàn)常見(jiàn)的非對(duì)稱(chēng)加密算法
- 教你用Java實(shí)現(xiàn)RSA非對(duì)稱(chēng)加密算法
- Java 實(shí)現(xiàn)RSA非對(duì)稱(chēng)加密算法
- Java對(duì)稱(chēng)與非對(duì)稱(chēng)加密算法原理詳細(xì)講解
- 淺析Java中對(duì)稱(chēng)與非對(duì)稱(chēng)加密算法原理與使用
- Java實(shí)現(xiàn)非對(duì)稱(chēng)加密的三種方法
相關(guān)文章
關(guān)于如何搭建CAS服務(wù)并將CAS項(xiàng)目導(dǎo)入IDEA
這篇文章主要介紹了關(guān)于如何搭建CAS服務(wù)并將CAS項(xiàng)目導(dǎo)入IDEA的問(wèn)題,文中提供了詳細(xì)的圖文講解,需要的朋友可以參考下,如果有錯(cuò)誤的地方還請(qǐng)指正2023-03-03Spring應(yīng)用拋出NoUniqueBeanDefinitionException異常的解決方案
這篇文章介紹了解決org.springframework.beans.factory.NoUniqueBeanDefinitionException異常的一些解決方案,從這些解決方案可以看出Spring框架的設(shè)計(jì)精妙,遇見(jiàn)此問(wèn)題的朋友可以參考下該解決方案2021-06-06Java使用OpenFeign管理多個(gè)第三方服務(wù)調(diào)用
最近開(kāi)發(fā)了一個(gè)統(tǒng)一調(diào)度類(lèi)的項(xiàng)目,需要依賴(lài)多個(gè)第三方服務(wù),這些服務(wù)都提供了HTTP接口供我調(diào)用。感興趣的可以了解一下2021-06-06如何基于JWT實(shí)現(xiàn)接口的授權(quán)訪(fǎng)問(wèn)詳解
授權(quán)是最常見(jiàn)的JWT使用場(chǎng)景,下面這篇文章主要給大家介紹了關(guān)于如何基于JWT實(shí)現(xiàn)接口的授權(quán)訪(fǎng)問(wèn)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-02-02java利用JAXB實(shí)現(xiàn)對(duì)象和xml互相轉(zhuǎn)換方法與實(shí)例詳解
這篇文章主要介紹了java利用JAXB實(shí)現(xiàn)對(duì)象和xml互相轉(zhuǎn)換方法與實(shí)例詳解,需要的朋友可以參考下2020-02-02@ConfigurationProperties綁定配置信息至Array、List、Map、Bean的實(shí)現(xiàn)
這篇文章主要介紹了@ConfigurationProperties綁定配置信息至Array、List、Map、Bean的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05Springboot如何通過(guò)自定義工具類(lèi)獲取bean
這篇文章主要介紹了Springboot通過(guò)自定義工具類(lèi)獲取bean方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09