共计 9840 个字符,预计需要花费 25 分钟才能阅读完成。
简介:SRTP:平安传输协定(Secure Real-time Transport)
通过 DTLS 协商后,RTC 通信的单方实现
MasterKey
和MasterSalt
的协商。接下来,咱们持续剖析在 WebRTC 中,如何应用替换的密钥,来对 RTP 和 RTCP 进行加密,实现数据的平安传输。同时,本文会对 libsrtp 应用中,遇到的问题的进行解答,例如,什么是 ROC,ROC 为什么是 32-bits?为什么会返回 error\_code=9, error\_code=10?替换的密钥有生命周期吗,如果有是多长时间呢?浏览本篇之前倡议浏览 DTLS 协商篇,两者联合,成果更佳哦!
作者|进学
审校|泰一
要解决的问题
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 构造
从 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 构造
从 SRTCP
结构图中能够看到:
1. 加密局部 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
的导出流程如下图所示:
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。
序列号治理 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
。否则示意收到一个乱序包。
下图更加直观阐明防重放攻打的三个区域:
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
上图形容了 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 治理和序列号治理与本文中形容的雷同,须要留神的是:
AES-GCM
作为一种 AEAD(Authenticated Encryption with Associated Data)加密算法,输出和输入是什么,对应到SRTP/SRTCP
的包构造中了解。
Counter
的是计算形式和 AES-ICM 中形容的计算形式不同,须要重点关注。
libsrtp 曾经实现了 AES-GCM
,有趣味的同学,能够联合代码进行研读。
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 感兴趣的同学,能够疾速在本机搭起调试环境,进行相干测试,更加深刻了解相干的算法。
总结
本文通过对 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
「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实际技术文章,在这里与音视频畛域一流工程师交换切磋。公众号后盾回复【技术】可退出阿里云视频云技术交换群,和作者一起探讨音视频技术,获取更多行业最新信息。
版权申明: 本文内容由阿里云实名注册用户自发奉献,版权归原作者所有,阿里云开发者社区不领有其著作权,亦不承当相应法律责任。具体规定请查看《阿里云开发者社区用户服务协定》和《阿里云开发者社区知识产权爱护指引》。如果您发现本社区中有涉嫌剽窃的内容,填写侵权投诉表单进行举报,一经查实,本社区将立即删除涉嫌侵权内容。