Java实现SSH模式加密(1)

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;
}


上一篇:算法设计与分析复习——第五章:回溯法


下一篇:Java中数字格式化