关闭

[置顶] 国密SM2算法密钥派生函数KDF的实现

标签: 密钥派生函数KDFSM2国密算法加解密
2188人阅读 评论(4) 收藏 举报
分类:

前段时间需要实现国密算法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;
}

特别说明:代码中 sm3( ) 为 国密算法中的 密码杂凑算法sm3,已有前辈共享了实现代码,直接拿来使用,请自行搜索。

示例数据1:
输入数据 cdata : 00000000000000000000000000000000,
派生长度keylen:32,
返回内容retdata:2744A6D84E20D493696906799924577BEF6E900E40629D55F2D9677C825D64B2

示例数据2:
输入数据 cdata : 11223344556677881122334455667788,
派生长度keylen:32,
返回内容retdata:7EA06CE33DE666F0DDABFD22F6FA57F843059CA717F712150E2ACCC71F82317B

1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:19286次
    • 积分:315
    • 等级:
    • 排名:千里之外
    • 原创:12篇
    • 转载:3篇
    • 译文:0篇
    • 评论:6条
    文章存档
    最新评论