WebRTC 传输安全机制第二话:深入显出 SRTP 协议

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通过 ","attrs":{}},{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/tHW6sWRZUzkOtl2BsRbV1w","title":"","type":null},"content":[{"type":"text","text":"DTLS 协商","attrs":{}}]},{"type":"text","text":"后,RTC 通信的双方完成 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"MasterKey","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"MasterSalt","attrs":{}}],"attrs":{}},{"type":"text","text":" 的协商。接下来,我们继续分析在 WebRTC 中,如何使用交换的密钥,来对 RTP 和 RTCP 进行加密,实现数据的安全传输。同时,本文会对 libsrtp 使用中,遇到的问题的进行解答,例如,什么是 ROC,ROC 为什么是 32-bits?为什么会返回 error_code=9, error_code=10?交换的密钥有生命周期吗,如果有是多长时间呢?阅读本篇之前建议阅读","attrs":{}},{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/tHW6sWRZUzkOtl2BsRbV1w","title":"","type":null},"content":[{"type":"text","text":" DTLS 协商篇","attrs":{}}]},{"type":"text","text":",两者结合,效果更佳哦!","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者|进学","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"审校|泰一","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"要解决的问题","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"RTP/RTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 协议并没有对它的负载数据进行任何保护。因此,如果攻击者通过抓包工具,如 Wireshark,将音视频数据抓取到后,通过该工具就可以直接将音视频流播放出来,这是非常恐怖的事情。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 WebRTC 中,为了防止这类事情发生,没有直接使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTP/RTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 协议,而是使用了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP/SRTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 协议 ,即安全的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTP/RTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 协议。WebRTC 使用了非常有名的 libsrtp 库将原来的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTP/RTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 协议数据转换成 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP/SRTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 协议数据。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://datatracker.ietf.org/doc/html/rfc3711","title":"","type":null},"content":[{"type":"text","text":"SRTP","attrs":{}}]},{"type":"text","text":" 要解决的问题:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTP/RTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 的负载 (payload) 进行加密,保证数据安全;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"保证 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTP/RTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 包的完整性,同时防重放攻击。","attrs":{}}]}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"SRTP/SRTCP 结构","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"SRTP 结构","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b0/b0d65849547a19e1ac9daf0ca5ca1cb3.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从 SRTP 结构图中可以看到:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"加密部分 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Encrypted Portion","attrs":{}}],"attrs":{}},{"type":"text","text":",由 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"payload","attrs":{}}],"attrs":{}},{"type":"text","text":", ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTP padding","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTP pad count","attrs":{}}],"attrs":{}},{"type":"text","text":" 部分组成。也就是我们通常所说的仅对 RTP 负载数据加密。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"需要校验部分 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Authenticated Portion","attrs":{}}],"attrs":{}},{"type":"text","text":",由 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTP Header","attrs":{}}],"attrs":{}},{"type":"text","text":", ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTP Header extension","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Encrypted Portion","attrs":{}}],"attrs":{}},{"type":"text","text":" 部分组成。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通常情况下只需要对 RTP 负载数据进行加密,如果需要对 RTP header extension 进行加密,","attrs":{}},{"type":"link","attrs":{"href":"https://datatracker.ietf.org/doc/html/rfc6904","title":"","type":null},"content":[{"type":"text","text":"RFC6904","attrs":{}}]},{"type":"text","text":" 给出了详细方案,在 libsrtp 中也完成了实现。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"SRTCP 结构","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/91/916e6979f2c041fcc2c1f1990e5f3cec.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"从 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 结构图中可以看到:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"加密部分 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Encrypted Portion","attrs":{}}],"attrs":{}},{"type":"text","text":",为 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTCP Header","attrs":{}}],"attrs":{}},{"type":"text","text":" 之后的部分,对 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Compound RTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 也是同样。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"E-flag 显式给出了 RTCP 包是否加密。(PS:一个 RTP 包怎么判断是加密的?)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"SRTCP index","attrs":{}}],"attrs":{}},{"type":"text","text":" 显示给出了 RTCP 包的序列号,用来防重放攻击。(PS:一个 RTP 包的 16-bits 的序列号可以防重放攻击吗?)","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"待校验部分 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Authenticated Portion","attrs":{}}],"attrs":{}},{"type":"text","text":",由 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTCP Header","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Encrypted Portion","attrs":{}}],"attrs":{}},{"type":"text","text":" 部分组成。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在初步认识了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 的结构后,接下来介绍 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Encrypted Portion","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Authenticated Portion","attrs":{}}],"attrs":{}},{"type":"text","text":" 如何得到了。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Key 管理","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP/SRTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 协议中,使用二元组 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":" ","attrs":{}}],"attrs":{}},{"type":"text","text":"的方式来标识一个通信参与者的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP/SRTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 会话,称为 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP/SRTCP Session","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 SRTP 协议中使用三元组","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"","attrs":{}}],"attrs":{}},{"type":"text","text":"来标识一个 stream,一个 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP/SRTCP Session","attrs":{}}],"attrs":{}},{"type":"text","text":" 由多个 stream 组成。对每个 stream 的加解密相关参数的描述,称为 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Cryptographic Context","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每个 stream 的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Cryptographic Context","attrs":{}}],"attrs":{}},{"type":"text","text":" 中 中的包含如下参数:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SSRC: Stream 使用的 SSRC。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Cipher Parameter:加解密使用的 key, salt,算法描述 (类型,参数等)。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Authentication Parameter: 完整性使用的 Key, salt,算法描述 (类型,参数等)。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Anti-Replay Data: 防止重放攻击缓存的数据信息,例如,ROC,最大序号等。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP/SRTCP Session","attrs":{}}],"attrs":{}},{"type":"text","text":" 中,每个 Stream 都会使用到属于自己的,加解密 Key,Authentication Key。这些 Key 都是在同一个 Session 中使用到的,称为 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Session Key","attrs":{}}],"attrs":{}},{"type":"text","text":"。这些 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Session Key","attrs":{}}],"attrs":{}},{"type":"text","text":" 是通过对 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Master Key","attrs":{}}],"attrs":{}},{"type":"text","text":" 使用 KDF (Key Derivation Function) 导出的。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"KDF","attrs":{}}],"attrs":{}},{"type":"text","text":" 是用于导出 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Session Key","attrs":{}}],"attrs":{}},{"type":"text","text":" 函数,KDF 默认使用是加解密函数。例如,在完成 DTLS 后,协商得到的 SRTP 加密算法的 Profile 为:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"SRTP_AES128_CM_HMAC_SHA1_80\n cipher: AES_128_CM\n cipher_key_length: 128\n cipher_salt_length: 112\n maximum_lifetime: 2^31\n auth_function: HMAC-SHA1\n auth_key_length: 160\n auth_tag_length: 80\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对应的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"KDF","attrs":{}}],"attrs":{}},{"type":"text","text":" 为 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"AES128_CM","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Session Key","attrs":{}}],"attrs":{}},{"type":"text","text":" 的导出流程如下图所示:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f9/f998a5e93472ea59bb2ac1492269819f.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"Session Key","attrs":{}}],"attrs":{}},{"type":"text","text":" 的导出依赖于如下参数:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"key_label","attrs":{}}],"attrs":{}},{"type":"text","text":": 根据导出的 Key 的类型不同,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"key_label","attrs":{}}],"attrs":{}},{"type":"text","text":" 取值如下:","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":"none"},"content":[{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/20/20bf4c9ae525221674319ee6e82c2024.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"master_key: DTLS 完成后,协商得到的 Key。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"master_salt: DTLS 完成后,协商得到的 Salt。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"packet_index: RTP/RTCP 的包序号。SRTP 使用 48-bits 的隐式包需要,SRTCP 使用 31-bits 包序号。参考序号管理。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"key_derivation_rate: key 导出速率,记为 kdr。默认取值为 0,执行 1 次 Key 导出。取值范围 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"{{1,2,4,...,2^24}","attrs":{}}],"attrs":{}},{"type":"text","text":"。在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"key_derivation_rate>0","attrs":{}}],"attrs":{}},{"type":"text","text":" 的情况下,在加密之前,执行一次 key 导出,后续在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"packet_index/key_derivation_rate > 0","attrs":{}}],"attrs":{}},{"type":"text","text":" 时,执行 key 导出。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"r = packet_index / kdr\nkey_id = label || r\nx = key_id XOR master_salt\nkey = KDF(master_key, x)\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"'/':表示整除,B=0 时,C = A/B=0。||:表示连接的含义。A,B,C 使用网络字节序表示,C = A||B, 则 C 的高字节为 A,低字节位为 B。XOR:是异或运算,计算时按照低字节位对齐。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以下使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"AES128_CM","attrs":{}}],"attrs":{}},{"type":"text","text":",举例说明 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Session Key","attrs":{}}],"attrs":{}},{"type":"text","text":" 的导出过程,假设 DTLS 协商得到:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"master_key: E1F97A0D3E018BE0D64FA32C06DE4139 // 128-bits\nmaster_salt: 0EC675AD498AFEEBB6960B3AABE6 // 112-bits\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"导出加密 Key (cipher key):","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"packet_index/kdr: 000000000000\nlabel: 00\nmaster_salt: 0EC675AD498AFEEBB6960B3AABE6\n-----------------------------------------------\nxor: 0EC675AD498AFEEBB6960B3AABE6 (x, KDF input)\nx*2^16: 0EC675AD498AFEEBB6960B3AABE60000 (AES-CM input)\ncipher key: C61E7A93744F39EE10734AFE3FF7A087 (AES-CM output)\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"导出 SALT Key (cipher salt):","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"packet_index/kdr: 000000000000\nlabel: 02\nmaster_salt: 0EC675AD498AFEEBB6960B3AABE6\n----------------------------------------------\nxor: 0EC675AD498AFEE9B6960B3AABE6 (x, KDF input)\nx*2^16: 0EC675AD498AFEE9B6960B3AABE60000 (AES-CM input)\n 30CBBC08863D8C85D49DB34A9AE17AC6 (AES-CM ouptut)\ncipher salt: 30CBBC08863D8C85D49DB34A9AE1\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"导出校验 Key (auth key),需要 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"auth key","attrs":{}}],"attrs":{}},{"type":"text","text":" 长度为 94 字节:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"packet_index/kdr: 000000000000\nlabel: 01\nmaster salt: 0EC675AD498AFEEBB6960B3AABE6\n-----------------------------------------------\nxor: 0EC675AD498AFEEAB6960B3AABE6 (x, KDF input)\nx*2^16: 0EC675AD498AFEEAB6960B3AABE60000 (AES-CM input)\n\nauth key AES input blocks\nCEBE321F6FF7716B6FD4AB49AF256A15 0EC675AD498AFEEAB6960B3AABE60000\n6D38BAA48F0A0ACF3C34E2359E6CDBCE 0EC675AD498AFEEAB6960B3AABE60001\nE049646C43D9327AD175578EF7227098 0EC675AD498AFEEAB6960B3AABE60002\n6371C10C9A369AC2F94A8C5FBCDDDC25 0EC675AD498AFEEAB6960B3AABE60003\n6D6E919A48B610EF17C2041E47403576 0EC675AD498AFEEAB6960B3AABE60004\n6B68642C59BBFC2F34DB60DBDFB2 0EC675AD498AFEEAB6960B3AABE60005\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"AES-CM 的介绍,参考","attrs":{}},{"type":"link","attrs":{"href":"https://www.rfc-editor.org/rfc/rfc3711.html#appendix-B.3","title":"","type":null},"content":[{"type":"text","text":" AES-CM","attrs":{}}]},{"type":"text","text":"。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"至此,我们得到了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP/SRTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 加密和认证需要的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Session Key","attrs":{}}],"attrs":{}},{"type":"text","text":":cipher key,auth key,salt key。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"序列号管理","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"SRTP 序列号管理","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"RTP","attrs":{}}],"attrs":{}},{"type":"text","text":" 包结构定义中使用 16-bit 来描述序列号。考虑到防重放攻击,消息完整性校验,加密数据,导出 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SessionKey","attrs":{}}],"attrs":{}},{"type":"text","text":" 的需要,在 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP","attrs":{}}],"attrs":{}},{"type":"text","text":" 协议中,SRTP 包的序列号,使用隐式方式来记录包序列号 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"packet_index","attrs":{}}],"attrs":{}},{"type":"text","text":",使用 i 标识 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"packet_index","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于发送端来说,i 的计算方式如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"i = 2^16 * ROC + SEQ\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中,SEQ 是 RTP 包中描述的 16-bit 包序号。ROC (rollover couter) 是 RTP 包序号 (SEQ) 翻转计数,也就是每当 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SEQ/2^16=0","attrs":{}}],"attrs":{}},{"type":"text","text":", ROC 计数加 1。ROC 初始值为 0。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"对于接收端来说,考虑到丢包和乱序因素的影响,除了维护 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"ROC","attrs":{}}],"attrs":{}},{"type":"text","text":",还需要维护一个当前收到的最大包序号 s_l,当一个新的包到来时候,接收端需要估计出当前包所对应的实际 SRTP 包的序号。ROC 的初始值为 0,s_l 的初始值为收到第一个 SRTP 包的 SEQ。后续通过如下公式,估计接收到的 SRTP 序号 i:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"i = 2^16 * v + SEQ\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"v ","attrs":{}}],"attrs":{}},{"type":"text","text":"可能的取值","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":" { ROC-1, ROC, ROC+1 }","attrs":{}}],"attrs":{}},{"type":"text","text":",ROC 是接收端本地维护的 ROC,SEQ 是收到 SRTP 的序号。v 分别取 ROC-1,ROC,ROC+1 计算出 i,与 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"2^16*ROC + s_l ","attrs":{}}],"attrs":{}},{"type":"text","text":" 进行比较,那个更接近,v 就取对应的值。完成 SRTP 解密和完整性校验后,更新 ROC 和 s_l,分如下 3 种情况:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"v = ROC - 1, ROC 和 s_l 不更新。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"v = ROC,如果 SEQ > s_1,则更新 s_l = SEQ。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"v = ROC + 1, ROC = v = ROC + 1,s_l = SEQ。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更直观的代码描述:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"if (s_l < 32768)\n if (SEQ - s_l > 32768)\n set v to (ROC-1) mod 2^32\n else\n set v to ROC\n endif\nelse\n if (s_l - 32768 > SEQ)\n set v to (ROC+1) mod 2^32\n else\n set v to ROC\n endif\nendif\nreturn SEQ + v*65536\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"SRTCP 序列号管理","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"RTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 中没有描述序号的字段,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 的序号在 SRTCP 包,使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"31-bits","attrs":{}}],"attrs":{}},{"type":"text","text":" 中显示描述,详见 SRTCP 格式,也就是说在 SRTCP 的最大序列号为 2^31。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"序列号与通信时长","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到 SRTP 的序列号最大值为 2^48, SRTCP 的序列号最大值为 2^16。在大多数应用中(假设每 128000 个 RTP 数据包至少有一个 RTCP 数据包),SRTCP 序号将首先达到上限。以 200 SRTCP 数据包 / 秒的速度, SRTCP 的 2^31 序列号空间足以确保大约 4 个月的通信。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"防重放攻击","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"攻击者将截获的 SRTP/SRTCP 包保存下来,然后重新发送到网络中,实现了包的重放。SRTP 接收者通过维护一个重放列表 (ReplayList) 来防止这种攻击。理论上 Replay List 应该保存所有接收到并完成校验的包的序列号 index。在实际情况下 ReplayList 使用滑动窗口(sliding window)来实现防重放攻击。使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP-WINDOW-SIZE","attrs":{}}],"attrs":{}},{"type":"text","text":" 来描述滑动窗口的大小。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"SRTP 防重放攻击","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在序列号管理部分,我们详述了接收者,根据接收到的 SRTP 包的 SEQ,ROC,s_l 估算出 SRTP 包的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"packet_index","attrs":{}}],"attrs":{}},{"type":"text","text":" 的方法。同时,将接收者已经接收到 SRTP 包的最大序列号,记为 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"local_packet_index","attrs":{}}],"attrs":{}},{"type":"text","text":"。计算差值 delta:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"delta = packet_index - local_packet_index\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"分如下 3 种情况说明:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"delta > 0:表示收到了新的包。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"delta = -(SRTP-WINDOW-SIZE - 1)","attrs":{}}],"attrs":{}},{"type":"text","text":": 表示收到了重放窗口之内的包。如果在 ReplayList 找到对应的包,则是一个 index 重复的重放包。libSRTP 收到这样的包时,会返回 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"srtp_err_status_replay_fail=9","attrs":{}}],"attrs":{}},{"type":"text","text":"。否则表示收到一个乱序包。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下图更加直观说明防重放攻击的三个区域:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e3/e31a9ff769993866cd4340950949bfe0.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"SRTP-WINDOW-SIZE 的取值,最小是 64。应用可以根据需要设置成较大的值,libsrtp 会向上取整为 32 的整数倍。例如,在 WebRTC 中 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTP-WINDOW-SIZE = 1024","attrs":{}}],"attrs":{}},{"type":"text","text":"。使用者可以根据需要进行调整,但要达到防重放攻击的目的。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"SRTCP 防重放攻击","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 SRTCP 中,packet index 显式给出。在 libsrtp 中,SRTCP 的防重放攻击的窗口大小为 128。使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"window_start","attrs":{}}],"attrs":{}},{"type":"text","text":" 记录防重放攻击的起始序列号。SRTCP 防重放攻击的检查步骤如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"index > window_start + 128: 收到新的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SRTCP","attrs":{}}],"attrs":{}},{"type":"text","text":" 包。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"index < window_start: 收到包的序列号在重放窗口的左侧,可以认为我们收到了比较老的包。libsrtp 收到这样的包之后,会返回到 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"srtp_err_status_replay_old=10","attrs":{}}],"attrs":{}},{"type":"text","text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"replay_list_index = index - windwo_start:在 ReplayList 中 replay_list_index 对应的标识位为 1,表示已经收到包,libsrtp 返回 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"srtp_err_status_replay_fail=9","attrs":{}}],"attrs":{}},{"type":"text","text":"。对应的标识位为 0,表示收到乱序包。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"加密和校验算法","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 SRTP 中,使用了 CTR(Counter mode)模式的 AES 加密算法,CTR 模式通过递增一个加密计数器以产生连续的密钥流,计数器可以是任意保证长时间不产生重复输出的密钥。根据计数方式的不同,分为以下两种类型:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"AES-ICM","attrs":{}}],"attrs":{}},{"type":"text","text":": ICM 模式(Integer Counter Mode,整数计数模式),使用整数计数运算。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"AES-GCM","attrs":{}}],"attrs":{}},{"type":"text","text":": GCM 模式(Galois Counter Mode,基于伽罗瓦域计数模式),计数运算定义在伽罗瓦域。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在 SRTP 中,使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"AES-ICM","attrs":{}}],"attrs":{}},{"type":"text","text":" 完成加密算法,同时使用 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"HMAC-SHA1","attrs":{}}],"attrs":{}},{"type":"text","text":" 完成 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"MAC","attrs":{}}],"attrs":{}},{"type":"text","text":" 计算,对数据进行完整性校验,加密和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"MAC","attrs":{}}],"attrs":{}},{"type":"text","text":" 计算需要分两步完成。","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"AES-GCM","attrs":{}}],"attrs":{}},{"type":"text","text":" 基于 AEAD(Authenticated-Encryption with Associated-Data,关联数据的认证加密)的思想,在对数据进行加密的同时计算 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"MAC","attrs":{}}],"attrs":{}},{"type":"text","text":" 值,实现了一个步骤,完成加密和校验信息的计算。下面分别对这个 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"AES-ICM","attrs":{}}],"attrs":{}},{"type":"text","text":" 和 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"AES_GSM","attrs":{}}],"attrs":{}},{"type":"text","text":" 的用法进行介绍。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"AEC—ICM","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/77/773d6277a7882449a615f5fedf216185.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上图描述了 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"AES-ICM","attrs":{}}],"attrs":{}},{"type":"text","text":" 的加密和解密过程,图中的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"K","attrs":{}}],"attrs":{}},{"type":"text","text":" 是通过 KDF 导出的 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"SessionKey","attrs":{}}],"attrs":{}},{"type":"text","text":"。加密和加密都是通过对 Counter 进行加密,与明文 P 异或运算得到加密数据 C,反之,与密文 C 异或运算得到明文数据 P。考虑到安全性,Counter 生成依赖于 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"Session Salt","attrs":{}}],"attrs":{}},{"type":"text","text":", 包的索引(packet index)和包的 SSRC。Counter 是 128-bits 的计数,生成方式如下定义:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"one byte\n\n0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15\n+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\n|00|00|00|00| SSRC | packet index | b_c |---+\n+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |\n |\n+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ v\n| salt (k_s) |00|00|->(+)\n+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |\n |\n v\n +-------------+\n encryption key (k_e) -> | AES encrypt |\n +-------------+\n |\n+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |\n| keystream block | B。当 K 长度大于 ","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"B","attrs":{}}],"attrs":{}},{"type":"text","text":" 时候,会先在 K 上面执行 hash 算法,将得到的 L 长度结果作为新的共享密钥。如果 K 的长度
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章