Java实现SSH模式加密
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两种加密就够我们使用了!
至于其他的辅助类我就不多介绍了,网上有很多资源,希望大家可以结合学习。