HDMI或者DP接口中HDCP2.x流程分析
一、read versioni2c_read(0x37, 0x50, 1)通过i2c读取1字节数据注意dev_addr0x37和offset_addr0x50value 0x4表示支持HDCP2.2或者更高版本二、AKE(Authentication and Key Exchange)用私钥加密信息的过程我们称之为数字签名 常见数字签名算法RSA/DSA/ECDSA用私钥加密的信息必须用对应的公钥才能解开这个过程称之为验证签名(数字验签)权威机构CA(Certificate Authority)证书授权中心在HDCP协议里面是DCP LLC所有的HDCP Tx都会有一个DCP LLC发布的3072-bit RSA公钥用于对HDCP Rx数字签名进行解密(公钥解密)即1、HDCP Rx使用DCP LLC的3072-bit RSA私钥对HDCP Rx公钥进行加密生成数字签名2、HDCP Tx使用DCP LLC的3072-bit RSA公钥对数字签名进行解密得到HDCP Rx公钥所有的HDCP Rx都会有一个1024-bit的公钥和私钥公钥通过DCP LLC发布的私钥进行加密生成数字签名然后数字签名公钥保存到HDCP Rx的公钥证书(Public Key Certificate)里面因此当HDCP Tx读取到公钥证书后可以进行如下操作来确认HDCP Rx的公钥是否可信1、使用HDCP Tx的3072-bit RSA公钥对公钥证书里面的数字签名进行解密(数字验签)得到HDCP Rx公钥2、将解密后得到的HDCP Rx公钥与公钥证书里面的HDCP Rx公钥进行比对若比对一致则验证通过就可以使用HDCP Rx进行下一步的操作当然我们也可以直接相信这就是HDCP Rx公钥直接从公钥证书里面获取HDCP Rx公钥后进行使用即可跳过数字验签的过程4176/8522Byte HDCP Rx公钥证书大小为522Byte注意公钥证书里面的4176-bit是以大端模式存储的所以我们驱动程序里面读取回来的数据不需要转换就可以直接使用2.1 AKE_Init说明rtx是自己定义的任意8个字节数据均可TxCaps是按照spce里面的定义实现的然后通过i2c将这13个字节发送出去即可注意offset_addr为0x60发送AKE_Init msg后100ms之内必须发送AKE_Send_Cert msg用于获取Rx公钥证书具体来讲是TxCaps这三个字节写入后的100ms内注意在发送AKE_Init msg之前需要先判断Rx是否准备好数据代码实现如果从0x70读取回来的数据为0(rx_status0)那就说明Rx端没有准备好数据也就不需要进行下一步读取操作了即使读取了那么读取回来的值也全是0Rx端最大可以准备1023个字节供HDCP Tx读取然后通过i2c从0x80读取指定字节的数据即可2.2 AKE_Send_Cert152283534AKE_Send_Cert是一个i2c_read操作正常会从0x80处读取534Byte数据回来代码实现HDCP Rx公钥证书以大端模式存储我们读取回来的数据rx_cert可以直接使用共522ByteReceiver ID: 0~4 5ByteReceiver Public Key: 5~135 131ByteReserved: 136~137 2ByteDCP LLC Signature: 138~521 384Byte有了kpub和sign正常情况下我们要做的是使用从DCP LLC购买的3072-bit公钥对签名进行解密然后与kpub进行比对比对通过则认为kpub可信然后进行下一步操作2.3 AKE_No_Stored_km代码实现正常做法km是16个字节我们可以任意定义然后使用kpub通过RSA加密算法(纯软件实现)对km进行加密生成Ekpub_km(大小为128个字节)HDCP Rx收到Ekpub_km后会使用私钥对其进行解密从而得到HDCP Tx的km发送AKE_No_Stored_km msg后1s之内必须发送AKE_Send_H_prime msg用于获取Rx端的H值具体来讲是Ekpub_km的最后一个字节写入后的1s内注意在发送AKE_Send_H_prime msg之前需要先判断Rx是否准备好数据代码实现2.4 AKE_Stored_km我们默认接入的显示器都是第一次连接不走AKE_Stored_km流程即代码里面可以选择不使用该方式后面内容也会讲解AKE_Stored_km流程2.5 AKE_Send_H_prime代码实现这里关注一下H值是怎么产生的派生机制基于km(主秘钥)和随机数rtx、rrx通过AES加密算法(纯软件实现)生成动态秘钥dkeyi在AKE阶段也就是产生dkey0和dkey1的期间rn被初始化为0并且整个阶段都为0在LC阶段rn被初始化为一个16-bytes的随机值然后与Km的低8-bytes数据进行异或操作后送入AES-CTR后产生dkey2所以rn的高8-bytes数据相当于没有什么作用在代码中就可以将rn高8-bytes数据全部定义为0然后将rn低8-bytes数据定义为不为0的任意值Kd dkey0 || dkey1H HMAC-SHA256(rtx || RxCaps || TxCaps, kd)变量 km rn kd dkey0 dkey1 H大小 16Byte 16Byte 32Byte 16Byte 16Byte 32Byte代码实现我们从Rx端读取rx_H值回来后Tx端也需要计算得到一个tx_H值二者进行比较若值相等则认证通过继续进行下一步否则认证失败直接退出看一下Tx端如何计算tx_H值再来进行tx_H与rx_H的比较发送AKE_Send_H_prime msg后200ms之内必须发送AKE_Send_Pairing_Info msg用于获取Rx端的H值具体来讲是rx_H值最后一个字节读取后的200ms内注意在发送AKE_Send_Pairing_Info msg之前需要先判断Rx是否准备好数据代码实现2.6 AKE_Send_Pairing_Info代码实现我们来看一下spec关于这个部分是怎么说的为了加快AKE的过程在HDCP Tx和Rx之间必须执行pair具体的过程如下1、HDCP Rx生成一个Ekh(km)发送给HDCP Tx2、HDCP Tx收到Ekh(km)后与m值、km值和rx_id值保存在一起这样当同一款显示器再次插入时我们通过AKE_Send_Cert获取到rx_id后与本地保存的pair_info数据进行比较找到后就可以直接走AKE_Strored_km流程从而节省时间3、HDCP Rx收到Ekh(km)后就可以解密得到km注意1Ekh(km)是如何产生的1.HDCP Rx会通过SHA-256算法使用私钥对[127:0]的数据进行加密得到128-bit kh这个[127:0]的数据是什么我们不关心这个是HDCP Rx特有的它愿意用什么数据就用什么数据2.kh与m值送入AES后输出128-bit数据其与km进行异或操作从而得到Ekh(km)3.在AKE_Stored_km过程中HDCP Rx收到Ekh(km)后会使用私钥进行解密(这个过程应该会使用到步骤1提到的[127:0]的数据)得到km所以说[127:0]的数据自始至终都是HDCP Rx自己使用HDCP Tx根本不会用到所以HDCP Tx不必关心它具体是什么数据综上Ekh(km)我们可以称之为使用kh对km进行加密后产生的值注意2我们可以不使用AKE_Stored_km流程即每一次都使用AKE_No_Stored_km流程即使说某一个显示器已经接入过一次那么下一次接入的时候我依然走AKE_No_Stored_km流程这里就有一个问题AKE_Send_Pairing_Info流程可以不执行嘛必须执行走AKE_No_Stored_km流程就必须同时走AKE_Send_Pairing_Info流程这是spec规定的不这样做可能会出问题但是通过AKE_Send_Pairing_Info流程获取到的Ekh(km)值我们可以置之不理就当没有这个东西就好了也不需要与m值、km值和rx_id值保存在一起三、Locality CheckLocality Check分为两个阶段3.1 LC_Init用于将8-bytes大小的随机值rn发送给HDCP Rxrn值软件代码中定义不是16-bytes嘛怎么这里就发送8-bytes大小呢代码实现通过代码我们可以看到发送的不仅仅是8-bytes大小的rn数据而且还是rn的低8-bytes数据为什么要这样做呢在SKE_Send_Eks阶段我们会进行详细说明在发送LC_Init msg后20ms之内必须发送LC_Send_L_Prime msg用于获取Rx端的L值具体来讲是rn值最后一个字节写入后的20ms内注意在发送LC_Send_L_Prime msg之前需要先判断Rx是否准备好数据代码实现3.2 LC_Send_L_prime从HDCP Rx读取回来的rx_L值与我们计算出来的tx_L值进行比较这里我们关注一下tx_L值的计算过程以及rx_L值与tx_L值的比较过程若rx_L值与tx_L值比较通过则进入下一阶段若比较失败则可以再次发起LC_Init和LC_Send_L_prime过程最大可以循环执行1023次需要注意的是再次发起LC_Init的时候需要使用新的8-bytes rn值也就是说8-bytes rn值不能与上一次一样代码实现获取了rx_L值后就需要与tx_L进行比对判断是否认证通过我们看一下Tx端是如何进行tx_L值的计算我们可以发现L_Prime值的计算时用到的也是rn低8-bytes数据再来进行tx_L与rx_L的比较四、SKE(Session Key Exchange)ks会话秘钥riv随机初始化向量注意在完成SKE_Send_Eks后至少需要200ms时间后HDCP Tx才能发送加密数据所以我们驱动代码中需要进行延时处理代码实现1、Eks的产生过程综上就是eks高8-bytes数据 (dkey2高8-bytes数据 异或 ks高8-bytes数据)eks低8-bytes数据 (dkey2低8-bytes数据 异或 ks低8-bytes数据 异或 rrx的8-bytes数据)我们再来回顾一下dkey2的产生过程在spec中规定LC阶段rn被初始化为一个16-bytes的随机值然后与Km的低8-bytes数据进行异或操作后送入AES-CTR后产生dkey2所以rn的高8-bytes数据相当于没有什么作用在代码中就可以将rn高8-bytes数据全部定义为0然后将rn低8-bytes数据定义为不为0的任意值也就是说dkey2的高8-bytes数据与rn高8-bytes数据没有什么关系那么eks的高8-bytes数据也就与rn高8-bytes数据没有什么关系那么HDCP Rx在解密ks时就用不到rn高8-bytes数据再加上L_Prime值的计算用的也是rn低8-bytes数据所以在LC阶段只需要发送rn的低8-bytes数据即可2、SKE_Send_Eks至此HDCP2.x认证过程已全部完成该过程是纯软件行为没有任何HDCP Tx硬件参与接下来就是HDCP Tx发送加密数据了看一下HDCP Tx是如何使能HDCP硬件的所有的HDCP设备不论是Tx还是Rx都共享秘密常数lc128秘密常数由DCP LLC提供用于生成最终加密秘钥k_finalk_final ks ^ lc128目的是为了防止ks直接泄露导致内容被解密最终的数据加密方式如上图所示重点关注一下inputCtrinputCtr FrameNumber || DataNumberFrameNumbe帧号顾名思义每发送一帧数据后FrameNumber 1DataNumber 数据号与key stream相关每生成一次key stream则DataNumber 1(ks^lc128, riv, inputCtr)经过AES-CTR后产生128-bits key stream其会与每5个24-bit像素数据进行异或操作这就是数据加密操作然后发送给HDCP Rx同样对于HDCP Rx而言在收到eks后会解密得到ks同时使用收到的riv和自身的ls128对接收到的加密视频进行解密。代码实现最后我们再来说明一下HDCP2.x中用到的伪随机值(pseudo-random number generator)在HDCP2.x认证过程中用到的8-bytes rrx/rtx/riv/rn都是高质量伪随机数正常流程应该是使用硬件PRNG(符合NIST SP 800-90标准)生成但是实际测试过程中我们驱动代码是自己定义的随机数最后我们也来说明一下SRM(system renewability message-系统可更新性消息)也就是说如果HDCP Tx要支持SRM功能就需要将DCP LLC发布的加密文件存储并且进行解析(要求以binary格式存储)里面包含了被revoke(撤销)掉的Device IDs所以当在认证过程中获取到HDCP Rx公钥证书后与Receiver IDs进行比对若比对通过则终止认证过程实际上我们很少会使用SRM机制

相关新闻

Apktool 反编译与重打包 APK:新手 3 分钟跑通指南

Apktool 反编译与重打包 APK:新手 3 分钟跑通指南

Apktool 反编译与重打包 APK:新手 3 分钟跑通指南 【免费下载链接】Apktool A tool for reverse engineering Android apk files 项目地址: https://gitcode.com/GitHub_Trending/ap/Apktool 它解决什么问题 拿到一个 APK,想看看里面的界面长什么…

2026/11/7 22:41:56 阅读更多 →
Astro + Vue 集成实战:framework-vue 示例项目全流程解析

Astro + Vue 集成实战:framework-vue 示例项目全流程解析

Astro Vue 集成实战:framework-vue 示例项目全流程解析 【免费下载链接】astro The web framework for content-driven websites. ⭐️ Star to support our work! 项目地址: https://gitcode.com/GitHub_Trending/as/astro 本篇以 Astro 官方示例项目 fram…

2026/10/25 8:52:49 阅读更多 →
OmniParser 屏幕解析工具快速教程:三步把任意截图变成结构化 GUI 元素

OmniParser 屏幕解析工具快速教程:三步把任意截图变成结构化 GUI 元素

OmniParser 屏幕解析工具快速教程:三步把任意截图变成结构化 GUI 元素 【免费下载链接】OmniParser A simple screen parsing tool towards pure vision based GUI agent 项目地址: https://gitcode.com/GitHub_Trending/omn/OmniParser OmniParser 是一个面…

2026/11/10 8:00:49 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/13 5:13:25 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/13 5:13:25 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/13 5:13:25 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/12 18:22:26 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/12 18:22:25 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/13 5:13:25 阅读更多 →

日新闻

周新闻

月新闻