秘钥协商算法

从前面的介绍的密码学的4个目标中,了解到业务通信过程中的加解密常常使用的是对称加密来保证加解密的效率,而这个对称加密的秘钥也不是固定不变的,而是一个动态秘钥,在每一次的会话中,秘钥均不相同。那么,这个会话秘钥,该如何在业务通信前,通信双方都能获取到该会话秘钥,将是这一篇文章的主题。

网络通信中,对称加解密采用动态秘钥,也叫作会话秘钥,秘钥的特点如下:

  • 会话秘钥用途:加解密通信业务数据。
  • 会话秘钥来源:是通过秘钥协商算法协商而来,且只有通信双方的客户端和服务端知晓。
  • 会话秘钥生命周期:会话秘钥,顾名思义,仅用于该会话,会话建立时,协商而来的动态秘钥,无需存储,会话一旦结束,那么这个会话秘钥也就失去其存在的价值。因此,会话秘钥,仅存在于内存,极大保证通信的安全性。

常见秘钥协商算法:

  • RSA秘钥协商算法
  • DH秘钥协商算法
  • ECDH秘钥协商算法

RSA秘钥协商算法

客户端向服务端发送连接请求后,服务端将其公钥返回给客户端,客户端生成一个会话秘钥,使用服务端提供的公钥对会话秘钥进行加密,在服务端使用私钥对其进行解密。此时,客户端和服务端均知晓会话秘钥。通信双方可以使用协商的这个会话秘钥进行业务数据对称加解密通信。

请添加图片描述

特点

  • 每次连接请求,都会产生一个动态的会话秘钥。
  • 协商流程简单。

缺点

  • 会话秘钥由客户端决定。如果客户端生成会话秘钥时,生成的秘钥较简单,那么攻击者可以想到暴力破解,不会去直接破解RSA加密算法的私钥,而是直接暴力破解会话秘钥,反解出明文。

请添加图片描述

  • 一旦服务端的私钥被泄漏,那么之前攻击者保存下来的密文,都可以通过服务端的私钥解密出会话秘钥,再使用会话秘钥解密通信数据。这就不能提供前向安全性

DH(Diffe-Hellman)秘钥协商算法

RSA秘钥协商算法,其实会话秘钥完全有客户端决定,并没有服务端的参与,未体现出通信双方的协商过程,更像是秘钥传输。

为了避免会话秘钥由通信双方单一决定,需要通信双方共同参与协商,计算出相同的会话秘钥。

请添加图片描述

特点

  • 每次连接请求,都会产生一个动态的会话秘钥。
  • 会话秘钥由通信双方共同计算获得,而非单一方决定。
  • 只要有一方的私钥未泄密,攻击者都无法计算获得会话秘钥。

静态DH算法(DH算法)

p、g、服务器公钥(Ys)永远固定。避免服务端频繁生成p、g,公钥,减少对CPU的开销。

缺点:服务器端的私钥泄密,加之客户端私钥泄密,不能保证前向安全性。

临时(Ephemeral)DH算法(EDH算法)

为了避免在静态DH算法中,因服务器端的私钥泄密导致的前向安全性问题。EDH算法,每次客户端连接请求时,服务器端都重新生成DH秘钥对。如此一来,就算服务端的某一次通信的私钥被泄漏,因为当次的私钥不能计算出之前会话的秘钥,因此也能保证前向安全性。

另外,在协商出会话秘钥后,客户端和服务端的私钥a和b,都可以丢弃。这就是在有限的时间、有效的空间生成了秘钥对,从而让黑客攻击变得更难,进一步提升安全性。

ECDH秘钥协商算法

为了进一步提升DH算法的安全性,避免DH的秘钥对不被破解,一种有效的方案就是,增加秘钥对的长度,但随之而来的就是,秘钥长度越长,CPU资源开销越大,计算耗时越长。因此,椭圆曲线密码学(Elliptic Curve Cryptography, ECC)应运而生。

ECDH秘钥协商算法,就是ECC和DH算法的结合组成。可以⽤更少的计算量计算出公钥,以及最终的会话密钥。比如,ECC只需224bits就能达到RSA 2048bits同样的安全水平。

ECC过于复杂,作者也未深入理解,此处暂且不论。读者只需了解,ECC为DH算法提供难于破解的公私钥对即可。

好的,以下是一个为两个客户端添加秘钥协商及对称加密部件的Python代码,需要使用Socket套接字编程实现: ```python import socket import pickle from Crypto.Cipher import AES from Crypto.Random import get_random_bytes # 创建Socket对象 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 获取本地主机名 host = socket.gethostname() # 设置端口号 port = 9999 # 绑定端口号 s.bind((host, port)) # 等待客户端连接 s.listen(2) print('等待客户端连接...') # 定义秘钥协商函数 def key_exchange(conn): # 生成256位秘钥 key = get_random_bytes(32) # 发送秘钥到客户端 conn.send(pickle.dumps(key)) # 接收客户端加密后的秘钥 encrypted_key = conn.recv(1024) # 解密秘钥 cipher = AES.new(key, AES.MODE_EAX, nonce=encrypted_key[:16]) decrypted_key = cipher.decrypt(encrypted_key[16:]) return decrypted_key while True: # 建立客户端连接 conn1, addr1 = s.accept() print('客户端1已连接,地址:', addr1) # 客户端1进行秘钥协商 key1 = key_exchange(conn1) # 等待第二个客户端连接 conn2, addr2 = s.accept() print('客户端2已连接,地址:', addr2) # 客户端2进行秘钥协商 key2 = key_exchange(conn2) # 发送秘钥到对方 conn1.send(key2) conn2.send(key1) while True: # 客户端1发送消息 data1 = conn1.recv(1024) if not data1: break cipher = AES.new(key1, AES.MODE_EAX) nonce = cipher.nonce encrypted_data1, tag1 = cipher.encrypt_and_digest(data1) conn2.send(pickle.dumps((nonce, encrypted_data1, tag1))) # 客户端2发送消息 data2 = conn2.recv(1024) if not data2: break cipher = AES.new(key2, AES.MODE_EAX) nonce = cipher.nonce encrypted_data2, tag2 = cipher.encrypt_and_digest(data2) conn1.send(pickle.dumps((nonce, encrypted_data2, tag2))) # 关闭连接 conn1.close() conn2.close() ``` 上述代码中,我们首先定义了一个key_exchange()函数,用于进行秘钥协商。在秘钥协商中,我们生成了一个256位的随机秘钥,并将其发送到客户端。客户端使用该秘钥加密后再发送回来,我们在服务端解密该秘钥并返回给客户端。 在等待客户端连接的while循环中,我们先等待第一个客户端的连接,并进行秘钥协商。接着,等待第二个客户端的连接,并进行秘钥协商秘钥协商完成后,我们将对方的秘钥发送给另一个客户端。 在通信过程中,我们使用AES对称加密算法对通信内容进行加密。每次客户端发送消息时,我们将消息使用秘钥进行加密,并将加密后的密文和认证标签一起发送给对方;对方接收到消息后,使用自己的秘钥进行解密,并检查认证标签是否正确。 最后,当某一方关闭连接时,我们关闭所有连接并结束程序。需要注意的是,该程序只能进行点对点通信,即一次只能连接两个客户端。如果需要进行多客户端通信,需要使用多线程或多进程等技术。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值