天天看點

密鑰交換算法(常用)

密鑰交換的握手過程中最引人入勝的部分。在TLS中,會話安全性取決于稱為主密鑰(masteer secret)的48位元組共享密鑰。密鑰交換的目的是計算另一個值,即預主密鑰(premaster secret)。這個值是組成主密鑰的來源。

TLS支援許多密鑰交換算法,能夠支援各種證書類型、公鑰算法和密鑰生成協定。它們之中有一些在TLS協定主規格書中定義,但更多的則是在其他規格說明中定義。

常用的密鑰交換算法

dh_anon                 Diffie-Hellman(DH)密鑰交換,未經身份驗證

dhe_rsa                   臨時DH密鑰交換,使用RSA身份驗證

ecdh_anon             臨時橢圓曲線DH(elliptic curve DH,ECDH)密鑰交換,未經身份驗證

ecdhe_rsa               臨時ECDH密鑰交換,使用RSA身份驗證

ecdhe_ecdsa          臨時ECDH密鑰交換,使用ECDSA身份驗證

krb5                        Kerberos密鑰交換

rsa                           RSA密鑰交換和身份驗證

psk                          預共享密鑰(pre-shared key,PSK)密鑰交換和身份驗證

dhe_psk                  臨時DH密鑰交換,使用PSK身份驗證

rsa_psk                    PSK密鑰交換,使用RSA身份驗證

srp                           安全遠端密碼(secure remote password,SRP)密鑰交換和身份驗證

使用哪一種密鑰交換由協商的套件所決定。一旦套件決定下來,兩端都能了解按照哪種算法繼續操作。實際使用的密鑰交換算法主要有以下4種。

  • RSA

RSA是一種标準密鑰交換算法,它得到了廣泛的支援。但它受到一個問題的嚴重威脅:它的設計使被動攻擊者可以解碼所有加密資料,隻要她能夠通路伺服器的私鑰。是以RSA密鑰交換正慢慢被其他支援前向保密(forward secrecy)的算法所替代。RSA密鑰交換是一種密鑰傳輸(key transport)算法,這種算法由用戶端生成預主密鑰,并以伺服器公鑰加密傳送給伺服器。

  • DHE_RSA

臨時Diffie-Hellman(ephemeral Diffie-Hellman,DHE)密鑰交換是一種構造完備的算法。它的優點是支援前向保密,缺點是執行緩慢。DHE是一種密鑰協定算法,進行協商的團體都對密鑰生成産生作用,并對公共密鑰達成一緻。在TLS中,DHE通常與RSA身份驗證聯合使用。

  • ECDHE_RSA和ECDHE_ECDSA

臨時橢圓曲線Diffie-Hellman(ephemeral elliptic curve Diffie-Hellman,ECDHE)密鑰交換建立在橢圓曲線加密的基礎上。橢圓曲線算法是相對較新的算法。大家認可它執行很快而且提供了前向保密。但是隻有較新的用戶端才能較好的支援。ECDHE也是一種密鑰協定算法,其理論原理與DHE類似。在TLS中,ECDHE可以與RSA或者ECDSA身份驗證一起使用。

無論使用哪一種密鑰交換,伺服器都有機會發送ServerKeyExchange消息率先發話:

struct{
    select (KeyExchangeAlgorithm) {
    case dh_anon:
        ServerDHParams     params;
    case dhe_rsa:
        ServerDHParams     params:
        Signature          params_signature:
    case ecdh_anon:
        ServerECDHParams   params:
    case ecdhe_rsa:
    case ecdhe_ecdsa:
        ServerECDHParams   params;
        Signature          params_signature;
    case rsa:
    case dh_rsa:
        /* 無消息 */
      };
} ServerKeyExchange;      

在上面的消息定義中發現,在某些算法内,伺服器不發送任何資訊。原因是在這些情況下,所有需要的資訊已經通過其他消息得到;不然,伺服器就會在此發送其密鑰交換的參數。關鍵的是,伺服器也會發送參數的簽名用于身份驗證。使用簽名,用戶端得以确認它正在與持有私鑰對應證書中的公鑰的團體進行通信。

用戶端發送ClientKeyExchange消息傳送它的密鑰交換參數,這個消息總是必須的:

struct{
    select (KeyExchangeAlgorithm) {
    case rsa:
        EncryptedPreMasterSecret;
    case dhe_dss:
    case dhe_rsa:
    case dh_dss:
    case dh_rsa:
    case dh_anon:
        ClientDiffieHellmanPublic;
    case ecdhe:
        ClientECDiffieHellmanPublic;
      } exchange_Keys;
} ClientKeyExchange;      

RSA密鑰交換

RSA密鑰交換的過程十分直截了當。用戶端生成預主密鑰(46位元組随機數),使用伺服器公鑰對其加密,将其包含在ClientKeyExchange消息中,最後發送出去。伺服器隻需要解密這條消息就能取出預主密鑰。TLS使用的是RFC 3447定義的RSAES-PKCS1-v1_5加密方案。

因為RSA算法可以同時用于加密和數字簽名,是以RSA密鑰交換可以按照這種方式工作。其他流行的密鑰類型,比如DSA(DSS)和ECDSA,隻能用于簽名。

RSA密鑰交換的簡單性也是它最大的弱點。用于加密預主密鑰的伺服器公鑰,一般會保持多年不變。任何能夠接觸到對應私鑰的人都可以恢複預主密鑰,并建構相同的主密鑰,進而危害到會話安全性。

對目标的攻擊并不需要實時進行,強大的對手可以制定長期行動。攻擊者會記錄所有的加密的流量,耐心等待有朝一日可以得到密鑰。比如計算機能力的進步使暴力破解成為可能;也可以通過法律強制力、政治高壓、賄賂或強行進入使用該密鑰的伺服器來取得密鑰。隻要密鑰洩露,就可以解密之前記錄的所有流量了。

TLS中其他常見的密鑰交換方式都不受這個問題的影響,被稱為支援前向保密。使用那些密鑰交換時,每個連接配接使用的主密鑰互相獨立。洩露的伺服器密鑰可以用于冒充伺服器,但不能用于追溯任何流量。

Diffie-Hellmac密鑰交換

Diffie-Hellman(DH)密鑰交換時一種密鑰協定的協定,它使兩個團體在不安全的信道上生成共享密鑰成為可能。

以這種方式協商共享密鑰時不會受到被動攻擊的威脅,但主動攻擊者卻可以劫持通信信道,冒充對端。這就是DH密鑰交換通常與身份驗證聯合使用的原因。

抛開算法的細節,DH的訣竅是用了一種正向計算簡單、逆向計算困難的數學函數,即使交換中某些因子已被知曉,情況也是一樣。最恰當的類比示例是混色:如果有兩種顔色,那麼很容易将其混在一起得到第三種顔色;但是如果隻有第三種顔色的話,就很難确定究竟它是由哪兩種顔色混合而成的。

DH密鑰交換需要6個參數:其中兩個(dh_p和dh_g)稱為域參數,由伺服器選取。協商過程中,用戶端和伺服器各自生成另外兩個參數,互相發送其中一個參數(dh_Ys和dh_Yc)到對端,再經過計算,最終得到共享密鑰。

臨時Diffie-Hellman(ephemeral Diffie-Hellman,DHE)密鑰交換中沒有任何參數被重複使用。與之相對,在一些DH密鑰交換方式中,某些參數是靜态的,并被嵌入到伺服器和用戶端的證書中。這樣的話,密鑰交換的結果是一直不變的共享密鑰,就無法具備前向保密的能力。

TLS支援靜态DH密鑰交換,但無人使用。在協商DHE套件時,伺服器将其所有參數填入ServerDHParams塊并發送:

struct{
    opaque dh_p;
    opaque dh_g;
    opaque dh_Ys;
} ServerDHParams;      

用戶端響應并發送其公開參數(dh_Yc):

struct{
    select (PublicValueEncoding) {
    case implicit:
        /* 空的,當用戶端公共參數嵌入其用戶端時 */
    case explicit:
        opaque dh_Yc;
      } dh_public;
} ClientDiffieHellmanPublic;      

目前使用的DH交換存在以下這些現實問題。

  • DH參數的安全性

DH密鑰交換的安全性取決于域參數的品質。伺服器發送弱的或者不安全啊的參數,将對會話的安全性造成損害。弱DH參數被用作一種攻擊向量。

  • DH參數協商

TLS并沒有為用戶端提供傳遞期望使用的DH參數的強度的設施。比如,用戶端可能希望避免使用弱參數,抑或可能不支援強參數。是以,選擇DHE套件的伺服器事實上隻能期待DH參數可以被用戶端接受。

  • 參數強度不夠

以曆史角度來說,DH參數很大程度上被忽略了,其安全性也被忽視了。許多庫和伺服器預設使用弱DH參數,而且經常不提供配置DH參數強度的方法。是以,伺服器使用1024位弱參數、768位非安全參數、更有甚至使用512位參數,這些情況都很常見。知道最近,一些平台才開始使用2048位或者更高位數的強參數。

2015年5月披露的Logjam攻擊表明,512位的DH參數在使用合适資源的情況下可以被攻擊者在很短的時間内成功利用,同時可以估計傷害的攻擊者可能利用768位的參數。同樣的研究還強調非常厲害的攻擊者甚至有可能可以攻破那些被廣泛使用的、長度位1024位的标準參數組,進而以被動方式入侵數以百萬計的網際網路伺服器。

這些問題通過對不同強度的域參數定義來進行标準化,或者擴充TLS允許用戶端告知其偏好的方法來解決。

橢圓曲線Diffie-Hellman密鑰交換

臨時橢圓曲線Diffie-Hellman(elliptic curve Diffie-Hellman,ECDH)密鑰交換原理與DH相似,但它的核心使用了不同的數學基礎。正如名稱所示,ECDHE基于橢圓曲線(elliptic curve

,EC)加密。

ECDH密鑰交換發生在一條由伺服器定義的特定的橢圓曲線上。這條曲線代替了DH中域參數的角色。理論上,ECDH支援靜态的密鑰交換,但實際使用時,隻使用了這種臨時的變種(ECDHE)。

密鑰交換由伺服器發起,它選擇一條橢圓曲線和公開參數(EC point)并送出:

struct{
    ECParameters curve_params;
    ECPoint public;
} ServerDHParams;      

伺服器可以為密鑰交換明确指定一條曲線,但TLS并未使用這個功能。作為替代,在TLS中,伺服器通過指定某個名稱引用一條可能預先定義好參數的曲線(命名曲線,named curve):

struct{
    ECCurveType curve_type;
    select (curve_type) {
    case eexplicit_prime:
        /* 省略 */
    case explicit_char2:
        /* 省略 */
    case named_curve:
        NamedCurve nnamedcurve:
      };
} ECParameters;      
struct{
    select (PublicValueEncoding) {
    case implicit:
        /* 空的 */
    case explicit:
        ECPoint ecdh_Yc;
     } ecdh_public;
} ClientECDiffieHellmanPublic;      

繼續閱讀