<!-- title: 5G切换密钥链KNgRAN*水平与垂直派生拆解 -->
<!-- domain: security -->

# 5G 切换密钥链 KNgRAN\* 水平与垂直派生机制全链拆解

> 本文聚焦 3GPP TS 33.501 §6.9《Security handling in mobility》中最容易被忽视、却直接决定前向安全（forward security）是否成立的子机制——**NG-RAN 切换时的接入层（AS）密钥再派生**。我们将逐条拆解 NH 链、NCC 计数器、水平（Horizontal）与垂直（Vertical）派生，并落到 Xn/N2 两条切换信令路径上的密钥交付。

---

## 一、为什么切换时必须"换钥匙"

主认证完成时，UE 与核心网共享的只是 NAS 层密钥 `KAMF`，而空口上的 RRC 加密/完整性、用户面加密用的是 **AS 层密钥 `KgNB`（也称 `KNgRAN`）**。`KgNB` 由 `KAMF` 派生后，下发到 UE 当前驻留的那一个 gNB。

问题随之而来：**UE 每发生一次切换，密钥就从源 gNB 流向目标 gNB**。如果每次切换都用"同一个 `KgNB`"或者用源 gNB 能预测的方式生成新密钥，那么一个被攻破的源 gNB 就能推算出此后所有目标 gNB 的密钥——这叫**前向安全被打破**。

3GPP 的解法是设计一条"单向派生链"：每跳切换都产生一个新的 `KgNB*`，并且通过 NH（Next Hop）链保证**已离开的 gNB 无法推算未来的密钥**。TS 33.501 §6.9.2.1 把这套机制定义在 AS 安全上下文里，是我们今天的主角。

---

## 二、5G AS 密钥层级回顾（先理清家谱）

在进入切换密钥之前，必须先看清整条密钥树的根与枝。所有派生都基于 TS 33.220 Annex B.2 定义的 **HMAC-SHA256 KDF**：`KDF(Key, S) = HMAC-SHA256(Key, FC ‖ P0‖L0 ‖ P1‖L1 ‖ …)`。

```mermaid
flowchart TD
    K["永久密钥 K<br/>(USIM / UDM)"] --> AKA["主认证 5G AKA / EAP-AKA'"]
    AKA --> KAUSF["KAUSF"]
    KAUSF --> KSEAF["KSEAF"]
    KSEAF --> KAMF["KAMF<br/>(NAS 级, AMF 持有)"]
    KAMF -->|"Annex A.6  FC=0x6E<br/>AccessType ‖ SUPI"| KgNB["KgNB / KNgRAN<br/>(NCC = 0, 锚点)"]
    KAMF -->|"Annex A.7  FC=0x6F<br/>SYNC"| NH["NH 链 NH₁ .. NHₙ<br/>(NCC = 1 .. n)"]
    KgNB -->|水平派生| KH["KgNB*<sub>水平</sub><br/>= KDF(KgNB, PCI, ARFCN-DL, SSB-off)"]
    NH -->|垂直派生| KV["KgNB*<sub>垂直</sub><br/>= KDF(NH[n], PCI, ARFCN-DL, SSB-off)"]
    KH --> AS["目标 gNB 新 KgNB<br/>→ K<sub>RRCenc/int</sub>, K<sub>UPenc/int</sub>, K<sub>MAC</sub>"]
    KV --> AS
```

要点：`KgNB` 与 `NH` 是**并列的两条派生支**，都以 `KAMF` 为根。`KgNB` 自身对应 NCC=0，是水平派生的锚；`NH` 链对应 NCC=1,2,…，是垂直派生的素材。

---

## 三、NH 链与 NCC 计数器：前向安全的核心齿轮

### 3.1 NCC 是什么

NCC（Next hop Chaining Count）是一个计数器，记录 NH 链被推进了多少次。它的真正作用是**让 UE 和网络对一个"用过的密钥"达成共识**：

- NCC=0：表示当前 `KgNB` 是初始锚点（来自 `KAMF` 直派生），尚未使用任何 NH。
- NCC=n（n≥1）：表示当前 AS 密钥是用第 n 个 NH 经垂直派生得到的。

UE 侧也维护一个 NH 数组与 NCC 指针。当收到切换命令中的 NCC 时，UE 用该 NCC 决定用"水平锚"还是"第 n 个 NH"去派生 `KgNB*`。**UE 与目标 gNB 必须用相同的 NCC，否则 SRB1 的第一条 `RRCReconfigurationComplete` 就会因完整性校验失败而丢弃。**

### 3.2 NH 如何被推进

NH 链是一条由 AMF 维护的**单向哈希链**（TS 33.501 §6.9.2.1.1）：

- 第一个 NH（NCC=1）由 AMF 用 `KAMF` 作为 KDF 密钥、用一个同步输入派生；
- 后续每个 NH 都由前一个 NH 派生，密钥始终是 `KAMF`；
- 链的单向性保证了：拿到 `NH[n]` 也无法反推 `NH[n-1]`，更无法前推 `NH[n+1]`（因为推进需要 `KAMF`，而 `KAMF` 从不下发给 gNB）。

```mermaid
flowchart LR
    KAMF["KAMF (仅 AMF/UE 知晓)"] --> D0["派生 KgNB, NCC=0"]
    KAMF --> D1["NH₁, NCC=1"]
    D1 --> D2["NH₂, NCC=2"]
    D2 --> D3["NH₃, NCC=3"]
    D3 --> Dn["NHₙ, NCC=n ..."]
    style KAMF fill:#ffe4e1
```

注意一个关键的"投放窗口"：AMF 不会一次性把整条 NH 链发给 gNB。它只在**初始上下文建立**和**每次 N2 切换 / Path Switch 成功**时，把"下一个可用的 NH + 它的 NCC"投递给当前服务 gNB。这意味着 gNB 手里的 NH 是"配额制"的——这正是下一节前向安全漏洞的来源。

---

## 四、水平 vs 垂直派生：一字之差，安全天壤

TS 33.501 §6.9.2.3.2 规定了源 gNB 在 Xn 切换时的**派生方式选择规则**：

> 若源 gNB 当前 NCC 已等于其持有的"最高可用 NH 的 NCC"（即没有更新的 NH 在手），执行**水平派生**；否则执行**垂直派生**。

直观理解：**手里有没用过的 NH 就用 NH（垂直），没有就只能在自己 `KgNB` 上接着磨（水平）。**

```mermaid
flowchart TD
    S(["源 gNB 决定切换"]) --> Q{"当前 NCC < 已持有 NH 的 NCC?<br/>(还有没用的 NH)"}
    Q -->|是| V["垂直派生 VERTICAL"]
    Q -->|否| H["水平派生 HORIZONTAL"]
    V --> V1["KgNB* = KDF(NH[n], PCI, ARFCN-DL, SSB-off)"]
    V1 --> V2["NCC 置为 n<br/>提供完整前向安全"]
    H --> H1["KgNB* = KDF(KgNB, PCI, ARFCN-DL, SSB-off)"]
    H1 --> H2["NCC 不变<br/>仅一跳前向安全"]
    V2 --> F(["派生目标 AS 算法密钥"])
    H2 --> F
```

### 4.1 KDF 输入参数剖析（Annex A）

`KgNB*` 的派生函数（对应 LTE TS 33.401 的 `KeNB*` 派生）输入参数如下表。**请注意 5G NR 相较 LTE 新增了第三个输入 P2——SSB 子载波偏移**，这是 NR 灵活参数集下的必要扩展：在 NR 中，PCI + 下行频点在某些部署下不足以唯一锚定一个 SSB，必须再绑定 SSB 相对 Point A 的子载波偏移，否则会出现"两小区复用同一密钥"的歧义。

| 输入参数 | 含义 | 长度 | 来源 / 说明 |
|---------|------|------|------------|
| KEY（密钥输入） | 派生用的根密钥 | 256 bit | 水平=`KgNB`；垂直=`NH[n]` |
| FC | 函数码（区分用途） | 1 octet | 见 TS 33.501 Annex A |
| P0 | 目标小区 PCI | 2 octet | Physical Cell ID，绑定目标物理小区 |
| P1 | 目标下行载频 ARFCN-DL | 2 octet | 绑定目标频点 |
| P2 | SSB subcarrier offset | — | **5G NR 新增**，绑定 SSB 频率位置 |

> 对照：LTE（TS 33.401）`KeNB*` 派生只有 PCI + EARFCN-DL 两个输入，FC=0x19；5G 增补 P2，并把体系搬到 TS 33.501 Annex A 与 §6.9.2。`KAMF→KgNB`（FC=0x6E）和 `NH` 派生（FC=0x6F）是另外两个独立 KDF。

### 4.2 两种派生的对比

| 维度 | 水平派生 Horizontal | 垂直派生 Vertical |
|------|--------------------|-------------------|
| 密钥输入 | 当前 `KgNB` | `NH[n]` |
| 前向安全 | ❌ 仅"一跳"——源 gNB 仍可推算下一跳 | ✅ 完整——源 gNB 不知未来 NH |
| 谁负责选择 | 源 gNB（Xn）/ AMF（N2） | 同左 |
| NCC 变化 | 不变 | +1 |
| 触发条件 | 手里没有更新 NH | 手里有未用 NH |
| 被攻破风险 | 源 gNB 被攻破→后续链失守 | 即使源 gNB 被攻破也安全 |

---

## 五、Xn 切换密钥派生全链时序

Xn 切换是 gNB 间直接完成、**不经过 AMF 参与密钥派生决策**的路径，因此 NH 的"配额"问题在这里最为突出。

```mermaid
sequenceDiagram
    participant UE
    participant SgNB as 源gNB (持 KgNB, NCC=n)
    participant TgNB as 目标gNB
    participant AMF
    Note over UE,AMF: 初始: AMF 已下发 KgNB(NCC=0) + 若干 NH(NCC=1..k)
    SgNB->>SgNB: 判定 H/V: 是否还有未用 NH?
    SgNB->>TgNB: XnAP Handover Request (含 KgNB*, NCC)
    Note over SgNB,TgNB: 水平: KgNB*=KDF(KgNB,PCI,ARFCN,SSBoff)<br/>垂直: KgNB*=KDF(NH[n],PCI,ARFCN,SSBoff)
    TgNB->>SgNB: XnAP Handover Request Acknowledge
    SgNB->>UE: RRCReconfiguration (含 NCC, 目标 PCI/SSB-offset)
    UE->>UE: 按 NCC 派生同一 KgNB*
    UE->>TgNB: RRCReconfigurationComplete (SRB1 受新密钥完整性保护)
    TgNB->>AMF: NGAP Path Switch Request (上报当前 NCC)
    AMF->>AMF: 若 NCC 接近耗尽, 推进 NH 链, 生成新 NH
    AMF->>TgNB: Path Switch Request Acknowledge (含下一可用 NH, NCC+1)
```

**关键信令单元逐条解析：**

1. **XnAP Handover Request**：源 gNB 把算好的 `KgNB*` 和对应 NCC 直接传给目标 gNB。注意：这条消息里传的是**已经派生完成**的密钥，而不是 NH——因为 AMF 不在场，源 gNB 不能把 `KAMF` 或 NH 链递交给目标。
2. **RRCReconfiguration（切换命令）**：源 gNB 必须在发给 UE 的切换命令里携带**新 NCC**以及目标 PCI、ARFCN、SSB-offset。UE 据此判定该走水平还是垂直、用第几个 NH，并在本地算出与目标 gNB 完全相同的 `KgNB*`。
3. **Path Switch Request**：这是 NH 链的"补货窗口"。目标 gNB 上报当前 NCC，AMF 判断是否需要推进 NH 链。如果连续 Xn 切换把 NH 配额耗尽，正是这一步让 AMF 把新的 NH 重新投回 gNB，恢复垂直派生能力。

---

## 六、N2（NGAP）切换：天然带前向安全的路径

N2 切换由 AMF 居中转发，密钥派生决策回到 AMF 手中。AMF 持有 `KAMF` 和整条 NH 链，因此**N2 切换强制走垂直派生**，前向安全由 AMF 的信任级别兜底。

```mermaid
sequenceDiagram
    participant UE
    participant SgNB as 源gNB
    participant AMF
    participant TgNB as 目标gNB
    SgNB->>AMF: NGAP Handover Required (含 NCC_current)
    AMF->>AMF: 推进 NH 链取下一 NH (NCC+1)<br/>KgNB*=KDF(NH, PCI, ARFCN-DL, SSB-off) [垂直]
    AMF->>TgNB: NGAP Handover Request (含 KgNB*, NCC)
    TgNB->>AMF: NGAP Handover Request Acknowledge
    AMF->>SgNB: NGAP Handover Command (含给 UE 的 NCC)
    SgNB->>UE: RRCReconfiguration (含 NCC)
    UE->>TgNB: 完成切换, 派生同一 KgNB*
```

差异要点：N2 路径里源 gNB **永远不知道**目标 gNB 的 `KgNB*`，这是它与 Xn 路径的根本安全差别。代价是多一次 AMF 往返时延，所以高速移动/密集小区场景仍优先 Xn。

---

## 七、前向安全何时"破"：Xn 链的已知隐患

Linköping 大学与 ETH Zürich 的形式化分析（WISEC'21、SECRYPT'23）揭示了一个标准本身允许、但实现须警惕的窗口：**当 gNB 手里的 NH 配额耗尽、又来不及通过 Path Switch 补货时，连续的 Xn 切换会强制退化为水平派生链**。此时若某一跳的源 gNB 被攻破（如伪基站/被入侵的 gNB），攻击者即可推算该跳之后所有水平派生的 `KgNB*`，前向安全在链上彻底失效。

```mermaid
flowchart TD
    A["正常: 垂直派生链<br/>NCC=1,2,3..."] --> B{"NH 配额耗尽?"}
    B -->|否| A
    B -->|是, PathSwitch 未及时补货| C["退化为水平链<br/>KgNB → KgNB* → KgNB** ..."]
    C --> D["某跳源 gNB 被攻破"]
    D --> E["攻击者推算后续所有 KgNB*<br/>前向安全失效 ❌"]
    E --> F["缓解: AMF 主动预投多 NH<br/>或缩短 PathSwitch 补货周期"]
```

工程缓解：让 AMF 在初始上下文建立和每次 Path Switch 时**一次预投多个 NH**（而非单个），把垂直派生的"续航里程"拉长；或在 NG-RAN 配置上限制连续 Xn 跳数，超出则强制走 N2。

---

## 八、抓包识别与常见故障排查

### 8.1 抓包里如何看到这套机制

在 NGAP/XnAP/5G-RRC 抓包中，关键识别点：

- **NGAP Initial Context Setup Request** → 携带 `Security Key`（即 `KgNB`，NCC=0），标志着 NH 链起点。
- **NGAP Path Switch Request Acknowledge** → 携带 `New Security Key Indication` / 下一个 `NH`，是补货证据。
- **XnAP Handover Request** → 内含 `UESecurityCapabilities` 与安全上下文，但**密钥本身经 NDS/IP（TLS）保护**，明文抓包看不到 `KgNB*` 字节，只能靠 NCC 字段与流程时序推断。
- **RRCReconfiguration（切换命令）** → `reconfigurationWithSync` 中的目标 PCI、ARFCN、SSB-offset；NCC 通常体现在 AS 安全上下文相关字段。

### 8.2 典型故障点

| 现象 | 可能根因 | 排错方向 |
|------|---------|---------|
| UE 切换后 SRB1 第一条消息完整性失败、立即触发 RRC 重建 | UE 与目标 gNB NCC 不一致，或 SSB-offset 输入不匹配 | 核对切换命令里的 NCC/SSB-offset；检查 gNB 派生实现是否遗漏 P2 |
| 频繁水平派生、安全审计告警 | AMF 投递 NH 配额不足、Path Switch 过频失败 | 检查 AMF NH 链推进逻辑与预投策略 |
| Xn 切换成功但 N2 切换失败 | AMF 推进 NH 链时 NCC 计算与 UE 不同步 | 比对 AMF/UE 维护的 NCC 指针 |
| 跨 SA/NSA、NR↔E-UTRA 切换后密钥错乱 | KeNB↔KgNB 桥接（N26/inter-RAT）的密钥映射函数用错 | 检查 TS 33.501 §6.9.3 inter-RAT 密钥派生 |

---
## 十、常见问题

**Q1：水平派生和垂直派生到底差在哪？**
A：差在"派生用谁的密钥"。水平用源 gNB 自己的 `KgNB` 继续 KDF，源 gNB 能预测结果，所以被攻破后危及下一跳；垂直用 AMF 投递的 `NH`，源 gNB 不知道未来 NH，被攻破也无害。安全强度上垂直 ≫ 水平。

**Q2：NCC=0 意味着什么？为什么初始就是 0？**
A：NCC=0 表示当前 AS 密钥是 `KAMF` 直接派生的初始 `KgNB`，尚未消耗任何 NH。把它定为 0 是为了与"水平锚点"语义统一——只要 NCC 没动，就说明走的是水平路径。

**Q3：Xn 切换为什么会出现前向安全被打破？标准不是已经设计了 NH 链吗？**
A：标准设计了 NH 链，但**没有强制 gNB 在每跳都用垂直派生**。当 gNB 手里 NH 配额耗尽、Path Switch 又没及时补货时，§6.9.2.3.2 允许它退化为水平派生以维持切换可用性。这是"可用性优先于安全"的工程权衡，也正是形式化分析批评的焦点。

**Q4：UE 怎么知道该用第几个 NH？**
A：靠切换命令（`RRCReconfiguration`）里携带的 NCC。UE 本地维护 NH 数组，收到 NCC 后取对应 NH（若 NCC 未变则用水平锚），再配合目标 PCI/ARFCN/SSB-offset 派生出与目标 gNB 一致的 `KgNB*`。

**Q5：N2 切换会退化成水平派生吗？**
A：正常情况下不会。N2 切换由 AMF 居中，AMF 总能用自己掌握的 `KAMF` 推进 NH 链、取下一 NH 做垂直派生并把 `KgNB*` 下发目标。除非 AMF 实现有缺陷，否则 N2 路径天然具备完整前向安全，这也是安全敏感场景倾向 N2 的原因。

---

## 参考来源

1. [3GPP TS 33.501 V18.10.0 — Security architecture and procedures for the 5G System](https://www.etsi.org/deliver/etsi_ts/133500_133599/133501/18.10.00_60/ts_133501v181000p.pdf) — §6.9 Security handling in mobility（§6.9.2.1.1 NH/NCC、§6.9.2.2 N2 切换、§6.9.2.3.2 Xn 切换）、Annex A.6/A.7 密钥派生
2. [TS 33.501 §6.9.2.3.2 — Xn-handover（iTecSpec 解读）](https://itecspec.com/3gpp/33.501/s/6.9.2.3.2) — 水平/垂直派生选择规则原文
3. [5G Handover: When Forward Security Breaks（LiU, SECRYPT 2023）](https://www.ida.liu.se/labs/rtslab/publications/2023/SECRYPT_2023.pdf) — Xn 切换 NH 配额耗尽导致前向安全退化的形式化证明
4. [A Comprehensive Formal Analysis of 5G Handover（ETH Zürich, WISEC 2021）](https://people.inf.ethz.ch/rsasse/pub/5G-handover-WISEC21.pdf) — 水平 vs 垂直派生的安全属性对比
5. [NH (Next Hop key) — 3GPP Glossary（3GPP Explorer）](https://3gpp-explorer.com/glossary/nh/) — NH 链与 NCC 计数器的概念释义

---
> 本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵**爱卫生**（微信ID: gprshome201101）维护，聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。
> 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
