srt是什么意思中文,srt是什么意思的缩写

  

     

  

  在DTLS谈判之后,RTC通信双方完成MasterKey和MasterSalt之间的谈判。接下来继续分析如何在WebRTC中用交换密钥加密RTP和RTCP,从而实现数据的安全传输。   

  

  RTP/RTCP协议不保护其有效载荷数据。所以,如果攻击者通过一个数据包捕获工具,比如Wireshark,来捕获音视频数据,那么音视频流就可以通过这个工具直接播放出来,这是一件非常恐怖的事情。   

  

  在WebRTC中,为了防止这种事情的发生,没有直接使用RTP/RTCP协议,而是使用SRTP/SRTCP协议,也就是安全的RTP/RTCP协议。WebRTC使用众所周知的libsrtp库将原始的RTP/RTCP协议数据转换成SRTP/SRTCP协议数据。   

  

  SRTP需要解决的问题:   

  

  加密RTP/RTCP的有效载荷,确保数据安全;   

  

  确保RTP/RTCP数据包的完整性,防止重放攻击。   

  

  2.SRTP/SRTCP结构   

  

  SRTP结构   

  

     

  

  从SRTP结构图可以看出:   

  

  1.加密部分,由有效载荷、RTP填充和RTP填充计数组成。也就是我们通常说的只加密RTP净荷数据。   

  

  2.待验证的认证部分由RTP报头、RTP报头扩展和加密部分组成。   

  

  通常,只有RTP有效载荷数据需要加密。如果RTP头扩展需要加密,RFC6904给出了详细的方案,同样在libsrtp中实现。   

  

     

  

  SRTCP结构   

  

  从SRTCP结构图可以看出:   

  

  1.加密部分是RTCP报头之后的部分,对于复合RTCP也是如此。   

  

  2.E-flag明确给出RTCP包是否加密。(PS:一个RTP包怎么判断是加密的?)   

  

  3.SRTCP索引显示RTCP数据包的序列号,用于防止重放攻击。(PS:一个RTP包的16位序列号能防止重放攻击吗?)   

  

  4.待验证的认证部分由RTCP报头和加密部分组成。   

  

  在初步了解了SRTP和SRTCP的结构之后,下一步是介绍如何获得加密部分和认证部分。   

  

  3.密钥管理   

  

  在SRTP/srtcp协议中,通过使用二进制SRTP目的IP地址和SRTP/SRTCP目的端口来识别通信参与者的SRTP/SRTCP会话,这被称为SRTP/SRTCP会话。   

  

  在SRTP协议中,使用三重SSRC、RTP/RTCP目的地址和RTP/RTCP目的端口来标识一个流,一个SRTP/SRTCP会话由多个流组成。每个流的加密和解密相关参数的描述被称为密码上下文。   

  

  每个流的加密上下文中的包含以下参数:   

  

  ssc:stream使用的SSRC。   

  

  密码参数:密钥、盐、算法描述(类型、参数等。)用于加密和解密。   

  

  认证参数:完整性密钥、salt、算法描述(类型、参数等。).   

  

  反重放数据:防止对缓存数据信息的重放攻击,如ROC、最大序列号等。   

  

  在SRTP/SRTCP会话中,每个流将使用自己的加密和解密密钥,即身份验证密钥。这些密钥都在同一个会话中使用,称为会话密钥。这些会话密钥通过对主密钥使用KDF(密钥导出函数)来导出。   

  

  KDF是用于导出会话密钥的函数。   

数,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 的导出流程如下图所示:

  

  

Session Key的导出依赖于如下参数:key_label: 根据导出的 Key 的类型不同,key_label取值如下:

  

  

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。

  

4. 序列号管理

  

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 个月的通信。

  

5. 防重放攻击

  

攻击者将截获的 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。否则表示收到一个乱序包。

  

下图更加直观说明防重放攻击的三个区域:

  

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,表示收到乱序包。

  

6. 加密和校验算法

  

在 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

  

上图描述了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 |<--+

  

+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

  

其中,b_c是Counter的计数,初始b_c的取值为0,对应Counter 0, 每加密128-bits数据,b_c增加1,作为下一个Counter。根据一个RTP包的index,SSRC计算出来的Counter,组成了keystream,每个Counter是一个keystream block。

  

通过使用AES-ICM算法,对RTP/RTCP的负载进行加密得到了Encrypted Portion Portion部分。

  

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 的长度 <B, 那么会在 K 后面填充 0x00 一直到等于长度 B。

  

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管理和序列号管理与本文中描述的相同,需要注意的是:

  

AES-GCM作为一种AEAD(Authenticated Encryption with Associated Data)加密算法,输入和输出是什么,对应到SRTP/SRTCP的包结构中理解。

  

Counter的是计算方式和AES-ICM中描述的计算方式不同,需要重点关注。

  

libsrtp已经实现了AES-GCM,有兴趣的同学,可以结合代码进行研读。

  

7. libsrtp的使用

  

libsrtp 是被广泛使用的 SRTP/SRTCP 加密的开源项目。经常用到的 api 如下:

  

1. srtp_init,初始化 srtp 库,初始化内部加密算法,在使用 srtp 前,必须要调用了。

  

2. srtp_create, 创建 srtp_session,可以结合本文中介绍的 session,session key 等概念一起理解。

  

3. 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 的生成。

  

2. window_size,对应我们之前描述的 srtp 防重放攻击的窗口大小。

  

3. allow_repeat_tx,是否允许重传相同序号的包。

  

SRS是一个新生代实时通信服务器,对 libsrtp 感兴趣的同学,可以快速在本机搭起调试环境,进行相关测试,更加深入理解相关的算法。

  

8. 总结

  

本文通过对 SRTP/SRTCP 相关原理的深入详细解读,对 libsrtp 使用遇到的问题进行解答,希望能够给实时音视频通信的相关领域的同学以帮助。

相关文章