前言
最近项目需要使用KDF生成秘钥,对比国密标准(GB_T 32918.4-2016)及网络资料,发现确实没有让我满意的, 自己结合标准和大佬:Heidlyn的帖子《国密SM2算法密钥派生函数KDF的实现》动手写了一个并成功通过标准下面的测试用例,个人认为更加通俗易懂。现分享给大家
代码
//KDF函数的实现基于GB_T32918_4-2016 5.3.4章《密钥派生函数》实现
//函数功能:KDF秘钥派生函数
//输入参数: Z -用于计算的比特串
// Zlen -Z的字节数
// klen -需要获得秘钥数据的字节长度
//输出参数: K -长度为klen的秘钥数据比特串K(这里设置为128位)
void my_KDF(const unsigned char* Z, const unsigned int Zlen, const unsigned int Klen, unsigned char* K)
{
unsigned int ct = 1; //计数器
unsigned char cCt[4] = { 0 }; //计数器的内存表示值
unsigned char *pData = new unsigned char[Zlen + 4];
unsigned char cdgst[32] = { 0 }; //摘要
int nDgst = 32; //摘要长度 单位:字节
unsigned int hash_len; //sm3输出串长度
int index = (Klen + 32) / 32; //需要计算的次数,这里+32表示至少要进行一次循环
if (Z == NULL || Klen <= 0 || Zlen < 0 || K == NULL)
{
return -1;
}
//初始化空间
memset(pData, 0, Zlen + 4);
//复制比特串Z
memcpy(pData, Z, Zlen);
for (size_t i = 0; i < index ; i++)
{
//内存表示计数器
{
cCt[0] = (ct >> 24) & 0xFF;
cCt[1] = (ct >> 16) & 0xFF;
cCt[2] = (ct >> 8) & 0xFF;
cCt[3] = (ct) & 0xFF;
}
//拼接比特串
memcpy(pData + Zlen, cCt, 4);
//sm3函数处理,这里使用openssl内的EVP_SM3接口处理
SM3_HASH(pData, Zlen + 4, cdgst, &hash_len);
//最后一次计算,根据klen/32是否整除,若未整除,则截取最后一次hash的值
if (i == index - 1)
{
if (Klen % 32 != 0)
{
nDgst = (Klen) % 32;
}
}
memcpy(K + 32 * i, cdgst, nDgst);
ct++;
}
return ;
}
测试部分
测试用例截取(GB_T 32918.4-2016)标准中的部分涉及到KDF的计算,下面是截图
图里的用例是将坐标x2和y2拼接后进行KDF运算,其中生成消息
比特长度
为152
我将截图里的测试用例文字显示出,方便各位测试:
坐标x2: 64D20D27D0632957F8028C1E024F6B02EDF23102A566C932AE8BD613A8E865FE
坐标y2: 58D225ECA784AE300A81A2D48281A828E1CEDF11C4219099840265375077BF78
应 得: 006E30DAE231B071DFAD8AA379E90264491603
测试结果:
上述代码中使用到的SM3函数为openssl中的EVP_SM3接口,我自己做了简单封装,可以直接调用EVP_SM3使用。
版权声明:本文为daojuedi1023原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。