一、SSH加密原理

SSH是先通过非对称加密告诉服务端一个对称加密口令,然后进行验证用户名和密码的时候,使用双方已经知道的加密口令进行加密和解密,见下图:

解释:SSH中为什么要使用非对称加密,又使用对称加密,到底有什么用处?到底安全不安全?既然后来又使用了对称加密,开始的时候为什么还要用非对称加密?反过来,既然用非对称加密,为什么又要使用对称加密呢?

  1. 非对称加密,是为了将客户端产生的256位随机的口令传递到服务端,那么在传递的过程中,使用公钥进行了加密,这样,这个256位的加密口令就很难被网络上进行破解。
  2. 对称加密,因为频繁的使用非对称加密是非常浪费性能的,那么SSH就是用了256位长度的口令作为接下来传递用户名密码时的加密口令,其破解的难度,想必大家都知道了,每一位上都有0-9种变化。
  3. 这样安全吗,我觉得还是很不错的,具体使用起来也易于让人理解。

二、我的SSH加密原理

①、使用场景

我所开发的项目是大宗期货交易,主要服务于交易所,这也就产生一个需求就是,我们需要控制交易所使用我们软件的周期。也就是说我们的项目留有一个后门,用来控制项目的周期,假如交易所使用软件的周期到了,那么如果他不续费,而项目的代码部署在人家的服务器上,此时我们就很难控制了,但是有了这个后门,到期后会自动停止软件,这样就不担心交易所不给我们钱了。

②、使用方式

  1. 我们给交易的项目代码中包含一个后门,该后门通过webservice client发送一个请求到web service。
  2. 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;
}

再赘述一下:

  1. 第一个判断语句中的内容就是生成公钥和私钥,并且返回公钥。
  2. 第二个判断语句中的内容就是保存client发送的随机字符串,这一步非常关键,随机字符串首先通过公钥进行了加密,这大大加强了加密的深度。
  3. 第三个判断语句中的内容就是将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;
}

稍作解释:

  1. 通过循环主要为了防止网络断开时服务不停的发送请求,最多10次就够了。
  2. 主要有四步操作,注释中我想解释的还可以。

③、共享加密解密公共类

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两种加密就够我们使用了!

至于其他的辅助类我就不多介绍了,网上有很多资源,也许你的项目也有类似的实现方式。

Java实现SSH模式加密原理及代码的更多相关文章

  1. 浅谈远程登录时,ssh的加密原理

    SSH:Secure Shell,是一种网络安全协议,主要用于登录远程计算机的加密过程. 登录方式主要有两种: 1.基于用户密码的登录方式:   加密原理:   当服务器知道用户请求登录时,服务器会把 ...

  2. When I see you again(加密原理介绍,代码实现DES、AES、RSA、Base64、MD5)

    关于网络安全的数据加密部分,本来打算总结一篇博客搞定,没想到东西太多,这已是第三篇了,而且这篇写了多次,熬了多次夜,真是again and again.起个名字:数据加密三部曲,前两部链接如下: 整体 ...

  3. JAVA NIO工作原理及代码示例

    简介:本文主要介绍了JAVA NIO中的Buffer, Channel, Selector的工作原理以及使用它们的若干注意事项,最后是利用它们实现服务器和客户端通信的代码实例. 欢迎探讨,如有错误敬请 ...

  4. 加密原理介绍,代码实现DES、AES、RSA、Base64、MD5

    阅读目录 github下载地址 一.DES对称加密 二.AES对称加密 三.RSA非对称加密 四.实际使用 五.关于Padding 关于电脑终端Openssl加密解密命令 关于网络安全的数据加密部分, ...

  5. SSH加密原理、RSA非对称加密算法学习与理解

    首先声明一下,这里所说的SSH,并不是Java传统的三大框架,而是一种建立在应用层和传输层基础上的安全外壳协议,熟悉Linux的朋友经常使 用到一 个SSH Secure Shell Cilent的工 ...

  6. Base64加密解密原理以及代码实现(VC++)

    Base64加密解密原理以及代码实现 转自:http://blog.csdn.net/jacky_dai/article/details/4698461 1. Base64使用A--Z,a--z,0- ...

  7. Java基础知识强化之集合框架笔记47:Set集合之TreeSet保证元素唯一性和比较器排序的原理及代码实现(比较器排序:Comparator)

    1. 比较器排序(定制排序) 前面我们说到的TreeSet的自然排序是根据集合元素的大小,TreeSet将它们以升序排列. 但是如果需要实现定制排序,比如实现降序排序,则要通过比较器排序(定制排序)实 ...

  8. md5 32位 加密原理 Java实现md5加密

    md5 32位 加密原理 简单概括起来,MD5 算法的过程分为四步:处理原文,设置初始值,循环加工,拼接结果. 第一步:处理原文 首先,我们计算出原文长度(bit)对 512 求余的结果,如果不等于 ...

  9. Java线程:概念与原理

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

随机推荐

  1. 华硕_ZX50JX4200 安装ssd固态盘

    本人亲身的一次经历,帮朋友的华硕手提装一个内存和ssd固态 内存5分钟搞定,但是ssd固态盘就经过了一番的折腾 首先要拧掉所有后盖的螺丝,把光驱拆下来,注意撬开键盘板的时候有排线,不能弄断了.然后一定 ...

  2. GridBagLayout的帮助类

    自备详细注释 /* * To change this license header, choose License Headers in Project Properties. * To change ...

  3. [LeetCode OJ] Best Time to Buy and Sell Stock I

    Say you have an array for which the ith element is the price of a given stock on day i. If you were ...

  4. PHPCMS V9 学习总结(转)

    转自:http://www.cnblogs.com/Braveliu/p/5074930.html 在实现PHPCMS网站过程中,根据业务需求,我们遇到很多问题,特此总结如下,以便大家参考学习. [1 ...

  5. 用Python高亮org-mode代码块

    文章同时可在我的github blog上阅读:http://cheukyin.github.io/python/2014-08/pygments-highlight-src-export-html.h ...

  6. 使用Thinkphp框架开发移动端接口

     本文给大家分享的是使用thinkphp框架开发移动端接口的2种方法,一种是开发API,另外一种是实现移动端访问自动切换移动主题模板,从而实现伪app访问,下面我们就来详细看下如何实现吧. 方案一:给 ...

  7. MySql数据库3【优化2】sql语句的优化

    1.SELECT语句优化 1).利用LIMIT 1取得唯一行[控制结果集的行数] 有时,当你要查询一张表是,你知道自己只需要看一行.你可能会去的一条十分独特的记录,或者只是刚好检查了任何存在的记录数, ...

  8. STM32学习笔记——SPI串行通讯(向原子哥学习)

    一.SPI  简介 SPI是 Serial Peripheral interface 的缩写,就是串行外围设备接口.SPI 接口主要应用在  EEPROM, FLASH,实时时钟,AD 转换器,还有数 ...

  9. gcc常用的编译选项

    一.程序编译过程 程序编译的时候,要分四个阶段 : 1.预处理阶段,完成宏定义和include文件展开等工作: 2.根据编译参数进行不同程度的优化,编译成汇编代码: 3.用汇编器把汇编代码进一步生成目 ...

  10. 显示Mac电脑下的隐藏文件

    1. 在应用程序里打开终端, cd 你的文件夹名 ls -a 即可显示该文件夹下的所有隐藏文件 2. 如果你想打开整个系统的隐藏文件可以在终端下输入以下命令 defaults write com.ap ...