ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

第 9 章 密码学基础与白盒密码

第 9 章 密码学基础与白盒密码

所属:第三篇 高级保护技术

本章导读

这章先补充必要的密码学基础知识(对称加密、AES 是什么),然后讲一个特殊问题:正常加密是"把东西锁进保险箱,钥匙藏好",但如果攻击者能看到你打开保险箱的整个过程呢?白盒密码就是解决这个问题的——在攻击者能看到全部执行过程的情况下,仍然保护密钥不被提取。

本章结构:首先(9.1)讲密码学三大支柱——对称加密、非对称加密、哈希函数,并深入讲解 AES 算法的内部结构;然后(9.2)进入白盒密码学,解释为什么传统加密在客户端环境下会失效,以及白盒方案如何应对;接着介绍针对白盒方案的攻击方法和防御演进;最后(9.3--9.4)给出其他白盒密码原语和工程实践建议。

本章知识定位

本章整体偏理论支撑:对称/非对称密码学原理、AES 内部结构、GF(2^8) 数学细节(9.1)是帮助你看懂"这段代码为什么长这样"的数学背景,日常工作中你很少需要手推 GF(2^8) 乘法或密钥扩展算法,但需要能一眼认出"这是 AES 实现"。少量内容属于实践应用:在二进制中识别白盒密码的查找表化特征(9.2.1-9.2.2)、判断某个二进制是否值得发起 DCA/DFA 攻击以提取密钥(9.2.3)、在工程决策中选择是否使用白盒方案(9.4)——这些是需要直接动手判断或操作的内容;而 DCA/DFA 攻击背后的统计学/密码学原理,仍属于理论支撑。


9.0 为什么混淆工程师需要理解密码学

知识定位:本节属于理论支撑。它说明的是密码学与混淆的关系框架,帮助你建立"为什么要学这章"的动机认知,不涉及具体操作。

密码学和代码混淆看似不同领域,实际上深度交织:

  • 白盒密码学直接将密码算法变换为混淆形式——理解密码学原理是理解白盒方案的前提
  • 字符串加密、常量编码等数据混淆技术的实现质量取决于对加密原语的正确使用
  • 对称加密用于保护代码段和数据段——so(Shared Object,共享对象/动态链接库)加固、DEX(Dalvik Executable,Dalvik 可执行格式)加密的核心就是加密算法
  • 哈希函数用于代码完整性校验——反篡改系统的基石
  • 非对称密码用于 License 验证和代码签名——最常被逆向攻击的目标之一

本章先从密码学基础讲起,确保你理解每个概念的底层原理,然后深入白盒密码学这个将密码学与混淆直接结合的领域。


9.1 密码学基础

知识定位:本节属于理论支撑。对称/非对称加密的数学模型、AES 的轮函数与 GF(2^8) 运算、HMAC 构造,都是帮助你理解"密码学原语为什么这样设计"的背景知识。日常工作中你更多是识别"这是 AES/RSA/HMAC"并应用现成结论,而不需要亲手推导 S-Box 的仿射变换或 GF(2^8) 乘法表。

9.1.1 密码学的三大支柱

现代密码学建立在三大基础原语之上 [2]:

原语目标核心问题典型算法
对称加密保密性同一把钥匙加密和解密AES(Advanced Encryption Standard,高级加密标准)、ChaCha20、SM4(中国国家密码标准分组密码算法)
非对称加密密钥分发 + 数字签名公钥加密、私钥解密(反之亦然)RSA(Rivest-Shamir-Adleman 公钥密码算法)、ECDSA(Elliptic Curve Digital Signature Algorithm,椭圆曲线数字签名算法)、Ed25519
哈希函数完整性任意长度输入 → 固定长度输出,不可逆SHA-256、BLAKE3、SM3
对称加密:一把钥匙的世界

对称加密是最古老也是最基本的加密形式。核心模型:

明文(P) + 密钥(K) → 加密算法(E) → 密文(C) 密文(C) + 密钥(K) → 解密算法(D) → 明文(P) 数学表示: C = E_K(P) P = D_K(C) D_K(E_K(P)) = P (正确性)

安全性要求: -CPA(Chosen Plaintext Attack,选择明文攻击)安全:攻击者即使能选择任意明文并获得对应密文,也无法区分两个等长明文的加密结果——这是现代对称加密的基本安全标准 -密钥空间足够大:AES-128 的密钥空间为 2^128 ≈ 3.4 × 10^38,暴力搜索不可行 -无统计特征泄漏:密文应该与随机序列不可区分

分组密码 vs 流密码:

维度分组密码 (Block Cipher)流密码 (Stream Cipher)
处理单位固定长度块(如 128 bit)逐字节/逐位
状态无状态(每块独立加密)有状态(密钥流依赖前序状态)
代表AES、SM4、DES(Data Encryption Standard,数据加密标准,已废弃)ChaCha20、RC4(已废弃)
性能硬件加速后极快(AES-NI)软件实现通常更快
混淆场景字符串加密、so 段加密大数据流加密、通信保护
非对称加密:两把钥匙的突破

1976 年 Diffie 和 Hellman 提出公钥密码学概念,解决了对称加密的核心难题——密钥分发问题。

密钥对生成:(公钥 PK, 私钥 SK) = KeyGen(安全参数) 加密方向(保密): 明文 + 公钥 PK → 密文 密文 + 私钥 SK → 明文 签名方向(认证): 消息 + 私钥 SK → 签名 消息 + 签名 + 公钥 PK → 验证通过/失败

数学困难问题——非对称密码的安全性建立在特定数学问题的计算困难性之上:

困难问题描述基于此的算法密钥长度建议
大整数分解给定 N = p × q(p, q 为大素数),求 p, qRSA≥2048 bit
离散对数给定 g, h = g^x mod p,求 xDiffie-Hellman、DSA≥2048 bit
椭圆曲线离散对数给定点 G, Q = xG(椭圆曲线上),求标量 xECDSA、ECDH、Ed25519≥256 bit
格问题最短向量问题 (SVP)、学习附带误差 (LWE)CRYSTALS-Kyber/Dilithium实验阶段

在混淆场景中的应用: -License 验证:开发者用私钥签名 License 文件,客户端用内嵌的公钥验证。攻击者需要伪造签名(需要私钥)或 patch 验证逻辑 -代码签名:确保代码未被篡改。iOS/macOS 的 codesign、Android 的 APK(Android Package Kit,Android 应用包)签名 -安全通信:TLS 握手中的密钥交换,保护客户端与服务端的通信

哈希函数:不可逆的指纹

密码学哈希函数将任意长度的输入映射到固定长度的输出(称为"摘要"或"哈希值"):

H: {0,1}* → {0,1}^n 例如 SHA-256: H("Hello") = 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969 H("Hello!") = 334d016f755cd6dc58c53a86e183882f8ec14f52fb05345887c8a5edd42c87b7 // 输入差一个字符,输出完全不同(雪崩效应)

三大安全属性:

属性定义直觉解释
抗原像(Preimage Resistance)给定 h,找不到 m 使得 H(m) = h不能从哈希值反推出原始输入
抗第二原像(Second Preimage Resistance)给定 m1,找不到 m2 ≠ m1 使得 H(m1) = H(m2)不能找到与已知输入哈希相同的另一个输入
抗碰撞(Collision Resistance)找不到任何 m1 ≠ m2 使得 H(m1) = H(m2)不能找到任何两个不同输入产生相同哈希

在混淆场景中的应用: -代码完整性校验:计算 .text 段的 SHA-256,运行时定期校验是否被 patch -反篡改:Guard 函数计算被保护函数的哈希,检测 inline hook -设备指纹:将多个设备特征哈希后生成绑定 ID

9.1.2 AES 算法详解

背景知识 | AES(高级加密标准)

AES 是目前全世界使用最广泛的对称加密算法。你每天都在用它:连接 WiFi 时的 WPA2/WPA3 加密、访问 HTTPS 网站时的 TLS 加密、银行 App 的数据传输、手机的全盘加密——底层几乎都是 AES。它的安全性经过了 20 多年全球密码学家的检验,至今没有发现实际可行的攻击(暴力破解 AES-128 需要尝试 2^128 约等于 3.4 万亿亿亿亿亿次,目前的计算机完全不可能)。现代 CPU(Intel/AMD/ARM)都内置了专门的 AES 硬件加速指令(AES-NI),加解密速度极快。正因为 AES 如此重要且广泛使用,攻击者特别关注如何从客户端软件中提取 AES 密钥——这就是白盒密码学要解决的核心问题。

AES(Advanced Encryption Standard)是当前最广泛使用的对称加密算法,也是白盒密码学的主要目标。理解 AES 的内部结构是理解白盒 AES 的必备前提。

AES 的诞生
  • 1997 年:美国 NIST 发起征集新一代对称加密标准,替代老旧的 DES
  • 2000 年:比利时密码学家 Joan Daemen 和 Vincent Rijmen 的Rijndael算法胜出 [3]
  • 2001 年:正式发布为 FIPS 197(AES 标准) [1]
  • 至今:全球最广泛部署的对称加密算法,Intel/AMD/ARM 均有硬件加速指令
AES 参数
参数AES-128AES-192AES-256
密钥长度128 bit (16 字节)192 bit (24 字节)256 bit (32 字节)
分组长度128 bit (16 字节)128 bit (16 字节)128 bit (16 字节)
轮数101214

AES 处理的基本单元是4×4 字节矩阵(称为 State),128 bit 的明文被排列为:

AES 的四步轮函数

每一轮(Round)包含四个步骤。以下逐步详解每个步骤的数学原理和安全目的:

Step 1: SubBytes(字节替换)—— 非线性层

每个字节独立替换:State[i][j] = S-Box[State[i][j]]

S-Box(Substitution Box,替换盒)是一个 256 字节的查找表,定义了 0x00–0xFF 的映射。它不是随机生成的——有精确的数学定义:

  1. 在有限域 GF(2^8)(Galois Field,伽罗瓦域)中求字节的乘法逆元:b → b^{-1}(0 映射到 0)
  2. 对逆元结果做一个仿射变换(异或一个常量矩阵)
S-Box 部分内容: | 0 1 2 3 4 5 6 7 8 9 a b c d e f ----+------------------------------------------------ 0 | 63 7c 77 7b f2 6b 6f c5 30 01 67 2b fe d7 ab 76 1 | ca 82 c9 7d fa 59 47 f0 ad d4 a2 af 9c a4 72 c0 2 | b7 fd 93 26 36 3f f7 cc 34 a5 e5 f1 71 d8 31 15 ...

为什么需要 S-Box(非线性变换): - 如果 AES 全部是线性操作(加法、移位、矩阵乘法),整个加密过程就是一个大的线性方程组,可以用高斯消元 O(n^3) 求解 - S-Box 引入了非线性——这是抵抗线性密码分析和差分密码分析的关键

Step 2: ShiftRows(行移位)—— 扩散层(行间)

第 0 行:不移位 第 1 行:循环左移 1 字节 第 2 行:循环左移 2 字节 第 3 行:循环左移 3 字节

安全目的:确保同一列的 4 个字节在下一步(MixColumns)中分散到不同的列——实现列间扩散。

Step 3: MixColumns(列混合)—— 扩散层(列内)

对 State 的每一列做 GF(2^8) 上的矩阵乘法:

GF(2^8) 算术速查: - 加法 = XOR(没有进位) - 乘以 2 = 左移 1 位,如果最高位为 1 则 XOR 0x1B(模约化多项式 x^8 + x^4 + x^3 + x + 1) - 乘以 3 = 乘以 2 再 XOR 原值(因为 3 = 2 + 1,加法是 XOR)

// GF(2^8) 乘法的 C 实现 uint8_t gf_mul(uint8_t a, uint8_t b) { uint8_t result = 0; while (b) { if (b & 1) result ^= a; // 加法 = XOR uint8_t hi = a & 0x80; a <<= 1; // 乘以 x if (hi) a ^= 0x1B; // 模约化 b >>= 1; } return result; }

安全目的:MixColumns 确保单个字节的变化扩散到整列(4 字节)。结合 ShiftRows 的行间扩散,经过 2 轮后,单个输入字节的变化会影响全部 16 字节——这就是 AES 的"完全扩散"特性。

Step 4: AddRoundKey(轮密钥加)—— 密钥注入

State[i][j] = State[i][j] ⊕ RoundKey[i][j]

将当前 State 与该轮的轮密钥做逐字节 XOR。轮密钥由密钥扩展算法从主密钥派生。

密钥扩展(Key Schedule)将 16 字节主密钥扩展为 11 个轮密钥(AES-128):

W[0..3] = 主密钥的 4 个 word(每个 word = 4 字节) for i = 4 to 43: if i mod 4 == 0: W[i] = W[i-4] ⊕ SubWord(RotWord(W[i-1])) ⊕ Rcon[i/4] else: W[i] = W[i-4] ⊕ W[i-1]

其中SubWord对 word 的每个字节做 S-Box 替换,RotWord循环左移 1 字节,Rcon是轮常量。

AES 完整流程

最后一轮省略 MixColumns 是为了让加密和解密在结构上对称。

分组密码的工作模式

分组密码(如 AES)一次只处理 128 bit。对于更长的数据,需要工作模式来组织多个分组的处理:

模式全称特点安全性混淆场景适用性
ECBElectronic Codebook,电子密码本模式每块独立加密❌ 不安全(相同明文块→相同密文块)不推荐
CBCCipher Block Chaining,密码块链接模式每块与前一块密文 XOR 后加密✅ CPA 安全(需要 IV)字符串加密、so 段加密
CTRCounter Mode,计数器模式加密递增计数器,密文 = 明文 XOR 加密计数器✅ CPA 安全 + 可并行大数据加密、流式场景
GCMGalois/Counter Mode,伽罗瓦/计数器模式CTR + GHASH 认证✅ 加密 + 完整性通信保护
ECB 模式的著名缺陷(企鹅图): 原图 → ECB 加密 → 仍能看出轮廓(相同像素块→相同密文块) 原图 → CBC 加密 → 完全随机化

在混淆中的选择: - 字符串加密通常使用CBC或CTR模式(简单、安全、实现小巧) - so 段加密可以使用CTR模式(支持随机访问,不需要顺序解密) - 完整性校验同时需要认证时使用GCM模式

9.1.3 有限域 GF(2^8) —— AES 与白盒的数学基石

有限域(也称 Galois 域)是理解 AES 和白盒密码学的关键数学工具。这里用尽可能直觉的方式讲解。

什么是有限域

有限域是一个包含有限个元素的集合,其上定义了加法和乘法,满足我们熟悉的算术规则(交换律、结合律、分配律、逆元存在)。

最简单的有限域是GF(2)= {0, 1},运算就是模 2 算术:

GF(2^8)是 GF(2) 的 8 次扩域,包含 256 个元素(0x00 到 0xFF)——恰好是一个字节的取值范围。每个元素可以表示为 GF(2) 上的 7 次多项式:

字节 0x57 = 01010111 (二进制) = x^6 + x^4 + x^2 + x + 1 (多项式表示)
GF(2^8) 运算

加法:多项式系数逐项 XOR(因为系数在 GF(2) 中,1+1=0)

0x57 + 0x83 = 01010111 ⊕ 10000011 = 11010100 = 0xD4

乘法:多项式乘法后模一个不可约多项式 m(x) = x^8 + x^4 + x^3 + x + 1(0x11B)

例:0x57 × 0x83 (x^6 + x^4 + x^2 + x + 1) × (x^7 + x + 1) = x^13 + x^11 + x^9 + x^8 + x^7 + x^7 + x^5 + x^3 + x^2 + x + x^6 + x^4 + x^2 + x + 1 = x^13 + x^11 + x^9 + x^8 + x^6 + x^5 + x^4 + x^3 + 1 (GF(2) 中消去重复项) 然后 mod (x^8 + x^4 + x^3 + x + 1) = ... = 0xC1

为什么 AES 选择 GF(2^8): 1.元素大小 = 字节:天然适配计算机数据处理 2.每个非零元素都有乘法逆元:S-Box 的数学基础 3.加法 = XOR:在硬件中极其高效(无进位) 4.MDS 矩阵保证最大扩散距离:MixColumns 矩阵在 GF(2^8) 上有最优扩散特性

9.1.4 HMAC 与消息认证码

HMAC(Hash-based Message Authentication Code,基于哈希的消息认证码)在混淆中主要用于代码完整性校验:

HMAC-SHA256(key, message): ipad = key ⊕ 0x36(重复到块长度) opad = key ⊕ 0x5C(重复到块长度) return SHA256(opad || SHA256(ipad || message))

与普通哈希的区别:攻击者不知道 key 就无法伪造 HMAC 值,而 SHA-256(message) 谁都能算。这在反篡改场景中意义重大——如果只用 SHA-256 校验代码完整性,攻击者可以 patch 代码后重新计算哈希值并替换。使用 HMAC 则需要密钥。


9.2 白盒密码学

知识定位:本节是实践应用与理论支撑的混合。在二进制中识别白盒密码的典型特征(查找表化的密钥、T-Box/Ty-Box 结构)属于实践应用,是逆向分析白盒实现时要直接动手做的识别工作;而 Chow 方案的编码数学细节、BGE/DCA/DFA 攻击背后的代数与统计学原理,属于理论支撑,帮助理解"为什么这个方案能被攻破";如果你要实际发起 DCA/DFA 攻击提取密钥(9.2.3),具体操作步骤本身是实践应用。

9.2.1 问题定义

背景知识 | 白盒攻击模型

密码学中的"攻击模型"描述了攻击者到底有多大能力。最弱的是黑盒模型:攻击者只能看到输入和输出,就像面对一台上了锁的保险箱,只能试着往里塞东西、看它吐出什么。稍强的是灰盒模型:攻击者还能观察到一些"侧面信息",比如设备运行时的耗电量波动、处理时间长短——就像听保险箱转盘拨动时的声音来猜密码。最强的是白盒模型:攻击者能看到程序执行的全部过程——所有的代码、所有的内存数据、所有的中间计算结果,还能随意修改任何东西。这就像攻击者不只有保险箱,还有完整的设计图纸、X 光透视设备和任意改装工具。移动端 App、桌面客户端软件、DRM 解密模块等都处于白盒环境中,因为用户(潜在的攻击者)完全控制着运行程序的设备。

攻击模型对比:

模型攻击者能力典型场景密钥安全假设
黑盒只能观察输入/输出网络服务、远程 API密钥在安全硬件中,攻击者无法触及
灰盒可以观察侧信道(功耗、电磁辐射、时间)智能卡、嵌入式设备密钥在设备中,攻击者可物理接触但不能直接读取
白盒可以观察并修改所有执行状态(内存、寄存器、控制流)DRM、移动端、客户端软件无安全假设——攻击者完全控制执行环境

白盒场景的典型需求:

场景:视频流媒体 DRM - 用户设备上运行解密模块,解密受保护的视频流 - 密钥嵌入在客户端软件中 - 攻击者可以: 1. 反编译解密模块 2. 在调试器中运行,观察所有内存 3. dump 所有中间计算值 4. 修改任何代码和数据 - 目标:即使在这种条件下,攻击者也无法提取出密钥

为什么传统加密在白盒下失效:

// 标准 AES 加密 void aes_encrypt(uint8_t *plaintext, uint8_t *key, uint8_t *ciphertext) { // 密钥在内存中以明文存在 // 攻击者用调试器可以直接读取 key 参数 uint8_t state[16]; memcpy(state, plaintext, 16); // 密钥扩展——所有轮密钥都在内存中 uint8_t round_keys[176]; key_expansion(key, round_keys); // 断点在此→读取所有轮密钥 // 10 轮加密——每轮的中间状态都可观察 add_round_key(state, &round_keys[0]); // 断点→观察 state ⊕ key for (int r = 1; r <= 10; r++) { sub_bytes(state); // 断点→观察 S-Box 输入输出 shift_rows(state); if (r < 10) mix_columns(state); add_round_key(state, &round_keys[r*16]); } memcpy(ciphertext, state, 16); } // 结论:攻击者在任何断点处都能直接读取密钥

9.2.2 白盒 AES 的 Chow 方案

2002 年 Chow、Eisen、Johnson、Van Oorschot 提出了第一个白盒 AES 方案 [5],是所有后续白盒研究的起点。

核心思想:查找表化 + 编码

背景知识 | 查找表(Lookup Table)

查找表是一种"以空间换计算"的编程技巧:把某个计算的所有可能结果提前算好、存成一张表,运行时不再做计算,而是直接"查表"拿答案。举个例子,计算 x² 可以写循环逐位乘,也可以做一张 256 项的表sq[x] = x²,之后只需要一次数组访问。任何"输入范围有限、输出可以预先确定"的函数都能这样表化。AES 的轮函数恰好满足这个条件——每一步处理的都是字节级别的数据,取值范围最多 256 种。白盒方案的核心思想就是:把 AES 的所有计算步骤全部预先展开成查找表,并把密钥"藏"在这些表的内容里,使得程序中不再出现任何显式的密钥变量。

第一步:将 AES 轮函数转化为查找表

在标准 AES 中,第 r 轮对 state 的第 i 个字节先做:

SubBytes + AddRoundKey: out = S-Box[state[i] ⊕ roundkey[r][i]]

这个操作可以预计算为一张表——T-Box:

T-Box[r][i][x] = S-Box[x ⊕ roundkey[r][i]] // 密钥已经"溶解"到表中 // 查表时不需要显式的密钥

接下来把 MixColumns 也表化。MixColumns 对每列的 4 字节做 GF(2^8) 矩阵乘法:

展开为标量运算:

y0 = 2·x0 ⊕ 3·x1 ⊕ 1·x2 ⊕ 1·x3 y1 = 1·x0 ⊕ 2·x1 ⊕ 3·x2 ⊕ 1·x3 ...

每项 c·xi 可以预计算为Tyi 表:

Tyi_Table[xi] = (c0·xi, c1·xi, c2·xi, c3·xi) // 在 GF(2^8) 中 // 组合得: y = Tyi_Table[x0] ⊕ Tyi_Table[x1] ⊕ Tyi_Table[x2] ⊕ Tyi_Table[x3]

将 T-Box 和 Tyi 表合并得到Ty-Box:每个 Ty-Box 接受一个字节输入,输出 4 字节(一整列的贡献)。

最后还需要 XOR 操作的表化:

XOR_Table[a][b] = a ⊕ b // 4 bit × 4 bit → 4 bit,分 nibble 处理

到此为止的表结构:

第二步:外部编码(External Encoding)

上述查找表虽然隐藏了密钥,但表本身是"透明"的——攻击者可以分析表的内容提取密钥信息。外部编码在表的输入和输出上叠加随机可逆变换来保护表:

原始: Ty-Box[x] = T(x) 编码后: Ty-Box'[x] = G(T(F^{-1}(x))) 其中: F 是输入编码(8-bit 可逆变换,即 8-bit 到 8-bit 的双射) G 是输出编码(32-bit 可逆变换,可分解为 4 个 8-bit 编码)

关键设计:连续两个表的编码必须在连接处抵消——即前一个表的输出编码 = 后一个表的输入解码:

Table_A 的输出编码 = G_A Table_B 的输入解码 = G_A^{-1} 组合执行: Table_B'(Table_A'(x)) = G_B( B( G_A^{-1}( G_A( A( F_A^{-1}(x) ) ) ) ) ) = G_B( B( A( F_A^{-1}(x) ) ) ) ↑ ↑ B的输出编码 A的输入解码 中间编码互相抵消,整体功能正确
典型开销
指标标准 AES白盒 AES (Chow)
代码/表大小~1 KB~770 KB (x770)
执行速度~3 ns/block (AES-NI)~300 ns–3 μs/block (x100–x1000)
内存占用固定 ~200 B~800 KB 查找表
适用场景通用加密仅用于少量关键操作

9.2.3 已知攻击

背景知识 | DCA 与 DFA——两种攻破白盒密码的主要方法

DCA(Differential Computation Analysis,差分计算分析)是一种"统计学"攻击。攻击者运行白盒加密程序很多次(几千次),每次输入不同的明文,同时记录程序内部所有查找表的访问值(称为 trace)。然后用统计学方法(皮尔逊相关系数)分析这些 trace 与猜测的密钥之间的关联性——如果某个密钥猜测值和实际观察到的 trace 值高度相关,那这个猜测很可能就是正确的密钥。这个方法借鉴自硬件领域的"差分功耗分析(DPA)"——在硬件上是分析芯片的耗电曲线,在软件白盒中则是分析内存访问值,原理相通。

DFA(Differential Fault Analysis,差分故障分析)是一种"故意搞破坏"的攻击。攻击者在加密过程中的特定位置故意注入一个错误(比如用调试器把某个中间变量改掉一个字节),然后比较正常输出和错误输出的差异。通过数学分析这个差异,可以反推出密钥信息。在传统硬件场景中,注入故障需要激光、电磁脉冲等昂贵设备;但在白盒(软件)环境中,攻击者只需要用调试器改一个内存字节就完成了"故障注入",因此这种攻击在白盒环境中变得异常简单。

白盒密码学的历史一直是"提出方案→被攻破→提出改进→再被攻破"的循环。理解攻击方法对于评估白盒方案的实际安全性至关重要。

DCA(Differential Computation Analysis,差分计算分析)—— 软件侧信道攻击

背景知识:DPA(Differential Power Analysis,差分功耗分析)

在灰盒场景中,攻击者可以测量加密设备的功耗波形。密码芯片处理不同数据时的功耗略有差异——通过统计大量加密操作的功耗 trace,可以提取密钥。这就是 1999 年 Kocher 等人提出的 DPA 攻击。[4]

DCA 的核心洞察(Bos et al., 2016) [7]:白盒实现虽然看不到功耗,但攻击者可以观察内存访问的值——这与功耗在统计特性上等价。

DCA 攻击步骤: 1. 选择攻击目标:第 1 轮的 SubBytes 输出 (此处的值只取决于一个明文字节和一个密钥字节) 2. 收集 trace:运行白盒实现 N 次(N ≈ 几千),每次使用不同的随机明文 记录每次执行过程中所有查找表的访问值 → 形成 N × M 的 trace 矩阵 (N = 执行次数,M = 单次执行中的表访问次数) 3. 统计分析: for each key_guess in 0x00..0xFF: for each trace_column j: 计算 CPA 相关系数: correlation = Pearson( SubBytes(plaintext[i] ⊕ key_guess), // 假设的中间值 trace_matrix[:, j] // 实际观察到的值 ) if |correlation| 显著: key_guess 很可能是正确的密钥字节 4. 对 16 个字节重复上述过程 → 恢复完整密钥

效果:2016 年 Bos 等人的工作证明 DCA 可以在分钟级别攻破 Chow 方案——仅需几千次加密的 trace。[10]

为什么外部编码不能阻止 DCA:编码是固定的可逆变换,不影响统计相关性——如果SubBytes(plain ⊕ key)与表 T 的第 j 列相关,那么Encode(SubBytes(plain ⊕ key))与表 T' 的第 j 列仍然相关(相关系数的绝对值不变)。

DFA(Differential Fault Analysis,差分故障分析)—— 故障注入攻击

原理:在白盒实现的特定位置注入故障(修改一个中间计算值),通过观察输出差异推断密钥。

正常执行:input → [白盒 AES] → output_correct 注入故障:input → [白盒 AES ... fault ... ] → output_faulty 差分:Δ = output_correct ⊕ output_faulty 通过分析 Δ 与故障位置的关系,可以恢复密钥

在白盒环境中"注入故障"极其容易: - 在传统灰盒中,需要激光、电磁脉冲等物理手段注入故障 - 在白盒中,攻击者直接修改内存即可——用调试器改一个字节就是一次"故障注入"

BGE 攻击(Billet-Gilbert-Ech-Chatbi 攻击,针对白盒 AES 的结构性攻击,2004)

针对 Chow 方案的结构性攻击[6]:利用 AES 的代数结构(特别是 MixColumns 的线性性),从编码后的查找表中分离出编码变换,进而提取密钥。

攻击思路(简化): 1. 观察连续两个 Ty-Box 的组合:Ty-Box2(Ty-Box1(x)) 2. 由于 MixColumns 是 GF(2^8) 上的线性操作,编码后的组合保留了特定代数结构 3. 利用这些代数关系,解出外部编码的参数 4. 去掉编码后,直接读取表中的密钥信息 时间复杂度:O(2^30)——在现代 PC 上几分钟完成
攻击总结
攻击年份方法攻击目标时间所需条件
BGE2004代数分析Chow 方案分钟只需白盒实现的代码
DCA2016统计分析所有查找表方案分钟需要执行并收集 trace
DFA—故障注入所有白盒方案小时需要执行并修改中间值
格攻击2024格归约改进的白盒方案视方案而定高级数学工具

9.2.4 白盒方案的演进

面对上述攻击,研究者提出了多种改进方案 [8]:

第一代改进:增强编码
  • 更宽的编码:使用 16-bit 或 32-bit 编码(而非 Chow 的 4/8-bit),增加 BGE 攻击的复杂度
  • 非线性编码:在线性编码基础上叠加非线性变换,阻止代数分析
  • 问题:仍然无法抵抗 DCA——统计相关性不依赖编码的具体形式
第二代:抗 DCA 方案
  • 内部编码掩码化(Masking):借鉴灰盒防御中的"掩码"技术——在每个中间值上 XOR 一个随机掩码,使得单个 trace 列不直接暴露明文相关值
  • 随机化执行路径:每次加密走不同的查找表路径(从多套等价表中随机选择),破坏 DCA 所需的统计一致性
  • 问题:显著增加表大小和执行时间
第三代:不可区分混淆方向

理论上,如果能构造出不可区分混淆(Indistinguishability Obfuscation, iO)[12],就可以将任何程序(包括 AES)混淆为不可分析的形式。但 iO 目前仅存在于理论中 [13]——现有构造效率极低(单次 AES 可能需要数分钟),离工程应用还很远。

9.2.5 白盒方案与混淆的结合

单独使用白盒密码学已被证明不安全。工程实践中的最佳策略是"白盒 + 外层保护的组合":

方案 1:白盒实现 + 虚拟化保护
攻击成本叠加: 1. 攻击者首先要突破 VMProtect 保护的 dispatcher → 恢复所有 handler 的语义(数周工作量) 2. 然后才能对白盒实现做 DCA trace → 收集足够的 trace 数据(原本只需分钟) 3. 最后用统计方法提取密钥 总成本 = 虚拟化突破成本 + DCA 成本 >> 单独 DCA 成本
方案 2:白盒 + 运行时代码生成
查找表不预存在于二进制中: 1. 运行时动态生成查找表(基于设备指纹 + 时间种子) 2. 使用后立即擦除 3. DCA 的 trace 收集变得极其困难——每次表都不同
方案 3:多样化编译(Diversity)
每个设备/用户的白盒实现不同: - 不同的外部编码 - 不同的查找表排列 - 不同的冗余操作 效果:攻击一台设备的成果无法复用到其他设备 大规模破解不经济
方案 4:白盒 + 反 DCA 运行时保护
// 在白盒实现周围增加反分析层 void protected_wb_aes(uint8_t *in, uint8_t *out) { // 1. 环境检测:是否在调试器/模拟器中 if (detect_debugger() || detect_emulator()) { // 走入诱饵路径——返回错误结果 decoy_aes(in, out); return; } // 2. 时间检测:trace 收集会显著减速执行 uint64_t t1 = rdtsc(); wb_aes_encrypt(in, out); // 真正的白盒 AES uint64_t t2 = rdtsc(); if (t2 - t1 > THRESHOLD) { // 执行过慢——可能在做 trace 收集 memset(out, 0, 16); // 擦除输出 } // 3. 完整性校验:白盒表是否被篡改 if (verify_table_integrity() != EXPECTED_HASH) { corrupt_output(out); } }

9.3 其他白盒密码原语

知识定位:本节属于理论支撑。白盒 DES/SM4/HMAC 的原理与白盒 AES 类似,这里是帮你扩展认知边界——知道"查找表化+外部编码"这套思路可以迁移到哪些算法,不要求针对每种算法都亲自实现白盒版本。

9.3.1 白盒 DES

DES 的白盒实现原理与 AES 类似(查找表化),但由于 DES 本身已不安全(56-bit 密钥),白盒 DES 主要存在于遗留系统中。

9.3.2 白盒 SM4

SM4 是中国国家密码标准(GB/T 32907-2016) [11],结构与 AES 类似(32 轮 Feistel + S-Box + 线性变换)。白盒 SM4 的构造方法可以直接借鉴白盒 AES——将轮函数查找表化,叠加外部编码。

在国内合规场景(等保、金融行业)中,使用 SM4 而非 AES 是强制要求。白盒 SM4 的研究和工具链正在快速发展。

9.3.3 白盒 HMAC

将 HMAC 的密钥嵌入白盒实现中——与白盒 AES 不同,这里保护的不是加密密钥而是认证密钥。在反篡改场景中,可以用白盒 HMAC 计算代码段的消息认证码,避免密钥被提取后伪造 HMAC。


9.4 工程实践建议

知识定位:本节属于实践应用。何时选用白盒方案(9.4.1 的场景对照表)是做架构/安全方案决策时要直接动手判断的内容;安全性预期管理(9.4.2)中的设计建议(永远不单独使用白盒、密钥轮换、多样化、降级方案)同样是工程落地时需要直接执行的准则。

9.4.1 何时使用白盒密码

场景是否推荐白盒推荐方案
服务端加密❌ 不需要——密钥在安全环境中标准 AES + HSM
移动端 DRM 解密✅ 典型白盒场景白盒 AES + VM 保护
客户端 License 验证⚠️ 可选——ECDSA 签名验证可能更合适ECDSA 验证 + 代码混淆
通信协议密钥协商❌ 应使用 TLS——不要自己实现TLS 1.3
本地数据加密(密钥本地存储)✅ 如果不能使用 TEE(Trusted Execution Environment,可信执行环境)/Keychain白盒 AES + 设备绑定
代码完整性校验✅ 白盒 HMAC 保护校验密钥白盒 HMAC + 多点校验

9.4.2 安全性预期管理

诚实的评估:截至 2026 年,没有任何公开的白盒方案被证明是无条件安全的 [9]。所有方案都存在已知或潜在的攻击。

工程意义上的安全:白盒密码的价值不在于"不可破",而在于显著提高攻击成本——特别是与虚拟化保护、运行时保护结合后,攻击者需要突破多层防线才能到达白盒实现。

设计建议: 1.永远不要单独使用白盒——必须配合外层保护 2.密钥轮换:定期更新白盒实现(推送新版本),使攻击者的分析成果过期 3.多样化:每个设备/用户使用不同的白盒实例 4.降级方案:假设白盒最终会被攻破——设计系统时确保单个密钥泄露不会导致全面失陷


参考资料

密码学基础

[1][FIPS 197]"Advanced Encryption Standard (AES)", NIST, 2001. https://csrc.nist.gov/publications/detail/fips/197/final

[2][Katz & Lindell]Jonathan Katz, Yehuda Lindell,Introduction to Modern Cryptography, 3rd Edition, CRC Press, 2020 — 密码学教科书标杆

[3][Daemen & Rijmen]Joan Daemen, Vincent Rijmen,The Design of Rijndael: AES — The Advanced Encryption Standard, Springer, 2002 — AES 设计者的亲述

[4][Kocher et al.]Paul Kocher et al., "Differential Power Analysis", CRYPTO 1999 — DPA 攻击的奠基论文

白盒密码学

[5][Chow et al., 2002]Stanley Chow et al., "White-Box Cryptography and an AES Implementation", SAC 2002 — 白盒 AES 的开山之作

[6][Billet et al., 2004]Olivier Billet, Henri Gilbert, Charaf Ech-Chatbi, "Cryptanalysis of a White Box AES Implementation", SAC 2004 — BGE 攻击

[7][Bos et al., 2016]Joppe W. Bos et al., "Differential Computation Analysis: Hiding your White-Box Designs is Not Enough", CHES 2016 — DCA 攻击

[8][Biryukov et al., 2017]Alex Biryukov et al., "Cryptographic Obfuscation: A Survey", 2017 — 白盒密码综述

工程实践

[9]WhibOx Contest: https://whibox.io — 白盒密码挑战赛,历年参赛方案是了解实际安全水平的最佳窗口

[10]SideChannelMarvels: https://github.com/SideChannelMarvels — DCA/DFA 攻击工具集(Deadpool、JeanGrey、Tracer)

[11]GB/T 32907-2016: SM4 分组密码算法国家标准

扩展阅读

[12][Barak et al., 2001]Boaz Barak et al., "On the (Im)possibility of Obfuscating Programs", CRYPTO 2001 — 不可混淆性理论,证明通用白盒不存在

[13][Garg et al., 2013]Sanjam Garg et al., "Candidate Indistinguishability Obfuscation", FOCS 2013 — 第一个 iO 候选构造

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进