Browsed by
Tag: openssl

DTLS-SRTP

DTLS-SRTP

DTLS-SRTP 开发工作主要基于两点考虑:(1)后续和 webRTC 对接时,无论是 Chrome 还是 Firefox,都要求采用 DTLS-SRTP 传输媒体;(2)在企业通信领域,如果用户不部署「SIP over TLS」, SRTP 加密用的 key 和 salt 在 SIP 消息中明文传输,有可能被有心人士拦截,从而破解 SRTP 流。

与 webRTC 对接还有很多繁琐的细节需要处理,以后再另外讨论。

对于企业通信中可能存在的拦截破解问题,目前通用的解决方法就是部署 DTLS-SRTP。DTLS-SRTP 不再通过 SIP 会话消息传递 key 和 salt,而是在 SRTP 建立之时双方 RTP 端点先进行 DTLS 协商,双方交换证书和密钥,进而加密、解密出 key 和 salt。具体步骤如下图所示:

DTLS-SRTP 流程
DTLS-SRTP 流程

SIP 消息中有两处需要注意:

(1)fingerprint 参数,指示了各自证书的 fingerprint。双方在 DTLS 协商时以此验证证书的有效性。篡改 fingerprint 或者拦截证书,都会导致 DTLS 协商失败。

(2)setup 参数,指示 RTP 端点在 DTLS 协商过程中的角色。DTLS 协商明确要求一方是 client(即协商的发起方),另一方是 server,具体细节请参考 RFC5763

在 DTLS 协商过程中随机生成 key 和 salt,完成协商后 RTP 端点从结果中提取出双方的 key 和 salt,对 RTP 流加密和解密,也就是后续 SRTP 流的处理。

计算 IV

计算 IV

在 SRTP 对负荷进行加密(或者解密)时需要先计算 IV (Initialization vector, 初始化向量),RFC3711定义了该值的计算方法:

IV = (k_s * 2^16) XOR (SSRC * 2^64) XOR (i * 2^16)

看起来似乎很普通、也很容易理解,无非就是三个参数的异或计算:(1)k_s,(2)SSRC 以及(3)i。

IV 是 16 字节的数据流;k_s 是 session salt(大小14字节),要求左移2字节;SSRC 是 RTP 中的源标识参数,要求左移8字节。

i 参数有点特殊,定义为「包索引」,它是 48 比特的值,规范中定义如下:

i = 2^16 * ROC + SEQ.

ROC 是 rollover counter, RTP 包中没有这个参数,需要根据 SEQ 的值来判断是否需要设置 ROC。这里提一下, RTP 协议非常山炮地用 2 字节定义 SEQ 值,可想而知它完全不够用。因此应用层不得不自己计算ROC值,组合 ROC 值和 SEQ 值 才能完整判断 RTP 包的真实序列号。

组合出三个 16 字节的数据流后,异或计算得出 IV 值,请参考以下图表示意:

IV 异或计算

从图中也可以看出,IV 虽然有 16 个字节,但是实际上最后两个字节根本没用,因此默认设置为 0 即可。

roc + seq 的设置可以取巧一下。虽然完整定义是 48-bits,但用32-bits也足够了(考虑到 VoIP 对话中一般 20ms 一个包,序列号要溢出32bits的值需要超过990天)。而简化成 32-bits 的最大好处就是直接调用 C 函数(htonl)进行网络字节序转换即可,只需要填充第10个字节到第13个字节。

SSRC 是 32-bits 整数,因此也需要转换成网络字节序;而 session salt 本身是 14 字节的数据流,无需转换字节序。