前段时间需要实现国密算法SM2的签名、验签、加密、解密等功能,加解密过程使用到的密钥派生函数(KDF),从网上搜到的代码不符合《GMT 0003.4-2012 SM2椭圆曲线公钥密码算法 》的规定,不能直接使用,没法满足项目需要,后来决定自行实现,整理如下,欢迎大家讨论:
密钥派生函数算法逻辑
《GMT 0003.4-2012 SM2椭圆曲线公钥密码算法 》中 关于 密钥派生函数的规定如下:
密钥派生函数的C语言实现
代码实现:
//函数名称:my_KDF
//函数功能:实现国密SM2加解密算法中的密钥派生函数kdf
//输入参数:cdata -用于计算的数据串(二进制值)
// datalen -内容长度
// keylen -需要派生得到的长度
//输出参数:retdata -计算后返回的内容(二进制值),分配空间至少为需要keylen
//返回值:int 0表示成功,其他表示失败
int my_KDF(const char* cdata, int datalen, int keylen, char* retdata)
{
int nRet = -1;
unsigned char *pRet;
unsigned char *pData;
if(cdata==NULL || datalen<=0 || keylen<=0)
{
goto err;
}
if(NULL == (pRet=(unsigned char *)malloc(keylen)))
{
goto err;
}
if(NULL == (pData=(unsigned char *)malloc(datalen+4)))
{
goto err;
}
memset(pRet, 0, keylen);
memset(pData, 0, datalen+4);
unsigned char cdgst[32]={0}; //摘要
unsigned char cCnt[4] = {0}; //计数器的内存表示值
int nCnt = 1; //计数器
int nDgst = 32; //摘要长度
int nTimes = (keylen+31)/32; //需要计算的次数
int i=0;
memcpy(pData, cdata, datalen);
for(i=0; i<nTimes; i++)
{
//cCnt
{
cCnt[0] = (nCnt>>24) & 0xFF;
cCnt[1] = (nCnt>>16) & 0xFF;
cCnt[2] = (nCnt>> 8) & 0xFF;
cCnt[3] = (nCnt ) & 0xFF;
}
memcpy(pData+datalen, cCnt, 4);
sm3(pData, datalen+4, cdgst);
if(i == nTimes-1) //最后一次计算,根据keylen/32是否整除,截取摘要的值
{
if(keylen%32 != 0)
{
nDgst = keylen%32;
}
}
memcpy(pRet+32*i, cdgst, nDgst);
i ++; //
nCnt ++; //
}
if(retdata != NULL)
{
memcpy(retdata, pRet, keylen);
}
nRet = 0;
err:
if(pRet)
free(pRet);
if(pData)
free(pData);
return nRet;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
特别说明:代码中 sm3( ) 为 国密算法中的 密码杂凑算法sm3,已有前辈共享了实现代码,直接拿来使用,请自行搜索。
示例数据1:
输入数据 cdata : 00000000000000000000000000000000,
派生长度keylen:32,
返回内容retdata:2744A6D84E20D493696906799924577BEF6E900E40629D55F2D9677C825D64B2
示例数据2:
输入数据 cdata : 11223344556677881122334455667788,
派生长度keylen:32,
返回内容retdata:7EA06CE33DE666F0DDABFD22F6FA57F843059CA717F712150E2ACCC71F82317B