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

原创 2017年01月03日 11:42:33

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

版权声明:本文为博主原创文章,转载请务必注明出处!

密钥导出函数(Key derivation function)

在密码学中,KDF使用伪随机函数从秘密值导出一个或多个密钥,并可用于将密钥扩展到更长的密钥或获得所需格式的密钥。...
  • sjrGCkym
  • sjrGCkym
  • 2017年10月10日 18:30
  • 640

SM2算法第三篇:实现SM2秘钥交换协议的算法流程

秘钥交换协议
  • qq_30866297
  • qq_30866297
  • 2016年04月19日 21:30
  • 4883

国密SM3算法及基于SM3的密钥派生函数KDF

  • 2017年11月24日 17:59
  • 5KB
  • 下载

密钥算法

package com.sprucetec.tms.fee.utils; import java.security.Key; import javax.crypto.Cipher; import ...
  • java_dyq
  • java_dyq
  • 2016年12月21日 10:38
  • 525

SM2 生成秘钥 加解密

  • 2015年04月16日 08:55
  • 2.5MB
  • 下载

CSP设计之-密钥的产生和交换函数

密钥的产生和交换函数    CPDeriveKey    CPDestroyKey    CPDuplicateKey   ...
  • zcyu123
  • zcyu123
  • 2016年12月23日 14:37
  • 491

国密算法实现

  • 2014年06月30日 16:55
  • 18KB
  • 下载

KMS密钥算法总结

对称加密对称密钥加密在加密和解密时使用相同的密钥,或是使用两个可以简单地互相推算的密钥。对称加密的速度比公钥加密快很多,加密算法有DES,3DES,AES,Blowfish,IDEA,RC5,RC6。...
  • phantom_111
  • phantom_111
  • 2017年09月06日 12:11
  • 211

SM2算法第三篇:实现SM2秘钥交换协议的算法流程

秘钥交换协议
  • qq_30866297
  • qq_30866297
  • 2016年04月19日 21:30
  • 4883

MPI 数据结合体

即使是使用MPI接口实现并行编程,我们必须明确MPI最大的性能消耗在哪里,几乎所有的分布式内存系统,通信比本地计算的成本都会高出许多。 因此,如果减少发送的消息数量,就能肯定相对的提高程序的性能...
  • zmrlinux
  • zmrlinux
  • 2017年01月26日 22:29
  • 360
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:国密SM2算法密钥派生函数KDF的实现
举报原因:
原因补充:

(最多只允许输入30个字)