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對該字節串解密出明文。