国密SM2算法密钥派生函数KDF的实现

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

  • 7
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值