DH密钥交换算法

时间:2023-12-11 23:39:56

DH密钥交换算法:DH的全称为Diffie-Hellman ,该算法可以在需要安全传输的前提下,确定双方的对称密钥,该算法的核心在于双方的私钥没有进入网络传输流程,根据对方的公钥和己方的私钥,可以计算出同样的Key。攻击方即便获取到了公钥和P,G值,也无法计算出Key值。
公钥:会进入网络传输的密钥部分,该部分是公开的。
私钥: 由端自己保存的密钥部分,该部分不允许公开。
DK:加密算法中,用X对敏感数据进行加密后,再用Key对X加密得到DK,然后X就被舍弃了,这里的X没有持久化,使用完内存就被销毁,攻击者需要得到敏感数据,就必须得到X,然后X已经被销毁了,破解方必须通过DK去破解出X,DK是通过Key来保护的,只要保证Key是安全的,敏感数据就是安全的。
Key:通过对方公钥和己方私钥生成的Key值,只要私钥不被破解,该值就是安全的。
Token认证:接口的安全认证
SID:握手标识,由客户端生成,用户A和用户B握手后,双方需要记录握手成功后的SID和DH密钥交换中生成的Key。后续通信时,服务端通过请求header中的SID和DK来知道该如何解密敏感信息。
十六进制编码:字节在传输过程中,如果使用一般的编码,会导致网络传输后出现丢失字节的情况,这时就要使用到十六进制编码,在本文中,统一用S(byte[])来标示字符数组的十六进制编码处理。
AES-supports: 加密用的规则,请求方所支持的AES加密种类,如果支持多个,用分号分割。平台内支持的规则是固定的,由库中决定。
AES-param: 响应方从请求方的AES-supports挑选一个随机的加密方法,作为本次加密使用的AES规则。

A.预备知识
整个加密流程的实现,分成客户端部分和服务端部分,对于大部分的服务,均需实现。传输加密前,双方需要通过协商,来确定加密敏感信息所用的密钥。每一次的协商,都会生成一个唯一的SID,用于双方后续的通信。当服务端发现SID过期时,需要返回约定好的错误码,让客户端重新发起协商和请求。
本文以流程为主,代码为辅,介绍了整个流程中的执行细节。为了保证流程的完整性,这里轮流写客户端和服务端的流程。
B.客户端协商请求
P1.客户端生成P,G,PublicKeyA和PrivateKeyA。 P和G生成时均为BigInteger,需要调用方法toString(16)转化成字符串,后面使用的都是转换后的P和G。
P2.客户端生成一个唯一的会话ID,记为SID
P3.客户端生成客户端支持的加/解密规则AES-supports。
P4.客户端生成请求接口用的认证Token,Token的签名使用:
SID + S(publicKey1) + P + G
P5.客户端将Token放入header中,将P、G、S(PublicKeyA)、SID、AES-supports字段放入body中,并调用服务端的协商接口。详细的参数信息见下表:
  
C.服务端协商处理
P1.服务端收到客户端的协商请求后,首先要校验字段的完整性。
P2.通过完整性校验后,校验Token的有效性,其中签名同为:
SID + PublicKey + P + G
所有参数均为请求中的字段
P3.服务端对PublicKey十六进制解码得到PublicKeyA。
P4.服务端通过P,G,PublicKeyA,生成自己的PublicKeyB和PrivateKeyB
P5.服务端从AES-supports中,选择一个作为本地协商的加密规则AES-param
P6.服务端生成一个协商有效时间expireTime(单位、毫秒),并缓存PublicKeyA、PublicKeyB、PrivateKeyB、expireTime、SecuSID、AES-param。
P7.服务端生成一个双向认证用的Token,Token的签名如下:
SecuSID + S(PublicKeyB) + AES-param + expireTime
P7.返回协商结果。
D.客户端协商返回处理
P1.服务端的请求返回的字段对象见下: 
P2.客户端校验服务端生成的Token,校验用的签名如下:
SecuSID + PublicKey + AES-param + expireTime
以上参数均为请求返回的字段。
P3.客户端缓存下这些参数以及之前生成的P、G,其中expireTime决定了会话的过期时间,通过服务端返回的PublicKey十六进制解码后得到的PublicKeyB和之前生成的PrivateKeyA、P、G、本地加密规则AES-param,可以生成Key用于加密。SecuSID在后续数据传输中使用。
至此,握手结束。
E.客户端数据传输请求
P1.客户端先在本地查找是否有和该地址的该服务有握手记录,如果有且记录未过期,则使用该握手记录中的握手数据,否则重新握手。
P2. 客户端根据握手数据中服务端的PublicKeyB、本地的PrivateKeyA和本地加密规则AES- param,生成加密矢量localIv和加密密钥localKey。
P3.客户端生成随机数X,用X和加密矢量localIv、本地加密规则AES- param对请求body中的敏感信息加密得到A,再对A进行Base64加密得到最终用于传输的密文。
P4.客户端用加密矢量localIv、加密密钥localKey和本地加密规则AES- param对随机数X加密得到Y,并对Y进行十六进制编码得到DK。
P5.客户端生成认证Token,生成Token的签名如下:
SID + DK
P6.客户端向服务端发起请求,请求字段如下:

F.服务端数据传输处理
P1.服务端接受到客户端的请求,先校验Header中字段的完整性,
P2.服务端校验客户端请求Token的合法性,其中Token的签名如下:
SecuSID + SecuDK
P3.服务端判断该SecuSID对应的协商是否过期,如果过期,直接返回提示重新握手。
P4.服务端从该SecuSID对应的缓存中,取出之前协商的数据,通过其中的PublicKeyA和PrivateKeyB和客户端的加密规则AES-param,生成加密矢量localIv和加密密钥localKey。
P5.通过对SecuDK十六进制解码得到Y,再通过加密矢量localIv和加密密钥localKey以及客户端的加密规则AES- param对Y进行解密得到X。
P6.对body中的敏感信息密文进行Base64解密得到A,再通过对X和加密矢量localIv对A进行解密得到明文。
P7.业务处理,进入返回敏感信息加密流程。
P8.服务端端生成随机数X,用X和加密矢量localIv、服务端的加密规则AES-param对范围报文中的敏感信息加密得到A,再对A进行Base64加密得到最终用于传输的密文。
P9.服务端用加密矢量localIv、加密密钥localKey和服务端的加密规则AES-param对随机数X加密得到Y,并对Y进行十六进制编码得到DK。
P10.服务端生成认证Token,生成Token的签名如下:
SID + DK
    P11。服务端返回结果。
G.客户端数据传输返回处理
P1. 服务端的请求返回的字段对象见下:
 
 
P2.注意服务端返回的SecuDK和请求过去的SecuDK是不相同的,不能混淆。
P3.校验Token的合法性,校验规则中的签名如下:
SID + DK(服务端返回的)
P4.客户端先对DK用十六进制反编码出Y,再用加密矢量localIv、加密密钥localKey和之前协商返回的服务端加密规则AES-param对Y解密得到X。
P5. 客户端先对传输过来的敏感信息密文用base64解码成字节串,再用X和加密矢量localIv、服务端加密规则AES-param对该字节串解密出明文。