# SRTP 加密媒体 · SrtpSession 与 libsrtp

> 密钥就位，SRTP 开始加密每一个媒体包。这一章读 pc/srtp_session.h 与 srtp_transport.h:SrtpSession 如何封装 libsrtp、ProtectRtp/UnprotectRtp 就地加解密、SrtpTransport 怎么管 RTP 与 RTCP 两个会话，以及 rtcp-mux 如何省掉一个。

- 作者：David（道雾轩）
- 专栏：音视频与 WebRTC 详解（https://daiw.org/manual/webrtc.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/webrtc/srtp-encryption
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# SRTP 加密媒体 · SrtpSession 与 libsrtp

[密钥导出](https://daiw.org/manual/webrtc/dtls-srtp-key-export)完成，终于到了[安全模型](https://daiw.org/manual/webrtc/security-overview)的最后一环：**SRTP 真正加密每一个媒体包**。这活儿由 `SrtpSession` 干，它背后是业界标准库 libsrtp。这一章读它，收束「加密」这条线。

## SrtpSession：封装 libsrtp

`SrtpSession`（`pc/srtp_session.h`）不自己实现密码学，而是封装 Cisco 的 **libsrtp**(`g3doc/srtp.md`):

> The `SrtpSession` is providing encryption and decryption of SRTP packets using `libsrtp`.

<Callout type="info">
  **加解密的四个动词，就是 `SrtpSession` 的核心 API——而且都是「就地（in-place）」操作：**

  ```cpp
  // pc/srtp_session.h(节选)
  bool ProtectRtp(...);      // 加密一个 RTP 包(发送侧)
  bool ProtectRtcp(...);     // 加密一个 RTCP 包
  bool UnprotectRtp(...);    // 解密一个 RTP 包(接收侧)
  bool UnprotectRtcp(...);   // 解密一个 RTCP 包
  ```

  **就地**意味着：加解密**直接在包的缓冲区上进行**，不额外拷贝一份——对[每秒成百上千个媒体包](https://daiw.org/manual/webrtc/source-map)的实时系统，这点性能优化很实在。发送侧：[RTP 打包](https://daiw.org/manual/webrtc/source-map)好一个包 → `ProtectRtp` 就地加密 → [发出](https://daiw.org/manual/webrtc/p2p-transport-channel)。接收侧：[收到密文包](https://daiw.org/manual/webrtc/dtls-handshake) → `UnprotectRtp` 就地解密 → 交给 RTP 处理。密钥则由[上游的 `DtlsSrtpTransport`](https://daiw.org/manual/webrtc/dtls-srtp-key-export) 通过 `SetSend` / `SetReceive` 提前配好。
</Callout>

`SrtpSession` 还负责 libsrtp 的**初始化与去初始化**——它用引用计数追踪「当前有多少个实例在用 libsrtp」，最后一个走了才清理，避免重复 init/deinit（`g3doc/srtp.md`）。

## SRTP 保护了什么

SRTP 对一个 RTP 包做的，不只是「加密」：

- **机密性（加密）** —— 用 [AES](https://daiw.org/manual/webrtc/security-overview) 加密 RTP 的**负载**（媒体数据），链路上偷看只见密文。注意 RTP **头部通常不加密**（路由、[多路复用](https://daiw.org/manual/webrtc/dtls-handshake)要看头），但被认证保护。
- **完整性 + 认证（HMAC）** —— 给包附一个认证标签（如 HMAC-SHA1），接收方校验：包**没被篡改**、且**确实来自持有密钥的对端**。篡改一个比特，校验就失败，包被丢弃。
- **抗重放** —— SRTP 记住收过的序号，**重复的旧包**（攻击者录下来重发）会被识别并拒绝。

所以 SRTP 是「加密 + 认证 + 抗重放」三合一——[实时媒体安全](https://daiw.org/manual/webrtc/security-overview)需要的，它都给了。GCM [套件](https://daiw.org/manual/webrtc/security-overview)更是把加密和认证合成一步（AEAD），更高效。

## SrtpTransport：管两个会话

`SrtpSession` 处理单向的一类包，但一条媒体流有 **RTP** 和 **RTCP**（[第 4 部分](https://daiw.org/manual/webrtc/source-map)细讲 RTCP 是反馈信道）。管理它们的是 **`SrtpTransport`**（`pc/srtp_transport.h`，也是 [`DtlsSrtpTransport` 的基类](https://daiw.org/manual/webrtc/dtls-srtp-key-export)），`g3doc/srtp.md`：

> `SrtpTransport` is controlling the `SrtpSession` instances for RTP and RTCP.

正常要两个 `SrtpSession`（一个护 RTP、一个护 RTCP）。但——

<Callout type="info">
  **用了 rtcp-mux，就只需要一个 `SrtpSession`。** rtcp-mux（RFC 5761）让 **RTCP 和 RTP 复用同一个端口 / 传输**（又是 WebRTC [「一条路承载一切」](https://daiw.org/manual/webrtc/jsep-transport-controller)的体现）。`g3doc/srtp.md` 说明：「When rtcp-mux is used, the `SrtpSession` for RTCP is not needed.」——RTCP 既然和 RTP 走同一条加密流，自然共用同一个 SRTP 会话，省掉一个。现代 WebRTC 默认开 rtcp-mux，所以通常一条媒体一个 `SrtpSession` 足矣。
</Callout>

## 一张加密流水线图

把[整个第 3 部分](https://daiw.org/manual/webrtc/security-overview)串起来，发送一个媒体包的安全流水线：

```mermaid
flowchart LR
    ENC["编码 + RTP 打包(明文包)"] --> PROT["SrtpSession.ProtectRtp<br/>(libsrtp 就地加密 + 认证)"]
    PROT --> DEMUX["DTLS/SRTP 首字节多路复用"]
    DEMUX --> ICE["ICE 通路发出(密文)"]
    KEY["DtlsSrtpTransport 导出的密钥<br/>SetSend / SetReceive"] -.配置.-> PROT
```

## 小结与下一章

**SRTP 加密每个媒体包**，由 `SrtpSession`（`pc/srtp_session.h`）封装 **libsrtp** 实现：`ProtectRtp` / `UnprotectRtp`（及 RTCP 版）**就地加解密**，密钥由[上游 `DtlsSrtpTransport`](https://daiw.org/manual/webrtc/dtls-srtp-key-export) 配好。SRTP 提供**加密 + 认证（HMAC）+ 抗重放**三合一（GCM 套件用 AEAD 合并）。**`SrtpTransport`** 管 RTP 与 RTCP 两个会话，而 **rtcp-mux** 让二者复用、省掉一个。

加解密和握手都靠一个底层密码库——**BoringSSL**。下一章看 WebRTC 怎么接这个 SSL 库，以及 `OpenSSLStreamAdapter` 的角色。👉 [BoringSSL 集成](https://daiw.org/manual/webrtc/boringssl-integration)。

## 参考资料

- [1] libwebrtc 源码.`pc/srtp_session.h` / `.cc`（`ProtectRtp` / `UnprotectRtp`、libsrtp 封装）、`pc/srtp_transport.h`、`g3doc/srtp.md`。
- [2] libsrtp.https://github.com/cisco/libsrtp —— SRTP 参考实现。
- [3] IETF RFC 3711「SRTP」、RFC 5761「RTP/RTCP 复用」。
