1. 程式人生 > >Java安全之安全加密演算法

Java安全之安全加密演算法

# Java安全之安全加密演算法 ## 0x00 前言 本篇文來談談關於常見的一些加密演算法,其實在此之前,對演算法的瞭解並不是太多。瞭解的層次只是基於加密演算法的一些應用上。也來淺談一下加密演算法在安全領域中的作用。寫本篇文也是基於演算法的應用和實現,也是我的基本原則,能用就行。 ## 0x01 演算法體制 在加密演算法裡面大致分為四大類:對稱加密演算法、非對稱加密演算法、雜湊函式、組合加密。 對稱加密:指的是加密的金鑰和解密的金鑰相同。 非對稱加密:指的是加密的金鑰和加密的金鑰不同。分為公鑰和私鑰。 雜湊函式:主要用於驗證資料的完整性,長度不受限制,hash值容易計算,雜湊運算過程不可逆如:MD5、SHA ## 0x02 雜湊演算法 Hash,一般翻譯做雜湊、雜湊,或音譯為雜湊,是把任意長度的輸入(又叫做預對映pre-image)通過雜湊演算法變換成固定長度的輸出,該輸出就是雜湊值。這種轉換是一種壓縮對映,也就是,雜湊值的空間通常遠小於輸入的空間,不同的輸入可能會雜湊成相同的輸出,所以不可能從雜湊值來確定唯一的輸入值。簡單的說就是一種將任意長度的訊息壓縮到某一固定長度的訊息摘要的函式。 ### MD5 md5的運用範圍也比較廣,比如在一些資料庫儲存密碼的時候會去使用到該演算法去進行加密儲存。當然也可以看到網上的一些md5破解的。但是他們都是基於彩虹表去跑,使用字典進行md5加密,然後把加密的值進行對比,從而判斷該md5值的明文。 #### 程式碼例項: ```java package com.demo; import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MD5demo { private static String name = "xiaoming"; public static void main(String[] args) throws NoSuchAlgorithmException { MessageDigest md5 = MessageDigest.getInstance("MD5");//設定要返回的摘要演算法物件 byte[] digest = md5.digest(name.getBytes()); //計算hash值 System.out.println(HexBin.encode(digest));//輸出hash結果 } } ``` ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012500602-1424182850.png) ### SHA 安全雜湊演算法(英語:Secure Hash Algorithm,縮寫為SHA)是一個密碼雜湊函式家族,是FIPS所認證的安全雜湊演算法。能計算出一個數字訊息所對應到的,長度固定的字串(又稱訊息摘要)的演算法。且若輸入的訊息不同,它們對應到不同字串的機率很高。 SHA家族的五個演算法,分別是SHA-1、SHA-224、SHA-256、SHA-384,和SHA-512 下面是一張對照圖。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012522671-455942907.png) ### 程式碼例項: ```java package com.demo; import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class jdksha1 { private static String name = "xiaoming"; public static void main(String[] args) throws NoSuchAlgorithmException { MessageDigest sha = MessageDigest.getInstance("SHA"); byte[] digest = sha.digest(name.getBytes()); System.out.println(HexBin.encode(digest)); } } ``` ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012533036-2056041601.png) ## 0x03 對稱加密演算法 對稱加密演算法,他的加解密金鑰都是一樣的。而對稱加密的演算法又分兩大類,一種是每次對明文中的位元組使用金鑰進行加密,而第二種是對一組明文使用金鑰進行加密。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012542726-1715098483.png) 先來看看分組加密的工作模式。 #### 分組加密的工作模式 ``` 1. ECB:電子密碼本(最常用的,每次加密均產生獨立的密文分組,並且對其他的密文分組不會產生影響,也就是相同的明文加密後產生相同的密文) 2. CBC:密文連結(常用的,明文加密前需要先和前面的密文進行異或運算,也就是相同的明文加密後產生不同的密文) 除了這兩種常用的工作模式,還有: 3. CFB:密文反饋 4. OFB:輸出反饋 5. CTR:計數器 ``` #### 分組密碼填充方式 ``` 1. NoPadding:無填充 2. PKCS5Padding: 3. ISO10126Padding ``` 常用的加密方式DES、3DES、AES。可以來對比一下,這幾個演算法的區別。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012555057-1627206124.png) ### BASE64 因為BASE64的加密解密演算法是公開的,所以加密資料是沒有任何安全性可言。先來看看API文件中提供的BASE64加密的類。除了在JDK中內建的也有一些第三方類會提供BASE64加密的類。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012605636-821921847.png) ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012634299-991428367.png) #### 程式碼例項: ```java package com.demo; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import java.io.IOException; public class base64demo { public static void main(String[] args) throws IOException { String name = "xiaoming"; BASE64Encoder encoder = new BASE64Encoder//例項化BASE64Encoder物件 String encode = encoder.encode(name.getBytes());//呼叫encode進行加密 System.out.println(encode); BASE64Decoder base64Decoder = new BASE64Decoder();//例項化BASE64Decoder物件 byte[] bytes = base64Decoder.decodeBuffer(encode);//進行解密 System.out.println(bytes); String s = new String(bytes); System.out.println(s); } } ``` ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012644999-2078759273.png) BASE64的加解密比較簡單,在這裡就不細說了。 ### DES DES的演算法其實已經被公開了,其實是不太安全的。 #### 程式碼例項: ```java package com.demo; import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin; import javax.crypto.*; import javax.crypto.spec.DESKeySpec; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; public class desdemo { private static String name = "xiaoming"; public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException { //1.生成金鑰 KeyGenerator des = KeyGenerator.getInstance("DES");//設定獲取des的金鑰 des.init(56);//初始化金鑰生成器,設定為56長度的金鑰 SecretKey secretKey = des.generateKey();//獲取金鑰 // System.out.println(secretKey); byte[] deskey = secretKey.getEncoded(); //獲取金鑰的byte陣列 //2.金鑰轉換 DESKeySpec desKeySpec = new DESKeySpec(deskey); SecretKeyFactory des1 = SecretKeyFactory.getInstance("DES"); SecretKey secretKey1 = des1.generateSecret(desKeySpec); // System.out.println(secretKey1); //3.加密 Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");//選擇演算法、工作模式和填充方式 cipher.init(Cipher.ENCRYPT_MODE,secretKey1);//選擇加密模式和金鑰進行加密 byte[] res = cipher.doFinal(name.getBytes());//加密資料 // System.out.println(res); // String s = new String(res); System.out.println(HexBin.encode(res));//輸出加密後結果 //4.解密 cipher.init(Cipher.DECRYPT_MODE,secretKey1);//選擇金鑰,並使用解密模式 byte[] bytes = cipher.doFinal(res);//解密加密後的結果 String s1 = new String(bytes); System.out.println(s1); } } ``` ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012702065-128120240.png) ### 3DES 3DES也被叫做DESede,也就是基於DES三次加密。其實也有四層和兩層DES,但是平時中用的最多的還是3DES。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012711752-1336089810.png) 上面的圖是他的一個演算法的說明圖。 其實3DES和DES在程式碼中的實現方式很相似。但是要注意的一點是金鑰長度要選擇正確,否則會報錯。或者是可以使用`SecureRandom()`類,讓他根據選擇的加密演算法使用預設的金鑰長度。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012720765-1683694041.png) #### 程式碼例項: ```java package com.demo; import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin; import javax.crypto.*; import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.DESedeKeySpec; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; public class jdk3des { private static String name = "xiaoming"; public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, BadPaddingException, IllegalBlockSizeException { //1.生成金鑰 KeyGenerator des = KeyGenerator.getInstance("DESede");//設定獲取des的金鑰 // des.init(168);//初始化金鑰生成器,設定為168長度的金鑰 des.init(new SecureRandom());//根據加密演算法使用預設金鑰長度 SecretKey secretKey = des.generateKey();//獲取金鑰 // System.out.println(secretKey); byte[] deskey = secretKey.getEncoded(); //獲取金鑰的byte陣列 //2.金鑰轉換 DESedeKeySpec desKeySpec = new DESedeKeySpec(deskey); SecretKeyFactory des1 = SecretKeyFactory.getInstance("DESede"); SecretKey secretKey1 = des1.generateSecret(desKeySpec); // System.out.println(secretKey1); //3.加密 Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");//選擇演算法、工作模式和填充方式 cipher.init(Cipher.ENCRYPT_MODE,secretKey1);//選擇加密模式和金鑰進行加密 byte[] res = cipher.doFinal(name.getBytes());//加密資料 // System.out.println(res); // String s = new String(res); System.out.println(HexBin.encode(res));//輸出加密後結果 //4.解密 cipher.init(Cipher.DECRYPT_MODE,secretKey1);//選擇金鑰,並使用解密模式 byte[] bytes = cipher.doFinal(res);//解密加密後的結果 String s1 = new String(bytes); System.out.println(s1); } } ``` ### AES AES是目前用的最多的對稱加密演算法,一般用於移動通訊系統加密或者是基於SSH協議的軟體 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012749970-2078768787.png) #### 程式碼例項: ```java package com.demo; import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin; import com.sun.xml.internal.messaging.saaj.util.Base64; import sun.misc.BASE64Encoder; import javax.crypto.*; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; public class aesdemo { private static String name = "xiaoming"; public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { //1.獲取金鑰 KeyGenerator aes = KeyGenerator.getInstance("AES"); aes.init(128); SecretKey secretKey = aes.generateKey(); byte[] encoded = secretKey.getEncoded(); //2.金鑰轉換 Key key = new SecretKeySpec(encoded, "AES"); //3.加密 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE,key); byte[] bytes = cipher.doFinal(name.getBytes()); System.out.println(new BASE64Encoder().encode(bytes));//加密完成後,再使用base64進行加密 //4.解密 cipher.init(Cipher.DECRYPT_MODE,key); byte[] bytes1 = cipher.doFinal(bytes); System.out.println(new String(bytes1)); } } ``` 下面來放一張基於AES加解密的流程圖。 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012801518-2092407890.png) ### PBE PBE演算法(Password Based Encryption,基於口令加密)是一種基於口令的加密演算法,其特點是使用口令代替了金鑰,而口令由使用者自己掌管,採用隨機數雜湊多重加密等方法保證資料的安全性。PBE演算法在加密過程中並不是直接使用口令來加密,而是加密的金鑰由口令生成,這個功能由PBE演算法中的KDF函式完成。KDF函式的實現過程為:將使用者輸入的口令首先通過“鹽”(salt)的擾亂產生準金鑰,再將準金鑰經過雜湊函式多次迭代後生成最終加密金鑰,金鑰生成後,PBE演算法再選用對稱加密演算法對資料進行加密,可以選擇DES、3DES、RC5等對稱加密演算法 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012811431-1257786791.png) 以上這張圖是PBE演算法的實現方式 ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012819614-642462146.png) #### 程式碼例項: ```java package com.demo; import com.sun.xml.internal.messaging.saaj.util.Base64; import sun.misc.BASE64Encoder; import javax.crypto.*; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; import java.security.*; import java.security.spec.InvalidKeySpecException; public class pbedemo { private static String name = "xiaoming"; public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, BadPaddingException, IllegalBlockSizeException { //1.初始化鹽 SecureRandom secureRandom = new SecureRandom(); byte[] salt = secureRandom.generateSeed(8); //2. 獲取金鑰 String password = "123456"; PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray()); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHMD5andDES"); Key key = factory.generateSecret(pbeKeySpec); //3.加密 PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 100); Cipher cipher = Cipher.getInstance("PBEWITHMD5andDES"); cipher.init(Cipher.ENCRYPT_MODE,key,pbeParameterSpec); byte[] bytes = cipher.doFinal(name.getBytes()); System.out.println(new BASE64Encoder().encode(bytes)); //4.解密 cipher.init(Cipher.DECRYPT_MODE,key,pbeParameterSpec); byte[] res = cipher.doFinal(bytes); System.out.println(new String(res)); } } ``` ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012829877-1961932472.png) ## 0x04 非對稱加密演算法 非對稱加密演算法需要兩個金鑰:公鑰和私鑰。公鑰]與私鑰是一對,如果用公鑰對資料進行加密,只有用對應的私鑰才能解密。因為加密和解密使用的是兩個不同的金鑰,所以這種演算法叫作非對稱加密演算法。 ### DH 1976年非對稱加密演算法思想被提出,但是當時並沒有給出具體演算法和方案,因為當時沒有研究出`單向函式`(也就是資訊摘要演算法還沒出現),但是IEEE的期刊中給出了通訊時雙方如何`通過資訊交換協商金鑰`的演算法,也就是DH演算法,通過該演算法雙方可以協商對稱加密的金鑰。 ```java package com.demo; import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin; import javax.crypto.*; import javax.crypto.interfaces.DHPrivateKey; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import java.security.*; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; public class dhdemo { private static String name = "xiaoming"; public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidAlgorithmParameterException, InvalidKeyException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException { // 1.初始化傳送方金鑰 KeyPairGenerator sendKeyPairGenerator = KeyPairGenerator.getInstance("DH"); sendKeyPairGenerator.initialize(512); KeyPair sendKeyPair = sendKeyPairGenerator.generateKeyPair(); byte[] sendPublicKeyEnc = sendKeyPair.getPublic().getEncoded();//生成傳送方公鑰,傳送給接收方(網路、檔案...) // 2.初始化接收方金鑰: KeyFactory receiverKeyFactory = KeyFactory.getInstance("DH"); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(sendPublicKeyEnc); PublicKey receivePublicKey = receiverKeyFactory.generatePublic(x509EncodedKeySpec); DHParameterSpec dhParameterSpec = ((DHPublicKey)receivePublicKey).getParams(); KeyPairGenerator receiverKeyPairGenerator = KeyPairGenerator.getInstance("DH"); receiverKeyPairGenerator.initialize(dhParameterSpec); KeyPair receiverKeyPair = receiverKeyPairGenerator.generateKeyPair(); PrivateKey receiverPrivateKey = receiverKeyPair.getPrivate(); byte[] receiverPublicKeyEnc = receiverKeyPair.getPublic().getEncoded(); // 3.構建接收方金鑰: KeyAgreement receiverKeyAgreement = KeyAgreement.getInstance("DH"); receiverKeyAgreement.init(receiverPrivateKey); receiverKeyAgreement.doPhase(receivePublicKey, true); SecretKey receiverDESKey = receiverKeyAgreement.generateSecret("DES");//接收方Key // 4.構建傳送方金鑰: KeyFactory sendKeyFactory = KeyFactory.getInstance("DH"); x509EncodedKeySpec = new X509EncodedKeySpec(receiverPublicKeyEnc); PublicKey sendPublicKey = sendKeyFactory.generatePublic(x509EncodedKeySpec); KeyAgreement sendKeyAgreement = KeyAgreement.getInstance("DH"); sendKeyAgreement.init(sendKeyPair.getPrivate()); sendKeyAgreement.doPhase(sendPublicKey, true); SecretKey sendDESKey = sendKeyAgreement.generateSecret("DES");//傳送方Key // 5.傳送方加密: Cipher sendCipher = Cipher.getInstance("DES"); sendCipher.init(Cipher.ENCRYPT_MODE, sendDESKey); byte[] sendResult = sendCipher.doFinal(name.getBytes()); System.out.println("sendResult :"+ HexBin.encode(sendResult)); // 6.接收方解密: Cipher receiverCipher = Cipher.getInstance("DES"); receiverCipher.init(Cipher.DECRYPT_MODE, receiverDESKey); byte[] receiverResult = receiverCipher.doFinal(sendResult); System.out.println("receiverResult : "+new String (receiverResult)); } } ``` ### RSA RSA公開金鑰密碼體制是一種使用不同的加密金鑰與解密金鑰,“由已知加密金鑰推匯出解密金鑰在計算上是不可行的”密碼體制。RSA演算法實現了公鑰加密、私鑰解密 和私鑰解密、公鑰加密的一個機制。 也就是說使用公鑰來進行加密,想要解密獲取明文內容,就必須使用對應的私鑰來進行解密。而在其中私鑰中的內容其實是比較長的,而公鑰裡面的內容會偏短一些。因為私鑰一般會儲存在本地,而公鑰會放到各大網際網路上,公鑰比私鑰內容短也是為了方便傳輸和儲存。 #### 程式碼示例: ```java package com.demo; import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer; import sun.misc.BASE64Encoder; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.security.*; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; public class rsademo { private static String name = "xiaoming"; public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { // 1.初始化金鑰 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");//設定獲取RSA的金鑰 keyPairGenerator.initialize(512);//設定金鑰長度 KeyPair keyPair = keyPairGenerator.generateKeyPair();//生成金鑰對 RSAPublicKey rsaPublic =(RSAPublicKey) keyPair.getPublic();//獲取公鑰 RSAPrivateKey rsaPrivate = (RSAPrivateKey)keyPair.getPrivate();//獲取私鑰 // System.out.println(new BASE64Encoder().encode(rsaPublic.getEncoded()));//輸出公鑰 System.out.println(""); // System.out.println(new BASE64Encoder().encode(rsaPrivate.getEncoded()));//輸出私鑰 // 2.私鑰加密、公鑰解密 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivate.getEncoded());//對金鑰進行編碼處理 KeyFactory rsa = KeyFactory.getInstance("RSA");//設定獲取RSA的金鑰 PrivateKey privateKey = rsa.generatePrivate(pkcs8EncodedKeySpec);//從提供的金鑰規範生成私鑰物件。 // 2.1私鑰加密 Cipher encodecipher = Cipher.getInstance("RSA");//設定獲取RSA的金鑰 encodecipher.init(Cipher.ENCRYPT_MODE,privateKey);//設定為加密型別並傳入私鑰進行加密 byte[] res = encodecipher.doFinal(name.getBytes());//對內容進行加密 System.out.println(new BASE64Encoder().encode(res)); // 2.2公鑰解密 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublic.getEncoded());//對公鑰進行編碼處理 rsa = KeyFactory.getInstance("RSA");//設定獲取RSA的金鑰 PublicKey publicKey = rsa.generatePublic(x509EncodedKeySpec);//從提供的金鑰規範生成公鑰物件。 Cipher decodecipher = Cipher.getInstance("RSA");//設定獲取RSA的金鑰 decodecipher.init(Cipher.DECRYPT_MODE,publicKey);//設定解密型別並傳入公鑰進行解密 byte[] decoderes = decodecipher.doFinal(res);//對內容進行解密 System.out.println(new String(decoderes)); } } ``` ![](https://img2020.cnblogs.com/blog/1993669/202010/1993669-20201029012851487-1971999637.png) 下面再來看個公鑰加密私鑰解密的程式碼 ```JAVA package com.demo; import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer; import sun.misc.BASE64Encoder; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.security.*; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; public class rsademo { private static String name = "xiaoming"; public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { // 1.初始化金鑰 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");//設定獲取RSA的金鑰 keyPairGenerator.initialize(512);//設定金鑰長度 KeyPair keyPair = keyPairGenerator.generateKeyPair();//生成金鑰對 RSAPublicKey rsaPublic =(RSAPublicKey) keyPair.getPublic();//獲取公鑰 RSAPrivateKey rsaPrivate = (RSAPrivateKey)keyPair.getPrivate();//獲取私鑰 // System.out.println(new BASE64Encoder().encode(rsaPublic.getEncoded()));//輸出公鑰 System.out.println(""); // 3.公鑰加密、私鑰解密 // 3.1公鑰加密 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublic.getEncoded()); KeyFactory encodersa = KeyFactory.getInstance("RSA"); PublicKey publicKey = encodersa.generatePublic(x509EncodedKeySpec); Cipher encodecipher = Cipher.getInstance("RSA"); encodecipher.init(Cipher.ENCRYPT_MODE,publicKey); byte[] encoderes = encodecipher.doFinal(name.getBytes()); System.out.println(new BASE64Encoder().encode(encoderes)); // 3.2私鑰解密 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivate.getEncoded()); KeyFactory decodersa = KeyFactory.getInstance("RSA"); PrivateKey privateKey = decodersa.generatePrivate(pkcs8EncodedKeySpec); Cipher decodecipher = Cipher.getInstance("RSA"); decodecipher.init(Cipher.DECRYPT_MODE,privateKey); byte[] decoderes = decodecipher.doFinal(encoderes); System.out.println(new String(decoderes)); } } ``` 在程式碼中其實可以看到用到了`x509EncodedKeySpec`和`pkcs8EncodedKeySpec`的類,其實這兩個類一個用於對私鑰進行編碼的,一個是對私鑰進行編碼。 ## 0x05 結尾 在安全中其實加密演算法顯得格外的重要,舉個例子,比如說冰蠍,為什麼就能過一些裝置呢?其實分析過冰蠍的,或者是看過冰蠍作者大大的文章的應該會知道,冰蠍在流量傳輸中也是做了加密的。使用的是AES加密。首先是將客戶端傳送的命令轉換成位元組碼,然後使用aes進行加密,然後在客戶端也就是webshell獲取金鑰進行解密得到位元組碼,最後就是使用defineClass來動態載入位元組碼進行執行。 但是在後面各大廠商的裝置隨著各大廠商裝置的不斷升級,冰蠍2還是被殺了。這是因為在冰蠍aes傳輸金鑰的時候被識別出來了。那麼我們如果再對該金鑰進行更狠一點加密呢?雖然說也能實現,步驟繁瑣一些。但是這還是會產生一些流量。在冰蠍3中的做法是去除了握手的過程,直接寫死在Webshell中的字串作為AES金鑰解密流量包。 後面打算基於冰蠍進行一個重寫,並使用不同的演算法來實現