- 最近需要用加密算法,開始研究加密算法,果然大學落下的需要全都補回來。淚奔啊!
- 網上找各種資料,看別人的原理解釋看了了很多,使用非對稱算法和對稱算法混合加密在實際項目中是經常用的,但原理聽的差不多,沒有具體混合加密的可以參考的代碼,索性翻出以前寫的使用套接字創建服務端和客戶端的例子寫了個小程序,用來完整的模擬整個過程。
- 大致思路是A生成一對公私鑰,將公鑰發送給B,B接收到后用這個公鑰加密對稱算法的密鑰,然后發送給A,A接收到后利用私鑰解密得到對稱算法的密鑰,俗稱會話密鑰,再將自己要發送的消息用會話密鑰加密,發送給B,B接收到后利用自己知道的會話密鑰解密,得到密文,這就是一個完整的過程。具體細節我不做贅述了,不專業,我也講不透。下面直接貼代碼。
- 用Java實現的RSA算法和DES算法也是從網上搜刮來的,現在都忘了原帖在哪,感謝各位前輩。
- 整個過程全都是原生JDK的東西實現的,只用到了Apache的一個Base64編碼工具,其實那個東西JDK也有自帶的,在java.xml.DataConventer這個包下面。不想下載Apache那個的,可以用這個代替。
RSA算法(非對稱算法)的實現:
1 package socket; 2 3 import org.apache.commons.codec.binary.Base64; 4 5 import javax.crypto.Cipher; 6 import java.security.*; 7 import java.security.interfaces.RSAPrivateKey; 8 import java.security.interfaces.RSAPublicKey; 9 import java.security.spec.PKCS8EncodedKeySpec; 10 import java.security.spec.X509EncodedKeySpec; 11 import java.util.HashMap; 12 import java.util.Map; 13 14 15 /** 16 * 非對稱加密算法RSA算法組件 17 * 非對稱算法一般是用來傳送對稱加密算法的密鑰來使用的,相對於DH算法,RSA算法只需要一方構造密鑰,不需要 18 * 大費周章的構造各自本地的密鑰對了。DH算法只能算法非對稱算法的底層實現。而RSA算法算法實現起來較為簡單 19 * 20 * @author kongqz 21 */ 22 public class RSACoder { 23 //非對稱密鑰算法 24 public static final String KEY_ALGORITHM = "RSA"; 25 26 27 /** 28 * 密鑰長度,DH算法的默認密鑰長度是1024 29 * 密鑰長度必須是64的倍數,在512到65536位之間 30 */ 31 private static final int KEY_SIZE = 512; 32 //公鑰 33 public static final String PUBLIC_KEY = "RSAPublicKey"; 34 35 //私鑰 36 public static final String PRIVATE_KEY = "RSAPrivateKey"; 37 38 /** 39 * 初始化密鑰對 40 * 41 * @return Map 甲方密鑰的Map 42 */ 43 public static Map<String, Object> initKey() throws Exception { 44 //實例化密鑰生成器 45 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM); 46 //初始化密鑰生成器 47 keyPairGenerator.initialize(KEY_SIZE); 48 //生成密鑰對 49 KeyPair keyPair = keyPairGenerator.generateKeyPair(); 50 //甲方公鑰 51 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); 52 //甲方私鑰 53 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); 54 //將密鑰存儲在map中 55 Map<String, Object> keyMap = new HashMap<String, Object>(); 56 keyMap.put(PUBLIC_KEY, publicKey); 57 keyMap.put(PRIVATE_KEY, privateKey); 58 return keyMap; 59 60 } 61 62 63 /** 64 * 私鑰加密 65 * 66 * @param data 待加密數據 67 * @param key 密鑰 68 * @return byte[] 加密數據 69 */ 70 public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception { 71 72 //取得私鑰 73 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key); 74 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 75 //生成私鑰 76 PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec); 77 //數據加密 78 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 79 cipher.init(Cipher.ENCRYPT_MODE, privateKey); 80 return cipher.doFinal(data); 81 } 82 83 /** 84 * 公鑰加密 85 * 86 * @param data 待加密數據 87 * @param key 密鑰 88 * @return byte[] 加密數據 89 */ 90 public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception { 91 92 //實例化密鑰工廠 93 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 94 //初始化公鑰 95 //密鑰材料轉換 96 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key); 97 //產生公鑰 98 PublicKey pubKey = keyFactory.generatePublic(x509KeySpec); 99 100 //數據加密 101 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 102 cipher.init(Cipher.ENCRYPT_MODE, pubKey); 103 return cipher.doFinal(data); 104 } 105 106 /** 107 * 私鑰解密 108 * 109 * @param data 待解密數據 110 * @param key 密鑰 111 * @return byte[] 解密數據 112 */ 113 public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception { 114 //取得私鑰 115 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key); 116 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 117 //生成私鑰 118 PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec); 119 //數據解密 120 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 121 cipher.init(Cipher.DECRYPT_MODE, privateKey); 122 return cipher.doFinal(data); 123 } 124 125 /** 126 * 公鑰解密 127 * 128 * @param data 待解密數據 129 * @param key 密鑰 130 * @return byte[] 解密數據 131 */ 132 public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception { 133 134 //實例化密鑰工廠 135 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 136 //初始化公鑰 137 //密鑰材料轉換 138 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key); 139 //產生公鑰 140 PublicKey pubKey = keyFactory.generatePublic(x509KeySpec); 141 //數據解密 142 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 143 cipher.init(Cipher.DECRYPT_MODE, pubKey); 144 return cipher.doFinal(data); 145 } 146 147 /** 148 * 取得私鑰 149 * 150 * @param keyMap 密鑰map 151 * @return byte[] 私鑰 152 */ 153 public static byte[] getPrivateKey(Map<String, Object> keyMap) { 154 Key key = (Key) keyMap.get(PRIVATE_KEY); 155 return key.getEncoded(); 156 } 157 158 /** 159 * 取得公鑰 160 * 161 * @param keyMap 密鑰map 162 * @return byte[] 公鑰 163 */ 164 public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception { 165 Key key = (Key) keyMap.get(PUBLIC_KEY); 166 return key.getEncoded(); 167 } 168 169 /** 170 * @param args 171 * @throws Exception 172 */ 173 public static void main(String[] args) throws Exception { 174 //初始化密鑰 175 //生成密鑰對 176 Map<String, Object> keyMap = RSACoder.initKey(); 177 //公鑰 178 byte[] publicKey = RSACoder.getPublicKey(keyMap); 179 180 //私鑰 181 byte[] privateKey = RSACoder.getPrivateKey(keyMap); 182 System.out.println("公鑰:/n" + Base64.encodeBase64String(publicKey)); 183 System.out.println("私鑰:/n" + Base64.encodeBase64String(privateKey)); 184 185 System.out.println("================密鑰對構造完畢,甲方將公鑰公布給乙方,開始進行加密數據的傳輸============="); 186 String str = "RSA密碼交換算法"; 187 System.out.println("/n===========甲方向乙方發送加密數據=============="); 188 System.out.println("原文:" + str); 189 //甲方進行數據的加密 190 byte[] code1 = RSACoder.encryptByPrivateKey(str.getBytes(), privateKey); 191 System.out.println("加密后的數據:" + Base64.encodeBase64String(code1)); 192 System.out.println("===========乙方使用甲方提供的公鑰對數據進行解密=============="); 193 //乙方進行數據的解密 194 byte[] decode1 = RSACoder.decryptByPublicKey(code1, publicKey); 195 System.out.println("乙方解密后的數據:" + new String(decode1) + "/n/n"); 196 197 System.out.println("===========反向進行操作,乙方向甲方發送數據==============/n/n"); 198 199 str = "乙方向甲方發送數據RSA算法"; 200 201 System.out.println("原文:" + str); 202 203 //乙方使用公鑰對數據進行加密 204 byte[] code2 = RSACoder.encryptByPublicKey(str.getBytes(), publicKey); 205 System.out.println("===========乙方使用公鑰對數據進行加密=============="); 206 System.out.println("加密后的數據:" + Base64.encodeBase64String(code2)); 207 208 System.out.println("=============乙方將數據傳送給甲方======================"); 209 System.out.println("===========甲方使用私鑰對數據進行解密=============="); 210 211 //甲方使用私鑰對數據進行解密 212 byte[] decode2 = RSACoder.decryptByPrivateKey(code2, privateKey); 213 214 System.out.println("甲方解密后的數據:" + new String(decode2)); 215 } 216 }
DES算法(對稱算法)的實現:
1 package socket; 2 3 import javax.crypto.Cipher; 4 import javax.crypto.KeyGenerator; 5 import javax.crypto.SecretKey; 6 import javax.crypto.SecretKeyFactory; 7 import javax.crypto.spec.DESKeySpec; 8 9 import org.apache.commons.codec.binary.Base64; 10 import org.apache.commons.codec.binary.Hex; 11 12 public class DES{ 13 public byte[] bytes; 14 15 //生成一個DES密鑰 16 public static String getKey(){ 17 try { 18 KeyGenerator keyGenerator = KeyGenerator.getInstance("DES"); 19 keyGenerator.init(56); 20 // 生成一個Key 21 SecretKey generateKey = keyGenerator.generateKey(); 22 // 轉變為字節數組 23 byte[] encoded = generateKey.getEncoded(); 24 // 生成密鑰字符串 25 String encodeHexString = Hex.encodeHexString(encoded); 26 return encodeHexString; 27 } catch (Exception e) { 28 e.printStackTrace(); 29 return "密鑰生成錯誤."; 30 } 31 } 32 33 //加密 34 public static String encryptor(String str,String Key){ 35 String s=null; 36 try { 37 DESKeySpec desKey = new DESKeySpec(Key.getBytes()); 38 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 39 SecretKey securekey = keyFactory.generateSecret(desKey); 40 Cipher cipher = Cipher.getInstance("DES"); 41 cipher.init(Cipher.ENCRYPT_MODE,securekey); //初始化密碼器,用密鑰 secretKey 進入加密模式 42 byte[] bytes=cipher.doFinal(str.getBytes()); //加密 43 s= Base64.encodeBase64String(bytes); 44 } catch (Exception e) { 45 e.printStackTrace(); 46 return "加密錯誤."; 47 } 48 return s; 49 } 50 51 //解密 52 public static String decryptor(String buff,String Key){ 53 String s=null; 54 try { 55 DESKeySpec desKey = new DESKeySpec(Key.getBytes()); 56 SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 57 SecretKey securekey = keyFactory.generateSecret(desKey); 58 Cipher cipher = Cipher.getInstance("DES"); 59 cipher.init(Cipher.DECRYPT_MODE,securekey); 60 byte[] responseByte=cipher.doFinal(Base64.decodeBase64(buff)); 61 s=new String(responseByte); 62 return s; 63 } catch (Exception e) { 64 e.printStackTrace(); 65 return "解密錯誤."; 66 } 67 } 68 }
一個消息輔助類:
1 package socket; 2 3 public class MessageType { 4 public static final int PUBLIC_KEY_MESSAGE = 1; 5 public static final int SESSION_KEY_MESSAGE = 2; 6 public static final int CRYPTO_MESSAGE = 3; 7 public static final int RESULT_MESAAGE = 4; 8 }
服務端:
1 package socket; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 import java.io.PrintWriter; 7 import java.net.ServerSocket; 8 import java.net.Socket; 9 import java.util.Scanner; 10 11 import org.apache.commons.codec.binary.Base64; 12 13 public class Server { 14 static ServerSocket serverSocket; 15 16 public static void main(String[] args) { 17 try { 18 int i = 1; 19 serverSocket = new ServerSocket(8001); 20 System.out.println("服務器啟動,等待連接..."); 21 while (true) { 22 // 等待客戶端通過端口8001請求的連接 23 Socket socket = serverSocket.accept(); 24 System.out.println(socket.getInetAddress().getHostAddress() + "上線,當前第" + i + "個"); 25 Runnable runnable = new ThreadEchoHandler(socket); 26 Thread thread = new Thread(runnable); 27 thread.start(); 28 i++; 29 } 30 } catch (IOException e) { 31 e.printStackTrace(); 32 } finally { 33 try { 34 serverSocket.close(); 35 } catch (IOException e) { 36 e.printStackTrace(); 37 } 38 } 39 } 40 41 } 42 43 class ThreadEchoHandler implements Runnable { 44 private Socket incomingSocket; 45 private Scanner scanner; 46 private PrintWriter writer; 47 private String key; 48 49 public ThreadEchoHandler(Socket in) { 50 incomingSocket = in; 51 System.out.println("正在生成DES的密鑰..."); 52 key = DES.getKey(); 53 System.out.println("生成DES密鑰為:"+key); 54 } 55 56 public void run() { 57 try { 58 // 建立套接字的輸入輸出流 59 InputStream inputStream = incomingSocket.getInputStream(); 60 OutputStream outputStream = incomingSocket.getOutputStream(); 61 // 將輸入流轉化為掃描器,輸出流轉化為寫入器 62 scanner = new Scanner(inputStream); 63 writer = new PrintWriter(outputStream, true); 64 65 while(scanner.hasNext()) { 66 String backString = scanner.next(); 67 String[] split = backString.split(":"); 68 if(split.length>1) { 69 int flag = Integer.parseInt(split[0]); 70 switch(flag) { 71 case MessageType.PUBLIC_KEY_MESSAGE: 72 System.out.println("接收到客戶端的RSA的公鑰:"+split[1]); 73 System.out.println("=========用RSA公鑰加密DES會話密鑰============="); 74 byte[] decryptDesKey = RSACoder.encryptByPublicKey(key.getBytes(),Base64.decodeBase64(split[1])); 75 String decryptDesKeyString = Base64.encodeBase64String(decryptDesKey); 76 System.out.println("加密后的DES密鑰:" + decryptDesKeyString); 77 System.out.println("=========密鑰加密成功============="); 78 System.out.println("發送加密后的DES密鑰"); 79 writer.println(MessageType.SESSION_KEY_MESSAGE+":"+decryptDesKeyString); 80 break; 81 case MessageType.CRYPTO_MESSAGE: 82 System.out.println("接收到密文為"+split[1]); 83 System.out.println("用DES會話密鑰解密密文..."); 84 String message = DES.decryptor(split[1], key); 85 System.out.println("解密客戶端發過來的消息為:"+message); 86 String result = DES.encryptor("准奏!", key); 87 writer.println(MessageType.RESULT_MESAAGE+":"+result); 88 System.out.println("已處理相關請求,並回饋給客戶端!"); 89 break; 90 } 91 } 92 } 93 System.out.println("客戶端已斷開連接,會話結束!"); 94 } catch (IOException e) { 95 e.printStackTrace(); 96 } catch (Exception e) { 97 e.printStackTrace(); 98 } finally { 99 // 關閉套接字(很重要,防止造成資源浪費) 100 try { 101 scanner.close(); 102 incomingSocket.close(); 103 } catch (IOException e) { 104 e.printStackTrace(); 105 } 106 } 107 } 108 }
客戶端:
1 package socket; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 import java.io.PrintWriter; 7 import java.net.Socket; 8 import java.net.UnknownHostException; 9 import java.util.Map; 10 import java.util.Scanner; 11 12 import org.apache.commons.codec.binary.Base64; 13 14 public class Client { 15 public static void main(String[] args) throws Exception { 16 Socket socket=null; 17 InputStream inputStream=null; 18 OutputStream outputStream=null; 19 Scanner scanner=null; 20 PrintWriter writer=null; 21 String sessionKey=null; 22 23 24 try { 25 socket = new Socket("localhost",8001); 26 inputStream = socket.getInputStream(); 27 outputStream = socket.getOutputStream(); 28 scanner=new Scanner(inputStream); 29 writer= new PrintWriter(outputStream, true); 30 31 Map<String, Object> initKey = null; 32 try { 33 initKey = RSACoder.initKey(); 34 System.out.println("一對公私鑰生成成功,分別為:"); 35 System.out.println("公鑰為:" + initKey.get(RSACoder.PUBLIC_KEY)); 36 System.out.println("私鑰為:" + initKey.get(RSACoder.PRIVATE_KEY)); 37 } catch (Exception e) { 38 e.printStackTrace(); 39 } 40 System.out.println("正在發送RSA的公鑰給服務端..."); 41 writer.println(MessageType.PUBLIC_KEY_MESSAGE+":"+Base64.encodeBase64String(RSACoder.getPublicKey(initKey))); 42 writer.flush(); 43 44 //* 開始接受服務端發送的消息 45 boolean notExit =true; 46 while(notExit&&scanner.hasNext()) { 47 String backString = scanner.next(); 48 System.out.println(backString); 49 String[] split = backString.split(":"); 50 if(split.length>1) { 51 int flag = Integer.parseInt(split[0]); 52 switch(flag) { 53 case MessageType.SESSION_KEY_MESSAGE: 54 System.out.println("接收到服務端發送的會話密鑰:"+split[1]); 55 System.out.println("=========用RSA私鑰解密DES會話密鑰============="); 56 byte[] sessionKey_byte = RSACoder.decryptByPrivateKey(Base64.decodeBase64(split[1]), RSACoder.getPrivateKey(initKey)); 57 sessionKey = new String(sessionKey_byte); 58 System.out.println("DES會話密鑰解密完成:"+sessionKey); 59 60 System.out.println("用DES密鑰將明文“能否午時三刻行刑?”加密..."); 61 String cipherText = DES.encryptor("能否午時三刻行刑?", sessionKey); 62 System.out.println("加密過的明文為"+cipherText); 63 System.out.println("======================"); 64 System.out.println("==========發送加密后的消息給服務器============"); 65 writer.println(MessageType.CRYPTO_MESSAGE+":"+cipherText); 66 writer.flush(); 67 break; 68 case MessageType.RESULT_MESAAGE: 69 System.out.println("接收到服務端發送的處理結果密文:"+split[1]); 70 System.out.println("=========用DES會話密鑰解密============="); 71 String result = DES.decryptor(split[1], sessionKey); 72 System.out.println("解密的明文為:"+result); 73 System.out.println("==========所有流程結束============"); 74 notExit=false; 75 break; 76 } 77 } 78 } 79 } catch (UnknownHostException e) { 80 e.printStackTrace(); 81 } catch (IOException e) { 82 e.printStackTrace(); 83 }finally { 84 scanner.close(); 85 inputStream.close(); 86 outputStream.close(); 87 socket.close(); 88 } 89 } 90 }