3. HDCP 1.x 认证协议:AKE 握手流程详解

好,咱们直接进入正题。HDCP 1.x 的核心,就是这个 AKE(Authentication and Key Exchange)握手。说白了,就是发送端(比如你的机顶盒)和接收端(比如显示器)互相确认身份,然后商量一个临时密钥,用来加密视频流。

我当年第一次看这个协议时,觉得挺绕的。但后来拆解过几次,发现其实就三步:挑战 → 响应 → 密钥生成。咱们一步步来。

3.1 握手流程全景图

先看一张图,把整体逻辑理清楚。我习惯用 SVG 画这种流程,比文字直观多了。

发送端 (HDCP TX) 接收端 (HDCP RX) ① 发送 64-bit 随机挑战 (Aksv) ② 返回 RSA 签名 + 证书 (Bksv, REPEATER 等) ③ 验证 RSA 签名 ④ 生成会话密钥 共享密钥 (Km) AKE 握手完成后,双方开始加密传输视频内容 发送端动作 接收端动作 验证/密钥生成

嗯,这张图把核心流程画清楚了。发送端先扔一个随机数过去,接收端用自己的私钥签名后返回。发送端再用公钥验证签名。验证通过,双方就都有了共享密钥。

3.2 挑战-响应机制详解

为什么需要挑战-响应?你想想看,如果只是接收端单方面发个证书过来,发送端怎么知道这个证书是不是被篡改过?

所以 HDCP 1.x 用了经典的挑战-响应模式:

  • 发送端生成 Aksv:一个 64 位的随机数,每次握手都不一样。我习惯叫它「一次性挑战值」。
  • 接收端计算响应:接收端用自己的私钥对 Aksv 签名,生成 Rsv。同时把自己的公钥 Bksv 也发过去。
  • 发送端验证:用接收端的公钥 Bksv 验证签名 Rsv。如果验证通过,说明接收端确实持有对应的私钥。

核心要点:这个机制防止了「重放攻击」。因为每次的 Aksv 都不同,就算你截获了上一次的签名,也没法用在这次握手里。

我在项目中遇到过一个问题:有台显示器每次握手都失败,但换一台就正常。后来抓包发现,是接收端返回的 Bksv 证书过期了。嗯,证书有效期这个坑,后面会细说。

3.3 RSA-1024 签名验证机制

HDCP 1.x 用的是 RSA-1024 签名。1024 位,在今天看来不算强,但在当年是主流。

签名过程是这样的:

  1. 接收端用 SHA-1 对 Aksv 做哈希,得到一个 160 位的摘要。
  2. 然后用私钥对这个摘要加密,生成 1024 位的签名 Rsv。
  3. 发送端用公钥解密 Rsv,得到摘要。
  4. 再自己算一遍 Aksv 的 SHA-1 摘要,两者对比。

如果一致,签名验证通过。

个人经验:我建议你在实现时,注意一下字节序。HDCP 协议里很多字段是大端序,但有些芯片实现会搞成小端。我曾经因为这个 bug 调了整整两天。

代码层面,验证签名的核心逻辑大概是这样:

// 伪代码:HDCP 签名验证
bool verify_hdcp_signature(
    uint64_t aksv,          // 发送端生成的挑战
    uint8_t* bksv,          // 接收端公钥 (证书)
    uint8_t* rsv,           // 接收端签名
    uint8_t* public_key     // 预置的 RSA 公钥
) {
    // 1. 计算 Aksv 的 SHA-1 摘要
    uint8_t digest[20];
    sha1_calculate(&aksv, sizeof(aksv), digest);
    
    // 2. 用公钥解密签名
    uint8_t decrypted[128];
    rsa_decrypt(rsv, decrypted, public_key);
    
    // 3. 比较摘要
    return memcmp(digest, decrypted, 20) == 0;
}

注意,这里的 public_key 是 HDCP 联盟预置在发送端设备里的。不是从网络上下载的,是出厂时就烧录好的。这也是 HDCP 安全性的一个基础——公钥是可信的。

3.4 伪随机数生成与安全考量

Aksv 是随机数,但「随机」也有讲究。如果随机数生成器不够好,攻击者可以预测下一次的挑战值,那就麻烦了。

HDCP 规范要求使用密码学安全的伪随机数生成器(CSPRNG)。说白了,不能用简单的 rand() 函数。

随机数类型 适用场景 安全性
普通 PRNG (如 rand()) 游戏、模拟 低 — 可预测
CSPRNG (如 /dev/urandom) 加密、认证 高 — 不可预测

警告:千万不要用 rand() 生成 Aksv!我曾经见过一个山寨 HDMI 线,里面芯片就是用 rand() 生成挑战值,结果每次上电后的随机数序列都一样。这种设备在安全审计时直接判不合格。

正确的做法是:

  • 在 Linux 上,从 /dev/urandom 读取 8 字节。
  • 在嵌入式设备上,使用硬件随机数生成器(HRNG)。
  • 如果都没有,至少用 getrandom() 系统调用。

3.5 握手失败的处理

握手不是每次都能成功的。我总结了几种常见失败原因:

  1. 证书过期:接收端的 Bksv 证书不在发送端的信任列表里。
  2. 签名验证失败:可能是私钥损坏,或者传输过程中数据被篡改。
  3. 随机数重复:如果发送端生成了相同的 Aksv,接收端可能会拒绝。
  4. 时序超时:HDCP 握手有严格的时间限制,一般要求在 100ms 内完成。

遇到握手失败,发送端通常会重试 3 次。如果都失败,就会降级到不加密模式(如果设备支持的话),或者直接黑屏。

避坑指南:我曾经调试过一个项目,HDCP 握手总是失败。查了三天,最后发现是 PCB 走线太长,导致 I2C 通信不稳定。嗯,硬件问题有时候比软件更隐蔽。

3.6 小结

AKE 握手是 HDCP 1.x 的基石。它通过挑战-响应机制,用 RSA-1024 签名验证接收端的身份,然后双方协商出共享密钥。整个过程虽然只有几步,但每个环节都有坑。

我个人觉得,理解 AKE 的关键在于:信任链。发送端信任预置的公钥,公钥验证接收端的证书,证书里包含接收端的公钥,再用这个公钥验证签名。一环扣一环,缺一不可。

嗯,这一章就到这里。下一章咱们聊聊 HDCP 2.x 的升级,那个更复杂,但也更有意思。


可可精品资料库