Java實(shí)現(xiàn)SSH模式加密
Java實(shí)現(xiàn)SSH模式加密的實(shí)現(xiàn)原理思路分享給大家。
一、SSH加密原理
SSH是先通過非對稱加密告訴服務(wù)端一個(gè)對稱加密口令,然后進(jìn)行驗(yàn)證用戶名和密碼的時(shí)候,使用雙方已經(jīng)知道的加密口令進(jìn)行加密和解密,見下圖:
解釋:SSH中為什么要使用非對稱加密,又使用對稱加密,到底有什么用處?到底安全不安全?既然后來又使用了對稱加密,開始的時(shí)候?yàn)槭裁催€要用非對稱加密?反過來,既然用非對稱加密,為什么又要使用對稱加密呢?
非對稱加密,是為了將客戶端產(chǎn)生的256位隨機(jī)的口令傳遞到服務(wù)端,那么在傳遞的過程中,使用公鑰進(jìn)行了加密,這樣,這個(gè)256位的加密口令就很難被網(wǎng)絡(luò)上進(jìn)行破解。
對稱加密,因?yàn)轭l繁的使用非對稱加密是非常浪費(fèi)性能的,那么SSH就是用了256位長度的口令作為接下來傳遞用戶名密碼時(shí)的加密口令,其破解的難度,想必大家都知道了,每一位上都有0-9種變化。
這樣安全嗎,我覺得還是很不錯(cuò)的,具體使用起來也易于讓人理解。
二、我的SSH加密原理
①、使用場景
我所開發(fā)的項(xiàng)目是大宗期貨交易,主要服務(wù)于交易所,這也就產(chǎn)生一個(gè)需求就是,我們需要控制交易所使用我們軟件的周期。也就是說我們的項(xiàng)目留有一個(gè)后門,用來控制項(xiàng)目的周期,假如交易所使用軟件的周期到了,那么如果他不續(xù)費(fèi),而項(xiàng)目的代碼部署在人家的服務(wù)器上,此時(shí)我們就很難控制了,但是有了這個(gè)后門,到期后會(huì)自動(dòng)停止軟件,這樣就不擔(dān)心交易所不給我們錢了。
②、使用方式
我們給交易的項(xiàng)目代碼中包含一個(gè)后門,該后門通過webservice client發(fā)送一個(gè)請求到web service。
web service接收到請求后,回給client需要的信息。
在以上這個(gè)過程當(dāng)中,就會(huì)產(chǎn)生一個(gè)SSH加密的請求方式,請?jiān)试S我用一個(gè)拙劣的圖表示一下。
三、我的SSH具體實(shí)現(xiàn)
既然要用到webservice,那么就需要建立web service服務(wù),還有web service client。關(guān)于這方面,我暫時(shí)不想說太多,方式有很多,我在這就不誤導(dǎo)大家了。我是通過eclipse搞定的,可參照webservice之間通信 。
接下來,我將介紹代碼,但是考慮到篇幅問題,一些不必要的代碼我就不貼出來了,關(guān)鍵在于講解清楚這個(gè)原理。
①、service
ExchangeService.java
public byte[] request(String param, String resultType) { logger.info("請求參數(shù):" + param); // 返回對象 KeyResult keyResult = new KeyResult(); try { // 先獲取公鑰 if (resultType.equals(PUBLIC_KEY_RESULT_TYPE)) { Map<String, Object> keyMap = RSACoder.initKey(); // 產(chǎn)生公鑰和私鑰 privateKey = RSACoder.getPrivateKey(keyMap); keyResult.setKey(RSACoder.getPublicKey(keyMap)); logger.info("公鑰字符串:" + keyResult.getKey()); logger.info("私鑰字符串:" + privateKey); } else if (resultType.equals(ECHOSTR_RESULT_TYPE)) { // 設(shè)置客戶端的口令信息 byte[] paramByte = new BASE64Decoder().decodeBuffer(param); echoStr = new String(RSACoder.decryptByPrivateKey(paramByte, privateKey)); } else { // 通過數(shù)據(jù)庫獲取交易所對應(yīng)的權(quán)限信息. // 先將請求轉(zhuǎn)換為byte數(shù)組,然后再進(jìn)行解密,最后轉(zhuǎn)換為字符串 ExchangeInfo info = ExchangeInfo.dao.getInfoByName(new String(CryptUtil.decrypt( new BASE64Decoder().decodeBuffer(param), echoStr.getBytes()))); String result = ""; // 獲取系統(tǒng)啟用權(quán)限 if (resultType.equals(PRIVILEGE_RESULT_TYPE)) { // 先判斷使用權(quán)限 // 在判斷使用日期 // 當(dāng)前登錄用登錄時(shí)獲取登錄的當(dāng)前日期和開始日期進(jìn)行比較,然后計(jì)算還可以使用的日期 long time = (new Date().getTime() / 1000) - string2DateInt(openday); // 換算成天數(shù) int day = (int) (time / (60 * 60 * 24)); // 還可以使用的天數(shù) 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出錯(cuò)了!?。。?); logger.error(e.getMessage(), e); } return null; }
再贅述一下:
第一個(gè)判斷語句中的內(nèi)容就是生成公鑰和私鑰,并且返回公鑰。
第二個(gè)判斷語句中的內(nèi)容就是保存client發(fā)送的隨機(jī)字符串,這一步非常關(guān)鍵,隨機(jī)字符串首先通過公鑰進(jìn)行了加密,這大大加強(qiáng)了加密的深度。
第三個(gè)判斷語句中的內(nèi)容就是將client的權(quán)限通過隨機(jī)字符串進(jìn)行加密。
②、client
ExchangeUtil.java
public static boolean canRunForExchange(String resultType) { int i = 1; boolean result = false; while (true) { try { // webservice調(diào)用類 ExchangeServiceProxy proxy = new ExchangeServiceProxy(); BASE64Encoder encoder = new BASE64Encoder(); // step1.獲取service產(chǎn)生的公鑰 KeyResult keyResult = JsonUtil.byteToObject(proxy.request(null, PUBLIC_KEY_RESULT_TYPE), KeyResult.class); // step2.產(chǎn)生隨機(jī)字符串,發(fā)送到webserivce String echoStr = StrUtil.getEchoStrByLength(10); byte[] echoByteParam = RSACoder.encryptByPublicKey(echoStr.getBytes(), keyResult.getKey()); proxy.request(encoder.encode(echoByteParam), ECHOSTR_RESULT_TYPE); // step3.加密客戶端請求信息,然后發(fā)送到webservice // 先加密為byte數(shù)組,然后轉(zhuǎn)換成字符串 byte[] results = proxy.request( encoder.encode(CryptUtil.encrypt(Constants.client_type.getBytes(), echoStr.getBytes())), resultType); keyResult = JsonUtil.byteToObject(results, KeyResult.class); // step4.通過口令解密服務(wù)端返回消息 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; }
稍作解釋:
通過循環(huán)主要為了防止網(wǎng)絡(luò)斷開時(shí)服務(wù)不停的發(fā)送請求,最多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兩種加密就夠我們使用了!
至于其他的輔助類我就不多介紹了,網(wǎng)上有很多資源,希望大家可以結(jié)合學(xué)習(xí)。
- 詳解Java使用Jsch與sftp服務(wù)器實(shí)現(xiàn)ssh免密登錄
- Java編程ssh整合常見錯(cuò)誤解析
- 詳解JAVAEE——SSH三大框架整合(spring+struts2+hibernate)
- java通過ssh連接服務(wù)器執(zhí)行shell命令詳解及實(shí)例
- java-SSH2實(shí)現(xiàn)數(shù)據(jù)庫和界面的分頁
- Java框架SSH結(jié)合Easyui控件實(shí)現(xiàn)省市縣三級(jí)聯(lián)動(dòng)示例解析
- SSH框架網(wǎng)上商城項(xiàng)目第25戰(zhàn)之使用java email給用戶發(fā)送郵件
- Java的web開發(fā)中SSH框架的協(xié)作處理應(yīng)用筆記
- 基于Java實(shí)現(xiàn)ssh命令登錄主機(jī)執(zhí)行shell命令過程解析
相關(guān)文章
IDEA2021.2配置docker如何將springboot項(xiàng)目打成鏡像一鍵發(fā)布部署
這篇文章主要介紹了IDEA2021.2配置docker如何將springboot項(xiàng)目打成鏡像一鍵發(fā)布部署,本文圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09SpringCloud中的Ribbon負(fù)載均衡器詳細(xì)解析
這篇文章主要介紹了SpringCloud中的Ribbon負(fù)載均衡器詳細(xì)解析,Ribbon 是一個(gè)基于 HTTP 和 TCP 的客戶端負(fù)載均衡工具,它基于 Netflix Ribbon 實(shí)現(xiàn),通過封裝可以讓我們輕松地將面向服務(wù)的 REST 模版請求自動(dòng)轉(zhuǎn)換成客戶端負(fù)載均衡的服務(wù)調(diào)用,需要的朋友可以參考下2024-01-01spring boot整合scurity做簡單的登錄校驗(yàn)的實(shí)現(xiàn)
這篇文章主要介紹了spring boot整合scurity做簡單的登錄校驗(yàn)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04java使用Runtime執(zhí)行系統(tǒng)命令遇到的問題
這篇文章主要介紹了java使用Runtime執(zhí)行系統(tǒng)命令遇到的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Java實(shí)現(xiàn)局域網(wǎng)聊天室功能(私聊、群聊)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)局域網(wǎng)聊天室功能,包括私聊、群聊,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05