hdcp简介
HDCP(High-bandwidth Digital Content Protection,高带宽数字内容保护)HDCP 是 Intel 公司制定的,能够避免数字接口传输的音视频被非法复制。这些数字接口包括 HDMI,DVI,
DisplayPort 等。HDCP 要求音视频在接收端与发送端之间进行加密传输。
hdcp算法介绍
1.密码学算法
本文简单介绍hdcp涉及的加密算法流程,主要是dh和sha-1,后续可能会补充下des,rsa,hmac,伪随机数发生器,lfsr等内容。
1.1.Diffie-Hellman密钥交换算法
DH算法属于公钥加密的算法,公钥加密,私钥解密。
DH算法基于离散对数,假设a,p均为素数,则有如下的等式:
{}表示集合,这个公式很好理解,一个数mod一个素数p,其值一定不为0,只可能是1 和 p-1之间的数。
有 ,证明如下:
两者计算得到的一定相等,后面我们可以看到,hdcp第一阶段的交换过程的原理与之类似。
1.2 sha-1算法介绍及其c代码实现
sha-1,全称Secure Hash Algorithm,sha-1生成160bit的数据,sha-256生成256bit的数据,相比与sha256而言,sha-1安全性是比不上的,但是sha-1和sha-256大致流程类似,sha-1更容易理解其流程,更容易实现。
sha-1,输入为长度为0-2^64bit的消息,输出160bit的消息摘要,大致流程如下:
将消息m分组,每组512bit,最后一组不够512bit,在最后一组补1,其余位补0,直到满足最后一组的L mod 512 = 448;512 - 448 = 64,64为预留的消息的长度。
接着一组一组的进行处理,将每组的512bit分成16 * 32,也就是16份,每份32bit,进行预处理,按下图所示的方式处理成80组,
接着初始化5个常量,用于计算
将上面初始化的常量赋值给abced,再按如下图所示的方式进行80轮迭代
sha-1的代码如下:
#include<stdio.h>
/*定义用到的常量*/
unsigned int A = 0x67452301, B = 0xEFCDAB89, C = 0x98BADCFE, D = 0x10325476, E = 0xC3D2E1F0; //第一次迭代的链接变量
unsigned int K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6}; //循环中用到的常量
unsigned int A0 = 0x67452301,B0 = 0xEFCDAB89,C0 = 0x98BADCFE,D0 = 0x10325476,E0 = 0xC3D2E1F0;
/*字节转字*/
int CharToWord(unsigned char *character, int first)
{
int temp = (((int)character[first] & 0x000000ff) << 24) |
(((int)character[first + 1] & 0x000000ff) << 16) |
(((int)character[first + 2] & 0x000000ff) << 8) |
((int)character[first + 3] & 0x000000ff);
return temp;
}
/*f函数*/
unsigned int f(int B, int C, int D, int t)
{
return (t >= 0 && t <= 19) ? ((B&C) | (~B&D)) : ((t >= 20 && t <= 39) ? (B ^ C ^ D) : ((t >= 40 && t <= 59) ? ((B&C) | (B&D) | (C&D)) : ((t >= 60 && t <= 79) ? B ^ C ^ D : 0)));
}
/*从W消息分组中导出*/
void GetExtraMessage(unsigned int w[])
{
for (int i = 16; i < 80; i++)
w[i] = ((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) << 1) |
((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]) >> 31);
}
/*分组*/
void DevideToGroup(unsigned char *plaintext,unsigned int *group,int length)
{
//512 - 64 = 448;
//448 - (length + 1) 0的个数
//填充
unsigned char temp[64] = {0};
for (int i = 0; i < length; i++)
temp[i] = plaintext[i];
temp[length] = 0x80;
int len = length * 8;
for (int i = 0; i <= 7 && len; i++) {
temp[63 - i] = len & 0xff;
len = (len >> 8);
}
for (int i = 0; i < 16; i++)
group[i] = CharToWord(temp, i * 4);
}
unsigned int GetK(int t)
{
return (t >= 0 && t <= 19) ? K[0] : ((t >= 20 && t <= 39) ? K[1] : ((t >= 40 && t <= 59) ? K[2] : ((t >= 60 && t <= 79) ? K[3] : 0)));
}
/*步函数*/
unsigned int StepFunction(unsigned int w[],int t)
{
unsigned int temp = ((A << 5)|(A >> 27)) + f(B, C, D, t) + E + w[t] + GetK(t);
E = D,D = C,C = ((B << 30) | (B >> 2)),B = A,A = temp;
printf("第%2d轮加密后的密文是%08X %08X %08X %08X %08X\n", t + 1, A, B, C, D, E);
}
/*密文组合*/
unsigned int CombineCipher(unsigned int cipher[])
{
for (int i = 0; i <= 4; i == 0 ? cipher[i] = (A0 + A) : (i == 1 ? cipher[i] = (B0 + B) : (i == 2 ? cipher[i] = (C0 + C) : (i == 3 ? cipher[i] = (D0 + D) : (i == 4 ? cipher[i] = (E0 + E) : 0)))), i++);
}
int main()
{
int i, t, j, length, temp;
unsigned char plaintext[64] = "abc", hash[20] = { 0 };
unsigned int group[80] = { 0 }, cipher[5] = { 0 };
/*长度填充到最后*/
printf("当前明文字符串为:");
for (i = 0; plaintext[i]; length = i + 1,i++)
{
printf("%c", plaintext[i]);
group[15] = (i + 1) * 8; //长度是二进制位数
}
/*分组填补*/
printf("\n\n0x00 正在分组…………\n****************************");
DevideToGroup(plaintext, group, length);
/*从w消息分组中导出*/
GetExtraMessage(group);
/*80次步函数*/
printf("\n0x01 SHA-1加密中…………\n****************************\n");
for (t = 0; t < 80; t++)
{
StepFunction(group, t);
if (!((t + 1) % 20)) printf("\n");
}
/*密文组合*/
printf("\n0x02 hash值组合中…………\n****************************\n");
CombineCipher(cipher);
/*密文输出*/
printf("\n0x03 SHA-1加密成功!!!\n****************************\nHash:");
for (j = 0; j <= 4; j++) printf("%08X", cipher[j]);
printf("\n");
return 0;
}
运行结果如下:
文献给的算例结果如下:
可以看到,编写的c代码算出的结果与sha文献中给出的结果一致,验证了代码的正确性。
2.hdcp协议流程&代码注解与分析
hdcp流程参考上海交大的论文基于 HDMI 的 HDCP 认证及加密的软件实现以及hdcp1.4的spec来进行讲解,介绍hdcp1.4的流程与实现,hdcp1.4一般是用硬件来实现的,软件做的话会比较慢。交大的这篇论文最后的实验结果是跑在intel core i5双核超线程2.8G处理器上,用优化后的软件版本,软件在1920x1080的高清分辨率下,达不到60帧。说明软件实现速度是不够了,距离这篇论文过去十几年,电脑以及芯片性能肯定有提升,但跑在芯片上,最多只能支持hdmi1.4,hdmi2.0的4k60用软件去跑负载肯定会非常重,更不用提hdmi2.1了。
2.1 hdcp1.4流程
2.1.1 hdcp1.4第一阶段![](https://img-blog.csdnimg.cn/direct/a08a619a869f408191af5f8f3512bc2d.png)
![](https://img-blog.csdnimg.cn/direct/abf19735117e43af94174cbb88c35b34.png)
![](https://img-blog.csdnimg.cn/direct/ce1e547ffc8842dab90e9e284df41469.png)
看下spec给的例子:
0xb70361f714,选0,2,3,6,7,...,38,0x511ef21acd选2,4,8,9,10,...39,结果相加,写了个c代码验证,如下:
#include<stdio.h>
int main()
{
unsigned long long k[20] = {0x4da4588f131e69, 0x8a6a47abb9980d, 0xf3181b52cbc5ca,
0xa0d064c8112c41, 0xb39d5a28242044, 0x91a47b4a6ce4f6,
0x8c7fb706ee3fa0, 0xc02d8c9d7cbc28, 0x482f8e46785498,
0xe2d231767b3a54, 0x4d581aede66125, 0x326082bf7b22f7,
0xf61b463530ce6b, 0xa1e105618d49f9, 0xc98e9dd1053406,
0x20c36794426190, 0x964451ceac4fc3, 0x54c7ea5bdd7b43,
0x05d3408a78fb01, 0x373b634a2c9e40};
unsigned long long k1[20] = {0x24bf2185a36c60, 0xa72e69c5eb6388, 0x3b9857797d5103,
0x0dd170be615250, 0x1a748be4866bb1, 0x4bbb037899eea1,
0x190ecf9cc095a9, 0xa821c46897447f, 0x1a8a0bc4298a41,
0xaefc0853e62082, 0xe3053fa3e9fa69, 0x37d8002881c7d1,
0x9e93d41e0811f7, 0x2c4074509eec6c, 0x1280161221df6d,
0xca31a5f2406589, 0x1d30e8cb198e6f, 0xcec7ec09245b43,
0xb08129efedd583, 0xedeef9d099b78c};
unsigned long long sum = 0;
for (int i = 0; i < 20; i++) {
sum = (sum + k[i]) & 0xffffffffffffff;
}
printf("sum = 0x%llx\n", sum);
unsigned long long sum1 = 0;
for (int i = 0; i < 20; i++) {
sum1 = (sum1 + k1[i]) & 0xffffffffffffff;
}
printf("sum1 = 0x%llx\n", sum1);
}
可以看到,算出来的结果相等且同spec一致
计算出km之后,根据km,repeat和An算ks,m0和r0,验证r0和rx端读到的值是不是相等,相等则继续,不等则失败。以上是第一阶段的流程。
2.1.2 hdcp1.4第二阶段
HDCP 的接收器是一个 HDCP 中继器的时候需要第二阶段的认证,只有 REPEATER 位被置上表明下游设备是一个 HDCP 中继器的时候,HDCP 的发 送器才会执行第二阶段的认证协议。在这个阶段通过一个 HDCP 的连接树,收集下游所有连接到 HDCP 中继器设备的 Ksv 列表。HDCP 中继器下游保护的 HDCP 接口端口完成和它连接的所有 HDCP 接收 设备的认证协协议之后,HDCP 中继器会收集一个它所连接的 HDCP 接收器的列表。这 个列表为一个连续的字节序列,每个 Ksv 占据 5 个字节,即 40 个 bit,按照小端的方式 排列。这个字节序列的长度为下游连接的包括 HDCP 中继器在内的 HDCP 设备的数量 的 5 倍字节。一个 HDCP 保护的接口端口如果没有活动的设备连接,那么它下面连接的 的设备不会有任何信息加入到这个列表。当然,在任何一级上的 HDCP 中继器上的 KSV 列表都不包括 HDCP 中继器本身。如果一个 HDCP 保护的接口端口连接的是一个 HDCP 接收器而不是一个 HDCP 中继器,那么就把 BKsv 加入到列表当中。如果一个 HDCP 保 护的接口端口连接的是一个 HDCP 中继器,那么就把下游 HDCP 中继器的 Ksv 列表加 入到当前列表,在加上这个下游的 HDCP 中继器的本身的Ksv。
HDCP协议中V(V’)计算如下:V(V’)=SHA1(ksv_list||binfo||Mo(Mo’))。
KSV list存储于Repeater DPCD地址0x6802C~0x6803A的FIFO中,FIFO中有15字节,每个设备的KSV是40比特,也就是5字节,所以 FIFO中每次读取出来的是3个设备KSV。HDCP的Repeater最多支持下游有127个设备,也就是说FIFO最多需要读取127/3次。每次读取完后硬件会自动清掉被读走的数据,同时用下一组KSV填满。Binfo是存储下游设备拓扑结构的16比特数据,包括拓扑深度等。Mo(Mo’)是 64比特的私钥。也就是说计算V(V’)时,系统传输给SHA1的消息长度最大为127×40+16+64=5160(0x1428H)比特,对于长度小于2^64(0x40000000000000H)位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,这时候就会产生不同的消息摘要。 SHA1算法只接收位输入。字符串“KSV list||Binf||M0”消息摘要需转换成位字符串如下:01100001 01100010 01100011……010011010(5160位),SHA1根据这个消息来计算MD5。
2.1.3 hdcp认证第三阶段
Ki,类似Ks,56bits,用于HDCP cipher对HDCP内容加密、解密。Mi,一个新的64bits 随机数,由加密函数生成,Ri,16bits,用于链路完整性检查,每128frame时更新一次。ransmitter和Receiver各自计算出 (Ki, Mi, Ri)还是通过hdcpBlockCipher计算出来。检测两端ri相不相等。
2.2 代码注解
![](https://img-blog.csdnimg.cn/direct/0ebab3fd9f4e4fd1b913951d244c1d6e.png)
2.2.1 基本模块接口
![](https://img-blog.csdnimg.cn/direct/6ab68344cf714b57b37978fa612de7d5.png)
![](https://img-blog.csdnimg.cn/direct/31aade33ed4c4e338f8afe623674af23.png)
![](https://img-blog.csdnimg.cn/direct/fb71dd304933476d9ea12cd5eddf4574.png)
![](https://img-blog.csdnimg.cn/direct/4005324b8dbc47afbc693c4d38c67bd7.png)
![](https://img-blog.csdnimg.cn/direct/729b436660fc4487b6f62e5487521b6c.png)
![](https://img-blog.csdnimg.cn/direct/df4c350427d0488eb13799ca03ec67b8.png)