淺談TLS協議

1.什麼是協議?

網絡協議通俗的講是網絡上兩臺計算機之間通信所要共同遵守的標準。協議規定了一種信息交流的格式和規範。協議本身並不是一種軟件,只是一種通信的標準,協議最終需要由軟件來實現,網絡協議的實現就是在不同的軟件和硬件環境下,執行可運行於開中環境的“協議”翻譯程序。說白了就是軟件要實現這個協議翻譯程序,從而使雙方遵守這某一協議。不同的網絡交互軟件的功能可能不同,但是都會翻譯同一種網絡協議。實現網絡協議,就像是給所有接入網絡的設備配備了一個“通用語言翻譯器”,這些翻譯都懂通用語言:例如國際上的英語,同時它也懂得本國的語言。這樣就能實現不同國家不同環境的人接入同一個網絡並進行交流。
協議分層:我用英語說:“How are you.” 不一定表示“你好!”,我們可以事先約定,這句話表示“再看一遍”的意思。這就象是所謂的江湖“黑話”,或叫“專業術語”。實際上,這時我們自己制定了一個新的通信標準,一個新的“高層協議”己經誕生了。這個協議在“英語”的基礎上,再製定自己的通信標準,這種新的通信標準就是基於“英語”這種“底層協議”的“高層協議”,我們可以把這種協議取名爲“講課協議”。說白了協議的分層就是在一個既定的協議之上再添加某些限定條件。創造一個新的協議。比如果規定雙方用英語交流,那麼在使用英語交流的過程中,對英語中的“Hello”單詞,定義他的意思是”帥哥“。那麼它在雙方交流的時候就被理解爲帥哥的意思。這就是又制定了一個新的協議。協議除了分層之外,還可以組合,比如將IP協議,TCP協議以及UDP協議組合在一起稱爲TCP/IP協議。
所以說下面的SSL協議就是在TCP協議的基礎上,又對信息傳輸做了某些規定,從而產生的一種新的協議。

2.什麼是HTTPS協議

由於http明文傳輸,很不安全所以出現了https.http“調用”SSL/TLS中的加密算法和協議邏輯,實現保密傳輸。https不能說是一個協議,只能說是一種應用。SSL加密http中的內容。然後默認使用433端口進行傳輸,SSL還可以加密Email,默認使用955,465端口。任何一個應用層協議都可以調用TLS/SSL來加密其明文數據。
所以簡單總結就是 : https = http + SSL/TLS

3.什麼是SSL協議?

SSL協議是Netscape研發的,保障在Internet上數據傳輸安全的一個協議,它利用數據加密技術,可以確保數據在網絡上的傳輸過程不被截取或者竊聽。被廣泛應用於Web瀏覽器和服務器之間的身份認證和加密數據傳輸。SSL協議位於TCP/IP協議與各種應用層協議之間。爲數據通訊提供安全支持。SSL協議可以分爲兩層:SSL記錄協議:建立在可靠的傳輸協議(如TCP)上,爲高層協議提供數據封裝,壓縮,加密,解密基本功能。SSL握手協議:建立在SSL記錄協議止尚,用於在實際的數據傳輸開始之前,通訊雙方進行身份驗證,協商加密算法,交換加密密鑰等。

4.什麼是TLS協議?

TLS協議是SSL協議經歷了SSL1.0,2.0,3.0版本後發展成爲的一種新的安全標準協議。TLS有1.0,1.1,1.2,1.3這幾個版本
TLS全稱是安全傳輸層協議,用於在兩個通信應用程序之間提供保密性和數據完整性。該協議由兩層組成:TLS記錄協議,TLS握手協議,較底層的是TLS記錄協議。位於某個可靠的傳輸協議(如TCP)之上。
一次加密通信需要實現3個任務:機密性,完整性,身份認證。

5.TLS與SSL的區別都有什麼?

TLS的最大優勢在於:TLS是獨立於應用協議。高層協議可以同名地分佈再TLS協議上面。然後,TLS標準並沒有規定應用程序如何在TLS上增加安全性。它如何啓動TLS握手協議以及如何解釋交換的認證證書的決定權流給協議的設計者和實施者來判斷。
版本號:TLS記錄合適與SSL記錄格式相同,但是版本號值不同,TLS的版本1.0使用的版本號爲SSLV3.1.
報文鑑別碼:SSLv3.0和TLS的MAC算法記憶MAC計算的範圍不同。TLS使用RFC-2140定義的HMAC算法。SSLv3.0使用了相似的算法,兩者的主要差別在於SSLv3.0中,填充字節與密鑰之間採用的是連接運算。而HMAC算法採用的是異或運算,兩者的安全程度是相同的。
僞隨機函數:TLS使用了成爲PRF的僞隨機函數來將密鑰擴展爲數據塊,是更安全的方式。
報警代碼:TLS支持幾乎所有的SSLv3.0報警代碼。而且TLS還補充定義了很多報警代碼。如解密失敗,記錄溢出,位置CA,拒絕訪問等。
密文族和客戶證書:SSLv3.0和TLS存在少量差別,即TLS不支持Fortezza密鑰交換,加密算法和客戶證書。
Certificate_verify和finished消息;SSLv3.0和TLS在用certificate_verify消息計算MD5和SHA-1散列碼時,計算的輸入有稍許差別,但安全性相當。
加密計算:TLS和SSLv3.0在計算主密值時採用的方式不同。
填充:用戶數據加密之前需要增加的填充字節。在SSL中,填充後的數據長度達到密文塊長度的最小整數倍。而在TLS中,填充後的數據長度可以是密文塊長度的任意整數倍(但填充的最大長度爲255字節),這種方式可以防止基於對報文長度進行分析的攻擊。

6.TLS/SSL在網絡通信模型中的位置。

(1)在TCP/IP協議層中
在這裏插入圖片描述
(2)在OSI協議層中
在這裏插入圖片描述

7.TLS的結構

其實現上分爲記錄層和握手層兩部分,其中握手層又包含了四個子協議。包括握手協議(hand protocol),更改加密規範協議(chage cipher spec protocol),應用數據協議(application data protocol)和警告協議(alert protocol),具體結構如下圖。
在這裏插入圖片描述
密鑰變更協議是用來通知對方從加密狀態轉變爲非加密狀態。
應用數據協議是使用商量好的密鑰,加密應用數據,對數據進行打包和處理。
警報協議,告知對端通信出現異常狀況,通常會攜帶close_notify異常,在連接關閉時使用,報告錯誤。其具體組成如下
struct{
AlertLevel level; //表示警告的嚴重程度取warning或fatal
AlertDescription description;//表示警報代碼
}
嚴重程度爲fatal的消息會立即終止當前鏈接並使會話失效。其中有一種警報爲關閉連接警報,它用於以有序的方式關閉TLS連接。一旦一段決定關閉數據連接,就發送一個close_notify警報。在另一端收到該警報後,會丟棄任何未寫出的數據。併發送自己的close_notify警報。在警報之後到來的任何消息都將被忽略。可以避免截斷攻擊,及時關閉協議。
最重要的就是TLS的握手協議。握手協議的詳情在下文展開。

8.TLS握手協議

TLS握手協議是用來進行身份認證以及協商加密算法的。握手協議消息的標頭信息包含消息類型(1字節)和長度(3字節),餘下的信息則取決於消息類型。其具體過程如下。
在這裏插入圖片描述
我個人使用Python代碼進行了一次簡單的TLS握手的模擬:
客戶端:

# -*- coding: utf-8 -*-
import socket
import random
import json
import rsa
import hashlib
from Crypto.Cipher import AES

# 定義服務端基本信息進行連接
host = "127.0.0.1"
port = 12345
obj = socket.socket()
obj.connect((host, port))

# Hello握手信號中所包含的內容
randNumber = random.randint(0, 100)  # 第一次生成的不重數
SSLVersion = "1.0"  # SSL版本
algorithmList = ['AES']  # 由於目前我只知道AES算法。所以列表中只是AES算法
someNeededInformation = ['NotNull', 'Space']  # 隨意填充了一些必要信息
clientCertificate = "Client"  # 客戶端的證書,用於服務器對客戶端真實性的驗證


def hello_handShake(conn):
    print("----------Start to send handshake signal----------")
    helloHandShake = {'randNumber': randNumber,
                      'SSLVersion': SSLVersion,
                      'algorithmList': algorithmList,
                      'someNeededInformation': someNeededInformation}
    conn.send(bytes(json.dumps(helloHandShake), encoding="utf-8"))
    print("----------Hello HandShake Single Send Success----------")
    return True


def recvAfterShakeHand(conn):
    # 接收服務端所發過來的證書,證書中的公鑰,SSL的版本,服務端所確定的算法,
    # 服務端傳送過來的消息,以及是否需要確認客戶端合法性的信號
    print("----------Receive from Server Start----------")
    serverResponse = json.loads(str(conn.recv(1024), encoding="utf-8"))
    print("從服務端收到的服務端證書:" + serverResponse["certificate"])
    print("從服務端收到的SSL版本號:" + serverResponse["SSLVersion"])
    print("從服務端收到的算法列表:" + serverResponse["algorithm"])
    print("從服務端收到的消息:" + serverResponse["msg"])
    print("從服務端收到的客戶端是否確認的消息:" + str(serverResponse["clientConfirm"]))
    # 如果服務器需要要求客戶端的身份驗證則發送客戶端的身份驗證
    if serverResponse['clientConfirm']:
        conn.send(bytes(clientCertificate, "utf-8"))

    serverConfirm = serverResponse['certificate']
    if serverConfirm != "Server":
        s = input("該服務端證書不可信,是否繼續連接?Y/N")
        if s == 'N':
            return

    # 獲取服務端的公鑰
    serverPublicKey = rsa.PublicKey(serverResponse['publicKey']['n'], serverResponse['publicKey']['e'])
    print("從服務端收到的服務端的公鑰:" + str(serverPublicKey))
    # 發送一個隨機數
    rand = random.randint(0, 100)
    # 將此隨機數用服務端的公鑰加密
    msg = str(rand).encode("utf-8")
    cryptoRand = rsa.encrypt(msg, serverPublicKey)
    # 加密後的隨機數的md5值
    randHashCode = hashlib.md5(cryptoRand).hexdigest()
    # 編碼變更通知,表示隨後的信息都將用雙方商定的加密方法和密鑰發送
    # 雙方協定的加密算法的密鑰
    publicKey = "123456"
    # 編碼改變通知  注意此處publicKey經過處理後爲字節流 需要解碼爲字符串
    codeChangeNotify = {"finalAlgorithm": serverResponse['algorithm'], "publicKey": publicKey}

    # ChangeCipherSpec是一個獨立的協議,體現在數據包中就是一個字節的數據,
    # 用於告知服務端,客戶端已經切換到之前協商好的加密套件(Cipher Suite)的狀態,
    # 準備使用之前協商好的加密套件加密數據並傳輸了
    changeCiperSpec = True

    # 在ChangecipherSpec傳輸完畢之後,客戶端會使用之前協商好的加密套件和Session Secret加密
    # 一段 Finish 的數據傳送給服務端,此數據是爲了在正式傳輸應用數據之前對剛剛握手建立起來的
    # 加解密通道進行驗證。
    publicKey = addTo16(publicKey)
    aes = AES.new(publicKey, AES.MODE_ECB)
    finishInformation = "Client finish"
    finishInformation = addTo16(finishInformation)
    finishInformation = aes.encrypt(finishInformation)

    # 作者能力有限無法構造爲一整個報文,因此只能先將加密後的隨機數發送,然後再將其餘兩個值發送
    data = json.dumps({"codeChangeNotify": codeChangeNotify, "randHashCode": randHashCode,
                       "changeCiperSpec": changeCiperSpec})
    conn.send(cryptoRand)
    conn.send(bytes(data, encoding="GBK"))
    conn.send(finishInformation)
    print("----------Receive from server finish----------")
    return True


def finalRecv(conn):
    print("----------Final step of handshake start----------")
    data = json.loads(str(conn.recv(1024), encoding="utf-8"))
    print("從客戶端收到的changeCipherSpec:" + str(data['changeCipherSpec']))
    print("從客戶端收到的finish消息:" + str(data['finshInformation']))
    print("----------Final step of handshake end----------")


def addTo16(par):
    # 由於AES算法需要明文和密文都是16位 24位或32位字節。本次採用16位
    # 將不足16位的進行16位補足
    par = par.encode("utf-8")  # 先將字符串類型數據轉換成字節型數據
    while len(par) % 16 != 0:
        par += b'\x00'
    return par


def main():
    # 客戶端給服務端發送握手信號
    flg = hello_handShake(obj)
    if flg:
        # 如果握手成功,進行接收和第二次發送
        flg = recvAfterShakeHand(obj)
        if flg:
            # 如果第二次接收和發送成功,進行最後的數據接收
            finalRecv(obj)


if __name__ == '__main__':
    main()

服務端

# -*- coding: utf-8 -*-
import socket
import json
import rsa
import random
from Crypto.Cipher import AES
import hashlib

# TCP連接基本配置
host = "127.0.0.1"
port = 12345
sk = socket.socket()  # 創建一個套接字對象
sk.bind((host, port))  # 綁定地址和端口號
sk.listen(5)  # 設置最大連接數

# 服務端SSL配置
publicKey, privateKey = rsa.newkeys(1024)  # 使用RSA算法生成公鑰和私鑰
certificate = "Server"  # 由於不知道證書具體格式,以一個字符串代替
SSLVersion = "1.0"  # SSL協議版本
randNum = random.randint(100, 200)  # 服務端的不重數
clientConfirm = False  # 是否需要驗證客戶端有效性


def dealHelloAndSend(helloSignal, conn):
    if helloSignal is not None:

        print("---------The handshake signal from client----------")
        clientRandNum = helloSignal['randNumber']  # 從客戶端接收到的隨機數
        print("從客戶端收到的隨機數:" + str(clientRandNum))
        clientSSLVersion = helloSignal['SSLVersion']  # 從客戶端接受到的版本號
        print("從客戶端收到的版本號:" + clientSSLVersion)
        clientAlgorithmList = helloSignal['algorithmList']  # 從客戶端接收到的所支持的算法列表
        print("從客戶端收到的算法列表:",end=" ")
        print(clientAlgorithmList)

        if clientSSLVersion != SSLVersion:  # 協議版本不匹配則終止連接
            print("Version unknown")
            return
        needAlgorithm = clientAlgorithmList[0]  # 選定一個客戶端支持的算法,
        # 因爲目前只知道一個對稱加密算法,只選一個
        firstReturn = json.dumps({"certificate": certificate, "publicKey": {"n": publicKey.n, "e": publicKey.e},
                                  "SSLVersion": SSLVersion, "algorithm": needAlgorithm,
                                  "msg": "Hello Done", "clientConfirm": clientConfirm})
        conn.sendall(bytes(firstReturn, encoding="utf-8"))  # 將返回內容以json字符串發送回去

        print("----------Hello Done Finish----------")
        return True


def dealNextSendAndSend(clientRandomNum, afterHandSignal, finnishInformation, conn):
    print("----------Receive from Client Start----------")

    print("從客戶端收到的加密後的隨機數:" + str(clientRandomNum))
    print("從客戶端收到的編碼改變通知:" + str(afterHandSignal['codeChangeNotify']))
    print("從客戶端收到的完整性檢驗的hash值:" + str(afterHandSignal['randHashCode']))
    print("從客戶端收到的ChangeCipherSpec值:" + str(afterHandSignal['changeCiperSpec']))
    print("從客戶端收到的finish消息:" + str(finnishInformation))

    # 查看md5的值與所傳過來的是否一致,驗證消息完整性
    encodeMd5 = hashlib.md5(clientRandomNum).hexdigest()

    if afterHandSignal['randHashCode'] == encodeMd5:
        print("The information is complete")
        realRandNum = rsa.decrypt(clientRandomNum, privateKey).decode()
        print("The Client RandNumber is " + realRandNum)
        changeCiperSpec = afterHandSignal['changeCiperSpec']
        if changeCiperSpec == False:
            return False
        publicKey = afterHandSignal['codeChangeNotify']['publicKey']
        publicKey = addTo16(publicKey)
        if afterHandSignal['codeChangeNotify']['finalAlgorithm'] != 'AES':
            return False

        aes = AES.new(publicKey, AES.MODE_ECB)
        finnishInformation = aes.decrypt(finnishInformation).decode()
        print("The FinishInformation is " + finnishInformation)

        # 給客戶端發送一個changeCipherSpec,告知加密套件準備狀態
        changeCipherSpec = True
        # 給客戶端以協商的加密方式發送一段finsh消息
        finshInformation = "Server finish"
        sendToCilent = {"changeCipherSpec": changeCipherSpec, "finshInformation": finshInformation}
        data = json.dumps(sendToCilent)
        conn.send(bytes(data, encoding="utf-8"))
        print("Send Finish!")
    else:
        print("The code is invalid")
        return False

    print("----------Receive from Server End----------")


def addTo16(par):
    # 由於AES算法需要明文和密文都是16位 24位或32位字節。本次採用16位
    # 將不足16位的進行16位補足
    par = par.encode("utf-8")  # 先將字符串類型數據轉換成字節型數據
    while len(par) % 16 != 0:
        par += b'\x00'
    return par


def main():
    while True:
        print("The port is listening...")
        print("wait the client")  # 等待客戶端連接
        conn, address = sk.accept()
        print("Connecting...")
        print("Connect from: ", address)
        helloSignal = json.loads(str(conn.recv(1024), encoding="utf-8"))
        flg = dealHelloAndSend(helloSignal, conn)
        if flg:
            if clientConfirm:  # 如果客戶端驗證非法,終止連接
                ret = conn.recv(1024)
                if ret != "client":
                    return
            clientRandomNum = conn.recv(1024)
            afterHandSignal = json.loads(conn.recv(1024), encoding="GBK")
            finnishInformation = conn.recv(1024)
            dealNextSendAndSend(clientRandomNum, afterHandSignal, finnishInformation, conn)
        else:
            print("SSLConnectFail")
            return


if __name__ == '__main__':
main()

客戶端:
在這裏插入圖片描述
服務端:
在這裏插入圖片描述

9.TSL握手過程中的各個信號的詳解

(1)Client hello
在一次新的握手流程中,ClientHello消息總是第一條消息,這條消息將客戶端的功能和首選項傳送給服務器。客戶端會在新建連接之後,希望重新協商或者響應服務器發起的重新協商的請求(由HelloRequest消息指示)時,發送這條消息。在握手時,客戶端和服務器都會提供隨機數。這種隨機性對每次握手都是獨一無二的,在身份驗證中起着重要的作用,可以防止重放攻擊,並確認初始數據交換的完整性。詳細結構如下圖:
在這裏插入圖片描述
(2)Server hello
ServerHello將服務器選擇的連接參數傳回給客戶端,消息結構與ClientHello類似。但是每個字段只包含其選中的一個選項,結構如圖:
在這裏插入圖片描述
如果服務端所支持的版本與客戶端支持的版本不一致,可以提供其他版本期待客戶端能夠接受。
(3)Certificate
典型的Certificate消息用於攜帶服務器X.509證書鏈,該證書鏈是一種格式,證書鏈是以ASN.1 DER編碼的一系列證書,一個接一個組合而成。主證書必須第一個發送,中間證書按照正確的順序跟在主證書之後,根證書可以並且應該省略掉,因爲在這個場景中它沒有用處。
服務器必須保證它發送的證書與所選擇的算法套件一致。比如說,公鑰算法與套件中使用的必須匹配。除此之外,一些密鑰交換算法依賴嵌入證書的特定數據,而且要求證書必須以客戶端支持的簽名算法。所有這些都表明服務器需要配置多個證書(每個證書可能會配備不同的證書鏈)。
Certificate消息是可選的,因爲並非所有套件都使用身份驗證。也並非所有身份驗證方法都需要證書。更進一步的說,雖然消息默認使用X.509證書,但是也可以攜帶其他形式的標誌。一些套件就依賴PGP密鑰。
(4)ServerKeyExchange
ServerKeyExchange消息的目的是攜帶密鑰交換的額外數據,消息內容對於不同的協商算法套件都會存在差異,在某些場景中,服務器不需要發送任何內容,這意味着在這些場景中根本不會發送ServerKeyExchage消息。
(5)ServerHelloDone
ServerHelloDone消息表明服務器已經將所有預計的握手消息發送完畢,服務器會等待客戶端消息。
(6)ClientKeyExchange
ClientKeyExchagne消息攜帶客戶端爲密鑰交換提供的所有信息,這個消息受協商的密碼套件影響,內容隨着不同的協商密碼套件而不同。
(7)ChangeCipherSpec
ChangeCipherSpec消息表明發送端已經取得用以生成連接參數的足夠信息,已經生成加密密鑰,並且切換到加密模式。客戶端和服務器在條件成熟時都會發送這個消息。
(8)Finished
Finished消息意味着握手已經完成。消息內容將加密,以便雙方可以安全地交換驗證整個握手完整性所需要的數據。這個消息包verify_data字段,它的值是握手過程中所有消息的散列值,這些消息在連接兩端都按照各自所見的順序排列,並以協商新的到的主密鑰計算散列值。這個過程是通過一個爲隨機函數(PRF)來完成的,這個函數可以生成任意數量的僞隨機數據。在TLS1.2版本中,Finished消息的長度默認是12字節(96位),除了SSL3 使用36字節的定長消息,其他版本都是使用12字節的定長消息。

10.TLS短握手

一次完整的TLS握手需要發送多次信息,是一個十分耗時的操作。短握手可以通過認證Session來縮短握手的過程。短握手時,服務器爲會話指定唯一的會話ID,服務器在ServerHello消息中將會話ID發送給客戶端,希望恢復之前會話的客戶端將會話ID放入ClientHello消息。服務器如果願意恢復會話,就將相同的會話ID放入ServerHello消息返回,切換到加密模式,發送Finished消息。
具體步驟如下:
1.客戶端恢復握手(ClientHello),將session_id加入到握手消息中
2.服務器查找該session_id,如果找到並且想要恢復會話,就將該session_id傳回給客戶端並切換到加密模式,通知客戶端。
3.服務器計算之前發送和接收到的所有有關握手的消息,形成MAC併發送(簽名)。
4.客戶端切換到加密方式並通知服務器。
5.客戶端計算髮送和接收到的握手消息的MAC併發送。

11.對客戶端和服務器都進行身份驗證的握手

這種握手就是在傳統的握手方式的基礎上添加了服務端對客戶端身份的驗證。具體過程如下:
在這裏插入圖片描述

12.TLS密鑰交換

密鑰的協商和交換時TLS的一個關鍵。密鑰交換中有兩個重點的問題。一是,密鑰週期儘可能要短,最好是一次會話用一個密鑰。其次是密鑰不能明文傳輸,一旦被竊聽所有努力都白費。密鑰的傳輸採用非對稱加密,非對稱加密的特點是公鑰加密,只能用私鑰解密。
非對稱算法在密鑰交換中的具體應用是:假設服務器擁有公鑰和私鑰,服務器將自己的證書以及公鑰明文發送給客戶端,然後客戶端自己生成一個密鑰,再用服務端的公鑰加密這個密鑰。重點是,這個加密的結果,只有私鑰能解密。而私鑰只在服務端,也就是說,被非對稱加密的密鑰只能由服務端解密。這樣就完成了密鑰交換。
在原來,較爲廣泛使用的就是上述加密過程,該加密過程主要通過RSA算法進行實現。但是RSA面臨一個很大的問題就是一旦私鑰外泄,那麼第三方就能從之前所有加密的密鑰中解密得到Key,使用Key就可以破解之前監聽得到的密文。私鑰參與了密鑰交換,安全性也隨之取決於私鑰的安全性。除了RSA算法之外,還有DH,DHE,ECDHE都可以用於密鑰交換。
1.DHE算法的密鑰交換過程:
臨時Diffie-Hellman(DHE)密鑰交換是一種構造完備的算法,其優點是支持前向保密。基於的數學難題是離散對數。缺點是執行緩慢。其大致過程如下
客戶端A生成一個隨機數x,使用x作爲指數,即計算a = g^x mod p(g的x次方對p取模),p是個大素數,g是生成數,這兩個數是公開進行傳遞的。客戶端把a發送到服務器,x作爲自己的私鑰,且只有A知道。
服務器B和客戶端A流程一樣,生成一個隨機y值,用y作爲指數,計算b = g^y mod p,將結果b發送至客戶端,y自己保存。
客戶端A收到b以後計算key1=b^x mod p
服務端B收到a以後計算key2=a^y mod p
根據數學定理: key1 = ((g^y mod p)^x)mod p = g^yx mod p
Key2 = ((g^x mod p)^y)mod p = g^xy mod p
g^yx = g^yx,所以key1 = key2,密鑰交換成功,而且中間沒有傳輸客戶端與服務端私有的x和y,傳輸的只是p,g,g^x mod p, g^y mod p,在已知這四個數的情況下是很難得出x與y的,這是依賴於離散對數這個難題。由於每次生成不同的x和y,因此之前加密的數據不會泄露。
實際上,私鑰的功能被削弱到用來身份認證,實際上上文中的DHE參數和b都是通過server key exchange發送給客戶端,a通過client key exchange發送給服務器,server key exchange的結尾處需要用私鑰對該報文本身進行簽名,來證明自己擁有私鑰,證明身份。
在ECDHE密鑰交換中,使用的是橢圓曲線算法,橢圓曲線(如secp256k1)和b通過server key exchange報文發送,a通過client key exchange報文發送。
2.ECDHE算法的密鑰交換過程
首先ECDHE的全稱是臨時橢圓曲線Diffie-Hellman,它就是將DHE中模冪運算替換成了點乘運算,速度更快,破解更難。其密鑰交換建立在橢圓曲線加密的基礎之上,橢圓曲線算法是相對較新的算法。其流程如下:
客戶端A隨機生成隨機值a,計算F(x,y)=a * Q(x,y),將F(x,y)發送至服務器B。
服務器B隨機生成隨機值b,計算F(x,y)=b * Q(x,y),將F(x,y)發送至客戶端A。
客戶端A計算key1(x,y)= a * (b * Q(x,y))。
服務端B計算key2(x,y)= b * (a * Q(x,y))。
key1 = key2 = key,取key的x向量作爲主密鑰(預主密鑰,將預主密鑰通過一個方法的計算就能得到一個主密鑰)
Q(x,y)爲公認的某個橢圓曲線算法的基點,例如secp256k1與secp384r1這個橢圓曲線是一個事先定義好的。
3.ECDHE與RSA的區別
ECDHE(DHE)算法屬於DH類密鑰交換算法,私鑰不參與密鑰交換,即使密鑰泄露,加密的報文都無法破解,實現了前向安全(forward secrity),由於ECDHE每條會話都會重新計算一個密鑰(a,b),所以當一個會話被破解之後,其他會話仍是安全的。
然而,ECDH算法服務端的私鑰是固定的,即證書的密鑰作爲b,故ECDH不被認爲前向安全,因爲私鑰泄密相當b泄露,可以使用b計算出之前所有的密鑰。
4.常用的密鑰交換算法與套件
TLS中的常用算法:
rsa RSA密鑰交換和身份驗證。
dhe_rsa 臨時DH密鑰交換,使用RSA身份驗證。
ecdhe_rsa 臨時ECDH密鑰交換,使用RSA身份驗證(RFC 4492)
ecdhe_ecdsa 臨時ECDH密鑰交換,使用ECDSA身份驗證(RFC 4492)
krb5 Kerberos密鑰交換(RFC 2712)
ecdh_anno 臨時橢圓曲線DH(elliptic cure DH,ECDH)密鑰交換, 未經身份驗證(RFC 4492)
psk 預共享密鑰(pre-shared key,PSK)密鑰交換和身份驗證(RFC 4279)
dhe_psk 臨時DH密鑰交換,使用PSK身份驗證(RFC 4297)
rsa_psk PSK密鑰交換,使用RSA身份驗證(RFC 4279)
srp 安全遠程密碼(secure remote password,SRP)密鑰交換和身份 驗證
dh_anon Diffie-Hellman(DH)密鑰交換,未經身份驗證。

13.TLS中的密鑰套件

密鑰套件是一個協議框架,TLS爲實現安全屬性提供了很大的靈活性,之前的TLS版本將某些加密基元編碼到了協議中,但TLS1.2是完全可配置的。密碼套件是一組選定的加密基元和其他參數,它可以精確定義如何實現安全。套件大致由以下屬性定義。
在這裏插入圖片描述
本文整理了一週左右,如有不當之處,請在下方評論區指正,謝謝各位。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章