DH
Diffie-Hellman算法(D-H算法),密钥一致协议。是由公开密钥密码体制的奠基人Diffie和Hellman所提出的一种思想。简单的说就是允许两名用户在公开媒体上交换信息以生成"一致"的、可以共享的密钥。换句话说,就是由甲方产出一对密钥(公钥、私钥),乙方依照甲方公钥产生乙方密钥对(公钥、私钥)。以此为基线,作为数据传输保密基础,同时双方使用同一种对称加密算法构建本地密钥(SecretKey)对数据加密。这样,在互通了本地密钥(SecretKey)算法后,甲乙双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,同时可以使用对方的公钥和自己的私钥对数据解密。不单单是甲乙双方两方,可以扩展为多方共享数据通讯,这样就完成了网络交互数据的安全通讯!该算法源于中国的同余定理——中国馀数定理。 



流程分析:



1.甲方构建密钥对儿,将公钥公布给乙方,将私钥保留;双方约定数据加密算法;乙方通过甲方公钥构建密钥对儿,将公钥公布给甲方,将私钥保留。

2.甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给乙方加密后的数据;乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。

3.乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给甲方加密后的数据;甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。



通过java代码实现如下:Coder类见 Java加密技术(一)

  1. import java.security.Key;
  2. import java.security.KeyFactory;
  3. import java.security.KeyPair;
  4. import java.security.KeyPairGenerator;
  5. import java.security.PublicKey;
  6. import java.security.spec.PKCS8EncodedKeySpec;
  7. import java.security.spec.X509EncodedKeySpec;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. import javax.crypto.Cipher;
  11. import javax.crypto.KeyAgreement;
  12. import javax.crypto.SecretKey;
  13. import javax.crypto.interfaces.DHPrivateKey;
  14. import javax.crypto.interfaces.DHPublicKey;
  15. import javax.crypto.spec.DHParameterSpec;
  16. /**
  17. * DH安全编码组件
  18. *
  19. * @author 梁栋
  20. * @version 1.0
  21. * @since 1.0
  22. */
  23. public abstract class DHCoder extends Coder {
  24. public static final String ALGORITHM = "DH";
  25. /**
  26. * 默认密钥字节数
  27. *
  28. * <pre>
  29. * DH
  30. * Default Keysize 1024
  31. * Keysize must be a multiple of 64, ranging from 512 to 1024 (inclusive).
  32. * </pre>
  33. */
  34. private static final int KEY_SIZE = 1024;
  35. /**
  36. * DH加密下需要一种对称加密算法对数据加密,这里我们使用DES,也可以使用其他对称加密算法。
  37. */
  38. public static final String SECRET_ALGORITHM = "DES";
  39. private static final String PUBLIC_KEY = "DHPublicKey";
  40. private static final String PRIVATE_KEY = "DHPrivateKey";
  41. /**
  42. * 初始化甲方密钥
  43. *
  44. * @return
  45. * @throws Exception
  46. */
  47. public static Map<String, Object> initKey() throws Exception {
  48. KeyPairGenerator keyPairGenerator = KeyPairGenerator
  49. .getInstance(ALGORITHM);
  50. keyPairGenerator.initialize(KEY_SIZE);
  51. KeyPair keyPair = keyPairGenerator.generateKeyPair();
  52. // 甲方公钥
  53. DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
  54. // 甲方私钥
  55. DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
  56. Map<String, Object> keyMap = new HashMap<String, Object>(2);
  57. keyMap.put(PUBLIC_KEY, publicKey);
  58. keyMap.put(PRIVATE_KEY, privateKey);
  59. return keyMap;
  60. }
  61. /**
  62. * 初始化乙方密钥
  63. *
  64. * @param key
  65. *            甲方公钥
  66. * @return
  67. * @throws Exception
  68. */
  69. public static Map<String, Object> initKey(String key) throws Exception {
  70. // 解析甲方公钥
  71. byte[] keyBytes = decryptBASE64(key);
  72. X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
  73. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
  74. PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
  75. // 由甲方公钥构建乙方密钥
  76. DHParameterSpec dhParamSpec = ((DHPublicKey) pubKey).getParams();
  77. KeyPairGenerator keyPairGenerator = KeyPairGenerator
  78. .getInstance(keyFactory.getAlgorithm());
  79. keyPairGenerator.initialize(dhParamSpec);
  80. KeyPair keyPair = keyPairGenerator.generateKeyPair();
  81. // 乙方公钥
  82. DHPublicKey publicKey = (DHPublicKey) keyPair.getPublic();
  83. // 乙方私钥
  84. DHPrivateKey privateKey = (DHPrivateKey) keyPair.getPrivate();
  85. Map<String, Object> keyMap = new HashMap<String, Object>(2);
  86. keyMap.put(PUBLIC_KEY, publicKey);
  87. keyMap.put(PRIVATE_KEY, privateKey);
  88. return keyMap;
  89. }
  90. /**
  91. * 加密<br>
  92. *
  93. * @param data
  94. *            待加密数据
  95. * @param publicKey
  96. *            甲方公钥
  97. * @param privateKey
  98. *            乙方私钥
  99. * @return
  100. * @throws Exception
  101. */
  102. public static byte[] encrypt(byte[] data, String publicKey,
  103. String privateKey) throws Exception {
  104. // 生成本地密钥
  105. SecretKey secretKey = getSecretKey(publicKey, privateKey);
  106. // 数据加密
  107. Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
  108. cipher.init(Cipher.ENCRYPT_MODE, secretKey);
  109. return cipher.doFinal(data);
  110. }
  111. /**
  112. * 解密<br>
  113. *
  114. * @param data
  115. *            待解密数据
  116. * @param publicKey
  117. *            乙方公钥
  118. * @param privateKey
  119. *            乙方私钥
  120. * @return
  121. * @throws Exception
  122. */
  123. public static byte[] decrypt(byte[] data, String publicKey,
  124. String privateKey) throws Exception {
  125. // 生成本地密钥
  126. SecretKey secretKey = getSecretKey(publicKey, privateKey);
  127. // 数据解密
  128. Cipher cipher = Cipher.getInstance(secretKey.getAlgorithm());
  129. cipher.init(Cipher.DECRYPT_MODE, secretKey);
  130. return cipher.doFinal(data);
  131. }
  132. /**
  133. * 构建密钥
  134. *
  135. * @param publicKey
  136. *            公钥
  137. * @param privateKey
  138. *            私钥
  139. * @return
  140. * @throws Exception
  141. */
  142. private static SecretKey getSecretKey(String publicKey, String privateKey)
  143. throws Exception {
  144. // 初始化公钥
  145. byte[] pubKeyBytes = decryptBASE64(publicKey);
  146. KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
  147. X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKeyBytes);
  148. PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
  149. // 初始化私钥
  150. byte[] priKeyBytes = decryptBASE64(privateKey);
  151. PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKeyBytes);
  152. Key priKey = keyFactory.generatePrivate(pkcs8KeySpec);
  153. KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory
  154. .getAlgorithm());
  155. keyAgree.init(priKey);
  156. keyAgree.doPhase(pubKey, true);
  157. // 生成本地密钥
  158. SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM);
  159. return secretKey;
  160. }
  161. /**
  162. * 取得私钥
  163. *
  164. * @param keyMap
  165. * @return
  166. * @throws Exception
  167. */
  168. public static String getPrivateKey(Map<String, Object> keyMap)
  169. throws Exception {
  170. Key key = (Key) keyMap.get(PRIVATE_KEY);
  171. return encryptBASE64(key.getEncoded());
  172. }
  173. /**
  174. * 取得公钥
  175. *
  176. * @param keyMap
  177. * @return
  178. * @throws Exception
  179. */
  180. public static String getPublicKey(Map<String, Object> keyMap)
  181. throws Exception {
  182. Key key = (Key) keyMap.get(PUBLIC_KEY);
  183. return encryptBASE64(key.getEncoded());
  184. }
  185. }

再给出一个测试类:

  1. import static org.junit.Assert.*;
  2. import java.util.Map;
  3. import org.junit.Test;
  4. /**
  5. *
  6. * @author 梁栋
  7. * @version 1.0
  8. * @since 1.0
  9. */
  10. public class DHCoderTest {
  11. @Test
  12. public void test() throws Exception {
  13. // 生成甲方密钥对儿
  14. Map<String, Object> aKeyMap = DHCoder.initKey();
  15. String aPublicKey = DHCoder.getPublicKey(aKeyMap);
  16. String aPrivateKey = DHCoder.getPrivateKey(aKeyMap);
  17. System.err.println("甲方公钥:\r" + aPublicKey);
  18. System.err.println("甲方私钥:\r" + aPrivateKey);
  19. // 由甲方公钥产生本地密钥对儿
  20. Map<String, Object> bKeyMap = DHCoder.initKey(aPublicKey);
  21. String bPublicKey = DHCoder.getPublicKey(bKeyMap);
  22. String bPrivateKey = DHCoder.getPrivateKey(bKeyMap);
  23. System.err.println("乙方公钥:\r" + bPublicKey);
  24. System.err.println("乙方私钥:\r" + bPrivateKey);
  25. String aInput = "abc ";
  26. System.err.println("原文: " + aInput);
  27. // 由甲方公钥,乙方私钥构建密文
  28. byte[] aCode = DHCoder.encrypt(aInput.getBytes(), aPublicKey,
  29. bPrivateKey);
  30. // 由乙方公钥,甲方私钥解密
  31. byte[] aDecode = DHCoder.decrypt(aCode, bPublicKey, aPrivateKey);
  32. String aOutput = (new String(aDecode));
  33. System.err.println("解密: " + aOutput);
  34. assertEquals(aInput, aOutput);
  35. System.err.println(" ===============反过来加密解密================== ");
  36. String bInput = "def ";
  37. System.err.println("原文: " + bInput);
  38. // 由乙方公钥,甲方私钥构建密文
  39. byte[] bCode = DHCoder.encrypt(bInput.getBytes(), bPublicKey,
  40. aPrivateKey);
  41. // 由甲方公钥,乙方私钥解密
  42. byte[] bDecode = DHCoder.decrypt(bCode, aPublicKey, bPrivateKey);
  43. String bOutput = (new String(bDecode));
  44. System.err.println("解密: " + bOutput);
  45. assertEquals(bInput, bOutput);
  46. }
  47. }

控制台输出:

  1. 甲方公钥:
  2. MIHfMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHz
  3. W5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG
  4. kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANDAAJAdAWBVmIzqcko
  5. Ej6qFjLDL2+Y3FPq1iRbnOyOpDj71yKaK1K+FhTv04B0zy4DKcvAASV7/Gv0W+bgqdmffRkqrQ==
  6. 甲方私钥:
  7. MIHRAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX
  8. rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD
  9. TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQyAjACJRfy1LyR
  10. eHyD+4Hfb+xR0uoIGR1oL9i9Nk6g2AAuaDPgEVWHn+QXID13yL/uDos=
  11. 乙方公钥:
  12. MIHfMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHz
  13. W5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSG
  14. kx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANDAAJAVEYSfBA+I9nr
  15. dWw3OBv475C+eBrWBBYqt0m6/eu4ptuDQHwV4MmUtKAC2wc2nNrdb1wmBhY1X8RnWkJ1XmdDbQ==
  16. 乙方私钥:
  17. MIHSAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYX
  18. rgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpD
  19. TWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQzAjEAqaZiCdXp
  20. 2iNpdBlHRaO9ir70wo2n32xNlIzIX19VLSPCDdeUWkgRv4CEj/8k+/yd
  21. 原文: abc
  22. 解密: abc
  23. ===============反过来加密解密==================
  24. 原文: def
  25. 解密: def

如我所言,甲乙双方在获得对方公钥后可以对发送给对方的数据加密,同时也能对接收到的数据解密,达到了数据安全通信的目的!

分析DH加密算法,一种适基于密钥一致协议的加密算法。的更多相关文章

  1. Windows五种IO模型性能分析和Linux五种IO模型性能分析

    Windows五种IO模型性能分析和Linux五种IO模型性能分析 http://blog.csdn.net/jay900323/article/details/18141217 http://blo ...

  2. 如何在 Linux 中配置基于密钥认证的 SSH

    什么是基于 SSH 密钥的认证? 众所周知,Secure Shell,又称 SSH,是允许你通过无安全网络(例如 Internet)和远程系统之间安全访问/通信的加密网络协议.无论何时使用 SSH 在 ...

  3. Libreswan软件的密钥协商协议IKEv1主模式实现分析

    Libreswan软件的密钥协商协议IKEv1主模式实现分析 1 协商过程 IKEv1(互联网密钥交换协议第一版)是IPsec VPN隧道协商使用的标准密钥协商协议,其协商过程如下图所示. 总共来回交 ...

  4. linux net通信 基于密钥

    配置SSHD服务 SSH(Secure Shell)是一种能够以安全的方式提供远程登录的协议,也是目前远程管理 Linux 系统的首选方式.在此之前,一般使用 FTP 或 Telnet 来进行远程登录 ...

  5. sshd服务及基于密钥远程登陆(无需密码)

    上一条博客说明了用sshd服务远程登陆另一个系统,但是需要密码,如果不用密码呢?有没有简便的方法呢?下面为大家介绍一下,也就是基于密钥的安全验证:需要在本地生成”密钥对“后将公钥传送至服务端,进行公共 ...

  6. SSH服务搭建、账号密码登录远程Linux虚拟机、基于密钥的安全验证(Windows_Xshell,Linux)

    问题1:如果是两台虚拟机ping不同且其中一个虚拟机是克隆的另一个,需要更改一下MAC地址,关机状态下 一> "编辑虚拟机设置" 一>" 网络适配器" ...

  7. Netty中解码基于分隔符的协议和基于长度的协议

    在使用Netty的过程中,你将会遇到需要解码器的基于分隔符和帧长度的协议.本节将解释Netty所提供的用于处理这些场景的实现. 基于分隔符的协议 基于分隔符的(delimited)消息协议使用定义的字 ...

  8. Netty入门(十)解码分隔符和基于长度的协议

    我们需要区分不同帧的首尾,通常需要在结尾设定特定分隔符或者在首部添加长度字段,分别称为分隔符协议和基于长度的协议,本节讲解 Netty 如何解码这些协议. 一.分隔符协议 Netty 附带的解码器可以 ...

  9. 使用java做一个能赚钱的微信群聊机器人(2020年基于PC端协议最新可用版)

    前言 微信群机器人,主要用来管理群聊,提供类似天气查询.点歌.机器人聊天等用途. 由于微信将web端的协议封杀后,很多基于http协议的群聊机器人都失效了,所以这里使用基于PC端协议的插件来实现. 声 ...

随机推荐

  1. SQL SERVER特殊行转列案列一则

    今天有个同事找我,他说他有个需求,需要进行行转列,但是又跟一般的行转列有些区别,具体需求如下所说,需要将表1的数据转换为表2的显示格式. 我想了一下,给出了一个解决方法,具体如下所示(先给出测试数据) ...

  2. 不好的MySQL过程编写习惯

    刚才为了测试一个东西,写了个存储过程: delimiter $$ drop procedure if exists sp_test$$ create procedure sp_test() begin ...

  3. mac xcode c++ cin cout注意细节一

    #include <iostream> using namespace std; 要同时存在 要不然std命名空间无法生效

  4. Linux cut命令

    [root@wang /]# cat /etc/passwd root:x:::root:/root:/bin/bash bin:x:::bin:/bin:/sbin/nologin daemon:x ...

  5. NopCommerce 增加 Customer Field

    预期效果: Customer表新增一个Column 该新增字段可以在Admin段 新增 修改 列表查询及显示 示例步骤: 0.数据库表修改 alter table [Customer] add Mem ...

  6. CODEVS3037 线段覆盖 5[序列DP 二分]

    3037 线段覆盖 5   时间限制: 3 s   空间限制: 256000 KB   题目等级 : 钻石 Diamond 题解       题目描述 Description 数轴上有n条线段,线段的 ...

  7. 安装node-sass提示没有vendor目录的解决办法

    在node-sass目录下面新建一个vendor的空目录,然后运行npm/cnpm rebuild node-sass --save-dev即可,如果安装失败,会生成一个目录名为类似这样win32-x ...

  8. canvas事件处理机制

    可以查看demo:http://sandbox.runjs.cn/show/hjb2hzzx(建议查看console查看点击后的改变) 具体原理是每次点击的时候去判断当前的鼠标坐标是属于哪一个路径下的 ...

  9. 关于JSP---三大指令

    JSP三大指令: page    ------>最复杂的一个指令,属性很多,常用的像import,language,pageEncoding等等 include-------->静态包含, ...

  10. vijos P1780 【NOIP2012】 开车旅行

    描述 小\(A\)和小\(B\)决定利用假期外出旅行,他们将想去的城市从\(1\)到\(N\)编号,且编号较小的城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市\(i\)的海拔高度为 ...