在路上

 找回密码
 立即注册
在路上 站点首页 学习 查看内容

Java实现SSH模式加密原理及代码

2017-2-7 13:38| 发布者: zhangjf| 查看: 546| 评论: 0

摘要: 一、SSH加密原理 SSH是先通过非对称加密告诉服务端一个对称加密口令,然后进行验证用户名和密码的时候,使用双方已经知道的加密口令进行加密和解密,见下图: 解释: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

  1. public byte[] request(String param, String resultType) {
  2. logger.info("请求参数:" + param);
  3. // 返回对象
  4. KeyResult keyResult = new KeyResult();
  5. try {
  6. // 先获取公钥
  7. if (resultType.equals(PUBLIC_KEY_RESULT_TYPE)) {
  8. Map<String, Object> keyMap = RSACoder.initKey();
  9. // 产生公钥和私钥
  10. privateKey = RSACoder.getPrivateKey(keyMap);
  11. keyResult.setKey(RSACoder.getPublicKey(keyMap));
  12. logger.info("公钥字符串:" + keyResult.getKey());
  13. logger.info("私钥字符串:" + privateKey);
  14. } else if (resultType.equals(ECHOSTR_RESULT_TYPE)) {
  15. // 设置客户端的口令信息
  16. byte[] paramByte = new BASE64Decoder().decodeBuffer(param);
  17. echoStr = new String(RSACoder.decryptByPrivateKey(paramByte, privateKey));
  18. } else {
  19. // 通过数据库获取交易所对应的权限信息.
  20. // 先将请求转换为byte数组,然后再进行解密,最后转换为字符串
  21. ExchangeInfo info = ExchangeInfo.dao.getInfoByName(new String(CryptUtil.decrypt(
  22. new BASE64Decoder().decodeBuffer(param), echoStr.getBytes())));
  23. String result = "";
  24. // 获取系统启用权限
  25. if (resultType.equals(PRIVILEGE_RESULT_TYPE)) {
  26. // 先判断使用权限
  27. // 在判断使用日期
  28. // 当前登录用登录时获取登录的当前日期和开始日期进行比较,然后计算还可以使用的日期
  29. long time = (new Date().getTime() / 1000) - string2DateInt(openday);
  30. // 换算成天数
  31. int day = (int) (time / (60 * 60 * 24));
  32. // 还可以使用的天数
  33. if (usedays - day > 0) {
  34. // 可以使用
  35. result = "1";
  36. } else {
  37. // 无法使用
  38. result = "0";
  39. }
  40. }
  41. keyResult.setResult(CryptUtil.encrypt(result.getBytes(), echoStr.getBytes()));
  42. }
  43. return JsonUtil.objectToByte(keyResult);
  44. } catch (Exception e) {
  45. logger.error("webservice出错了!!!!");
  46. logger.error(e.getMessage(), e);
  47. }
  48. return null;
  49. }
复制代码

再赘述一下:

第一个判断语句中的内容就是生成公钥和私钥,并且返回公钥。 第二个判断语句中的内容就是保存client发送的随机字符串,这一步非常关键,随机字符串首先通过公钥进行了加密,这大大加强了加密的深度。 第三个判断语句中的内容就是将client的权限通过随机字符串进行加密。 ②、client

ExchangeUtil.java

  1. public static boolean canRunForExchange(String resultType) {
  2. int i = 1;
  3. boolean result = false;
  4. while (true) {
  5. try {
  6. // webservice调用类
  7. ExchangeServiceProxy proxy = new ExchangeServiceProxy();
  8. BASE64Encoder encoder = new BASE64Encoder();
  9. // step1.获取service产生的公钥
  10. KeyResult keyResult = JsonUtil.byteToObject(proxy.request(null, PUBLIC_KEY_RESULT_TYPE),
  11. KeyResult.class);
  12. // step2.产生随机字符串,发送到webserivce
  13. String echoStr = StrUtil.getEchoStrByLength(10);
  14. byte[] echoByteParam = RSACoder.encryptByPublicKey(echoStr.getBytes(), keyResult.getKey());
  15. proxy.request(encoder.encode(echoByteParam), ECHOSTR_RESULT_TYPE);
  16. // step3.加密客户端请求信息,然后发送到webservice
  17. // 先加密为byte数组,然后转换成字符串
  18. byte[] results = proxy.request(
  19. encoder.encode(CryptUtil.encrypt(Constants.client_type.getBytes(), echoStr.getBytes())),
  20. resultType);
  21. keyResult = JsonUtil.byteToObject(results, KeyResult.class);
  22. // step4.通过口令解密服务端返回消息
  23. String response = new String(CryptUtil.decrypt(keyResult.getResult(), echoStr.getBytes()));
  24. if (response.equals("1")) {
  25. result = true;
  26. }
  27. break;
  28. } catch (Exception e) {
  29. logger.debug("第" + i + "次加载webservice失败");
  30. i++;
  31. logger.error(e.getMessage(), e);
  32. if (i >= 10) {
  33. break;
  34. }
  35. }
  36. }
  37. return result;
  38. }
复制代码

稍作解释:

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

CryptUtil.java

  1. package com.honzh.socket.util;
  2. import javax.crypto.Cipher;
  3. import javax.crypto.SecretKey;
  4. import javax.crypto.SecretKeyFactory;
  5. import javax.crypto.spec.DESKeySpec;
  6. import javax.crypto.spec.IvParameterSpec;
  7. public class CryptUtil {
  8. /**
  9. * @Title: encrypt
  10. * @Description: 加密
  11. * @param data
  12. * @param key
  13. * @return
  14. * @throws Exception
  15. */
  16. public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
  17. key = get8(key);
  18. Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
  19. DESKeySpec desKeySpec = new DESKeySpec(key);
  20. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  21. SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
  22. IvParameterSpec iv = new IvParameterSpec(key);
  23. cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
  24. return cipher.doFinal(data);
  25. }
  26. /**
  27. * @Title: decrypt
  28. * @Description: 解密
  29. * @param data
  30. * @param key
  31. * @return
  32. * @throws Exception
  33. */
  34. public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
  35. key = get8(key);
  36. Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
  37. DESKeySpec desKeySpec = new DESKeySpec(key);
  38. SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
  39. SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
  40. IvParameterSpec iv = new IvParameterSpec(key);
  41. cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
  42. return cipher.doFinal(data);
  43. }
  44. private static byte[] get8(byte[] key) {
  45. byte[] key1 = new byte[8];
  46. for (int i = 0; i < 8; i++) {
  47. key1[i] = key[i];
  48. }
  49. return key1;
  50. }
  51. public static String toHexString(byte[] data) {
  52. String s = "";
  53. for (int i = 0; i < data.length; i++) {
  54. s += Integer.toHexString(data[i] & 0xFF)+"-";
  55. }
  56. return s;
  57. }
  58. }
复制代码

一般情况下,SHA和MD5两种加密就够我们使用了!

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

来源:qing_gee的专栏

最新评论

小黑屋|在路上 ( 蜀ICP备15035742号-1 

;

GMT+8, 2025-7-9 01:47

Copyright 2015-2025 djqfx

返回顶部