TL;DR
- E0 流密码:蓝牙 2.x~4.0 默认加密,硬件实现简单,但有已知相关攻击,无消息认证。
- AES-CCM:蓝牙 4.1+ Secure Connections 使用,提供加密 + 完整性 + 认证,安全性全面胜出。
- 核心差异:E0 只加密不认证;AES-CCM 加密 + 认证一体(AEAD)。
- 迁移路径:双模支持 → 优先协商 AES-CCM → 强制 AES-CCM → 淘汰 E0。
- 落地难点:旧设备兼容性、AES 硬件加速需求、密钥长度协商。
目录
1. 两种算法概览
蓝牙加密演进时间线:
2.x (2004) E0 流密码(16 位 Kc)
3.0+HS (2009) E0 + AES-CCM(可选)
4.0 (2010) BLE 用 AES-CCM
4.1 (2013) BR/EDR Secure Connections 引入 AES-CCM
5.x (2016+) AES-CCM 成为推荐
| 维度 | E0 流密码 | AES-CCM |
|---|---|---|
| 类型 | 流密码 | AEAD(加密+认证) |
| 密钥长度 | 128 位(实际有效可低至 56 位) | 128 位 |
| 完整性 | 无 | CBC-MAC |
| 认证 | 无 | 内置 |
| 蓝牙版本 | 2.x~4.0 | 4.1+ |
| 典型应用 | BR/EDR 旧设备 | BLE、BR/EDR SC |
| 标准化 | 蓝牙专用 | NIST 标准 |
2. E0 流密码原理
📋 Spec 参考:Bluetooth Core Spec Vol.2 Part H §3
2.1 算法结构
E0 是基于 LFSR(线性反馈移位寄存器)的流密码:
密钥流生成器:
4 个 LFSR(长度 25, 31, 33, 39 位)
↓
组合器(有限状态机 + 加法)
↓
密钥流输出(每时钟 1 位)
2.2 输入参数
| 参数 | 说明 | 长度 |
|---|---|---|
| Kc | 加密密钥(从 Linkkey 派生) | 128 位 |
| BD_ADDR | 设备地址 | 48 位 |
| CLK | 主时钟 | 28 位 |
| RAND | 随机数 | 128 位 |
2.3 密钥流生成
c
// 简化的 E0 密钥流生成
void e0_keystream(uint8_t *Kc, uint8_t *bd_addr, uint32_t clk,
uint8_t *rand, uint8_t *keystream, size_t len) {
// 1. 用 Kc, BD_ADDR, CLK, RAND 初始化 4 个 LFSR
lfsr_init(Kc, bd_addr, clk, rand);
// 2. 运行有限状态机生成密钥流
for (size_t i = 0; i < len; i++) {
keystream[i] = e0_next_byte();
}
}
// 加密 = 明文 XOR 密钥流
void e0_encrypt(uint8_t *plaintext, uint8_t *keystream,
uint8_t *ciphertext, size_t len) {
for (size_t i = 0; i < len; i++) {
ciphertext[i] = plaintext[i] ^ keystream[i];
}
}
2.4 E0 的优势
- 硬件实现简单:LFSR + 组合器,门电路少
- 低功耗:适合早期芯片(2000 年代初的工艺)
- 流密码无需分组对齐:任意长度数据都能加密
2.5 E0 的弱点
- 有已知相关攻击:2005 年 Lu 等人提出相关攻击,理论上 2^38 次操作可恢复密钥
- 无消息认证:只加密,不保证完整性,可被篡改
- 密钥流可被分析:如果密钥流复用(nonce 重用),明文可被恢复
- 有效密钥长度可被协商降低:早期实现允许 Kc 缩短到 56 位
3. AES-CCM 原理
📋 Spec 参考:Bluetooth Core Spec Vol.2 Part H §2 + NIST SP 800-38C
3.1 算法结构
AES-CCM = AES-CTR(加密) + CBC-MAC(认证):
输入:明文 P, 关联数据 A, Nonce N, Key K
1. CBC-MAC 计算:
B_0 = N || len(P)
B_1 = A
B_2..B_n = P 分块
Y_0 = AES_K(B_0)
Y_i = AES_K(Y_{i-1} XOR B_i)
T = Y_n[:8] ← MAC 标签(8 字节)
2. CTR 模式加密:
S_i = AES_K(N || counter_i)
C_i = P_i XOR S_i
C_0 = T XOR S_0 ← MAC 也加密
输出:密文 C || 加密的 MAC
3.2 蓝牙中的 AES-CCM
c
// 蓝牙 AES-CCM 加密
void bt_aes_ccm_encrypt(uint8_t *key, uint8_t *nonce,
uint8_t *plaintext, size_t pt_len,
uint8_t *aad, size_t aad_len,
uint8_t *ciphertext, uint8_t *mac) {
// 1. 计算 CBC-MAC
uint8_t T[8];
cbc_mac(key, nonce, plaintext, pt_len, aad, aad_len, T);
// 2. CTR 加密
uint8_t S0[16];
ctr_keystream(key, nonce, 0, S0);
xor_block(T, S0, 8); // MAC 也加密
for (size_t i = 0; i < pt_len; i += 16) {
uint8_t S[16];
ctr_keystream(key, nonce, i/16 + 1, S);
xor_block(plaintext + i, S, min(16, pt_len - i));
}
memcpy(ciphertext, plaintext, pt_len); // 已就地加密
memcpy(mac, T, 8);
}
3.3 AES-CCM 的优势
- 强安全性:AES 经过 NIST 标准化,广泛验证
- 完整性 + 认证:CBC-MAC 防篡改
- 硬件加速支持广泛:多数现代 MCU 有 AES 指令
- 标准化:NIST SP 800-38C,跨平台一致
3.4 AES-CCM 的弱点
- 实现复杂度高于 E0:需要 AES + MAC 两套逻辑
- 需要 AES 硬件加速:纯软件实现慢,早期芯片可能不支持
- 分组密码:需处理填充(但 CTR 模式实际不需填充)
4. 安全对比矩阵
| 维度 | E0 流密码 | AES-CCM | 胜者 |
|---|---|---|---|
| 安全性 | 有已知弱点 | 强安全 | AES-CCM ✅ |
| 完整性 | 无 | 有(CBC-MAC) | AES-CCM ✅ |
| 认证 | 无 | 有 | AES-CCM ✅ |
| 实现复杂度 | 低 | 中 | E0 ✅ |
| 功耗 | 低 | 中(有硬件加速时低) | E0 ✅ |
| 硬件需求 | 低 | 需 AES 加速 | E0 ✅ |
| 标准化 | 蓝牙专用 | 国际标准 | AES-CCM ✅ |
| 抗攻击 | 弱 | 强 | AES-CCM ✅ |
| 蓝牙版本 | 2.x~4.0 | 4.1+ | --- |
| Nonce 重用风险 | 高(密钥流复用) | 中(CTR 模式) | E0 ✅(更脆弱但限制少) |
5. 已知攻击分析
5.1 E0 相关攻击
📋 Spec 参考:Y. Lu, W. Meier, S. Vaudenay, "Conditional Privacy: Multi-Pass Authentication" (2005)
攻击原理:
- 利用 LFSR 输出的相关性
- 收集 2^23 位已知密钥流
- 2^38 次操作恢复 Kc
实际威胁:
- 理论上可行,但需要大量数据
- 对短连接(如耳机配对)威胁有限
- 对长期连接(如持续音频流)威胁较大
5.2 E0 字典攻击(PIN 弱)
E0 的 Kc 由 PIN 派生:
Kc = E22(PIN, BD_ADDR, RAND)
如果 PIN 是 4 位数字(0000-9999),攻击者可以:
- 抓配对包
- 离线穷举 10000 个 PIN
- 每个穷举计算 Kc,验证配对响应
防御:强制 6 位以上 PIN,或用 SSP(Secure Simple Pairing)。
5.3 AES-CCM 已知风险
AES-CCM 本身安全,但实现易错:
- Nonce 重用:同一密钥下 Nonce 重用会导致明文泄露
- MAC 长度太短:蓝牙用 8 字节 MAC,理论上 2^32 次可碰撞
- CTR 计数器溢出:长数据加密时计数器溢出会重用密钥流
5.4 KNOB Attack
📋 Spec 参考:KNOB Attack (CVE-2019-9506)
攻击原理:
- 利用蓝牙规范允许协商加密密钥长度(最低 1 字节)
- 攻击者中间人强制双方协商 8 位密钥
- 暴力破解 256 次
影响:E0 和 AES-CCM 都受影响(密钥长度协商在加密算法之前)。
防御:蓝牙 5.1+ 强制最小密钥长度 7 字节,Core Spec 增加规范层防护。
6. 迁移路径
6.1 阶段化策略
| 阶段 | 策略 | 时间 |
|---|---|---|
| 当前 | 双模支持(E0 + AES-CCM) | --- |
| 短期 | 优先协商 AES-CCM,E0 作为 fallback | 1-2 年 |
| 中期 | 强制 AES-CCM,E0 仅用于 2.x 设备 | 3-5 年 |
| 长期 | 完全淘汰 E0 | 5+ 年 |
6.2 双模实现示例
c
typedef enum {
CRYPTO_E0,
CRYPTO_AES_CCM,
} crypto_mode_t;
typedef struct {
crypto_mode_t mode;
union {
struct {
uint8_t kc[16];
uint8_t bd_addr[6];
uint32_t clk;
uint8_t rand[16];
} e0;
struct {
uint8_t key[16];
uint8_t nonce[13];
} aes_ccm;
};
} crypto_ctx_t;
int bt_encrypt(crypto_ctx_t *ctx, uint8_t *in, uint8_t *out, size_t len) {
switch (ctx->mode) {
case CRYPTO_E0:
return e0_encrypt(&ctx->e0, in, out, len);
case CRYPTO_AES_CCM:
return aes_ccm_encrypt(&ctx->aes_ccm, in, out, len);
}
return -1;
}
// 配对时协商
crypto_mode_t negotiate_crypto(peer_version_t peer) {
if (peer >= BT_VERSION_4_1 && local_has_aes_hw()) {
return CRYPTO_AES_CCM;
}
return CRYPTO_E0; // fallback
}
6.3 迁移检查清单
- 硬件支持 AES 加速(Cortex-M4+ AES 指令或外设)
- 固件实现 AES-CCM 且通过测试向量
- 配对逻辑支持 Secure Connections
- 兼容性测试:能与旧设备用 E0 配对
- 兼容性测试:能与 4.1+ 设备用 AES-CCM 配对
- 性能测试:AES-CCM 吞吐满足业务需求
- 安全审计:Nonce 生成不重用
- 密钥长度强制 ≥ 7 字节
7. 实战配置
7.1 检查当前加密模式
bash
# Linux 查看连接加密模式
hcitool enc <bd_addr>
# 输出中关注:
# Encryption: AES-CCM ← 新
# Encryption: E0 ← 旧
7.2 强制 AES-CCM
c
// 配对时拒绝 E0
int pair_with_security(peer_addr) {
io_cap_t io_cap = KEYBOARD_DISPLAY;
auth_req_t auth_req = {
.bonding = 1,
.mitm = 1,
.secure_connections = 1, // 强制 SC
.keypress = 0,
};
// 发起 Secure Connections 配对
return hci_le_start_pairing(peer_addr, io_cap, auth_req);
}
// 如果对端不支持 SC,拒绝配对
void on_pairing_failed(reason_t reason) {
if (reason == SC_NOT_SUPPORTED) {
log_warn("Peer does not support Secure Connections, rejecting");
disconnect(peer_addr);
}
}
7.3 调试日志
[PAIRING] Starting Secure Connections pairing with AA:BB:CC:DD:EE:FF
[PAIRING] IO Capability: KeyboardDisplay
[PAIRING] AuthReq: bonding=1, mitm=1, sc=1
[PAIRING] Public Key exchanged (64 bytes)
[PAIRING] Confirm value verified
[PAIRING] DHKey check passed
[CRYPTO] Encryption mode: AES-CCM
[CRYPTO] Key length: 16 bytes
[CRYPTO] Nonce: 0x11223344556677889900AABB