天天看點

WebRTC 傳輸安全機制第二話:深入顯出 SRTP 協定要解決的問題SRTP/SRTCP 結構Key 管理序列号管理SRTP 序列号管理防重播攻擊加密和校驗算法libsrtp 的使用總結參考文獻

通過  DTLS 協商 後,RTC 通信的雙方完成 

MasterKey

MasterSalt

的協商。接下來,我們繼續分析在 WebRTC 中,如何使用交換的密鑰,來對 RTP 和 RTCP 進行加密,實作資料的安全傳輸。同時,本文會對 libsrtp 使用中,遇到的問題的進行解答,例如,什麼是 ROC,ROC 為什麼是 32-bits?為什麼會傳回 error_code=9, error_code=10?交換的密鑰有生命周期嗎,如果有是多長時間呢?閱讀本篇之前建議閱讀 篇,兩者結合,效果更佳哦!

作者|進學

審校|泰一

要解決的問題

RTP/RTCP

協定并沒有對它的負載資料進行任何保護。是以,如果攻擊者通過抓包工具,如 Wireshark,将音視訊資料抓取到後,通過該工具就可以直接将音視訊流播放出來,這是非常恐怖的事情。

在 WebRTC 中,為了防止這類事情發生,沒有直接使用

RTP/RTCP

協定,而是使用了

SRTP/SRTCP

協定 ,即安全的

RTP/RTCP

協定。WebRTC 使用了非常有名的 libsrtp 庫将原來的

RTP/RTCP

協定資料轉換成

SRTP/SRTCP

協定資料。

SRTP

要解決的問題:

・對

RTP/RTCP

的負載 (payload) 進行加密,保證資料安全;

・保證

RTP/RTCP

包的完整性,同時防重播攻擊。

SRTP/SRTCP 結構

SRTP 結構

WebRTC 傳輸安全機制第二話:深入顯出 SRTP 協定要解決的問題SRTP/SRTCP 結構Key 管理序列号管理SRTP 序列号管理防重播攻擊加密和校驗算法libsrtp 的使用總結參考文獻
WebRTC 傳輸安全機制第二話:深入顯出 SRTP 協定要解決的問題SRTP/SRTCP 結構Key 管理序列号管理SRTP 序列号管理防重播攻擊加密和校驗算法libsrtp 的使用總結參考文獻

從 SRTP 結構圖中可以看到:

1. 加密部分

Encrypted Portion

,由

payload

,

RTP padding

RTP pad count

部分組成。也就是我們通常所說的僅對 RTP 負載資料加密。

2. 需要校驗部分

Authenticated Portion

RTP Header

RTP Header extension

Encrypted Portion

部分組成。

通常情況下隻需要對 RTP 負載資料進行加密,如果需要對 RTP header extension 進行加密,

RFC6904

給出了詳細方案,在 libsrtp 中也完成了實作。

SRTCP 結構

WebRTC 傳輸安全機制第二話:深入顯出 SRTP 協定要解決的問題SRTP/SRTCP 結構Key 管理序列号管理SRTP 序列号管理防重播攻擊加密和校驗算法libsrtp 的使用總結參考文獻

SRTCP

結構圖中可以看到:

Encrypted Portion

,為

RTCP Header

之後的部分,對

Compound RTCP

也是同樣。

2. E-flag 顯式給出了 RTCP 包是否加密。(PS:一個 RTP 包怎麼判斷是加密的?)

3.

SRTCP index

顯示給出了 RTCP 包的序列号,用來防重播攻擊。(PS:一個 RTP 包的 16-bits 的序列号可以防重播攻擊嗎?)

4. 待校驗部分

Authenticated Portion

RTCP Header

Encrypted Portion

部分組成。在初步認識了

SRTP

SRTCP

的結構後,接下來介紹

Encrypted Portion

Authenticated Portion

如何得到了。

Key 管理

SRTP/SRTCP

協定中,使用二進制組 的方式來辨別一個通信參與者的

SRTP/SRTCP

會話,稱為

SRTP/SRTCP Session

SRTP

協定中使用三元組 來辨別一個 stream,一個

SRTP/SRTCP Session

由多個 stream 組成。對每個 stream 的加解密相關參數的描述,稱為

Cryptographic Context

每個 stream 的

Cryptographic Context

中 中的包含如下參數:

・SSRC: Stream 使用的 SSRC。

・Cipher Parameter:加解密使用的 key, salt,算法描述 (類型,參數等)。

・Authentication Parameter: 完整性使用的 Key, salt,算法描述 (類型,參數等)。

・Anti-Replay Data: 防止重播攻擊緩存的資料資訊,例如,ROC,最大序号等。

SRTP/SRTCP Session

中,每個 Stream 都會使用到屬于自己的,加解密 Key,Authentication Key。這些 Key 都是在同一個 Session 中使用到的,稱為

Session Key

。這些

Session Key

是通過對

Master Key

使用 KDF (Key Derivation Function) 導出的。

KDF

是用于導出

Session Key

函數,KDF 預設使用是加解密函數。例如,在完成 DTLS 後,協商得到的 SRTP 加密算法的 Profile 為:

SRTP_AES128_CM_HMAC_SHA1_80
         cipher: AES_128_CM
         cipher_key_length: 128
         cipher_salt_length: 112
         maximum_lifetime: 2^31
         auth_function: HMAC-SHA1
         auth_key_length: 160
         auth_tag_length: 80      

對應的

KDF

AES128_CM

Session Key

的導出流程如下圖所示:

WebRTC 傳輸安全機制第二話:深入顯出 SRTP 協定要解決的問題SRTP/SRTCP 結構Key 管理序列号管理SRTP 序列号管理防重播攻擊加密和校驗算法libsrtp 的使用總結參考文獻

Session Key

的導出依賴于如下參數:•

key_label

: 根據導出的 Key 的類型不同,

key_label

取值如下:

WebRTC 傳輸安全機制第二話:深入顯出 SRTP 協定要解決的問題SRTP/SRTCP 結構Key 管理序列号管理SRTP 序列号管理防重播攻擊加密和校驗算法libsrtp 的使用總結參考文獻

・master_key: DTLS 完成後,協商得到的 Key。

・master_salt:  DTLS 完成後,協商得到的 Salt。

・packet_index:  RTP/RTCP 的包序号。SRTP 使用 48-bits 的隐式包需要,SRTCP 使用 31-bits 包序号。參考

序号管理

・key_derivation_rate: key 導出速率,記為 kdr。預設取值為 0,執行 1 次 Key 導出。取值範圍

{{1,2,4,...,2^24}

。在

key_derivation_rate>0

的情況下,在加密之前,執行一次 key 導出,後續在 packet_index/key_derivation_rate > 0 時,執行 key 導出。

r = packet_index / kdr
key_id = label || r
x = key_id XOR master_salt
key = KDF(master_key, x)      
'/':表示整除,B=0 時,C = A/B=0。

||

:表示連接配接的含義。A,B,C 使用網絡位元組序表示,C = A||B, 則 C 的高位元組為 A,低位元組位為 B。

XOR

:是異或運算,計算時按照低位元組位對齊。

以下使用

AES128_CM

,舉例說明

Session Key

的導出過程,假設

DTLS

協商得到:

master_key:  E1F97A0D3E018BE0D64FA32C06DE4139   // 128-bits
master_salt: 0EC675AD498AFEEBB6960B3AABE6           // 112-bits      

導出加密 Key (cipher key):

packet_index/kdr:              000000000000
label:                       00
master_salt:   0EC675AD498AFEEBB6960B3AABE6
-----------------------------------------------
xor:           0EC675AD498AFEEBB6960B3AABE6     (x, KDF input)
x*2^16:        0EC675AD498AFEEBB6960B3AABE60000 (AES-CM input)
cipher key:    C61E7A93744F39EE10734AFE3FF7A087 (AES-CM output)      

導出 SALT Key (cipher salt):

packet_index/kdr:              000000000000
label:                       02
master_salt:   0EC675AD498AFEEBB6960B3AABE6
----------------------------------------------
xor:           0EC675AD498AFEE9B6960B3AABE6     (x, KDF input)
x*2^16:        0EC675AD498AFEE9B6960B3AABE60000 (AES-CM input)
               30CBBC08863D8C85D49DB34A9AE17AC6 (AES-CM ouptut)
cipher salt:   30CBBC08863D8C85D49DB34A9AE1      

導出校驗 Key (auth key),需要 

auth key

 長度為 94 位元組:

packet_index/kdr:                000000000000
label:                         01
master salt:     0EC675AD498AFEEBB6960B3AABE6
-----------------------------------------------
xor:             0EC675AD498AFEEAB6960B3AABE6     (x, KDF input)
x*2^16:          0EC675AD498AFEEAB6960B3AABE60000 (AES-CM input)
auth key                           AES input blocks
CEBE321F6FF7716B6FD4AB49AF256A15   0EC675AD498AFEEAB6960B3AABE60000
6D38BAA48F0A0ACF3C34E2359E6CDBCE   0EC675AD498AFEEAB6960B3AABE60001
E049646C43D9327AD175578EF7227098   0EC675AD498AFEEAB6960B3AABE60002
6371C10C9A369AC2F94A8C5FBCDDDC25   0EC675AD498AFEEAB6960B3AABE60003
6D6E919A48B610EF17C2041E47403576   0EC675AD498AFEEAB6960B3AABE60004
6B68642C59BBFC2F34DB60DBDFB2       0EC675AD498AFEEAB6960B3AABE60005      

AES-CM 的介紹,參考 

AES-CM。

至此,我們得到了

SRTP/SRTCP

加密和認證需要的

Session Key

:cipher key,auth key,salt key。

序列号管理SRTP 序列号管理

RTP

包結構定義中使用

16-bit

來描述序列号。考慮到防重播攻擊,消息完整性校驗,加密資料,導出 SessionKey 的需要,在

SRTP

協定中,SRTP 包的序列号,使用隐式方式來記錄包序列号

packet_index

,使用 i 辨別 packet_index。

對于發送端來說,i 的計算方式如下:

i = 2^16 * ROC + SEQ      

其中,SEQ 是 RTP 包中描述的 16-bit 包序号。ROC (rollover  couter) 是 RTP 包序号 (SEQ) 翻轉計數,也就是每當

SEQ/2^16=0

, ROC 計數加 1。ROC 初始值為 0。

對于接收端來說,考慮到丢包和亂序因素的影響,除了維護

ROC

,還需要維護一個目前收到的最大包序号

s_l

,當一個新的包到來時候,接收端需要估計出目前包所對應的實際 SRTP 包的序号。ROC 的初始值為 0,s_l 的初始值為收到第一個 SRTP 包的 SEQ。後續通過如下公式,估計接收到的 SRTP 序号 i:

i = 2^16 * v + SEQ      

其中,

v

可能的取值

{ ROC-1, ROC, ROC+1 }

,ROC 是接收端本地維護的 ROC,SEQ 是收到 SRTP 的序号。v 分别取 ROC-1,ROC,ROC+1 計算出 i,與

2^16*ROC + s_l

 進行比較,那個更接近,v 就取對應的值。完成 SRTP 解密和完整性校驗後,更新 ROC 和 s_l,分如下 3 種情況:

1. v = ROC - 1, ROC 和 s_l 不更新。

2. v = ROC,如果 SEQ > s_1,則更新 s_l = SEQ。

3. v = ROC + 1,  ROC = v = ROC + 1,s_l = SEQ。

更直覺的代碼描述:

if (s_l < 32768)
    if (SEQ - s_l > 32768)
        set v to (ROC-1) mod 2^32
    else
        set v to ROC
    endif
else
    if (s_l - 32768 > SEQ)
        set v to (ROC+1) mod 2^32
    else
        set v to ROC
    endif
endif
return SEQ + v*65536      

SRTCP 序列号管理

RTCP

中沒有描述序号的字段,

SRTCP

的序号在 SRTCP 包,使用

31-bits

中顯示描述,詳見 

SRTCP 格式

,也就是說在 SRTCP 的最大序列号為 2^31。

序列号與通信時長

可以看到 SRTP 的序列号最大值為 2^48, SRTCP 的序列号最大值為 2^16。在大多數應用中(假設每 128000 個 RTP 資料包至少有一個 RTCP 資料包),SRTCP 序号将首先達到上限。以 200 SRTCP 資料包 / 秒的速度, SRTCP 的 2^31 序列号空間足以確定大約 4 個月的通信。

防重播攻擊

攻擊者将截獲的 SRTP/SRTCP 包儲存下來,然後重新發送到網絡中,實作了包的重放。SRTP 接收者通過維護一個重放清單 (ReplayList) 來防止這種攻擊。理論上 Replay List 應該儲存所有接收到并完成校驗的包的序列号 index。在實際情況下 ReplayList 使用滑動視窗(sliding window)來實作防重播攻擊。使用 

SRTP-WINDOW-SIZE

來描述滑動視窗的大小。

SRTP 防重播攻擊

在序列号管理部分,我們詳述了接收者,根據接收到的 SRTP 包的 SEQ,ROC,s_l 估算出 SRTP 包的 

packet_index

 的方法。同時,将接收者已經接收到 SRTP 包的最大序列号,記為 

local_packet_index

。計算內插補點 

delta

delta =  packet_index - local_packet_index      

分如下 3 種情況說明:

1. delta > 0:表示收到了新的包。

2. delta <-(SRTP-WINDOW-SIZE - 1) < 0:表示收到的包的序列号,小于重放視窗要求的最小序号。libSRTP 收到這樣的包時,會傳回 

srtp_err_status_replay_old=10

, 表示收到舊的重放包。

3. delta <0,  delta>= -(SRTP-WINDOW-SIZE - 1): 表示收到了重放視窗之内的包。如果在 ReplayList 找到對應的包,則是一個 index 重複的重放包。libSRTP 收到這樣的包時,會傳回 

srtp_err_status_replay_fail=9

。否則表示收到一個亂序包。

下圖更加直覺說明防重播攻擊的三個區域:

WebRTC 傳輸安全機制第二話:深入顯出 SRTP 協定要解決的問題SRTP/SRTCP 結構Key 管理序列号管理SRTP 序列号管理防重播攻擊加密和校驗算法libsrtp 的使用總結參考文獻
SRTP-WINDOW-SIZE 的取值,最小是 64。應用可以根據需要設定成較大的值,libsrtp 會向上取整為 32 的整數倍。例如,在 WebRTC 中 

SRTP-WINDOW-SIZE

= 1024。使用者可以根據需要進行調整,但要達到防重播攻擊的目的。

SRTCP 防重播攻擊

在 SRTCP 中,packet index 顯式給出。在 libsrtp 中,SRTCP 的防重播攻擊的視窗大小為 128。使用 

window_start

記錄防重播攻擊的起始序列号。SRTCP 防重播攻擊的檢查步驟如下:

1. index > window_start + 128: 收到新的 SRTCP 包。

2. index < window_start: 收到包的序列号在重放視窗的左側,可以認為我們收到了比較老的包。libsrtp 收到這樣的包之後,會傳回到

srtp_err_status_replay_old=10

3. replay_list_index = index - windwo_start:在 ReplayList 中 replay_list_index 對應的辨別位為 1,表示已經收到包,libsrtp 傳回 

srtp_err_status_replay_fail=9

。對應的辨別位為 0,表示收到亂序包。

加密和校驗算法

在 SRTP 中,使用了 CTR(Counter mode)模式的 AES 加密算法,CTR 模式通過遞增一個加密計數器以産生連續的密鑰流,計數器可以是任意保證長時間不産生重複輸出的密鑰。根據計數方式的不同,分為以下兩種類型:

• 

AES-ICM

:  ICM 模式(Integer Counter Mode,整數計數模式),使用整數計數運算。

AES-GCM

: GCM 模式(Galois Counter Mode,基于伽羅瓦域計數模式),計數運算定義在伽羅瓦域。

在 SRTP 中,使用 

AES-ICM

 完成加密算法,同時使用 

HMAC-SHA1

 完成 

MAC

 計算,對資料進行完整性校驗,加密和 MAC 計算需要分兩步完成。

AES-GCM

 基于 AEAD(Authenticated-Encryption with Associated-Data,關聯資料的認證加密)的思想,在對資料進行加密的同時計算 

MAC

值,實作了一個步驟,完成加密和校驗資訊的計算。下面分别對這個 

AES-ICM

 和 

AES_GSM

的用法進行介紹。

AEC—ICM

WebRTC 傳輸安全機制第二話:深入顯出 SRTP 協定要解決的問題SRTP/SRTCP 結構Key 管理序列号管理SRTP 序列号管理防重播攻擊加密和校驗算法libsrtp 的使用總結參考文獻
WebRTC 傳輸安全機制第二話:深入顯出 SRTP 協定要解決的問題SRTP/SRTCP 結構Key 管理序列号管理SRTP 序列号管理防重播攻擊加密和校驗算法libsrtp 的使用總結參考文獻

上圖描述了 

AES-ICM

 的加密和解密過程,圖中的 K 是通過 KDF 導出的 

SessionKey

。加密和加密都是通過對 Counter 進行加密,與明文 P 異或運算得到加密資料 C,反之,與密文 C 異或運算得到明文資料 P。考慮到安全性,Counter 生成依賴于 

Session Salt

,  包的索引(packet index)和包的 SSRC。Counter 是 128-bits 的計數,生成方式如下定義:

one byte
<-->
0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|00|00|00|00|   SSRC    |   packet index  | b_c |---+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+   |
                                                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+   v
|                  salt (k_s)             |00|00|->(+)
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+   |
                                                    |
                                                    v
                                            +-------------+
                    encryption key (k_e) -> | AES encrypt |
                                            +-------------+
                                                    |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+   |
|                keystream block                |<--+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+      

HMAC—SHA1

散列消息認證碼(Hash-based message authentication code,縮寫為 HMAC),是一種通過特别計算方式之後産生的消息認證碼(MAC),使用密碼散列函數,同時結合一個加密密鑰,它可以用來保證資料的完整性,同時可以用來作某個消息的身份驗證。HMAC 通過一個标準算法,在計算哈希的過程中,把 key 混入計算過程中。HMAC 的加密實作如下:

HMAC(K,M) = H ( (K XOR opad ) + H( (K XOR ipad ) + M ) )      

・H:hash 算法,比如,MD5,SHA-1,SHA-256。

・B:塊位元組的長度,塊是 hash 操作的基本機關。這裡 B=64。

・L:hash 算法計算出來的位元組長度。(L=16 for MD5, L=20 for SHA-1)。

・K:共享密鑰,K 的長度可以是任意的,但是為了安全考慮,還是推薦 K 的長度 > B。

當 K 長度大于 B 時候,會先在 K 上面執行 hash 算法,将得到的 L 長度結果作為新的共享密鑰。如果 K 的長度

・M:要認證的内容。

・opad:外部填充常量,是 0x5C 重複 B 次。

・ipad:内部填充常量,是 0x36 重複 B 次。

・XOR:異或運算。

・+:代表 "連接配接" 運算。

計算步驟如下:

1. 将 0x00 填充到 K 的後面,直到其長度等于 B。

2. 将步驟 1 的結果跟 ipad 做異或。

3. 将要加密的資訊附在步驟 2 的結果後面。

4. 調用 H 方法。

5. 将步驟 1 的結果跟 opad 做異或。

6. 将步驟 4 的結果附在步驟 5 的結果後面。

7. 調用 H 方法。

SRTP

SRTCP

計算 

Authentication tag

,使用的 

K

 對應 Key 管理部分描述的

RTP auth key

和 

RTCP auth key

,使用的 Hash 算法為 

SHA-1

Authentication tag

 的長度為 80-bits。

在計算 SRTP 的,要認證的内容 M 為:

M = Authenticated Portion + ROC      

+

代表 "連接配接" 運算,

Authenticated Portion

 在 

SRTP

 的結構圖中給出。

在計算 

SRTCP

 時,要認證的内容 M 為:

M=Authenticated Portion      

Authenticated Portion

SRTCP

的結構圖中給出。

通過使用

Authenticated Portion

算法,計算得到 SRTP/SRTCP 的

Encrypted Portion Portion

部分。

AES—GCM

AES-GCM

 使用計數器模式來加密資料,該操作可以有效地流水線化,GCM 身份驗證使用的操作特别适合于硬體中的有效實作。在

GCM-SPEC 

詳述了 GCM 的理論知識,

Section4.2 Hardware 

詳述了硬體實作。

AES-GCM

SRTP

 加密中的應用,在 

RFC7714

進行了較長的描述。Key 管理和序列号管理與本文中描述的相同,需要注意的是:

1. 

AES-GCM

作為一種 AEAD(Authenticated Encryption with Associated Data)加密算法,輸入和輸出是什麼,對應到 

SRTP/SRTCP

 的包結構中了解。

2. 

Counter

 的是計算方式和 AES-ICM 中描述的計算方式不同,需要重點關注。

libsrtp

已經實作了 

AES-GCM

,有興趣的同學,可以結合代碼進行研讀。

libsrtp 的使用

是被廣泛使用的 SRTP/SRTCP 加密的開源項目。經常用到的 api 如下:

1.

srtp_init

,初始化 srtp 庫,初始化内部加密算法,在使用 srtp 前,必須要調用了。

2.

srtp_create

, 建立 srtp_session,可以結合本文中介紹的 session,session key 等概念一起了解。

srtp_unprotect/srtp_protect

,RTP 包加解密接口。

4.

srtp_protect_rtcp/srtp_unprotect_rtcp

,RTCP 包的加解密接口。

5.

srtp_set_stream_roc/srtp_get_stream_roc

, 設定和擷取 stream 的 ROC,這兩個接口在最新的 2.3 版本加入。

重要的結構

srtp_policy_t

,用來初始化加解密參數,在

srtp_create

中使用這個結構。以下參數需要關注:

1. DTLS 協商後得到的

MasterKey

MasterSalt

通過這個結構傳遞給 libsrtp,用于 session key 的生成。

window_size

,對應我們之前描述的 srtp 防重播攻擊的視窗大小。

allow_repeat_tx

,是否允許重傳相同序号的包。

SRS 

是一個新生代實時通信伺服器,對 libsrtp 感興趣的同學,可以快速在本機搭起調試環境,進行相關測試,更加深入了解相關的算法。

總結

本文通過對

SRTP/SRTCP

相關原理的深入詳細解讀,對 libsrtp 使用遇到的問題進行解答,希望能夠給實時音視訊通信的相關領域的同學以幫助。

參考文獻

RFC3711:  SRTP RFC6904: Encrypted SRTP Header Extensions Integer Counter Mode RFC-6188: The Use of AES-192 and AES-256 in Secure RTP RFC7714:  AES-GCM for SRTP RFC2104:  HMAC RFC2202: Test Cases for HMAC-MD5 and HMAC-SHA-1 GCM-SPEC:  GCM
「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。公衆号背景回複【技術】可加入阿裡雲視訊雲技術交流群,和作者一起探讨音視訊技術,擷取更多行業最新資訊。

掃碼入群和作者一起探讨音視訊技術,擷取更多視訊雲行業最新資訊👇 

WebRTC 傳輸安全機制第二話:深入顯出 SRTP 協定要解決的問題SRTP/SRTCP 結構Key 管理序列号管理SRTP 序列号管理防重播攻擊加密和校驗算法libsrtp 的使用總結參考文獻

繼續閱讀