总结DH密钥协商(会话密钥)

密钥安全性

在对称加密中,无论加密解密,通信双方都是使用相同的密钥,如果其中一方密钥泄露了,信息便会遭到破解。使用公开密钥双向加密可以极大提高安全性,通信双方手握对方的公钥进行信息加密,保留自己的私钥进行解密,从客户端发去的加密信息即使被中途截获,没有私钥的话也无法解密,而私钥保存在服务器端,相反一样。这样将密钥对分成公钥和私钥的方式,比起对称加密共同使用相同的密钥,明显更安全。无论是对称加密还是公开密钥,安全性关键都是在于密钥的长度,例如上一篇日志讲到的公开密钥,它是怎么生成公钥的?是两个大质数相乘后结果n,和随机数e组成的,如果要解出私钥,首先就要得到这两个大质数,可以通过对n进行因式分解,不过只要这两个大质数足够大,对其进行因式分解是十分困难的。

传输问题

在密钥本身的安全性得到保证后,还不够,因为密钥是要发送给通信对方的,如果在发送密钥的时候被截获,那么前面做的一切都是徒劳。通常一个服务器端会接收处理多个客户端,双方建立连接后,开始消息发送,为了保证信息安全性,会使用相应的加密措施,无论是对称加密害死公开密钥,都需要发送密钥给对方进行加密解密,那么在发送密钥过程中,怎么保证密钥安全不泄露?

如果只是几人十几人的小组内进行互相通信,那么可以简单地通过外部方式例如邮件方式传输密钥,而不在通信线路上传输。可是对于C/S模式下服务器端需处理许多的客户端连接,但是服务器端并不知道这些客户端来自谁,没有办法通过外部如邮件的方式发送密钥,只能就彼此建立的连接线路上进行通信,怎么办?怎么把密钥安全地通过这条线路发送到客户端?

 

密钥协商算法

密钥协商算法可以解决上面提到的两个问题,生成安全的密钥,和安全的传输,还能解决密钥存储问题。密钥存储问题,简单来说,假如我们把密钥保存在本地磁盘中,每次加密解密都出本地获取密钥,那么就几乎没什么泄露的问题,但如果我们把密钥保存在是数据库中,数据库泄露便等于密钥泄露了。回到正题,看看密钥协商如何解决密钥安全生成,传输和存储三部分问题。

会话密钥

上面说到,一个服务器端需要处理很多很多的客户端连接,如果我们为每一个连接都保存一个固定的不同的密钥,那么存储量将十分庞大,但是我们又不能让它们使用统一的密钥,这显然是不安全的,要解决这个问题,可以用到会话密钥的方式。会话密钥就是在本次通信中使用的一次性密钥,当通信结束后密钥就失效了,等下一次建立连接时会生成不同的会话密钥,会话密钥仅在本次通信期内有效。在我们访问https协议的网址,即https://开始的网址时,我们的浏览器会和服务器之间使用SSL/TLS协议进行加密通信,用到的就是会话密钥。会话密钥是存储在客户端和服务器端的内存中的,当通信结束后,会话密钥失效,便会从内存中丢弃,解决了上面的密钥存储问题。

看到这里你可能想,虽然每次通信都更换密钥,但还是没有解决密钥传输问题啊,建立连接生成会话密钥后,不还是要先发送密钥给对方吗?接下来就是看密钥的生成过程,你会知道它是怎么保证密钥传输的安全性的。

DH密钥协商

DH(Diffie-Hellman)密钥协商的做法是让通信双方在通信上交换彼此的信息来共同计算出相同的会话密钥,即使中间一部分传递信息被截获,也无法根据其计算出会话密钥,因为计算会话密钥的另一部分信息在接收方处,而接收方并没有公开这部分信息,因此中间方并不会有足够的信息来得到会话密钥,进而破解之后的通信密文。在看DH密钥协商的处理过程前,先来看DH算法的密钥文件是怎么样的:

其中,p是一个大质数,g则是一个小整数,一个公钥和一个私钥,接下来服务器端和客户端都会根据这些参数生成各自的密钥对,然后协商出会话密钥。

可以看到,通常由服务器端生成DH密钥文件参数,在客户端和服务器端建立连接后,密钥协商过程可以归纳为:

  1. 客户端发送请求DH参数,服务器端生成DH密钥文件参数,包括p,g,公钥spub和私钥spri。

spub = (g^spri)mod p;

  1. 服务器端发送参数p,g以及公钥spub给客户端,客户端接收后,先是自己生成一个私钥cpri,然后根据参数p,g,服务器端公钥spub和自己的私钥cpri计算得出客户端公钥cpub。

cpub = (g^cpri)mod p;

  1. 客户端将公钥cpub发送给服务器端,服务器端根据客户端公钥cpub和自己的私钥spri计算得到会话密钥。

M = (cpub^spri)mod p;

  1. 客户端根据私钥cpri和服务器端公钥spub计算得到会话密钥。密钥协商完成。

M = (spub^cpri)mod p;

由上面的过程可以看到,生成会话密钥的关键是服务器端和客户端自己的私钥,这两个私钥是各自生成的,并不会发送出去,即使中间放拿到了客户端和服务器端的公钥以及参数p,g,也没办法计算出会话密钥。看到这里你可能会想,从上面的密钥协商过程可以看到,服务器端是需要发送参数p和g的,并且之后双方还会交换公钥,拿客户端处举例,客户端的公钥等于cpub = (g^cpri)mod p,那么带入公钥,g和p不就可以计算出客户端私钥cpri?

安全性-离散对数

表达式中4个参数,拥有了3个,看似是很容易能求出那唯一的未知数,但是我们看它的算法,g^x mod p,求x的过程就是离散对数,如果是数值很小的情况下,8^x mod 5 = 4,当然可以很轻易求出x=2,但是我们看回求公钥的表达式中,p是一个大质数,通常在1024字节或以上,私钥也是一个很大的数,因为密钥越长安全性越高,对这样大的数字做离散是很难的,上一篇日志说到,目前已被破解的最大二进制位为768个二进制位。

来看看使用这种方式实现密钥协商的过程:

  1. 服务器端生成DH密钥参数p和g,假设p是43,g是7。再生成一个随机数作为密钥spri,假设为9。计算服务器端公钥并发送给客户端:

spub = 7^9 mod 43 = 42。

  1. 客户端接收到DH密钥参数和公钥spub后,自己生成一个随机密钥cpri,假设为8,并计算出客户端公钥,发回给服务器:

cpub = 7^8mod 43 = 6。

  1. 服务器端计算出会话密钥:

M = (cpub^spri)mod p;

6^9 mod 43 = 1;(商为234365)

  1. 客户端计算出会话密钥:

42^8 mod 43 = 1;(商为225177953405)

 

完整示例

一个完整的DH密钥协商过程,首先由通信双方任意一方生成DH密钥参数文件dhparam.pem。接着通信双方各自生成自己的密钥对,并分离出公钥和私钥,私钥自己保存,公钥发送给对方,最后双方根据对方发来的公钥和自己的私钥协商出会话密钥,可以看到,双方的会话密钥是一样的。

 

完整命令已上传:

https://github.com/justinzengtm/Network-Engineering

发布了97 篇原创文章 · 获赞 71 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/justinzengTM/article/details/103554470