首页 › deep-tech › 改一位密文,明文跟着翻

空口完整性保护原理:加密防偷看,防改靠另一道锁

一、只防偷看的锁,防不了撬棍

先讲一个快递的类比。你寄一沓现金,套了个不透明的信封——别人看不见里面是什么,这叫加密。但如果信封只是普通纸,路上有人可以小心拆开、抽出一张、再封回去,你收到时毫无察觉。防偷看和防拆改,是两个完全不同的问题,需要两把不同的锁。

移动通信的空口安全设计者对此有清醒的认识。整个空口安全体系其实有四道防线:双向认证(确认对方是真人)、身份隐私(不泄露真名)、机密性保护(加密防偷看)、完整性保护(防篡改防伪造)。前三道在本系列前几篇里已经拆解过,今天讲最容易被忽视、却在工程上出事最多的一道:完整性保护。

它是四道防线里最后补齐的一块拼图,也是最反直觉的一块——因为它要防的攻击,恰恰发生在加密开启之后。

二、反直觉的事实:加了密的包,是可以被改的

多数人的直觉是:包都加密了,攻击者连内容都看不懂,怎么改?这正是流密码最容易被误解的地方。

回忆一下空口加密的基本形态:发送方把明文 $P$ 和密钥流 $K$ 逐位异或,得到密文 $C$:

$$C = P \oplus K_{\text{流}}$$

攻击者确实既不知道 $P$ 也不知道 $K_{\text{流}}$。但异或运算有一个致命的代数性质:他不需要知道任何一个,只需要把密文的某一位取反,解密后的明文对应位就会同步取反:

$$C' = C \oplus \Delta \;\Longrightarrow\; P' = P \oplus \Delta$$

来推一遍:$P' = C' \oplus K_{\text{流}} = (C \oplus \Delta) \oplus K_{\text{流}} = (P \oplus K_{\text{流}}) \oplus \Delta = P \oplus \Delta$。明文的每一位都完好看不出来,唯独攻击者选中的那一位,像被人隔着玻璃按了一下开关。

这在工程上叫比特翻转攻击(bit-flipping)。空口上的很多关键字段并不需要看懂全文才值得改:切换指令里的目标小区频点、测量上报里的是否“该小区信号良好”的布尔位、甚至协议里任何“是/否”型的开关位——攻击者只要知道结构(协议是公开的),不需要知道内容,就能精准地按下那一个开关。

flowchart TD
    A["明文P:继续发送"] -->|"密钥流加密"| B["密文C"]
    B -->|"经空口传输"| C["攻击者翻转C中一位"]
    C -->|"得到新密文"| D["接收方正常解密"]
    D --> E["明文变成:立即中止"]
    E --> F["解密不报错,无人察觉"]

注意图里最关键的一点:解密过程不会报任何错。流密码和计数器模式这类“异或型”加密,天然没有自检能力——它只负责遮住内容,不负责保证内容没被动过。这不是某个制式选错了算法,而是“加密”这个动作在数学上根本不承担“防改”的职责。块密码的某些模式在特定条件下也有同样的软肋。所以安全设计里有一句行话:加密防的是 Eve 看,完整性防的是 Mallory 改——防的人和防的事都不一样,缺一不可。

三、完整性保护:给每个包盖一枚防伪章

解决思路在密码学里早有成熟答案:消息认证码(Message Authentication Code,MAC)。

类比是防伪章:你寄出的每一份文件,除了内容,还附一个用你私章盖出来的短编码。收件人手里有同一枚章,把文件内容重新盖一遍,两个编码对得上,说明文件没被改过。关键在于——编码是内容和私章共同决定的:内容改一个字,章就盖不出原来的编码;没有私章,攻击者改完内容后盖不出新编码。

空口上的做法是,发送方在加密之外,用一把专门的完整性密钥,把整条消息连同几个“上下文字段”一起送进认证算法,算出一个 32 位的标签 MAC-I,附在包后面发送。以产业里最常用的 AES-CMAC 家族为例,形式上就是:

$$\text{MAC-I} = \text{Trunc}{32}\Big(\text{CMAC}\big(\,MESSAGE \,\Vert\, COUNT \,\Vert\, DIR \,\Vert\, BEARER\,\big)\Big)$$}}

接收方收到后,用同一把密钥、同样的输入重算一遍,比对两个标签:一致则放行,不一致则静默丢弃。整个过程不需要解密参与——这就是为什么完整性保护和加密是两套独立机制。

这个公式里特意拼进消息的三个上下文字段,每一项都是一次血的教训换来的设计,值得逐个拆开看:

第一,必须纳入 COUNT(序列号)。 如果标签只依赖消息内容,那么同一个包发两遍,标签一模一样——攻击者截存一个合法旧包,原样重发一百遍,每一次校验都会通过。这就是重放攻击,防它的唯一办法是让“第 100 号包”和“第 101 号包”在密码学上可区分,所以序列号必须吃进标签计算里。

第二,必须纳入方向位(上行/下行)。 上下行共用同一把密钥,如果不区分方向,攻击者可以把网络下发给手机的信令包原样反射回网络,冒充手机的上行信令——这叫反射攻击。方向位一纳进来,下行盖章的包永远过不了上行的校验。

第三,必须纳入承载标识。 每个无线承载有独立计数,把 A 承载的合法包搬到 B 承载上重放,也会因为计数和承载号对不上而露馅。

flowchart TD
    S1["发送侧PDCP"] --> S2["拼入COUNT与方向位"]
    S2 --> S3["承载号一起纳入"]
    S3 --> S4["密钥算出32位标签"]
    S4 --> S5["密文后附标签发出"]
    S5 --> R1["接收侧PDCP收包"]
    R1 --> R2["取出标签并重算"]
    R2 --> R3{"两者一致?"}
    R3 -->|"一致"| R4["继续解密并上交"]
    R3 -->|"不一致"| R5["静默丢弃并计数"]

四、为什么只有 32 位:一场安全预算与空口开销的讨价还价

细心的读者会问:标签才 32 位,够吗?这恰好是空口工程里最有味道的一个折中。

先算安全账。攻击者想伪造一条有效信令,每猜一个标签,成功概率是 $2^{-32}$,平均要试 $2^{31}$ 次(约 21 亿次)。而且每一次“试”都不是本地计算,必须真枪实弹地向网络发一个包——次数太多、耗时太长,密钥早就随认证和切换轮换掉了。穷举在工程上不成立。

再算开销账。完整性保护是逐包执行的,标签随每个包在空口上传。标签越长,每个包的固定开销越大,对短小高频的信令包尤其奢侈。32 位标签带来的自然误判概率是 $2^{-32}$——也就是说,纯粹因为运气差,两个不同的输入算出同一个标签,接收方会错杀一个好包。在每秒成千上万个包的链路上,这个概率意味着极偶发的丢包,而链路层本来就有重传机制兜底。错杀一个好包的代价是重传,放过一个假包的代价是被劫持——把前者压到可忽略,把后者压到不可行,32 位就是这个平衡点。

维度 加密(机密性) 完整性保护
防什么 偷看内容 篡改、伪造、重放
手段 密钥流逐位异或 带密钥的 32 位标签
被攻破的后果 内容泄露 指令被改、会话被劫持
覆盖信令时 可关闭(空算法) 永远强制,不可关
覆盖用户面时 默认开启 视代际与策略,5G 起可选

表里最后一行值得单独强调:加密可以被法规或测试场景关闭,但信令完整性保护在任何商用网络里都不允许关闭。原因很直白——加密关掉,损失的是隐私;完整性关掉,伪基站就能伪造切换、伪造释放指令,损失的是网络的控制权。两件事的严重性不在一个量级上。

五、谁来盖章,用什么章

执行位置在协议栈的 PDCP 层——它同时负责加密、完整性保护、头压缩和重排序,是空口安全的总闸门。算法上,产业采用“三选一”的家族式设计,加密算法和完整性算法一一配对:

算法组 4G 名称 5G 名称 底层积木 定位
组一 EEA1 / NIA1 NEA1 / NIA1 SNOW 3G(流密码) 早期默认
组二 EEA2 / NIA2 NEA2 / NIA2 AES(计数器 / CMAC) 产业事实默认
组三 EEA3 / NIA3 NEA3 / NIA3 ZUC(祖冲之算法) 中国自主设计
空算法 EEA0 NEA0 不做该保护 测试与特殊场景

这套设计的聪明之处在于加密与完整性解耦:SNOW 3G 是流密码,长于高速加密;AES-CMAC 是分组密码改造的认证码,长于稳健认证;祖冲之算法(ZUC)以中国古代数学家命名,是标准家族里的后起之秀。终端和网络在建立安全时分别协商加密用哪把、完整性用哪把,两边互不绑定。

协商的过程本身,就是完整性保护“第一枪”打响的时刻,也藏着标准设计里一个精巧的鸡生蛋问题:要校验标签,先得有密钥和算法;而密钥和算法,恰恰是通过一条叫安全模式命令的信令下发的。答案是——这条下发命令自己,就是第一条被盖章的信令。密钥在认证阶段就已派生到位,安全模式命令发出时就带上了第一个 MAC-I。手机若验不出这个标签,说明对面不是真网络,立即拒绝。保护从第一条敏感信令开始,不存在裸奔的窗口期。

sequenceDiagram
    participant U as 手机
    participant B as 基站
    participant C as 核心网
    U->>C: 完成双向认证,密钥就位
    C->>B: 下发派生密钥与算法
    B->>U: 安全模式命令
    Note over B,U: 这条命令自带第一个标签
    U->>B: 校验通过,回复完成
    B->>C: 安全已激活
    Note over U,B: 此后所有信令强制盖章

六、防重放:一枚只进不退的计数器

前面说序列号必须纳入盖章,那序列号本身怎么管理?空口的答案是 PDCP 层的 COUNT:一个由高位超帧号和低位序号拼成的长计数器,每发一个包加一,只进不退。接收侧维护一个滑动接收窗口——因为现代调度、混合重传会让包乱序到达,窗口允许一定范围的乱序,但窗口之外的“旧包”一律判为重放丢弃。

flowchart TD
    A["合法包 COUNT=100"] --> B["被攻击者截存"]
    B --> C["稍后原样重发"]
    C --> D{"接收窗口已到120"}
    D -->|"计数过旧"| E["判为重放并丢弃"]
    F["新包 COUNT=101"] -->|"落在窗口内"| G["正常接收"]

注意这里的设计分工:防篡改靠标签,防重放靠计数。单靠加密或单靠标签内容都无法识别“一个内容完全合法的旧包”,只有那个单调递增、双方严格同步的计数器,才能给时间本身做证。而计数器不能无限涨——临近回绕时,标准要求必须先更换密钥,否则同一密钥流会被重用,加密和认证一起失效。这也是为什么切换和重建流程里,计数器的交接是安全上下文移交的核心内容。

七、5G 补上的一课:用户面也盖章了

4G 时代有一个长期的“留白”:完整性保护只覆盖信令,用户面数据只加密、不盖章。为什么当年不做?三个现实约束:一是逐包认证的算力开销,在当时的芯片上对峰值速率影响明显;二是实时语音对时延极敏感,标签计算和校验是纯增加的处理环节;三是当年的用户面业务以智能手机为主,端到端加密(如网页的传输层安全)已经覆盖了大头。

5G 为什么补上了?因为前提变了。5G 的主要增量市场是行业专网——工厂机械臂、电网差动保护、远程吊车,这些终端和业务未必自带端到端加密,而它们恰恰是被篡改后果最严重的场景。同时芯片算力富余了,逐包认证的代价可以承受。于是 5G 首次把完整性保护扩展到用户面,由网络按策略逐承载开启。当然,折中仍在:实时语音类承载依旧豁免,可保护的速率也设有上限——盖章是安全税,实时流付不起这个时延税。

4G 5G
信令完整性保护 强制 强制
用户面完整性保护 无此功能 可选,按承载策略开启
实时语音 不涉及 豁免
补齐动机 算力与时延顾虑 行业专网篡改风险真实化

八、现网里它长什么样:工程师的实战视角

陷阱一:安全模式命令失败,注册卡死。 终端能力上报里会声明自己支持哪些算法组,网络据此选择。若网络选了终端不支持的组合,或加密与完整性算法协商不一致,安全模式命令会被拒绝,表现为注册失败、反复重试或掉话。排查时先对齐两端的能力清单,而不是急着换卡换机。

陷阱二:抓包看不到标签,不等于没保护。 空口信令在安全激活前是明文,抓得到、看得懂;激活后密文和标签对协议分析器同样不可读。新手常把“解不出来”误解为“这条链路没加密”——判断安全是否激活,看的是安全模式命令这条信令有没有成功,而不是密文能不能读懂。

陷阱三:计数器失步,完整性校验全军覆没。 收发两端 COUNT 对不上位时,每一个包的标签都验不过,表现为信令无线承载突然全断、触发重建甚至掉话。这类问题往往指向切换/重建过程中计数器交接的异常,是 PDCP 层疑难杂症里的一大类。

误解一:“开了完整性保护,性能必然大跌。” 对信令而言,包小量少,开销可忽略;对用户面,5G 有速率上限和豁免规则兜底,运营上按切片策略精细化开启,不会一刀切。

误解二:“业务自带端到端加密,空口完整性就是多余的。” 分层防御的逻辑在这里同样成立:端到端加密保护的是业务内容,空口完整性保护的是无线段上的一切包——包括不经业务层加密的信令、状态上报和控制面交互。伪基站攻击打的从来不是你的业务,是你的信令。

九、结语:四道防线的最后一块拼图

回头看空口安全的完整拼图:认证确认“你是谁”,身份隐私藏起“你的名字”,加密挡住“偷看的眼睛”,而完整性保护拦下“撬棍的手”。它建立在一个朴素的洞察之上——看得见不等于看得懂,看得懂不等于改不了。异或加密的代数性质决定了防偷看与防篡改必须分家,32 位标签是安全预算与空口开销的精确妥协,单调递增的计数器给时间本身做了证。

对工程师来说,记住一个判断标准就够了:这条链路上,加密关闭是隐私问题,完整性关闭是控制权问题。前者可以商量,后者没有商量。

常见问题

Q: 加密和完整性保护能不能只开一个? A: 可以,两者在设计上完全独立。信令的完整性保护永远强制;加密可以选空算法关闭(测试或特殊场景)。反过来则不成立——不能“只加密不盖章”,因为加密防不了比特翻转。5G 用户面完整性是可选特性,按承载策略开启。

Q: 标签只有 32 位,攻击者暴力试错行不行? A: 单次伪造成功概率是 $2^{-32}$,平均约 21 亿次尝试,且每次都必须真实发包而非本地计算;密钥又会随认证和切换周期性轮换,穷举远未完成密钥已换。而 $2^{-32}$ 的自然误判率对应极偶发的错杀好包,由链路重传兜底。这是刻意的工程折中。

Q: 为什么实时语音不用用户面完整性保护? A: 完整性保护是逐包计算、逐包校验的串行环节,给每个包增加处理时延;实时语音宁可丢包也不能迟到(见本系列“宁丢不迟”一篇),付不起这个时延税。标准为此把语音类实时承载豁免,并为可保护的速率设上限。

Q: 重放攻击现实中怎么发生,靠什么防住? A: 典型场景是攻击者在无线环境里截存合法包,稍后原样重注——包的内容和标签都完全合法,只有“时间”是伪造的。防线就是 PDCP 计数器:每包只进不退,接收窗口之外的旧包直接丢弃,旧包配旧标签也过不了关。

Q: 完整性校验失败会发生什么,该往哪个方向查? A: 接收侧静默丢弃该包,持续失败会导致信令无线承载失效、触发重建乃至掉话。排查优先级:先看收发两端计数器是否失步(尤其切换/重建后),再核对两端算法协商结果,最后排查密钥派生链路。计数器问题是大头。

参考来源

  1. SNOW 3G - Wikipedia — 4G/5G 算法家族组一流密码的原始设计,EEA1/NIA1 的底层积木
  2. ZUC (cipher) - Wikipedia — 祖冲之算法的设计背景及其在移动通信加密与完整性保护中的应用
  3. One-key MAC (OMAC1 / AES-CMAC) - Wikipedia — AES-CMAC 认证码的算法原理,NIA2 的核心积木
  4. ShareTechnote: NR PDCP — PDCP 层完整性与计数器机制的工程视角图解
  5. 威廉·斯托林斯《密码编码学与网络安全:原理与实践》— 消息认证码与重放防护的经典教材章节

本文由「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学通信知识星球海报-扫码加入