密钥协商算法Diffie-Hellman的Java实现

本文详细介绍了Diffie-Hellman密钥协商算法的流程原理,并结合Java实现,从生成密钥对到计算共享密钥,再到加密通信的全过程。通过示例代码展示了如何在Java中应用DH算法,同时也提到了JDK版本间的变化和应对策略,以及更安全的ECDH算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

  • Diffie-Hellman的流程原理
  • 流程原理在Java中的对应
  • Java应用代码
  • JDK源码中封装的原理细节
    • 生成密钥对
    • 通过对方公钥和自己的私钥生成相同的对称密钥

本文的思路:

  • 先了解Diffie-Hellman的流程原理,然后将其流程和Java的实现对应起来;理解了原理和Java实现的流程,再写应用代码进一步辅助验证;最后走一走源码流程中的相关细节,作最终验证。
  • 文末了解一下性能更好、安全性更高的ECDH(基于椭圆曲线来实现的Diffie-Hellman)

一、Diffie-Hellman的流程原理

DH的流程中涉及三个角色,主要是通信双方Alice、Bobby,和可能存在窃听的中间人Eaves。

场景:Alice要和Bobby通信,发送的信息可能会被中间人Eaves窃听到,Alice和Bobby如何通过DH算法来保证通信的机密性?

DH是密钥协商(key agreement)算法,通信双方并没有真正的交换密钥,而是通过交换部分可以公开的信息来计算生成出相同的对称密钥,然后通过对称密钥对消息进行加密,从而保证消息的机密性。

DH的流程原理如下:

  • 1.发送方Alice:
    • 选择两个质数P和G——大质数P和生成元G
    • 然后生成一个随机数A作为自己的私钥
    • 接着计算(G^A)modP作为自己的公钥
    • 最后把P、G和公钥(G^A)modP通过可能被监听的网络发送给接收方Bobby
    • 注意:私钥A是不公开、不发送的,Alice自己保留
  • 2.接收方Bobby:
    • 收到Alice的消息后,首先选择一个随机数B作为自己的私钥
    • 然后计算(G^B)modP作为自己的公钥
    • 最后Bobby将自己的公钥(G^B)modP发送给Alice
    • 注意:私钥B是不公开、不发送的,Bobby自己保留
  • 3.双方计算出相同的对称密钥
    • Alice通过自己的私钥A和对方的公钥(G^B)modP计算出相同的对称密钥:((G^BmodP)^A)modP,即(G^(B*A))modP
    • Bobby通过自己的私钥B和对方的公钥(G^A)modP计算出相同的对称密钥:((G^AmodP)^B)modP,即(G^(A*B))modP
  • 4.最后算双方通过计算出的、相同的对称密钥进行加密通信

再做进一步的抽象,四小步骤实际上可以抽象成两个阶段:

  1. 第一阶段(第1~3步):通过DH算法进行密钥协商,协商出对称密钥
  2. 第二阶段(第4步):通过协商出的对称密钥进行加密通信

我们分析一下在Alice、Bobby协商密钥的过程中,中间人Eaves通过窃听到的信息能否计算出密钥:

  • Alice拥有的信息:大质数P、生成元G、自己的公钥(G^A)modP和私钥A、对方Bobby的公钥(G^B)modP,然后通过自己的私钥和对方的公钥计算出对称密钥
  • Bobby拥有的信息:大质数P、生成元G、自己的公钥(G^B)modP和私钥B、对方Alice的公钥(G^A)modP,然后通过自己的私钥和对方的公钥计算出对称密钥
  • Eaves能窃听到的公开信息:大质数P、生成元G、Alice的公钥(G^A)modP、Bobby的公钥公钥(G^B)modP,因为Eaves没有私钥A或B,所以无法计算出密钥

二、流程原理在Java中的对应

JDK的API封装了很多细节(大质数P、生成元G、私钥A/B,公钥(G^A)modP/(G^B)modP都封装到了PublicKey或PrivateKey对象中),对外程序员能看到的类就是公钥、私钥,DH流程原理的细节对应放在第四部分再剖析,这一部分只做大概的、整体上的流程对应,目的是为了顺利写出第三部分的应用代码。

1.密钥协商阶段,这一部分主要是DH算法:

  • Alice通过KeyPairGenerator生成自己的密钥对,保留私钥PrivateKey,然后将公钥PublicKey发送给Bobby,通过网络一般不直接发送Java对象,而是发送公钥的字节数组;
  • Bobby收到Alice发过来的公钥数组:
    • 先通过X509EncodedKeySpec解析公钥规范,然后通过KeyFactory还原出公钥对象PublicKey(实际上公钥对象包含了大质数P、生成元G和Alice的公钥Y)
    • 接着通过还原出的公钥对象生成自己的密钥对
    • 然后将自己的公钥数组回送给Alice
  • 最后,Alice和Bobby都通过自己的私钥和对方的公钥经由KeyAgreement类计算出相同的共享密钥SecretKey(这里要重点关注)

2.加密通信阶段,这一部分主要是对称加密算法,本文选择现役、流行的AES算法为例:

  • 通过Cipher.getInstance工厂方法拿到加解密对象
  • 设置加密的参数:cipher_mode、密钥协商阶段得到的SecretKey、分组密码分组的模式所需的初始化向量IvParameterSpec
  • doFinal完成加解密

三、应用代码

我们按照第二部分中的流程来。

1.Alice生成密钥对

	// 密钥协商算法密钥对生成入参,查看KeyPairGenerator.getInstance文档
	private static String DH_KEY = "DH";

	/***
	 * Alice生成密钥对
	 * @return Alice的密钥对
	 * @throws Exception
	 */
	public static KeyPair generateKeyPair() throws Exception {
		KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(DH_KEY);
		return keyPairGenerator.generateKeyPair();
	}

代码很简洁,几乎都是固定格式,你需要关注的是KeyPairGenerator.getInstance方法的入参,这个字符串从哪里去找?

JDK中都在一个页面找,后面的getInstance都在相同的页面,只是要在页面找不同的类的文档,页面地址:​​​​​​Java Security Standard Algorithm Names

找到KeyPairGenerator类的文档,截图如下:

 2.Bobby根据Alice的公钥生成自己的密钥对

	/**
	 * Bobby收到Alice的公钥数组:
	 * 1.先将公钥数组解析成公钥对象
	 * 	KeyFactory.getInstance的入参查看KeyFactory的文档
	 *  文档地址:https://docs.oracle.com/en/java/javase/15/docs/specs/security/standard-names.html
	 * 2.根据Alice的公钥对象生成自己的密钥对
	 * @param publicKeyArray 收到的、对方的公钥数组
	 * @return
	 * @throws Exception
	 */
	public static KeyPair generateKeyPair(byte[] publicKeyArray) throws Exception {
		// 将Alice发过来的公钥数组解析成公钥对象
		X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyArray);
		KeyFactory keyFactory = KeyFactory.getInstance(DH_KEY);
		PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
		// Bobby根据Alice的公钥生成自己的密钥对
		DHParameterSpec dhParameterSpec = ((DHPublicKey)publicKey).getParams();
		KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(DH_KEY);
		keyPairGenerator.initialize(dhParameterSpec);
		return keyPairGenerator.generateKeyPair();
	}

Alice将自己的公钥通过网络传送给Bobby,一般传送的

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值