Java實現SSH模式加密原理及程式碼
一、SSH加密原理
SSH是先通過非對稱加密告訴服務端一個對稱加密口令,然後進行驗證使用者名稱和密碼的時候,使用雙方已經知道的加密口令進行加密和解密,見下圖:
解釋:SSH中為什麼要使用非對稱加密,又使用對稱加密,到底有什麼用處?到底安全不安全?既然後來又使用了對稱加密,開始的時候為什麼還要用非對稱加密?反過來,既然用非對稱加密,為什麼又要使用對稱加密呢?
- 非對稱加密,是為了將客戶端產生的256位隨機的口令傳遞到服務端,那麼在傳遞的過程中,使用公鑰進行了加密,這樣,這個256位的加密口令就很難被網路上進行破解。
- 對稱加密,因為頻繁的使用非對稱加密是非常浪費效能的,那麼SSH就是用了256位長度的口令作為接下來傳遞使用者名稱密碼時的加密口令,其破解的難度,想必大家都知道了,每一位上都有0-9種變化。
- 這樣安全嗎,我覺得還是很不錯的,具體使用起來也易於讓人理解。
二、我的SSH加密原理
①、使用場景
我所開發的專案是大宗期貨交易,主要服務於交易所,這也就產生一個需求就是,我們需要控制交易所使用我們軟體的週期。也就是說我們的專案留有一個後門,用來控制專案的週期,假如交易所使用軟體的週期到了,那麼如果他不續費,而專案的程式碼部署在人家的伺服器上,此時我們就很難控制了,但是有了這個後門,到期後會自動停止軟體,這樣就不擔心交易所不給我們錢了。
②、使用方式
- 我們給交易的專案程式碼中包含一個後門,該後門通過webservice client傳送一個請求到web service。
- web service接收到請求後,回給client需要的資訊。
在以上這個過程當中,就會產生一個SSH加密的請求方式,請允許我用一個拙劣的圖表示一下。
三、我的SSH具體實現
既然要用到webservice,那麼就需要建立web service服務,還有web service client。關於這方面,我暫時不想說太多,方式有很多,我在這就不誤導大家了。我是通過eclipse搞定的,可參照webservice之間通訊 。
接下來,我將介紹程式碼,但是考慮到篇幅問題,一些不必要的程式碼我就不貼出來了,關鍵在於講解清楚這個原理。
①、service
ExchangeService.java
public byte[] request(String param, String resultType) { logger.info("請求引數:" + param); // 返回物件 KeyResult keyResult = new KeyResult(); try { // 先獲取公鑰 if (resultType.equals(PUBLIC_KEY_RESULT_TYPE)) { Map<String, Object> keyMap = RSACoder.initKey(); // 產生公鑰和私鑰 privateKey = RSACoder.getPrivateKey(keyMap); keyResult.setKey(RSACoder.getPublicKey(keyMap)); logger.info("公鑰字串:" + keyResult.getKey()); logger.info("私鑰字串:" + privateKey); } else if (resultType.equals(ECHOSTR_RESULT_TYPE)) { // 設定客戶端的口令資訊 byte[] paramByte = new BASE64Decoder().decodeBuffer(param); echoStr = new String(RSACoder.decryptByPrivateKey(paramByte, privateKey)); } else { // 通過資料庫獲取交易所對應的許可權資訊. // 先將請求轉換為byte陣列,然後再進行解密,最後轉換為字串 ExchangeInfo info = ExchangeInfo.dao.getInfoByName(new String(CryptUtil.decrypt( new BASE64Decoder().decodeBuffer(param), echoStr.getBytes()))); String result = ""; // 獲取系統啟用許可權 if (resultType.equals(PRIVILEGE_RESULT_TYPE)) { // 先判斷使用許可權 // 在判斷使用日期 // 當前登入用登入時獲取登入的當前日期和開始日期進行比較,然後計算還可以使用的日期 long time = (new Date().getTime() / 1000) - string2DateInt(openday); // 換算成天數 int day = (int) (time / (60 * 60 * 24)); // 還可以使用的天數 if (usedays - day > 0) { // 可以使用 result = "1"; } else { // 無法使用 result = "0"; } } keyResult.setResult(CryptUtil.encrypt(result.getBytes(), echoStr.getBytes())); } return JsonUtil.objectToByte(keyResult); } catch (Exception e) { logger.error("webservice出錯了!!!!"); logger.error(e.getMessage(), e); } return null; }
再贅述一下:
- 第一個判斷語句中的內容就是生成公鑰和私鑰,並且返回公鑰。
- 第二個判斷語句中的內容就是儲存client傳送的隨機字串,這一步非常關鍵,隨機字串首先通過公鑰進行了加密,這大大加強了加密的深度。
- 第三個判斷語句中的內容就是將client的許可權通過隨機字串進行加密。
②、client
ExchangeUtil.java
public static boolean canRunForExchange(String resultType) { int i = 1; boolean result = false; while (true) { try { // webservice呼叫類 ExchangeServiceProxy proxy = new ExchangeServiceProxy(); BASE64Encoder encoder = new BASE64Encoder(); // step1.獲取service產生的公鑰 KeyResult keyResult = JsonUtil.byteToObject(proxy.request(null, PUBLIC_KEY_RESULT_TYPE), KeyResult.class); // step2.產生隨機字串,傳送到webserivce String echoStr = StrUtil.getEchoStrByLength(10); byte[] echoByteParam = RSACoder.encryptByPublicKey(echoStr.getBytes(), keyResult.getKey()); proxy.request(encoder.encode(echoByteParam), ECHOSTR_RESULT_TYPE); // step3.加密客戶端請求資訊,然後傳送到webservice // 先加密為byte陣列,然後轉換成字串 byte[] results = proxy.request( encoder.encode(CryptUtil.encrypt(Constants.client_type.getBytes(), echoStr.getBytes())), resultType); keyResult = JsonUtil.byteToObject(results, KeyResult.class); // step4.通過口令解密服務端返回訊息 String response = new String(CryptUtil.decrypt(keyResult.getResult(), echoStr.getBytes())); if (response.equals("1")) { result = true; } break; } catch (Exception e) { logger.debug("第" + i + "次載入webservice失敗"); i++; logger.error(e.getMessage(), e); if (i >= 10) { break; } } } return result; }
稍作解釋:
- 通過迴圈主要為了防止網路斷開時服務不停的傳送請求,最多10次就夠了。
- 主要有四步操作,註釋中我想解釋的還可以。
③、共享加密解密公共類
CryptUtil.java
package com.honzh.socket.util; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.IvParameterSpec; public class CryptUtil { /** * @Title: encrypt * @Description: 加密 * @param data * @param key * @return * @throws Exception */ public static byte[] encrypt(byte[] data, byte[] key) throws Exception { key = get8(key); Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); DESKeySpec desKeySpec = new DESKeySpec(key); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = keyFactory.generateSecret(desKeySpec); IvParameterSpec iv = new IvParameterSpec(key); cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); return cipher.doFinal(data); } /** * @Title: decrypt * @Description: 解密 * @param data * @param key * @return * @throws Exception */ public static byte[] decrypt(byte[] data, byte[] key) throws Exception { key = get8(key); Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); DESKeySpec desKeySpec = new DESKeySpec(key); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = keyFactory.generateSecret(desKeySpec); IvParameterSpec iv = new IvParameterSpec(key); cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); return cipher.doFinal(data); } private static byte[] get8(byte[] key) { byte[] key1 = new byte[8]; for (int i = 0; i < 8; i++) { key1[i] = key[i]; } return key1; } public static String toHexString(byte[] data) { String s = ""; for (int i = 0; i < data.length; i++) { s += Integer.toHexString(data[i] & 0xFF)+"-"; } return s; } }
一般情況下,SHA和MD5兩種加密就夠我們使用了!
至於其他的輔助類我就不多介紹了,網上有很多資源,也許你的專案也有類似的實現方式。
相關文章
- DES原理及程式碼實現
- java 橋接模式實現程式碼Java橋接模式
- UITableView的原理——探究及重新實現程式碼UIView
- java中的鎖及實現原理Java
- 簡單工廠模式(simple factory)及程式碼實現模式
- 一文搞懂對稱加密:加密演算法、工作模式、填充方式、程式碼實現加密演算法模式
- HashMap實現原理及原始碼分析HashMap原始碼
- synchronized實現原理及ReentrantLock原始碼synchronizedReentrantLock原始碼
- 常見排序演算法原理及JS程式碼實現排序演算法JS
- vysor原理與程式碼實現
- 【Redis】跳躍表原理分析與基本程式碼實現(java)RedisJava
- 單連結串列實現原理以及具體程式碼(java)Java
- Python物件導向多型實現原理及程式碼例項Python物件多型
- CRC校驗原理簡介及C程式碼實現說明C程式
- 支付對接常用的加密方式介紹以及java程式碼實現加密Java
- InnoDB MVCC實現原理及原始碼解析MVC原始碼
- golang 中,對稱加密的程式碼實現Golang加密
- 20 行 Python 程式碼實現加密通訊Python加密
- Java高階程式設計——MySQL索引實現及優化原理解析Java程式設計MySql索引優化
- AOP如何實現及實現原理
- 快速傅立葉變換原理介紹及遞迴程式碼實現遞迴
- ABtest原理及python程式碼Python
- BiLSTM介紹及程式碼實現
- CNN介紹及程式碼實現CNN
- 瀑布流程式碼實現及思路
- Android端程式碼染色原理及技術實踐Android
- angular髒檢查原理及虛擬碼實現Angular
- JAVA AQS 實現原理JavaAQS
- SpringMVC實現原理及解析SpringMVC
- KVO使用及實現原理
- Promise原理探究及實現Promise
- NNLM原理及Pytorch實現PyTorch
- Java及Jquery獲取螢幕解析度的實現程式碼JavajQuery
- Java併發包原始碼學習系列:阻塞佇列BlockingQueue及實現原理分析Java原始碼佇列BloC
- 多合一收款二維碼原理及實現(原始碼)原始碼
- 關於base64編碼的原理及實現
- 深度解析Spring Cloud Ribbon的實現原始碼及原理SpringCloud原始碼
- 深入理解Java中的底層阻塞原理及實現Java
- Java-JDK動態代理(AOP)使用及實現原理分析JavaJDK