OpenSSL/GMSSL EVP接口说明——3.4 签名验签

本文详细介绍了基于EVP_PKEY_CTX和EVP_MD_CTX的SM2签名验签流程,包括不同流程的步骤和相关函数的使用,如EVP_PKEY_sign_init、EVP_PKEY_CTX_set_ec_sign_type和EVP_PKEY_sign等,以及示例代码,展示了如何在签名和验签过程中初始化上下文、设置签名类型和执行签名验证操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3.4 签名验签

签名验签的几种流程

假设EVP_PKEY *pkey已经生成完毕。

签名和验签各有几套流程:

  1. 基于EVP_PKEY_CTX的流程。待签名的数据为SM2A1A2步的计算结果,必须是32字节,所以此流程内不再做签名的A1和A2步。验签同理。
  2. 基于EVP_MD_CTX的流程1。待签名的数据为SM2A1步的计算结果,可以是任意长度,所以此流程内不再做签名的A1步,从A2步开始执行。验签同理。
  3. 基于EVP_MD_CTX的流程2。待签名的数据为SM2A1步的计算结果,可以是任意长度,所以此流程内不再做签名的A1步,从A2步开始执行。验签同理。

SM2_signSM2_verify流程图

几种签名验签流程都要涉及SM2_sign和SM2_verify,这两个函数又存在层层调用,所以下面列出SM2_sign和SM2_verify的流程图。

图3.1 SM2_sign和SM2_verify流程图

基于EVP_PKEY_CTX的流程

表3.2基于EVP_PKEY_CTX的签名验签使用步骤

签名

验签

1

pkctx = EVP_PKEY_CTX_new(

pkey, NULL))

pkctx = EVP_PKEY_CTX_new(

pkey, NULL))

2

EVP_PKEY_sign_init(pkctx)

EVP_PKEY_verify_init(pkctx)

3

EVP_PKEY_CTX_set_ec_sign_type(

pkctx, NID_sm_scheme)

EVP_PKEY_CTX_set_ec_sign_type(

pkctx, NID_sm_scheme)

4

EVP_PKEY_sign(

pkctx, sig, &siglen, dgst, dgstlen)

EVP_PKEY_verify(

pkctx, sig, siglen, dgst, dgstlen)

5

EVP_PKEY_CTX_free(pkctx);

EVP_PKEY_CTX_free(pkctx);

其中

  1. EVP_PKEY_CTX_newEVP_PKEY_CTX_free函数的使用说明请参见3.2 EVP_PKEY_CTXEVP_PKEY操作。
  2. 剩余函数的说明见后。

基于EVP_PKEY_CTX的签名验签流程图如下。

图3.2 基于EVP_PKEY_CTX的签名验签流程图

以上流程图中的SM2_sign和SM2_verify的流程图见SM2_signSM2_verify的流程图

基于EVP_MD_CTX的流程1

表3.3基于EVP_MD_CTX的流程1的签名验签使用步骤

签名

验签

1

mdctx = EVP_MD_CTX_create()

mdctx = EVP_MD_CTX_create()

2

EVP_SignInit_ex(mdctx, md, NULL)

EVP_VerifyInit_ex(mdctx,md,NULL)

3

EVP_SignUpdate(mdctx, msg, mlen)

EVP_VerifyUpdate(mdctx, msg,mlen)

4

EVP_SignFinal(mdctx,sig,&slen,pkey)

EVP_VerifyFinal(mdctx,sig,slen,pkey)

5

EVP_MD_CTX_destroy(mdctx)

EVP_MD_CTX_destroy(mdctx)

其中

  1. EVP_MD_CTX_createEVP_MD_CTX_destroy函数的使用说明请参见2.2 EVP_MD_CTX操作
  2. 剩余函数的说明见后。

基于EVP_MD_CTX的流程1的签名验签流程图如下。

图3.3 基于EVP_MD_CTX的流程1的签名验签流程图

以上流程图中的SM2_sign和SM2_verify的流程图见SM2_signSM2_verify的流程图

基于EVP_MD_CTX的流程2

表3.4基于EVP_MD_CTX的流程2的签名验签使用步骤

签名

验签

1

mdctx = EVP_MD_CTX_create();

mdctx = EVP_MD_CTX_create();

2

EVP_DigestSignInit(

mdctx, &pkctx, md, NULL, pkey);

EVP_DigestVerifyInit(

mdctx, &pkctx, md, NULL, pkey);

3

EVP_PKEY_CTX_set_ec_sign_type(

pkctx, type);

EVP_PKEY_CTX_set_ec_sign_type(

pkctx, type);

4

EVP_DigestSignUpdate(

mdctx, msg, msglen);

EVP_DigestVerifyUpdate(

mdctx, msg, msglen);

5

EVP_DigestSignFinal(

mdctx, sig, &siglen);

EVP_DigestVerifyFinal(

mdctx, sig, siglen);

6

EVP_MD_CTX_destroy(mdctx);

EVP_MD_CTX_destroy(mdctx);

其中

  1. EVP_MD_CTX_createEVP_MD_CTX_destroy函数的使用说明请参见2.2 EVP_MD_CTX操作
  2. 剩余函数的说明见后。

基于EVP_MD_CTX的流程2的签名验签流程图如下。

图3.4 基于EVP_MD_CTX的流程2的签名验签流程图

以上流程图中的SM2_sign和SM2_verify的流程图见SM2_signSM2_verify的流程图

EVP_PKEY_sign_init

:   int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx);

功能描述:   签名之前的EVP_PKEY_CTX初始化

    :   -

参数说明:

       ctx         (in/out)         EVP_PKEY_CTX

:   1[成功],<=0[失败]

EVP_PKEY_CTX_set_ec_sign_type

:   #define EVP_PKEY_CTX_set_ec_sign_type(ctx, type)

功能描述:   利用曲线类型设置签名/验签的曲线参数

    :   -

  1. 签名和验签之前都要调用该函数
  2. 便于后续利用对应的曲线参数生成密钥
  3. SM2type = NID_sm_scheme
  4. 调用EVP_PKEY_CTX_ctrl

参数说明:

       ctx         (in/out)         EVP_PKEY_CTX

       type              (in)               类型

:   1[成功],<=0[失败]

EVP_PKEY_sign

:   int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen);

功能描述:   签名

    :  

              1. 需一次性将待签名数据送完

              2. 返回的签名值sig是对SM2签名数据(r,s)做i2d_ECDSA_SIG的结果。

参数说明:

       ctx         (in/out)         EVP_PKEY_CTX

       sig         (out)             签名(字符型)

       siglen   (out)             签名长度

       tbs         (in)               待签名数据

       tbslen    (in)               待签名数据长度

:   1[成功],<=0[失败]

EVP_PKEY_verify_init

:   int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx);

功能描述:   验签之前的EVP_PKEY_CTX初始化

    :   -

参数说明:

       ctx         (in/out)         EVP_PKEY_CTX

:   1[成功],<=0[失败]

EVP_PKEY_verify

:   int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen);

功能描述:   验签

    :  

              1. 需一次性将待验签数据送完

              2. 函数内做d2i_ECDSA_SIG将签名还原为SM2签名数据(r, s)。

参数说明:

       ctx         (in/out)         EVP_PKEY_CTX

       sig         (in)               签名(字符型)

       siglen   (in)               签名长度

       tbs         (in)               待验签数据

       tbslen    (in)               待验签数据长度

:   1[验签通过],<=0[验签失败]

EVP_SignInit

:   # define EVP_SignInit(ctx, md)

功能描述:   签名之前的EVP_MD_CTX初始化

    :   # define EVP_SignInit(ctx, md) EVP_DigestInit(ctx, md)

参数说明:

       ctx         (in/out)         EVP_MD_CTX数据

       md         (in)               杂凑算法,如EVP_sm3()

:   1[成功],<=0[失败]

EVP_SignInit_ex

:   # define EVP_SignInit_ex(ctx,md,eng)

功能描述:   签名之前的EVP_MD_CTX初始化

    :   # define EVP_SignInit_ex(ctx,md,eng) EVP_DigestInit_ex(ctx,md,eng)

参数说明:

       ctx         (in/out)         EVP_MD_CTX数据

       md         (in)               杂凑算法,如EVP_sm3()

       eng        (in)               引擎

:   1[成功],<=0[失败]

EVP_SignUpdate

:   # define EVP_SignUpdate(ctx,m,mlen)

功能描述:   设置签名数据

    :   -数据可分多次送入

              # define EVP_SignUpdate(ctx,m,mlen) EVP_DigestUpdate(ctx,m,mlen)

参数说明:

       ctx         (in/out)  EVP_MD_CTX数据

       m           (in)        数据

       mlen      (in)        数据长度

:   1[成功],<=0[失败]

EVP_SignFinal

:   int EVP_SignFinal(EVP_MD_CTX *ctx, unsigned char *sig, unsigned int *slen, EVP_PKEY *pkey);

功能描述:   签名结束获取签名值

    :   1. 返回的签名值sig是对SM2签名数据(r,s)做i2d_ECDSA_SIG的结果。

参数说明:

       ctx         (in/out)         EVP_MD_CTX数据

       sig         (out)             签名(字符型)

       slen       (out)             签名长度

       pkey      (in)               公钥

:   1[成功],<=0[失败]

EVP_VerifyInit

:   # define EVP_VerifyInit (ctx, md)

功能描述:   验签之前的EVP_MD_CTX初始化

    :   # define EVP_VerifyInit(ctx, md) EVP_DigestInit(ctx, md)

参数说明:

       ctx         (in/out)         EVP_MD_CTX数据

       md         (in)               杂凑算法,如EVP_sm3()

:   1[成功],<=0[失败]

EVP_VerifyInit_ex

:   # define EVP_VerifyInit_ex(ctx,md,eng)

功能描述:   验签之前的EVP_MD_CTX初始化

    :  

              # define EVP_VerifyInit_ex(ctx,md,eng) EVP_DigestInit_ex(ctx,md,eng)

参数说明:

       ctx         (in/out)         EVP_MD_CTX数据

       md         (in)               杂凑算法,如EVP_sm3()

       eng        (in)               引擎

:   1[成功],<=0[失败]

EVP_SignUpdate

:   # define EVP_VerifyUpdate(ctx,m,mlen)

功能描述:   设置待验签的消息数据

    :   -数据可分多次送入

              # define EVP_VerifyUpdate(ctx,m,mlen) EVP_DigestUpdate(ctx,m,mlen)

参数说明:

       ctx         (in/out)  EVP_MD_CTX数据

       m           (in)        数据

       mlen      (in)        数据长度

:   1[成功],<=0[失败]

EVP_VerifyFinal

:   int EVP_VerifyFinal(EVP_MD_CTX *ctx, const unsigned char *sig, unsigned int slen, EVP_PKEY *pkey);

功能描述:   获取验签结果(成功/失败)

    :   1. 输入的签名值sig是对SM2签名数据(r,s)做i2d_ECDSA_SIG的结果。

参数说明:

       ctx         (in/out)         EVP_MD_CTX

       sig         (in)        签名(字符型)

       slen       (in)        签名长度

       pkey      (in)               公钥

:   1[验签成功],<=0[验签失败]

签名验签示例代码

注意:其中密钥EVP_PKEY *pkey的生成代码参见密钥生成代码示例

#define DEAL_ERR(lab)\

        fprintf(stderr, "error: %s %d\n", __FILE__, __LINE__);\

        goto lab;

int test_evp_pkey_sign(EVP_PKEY *pkey, int do_sm2)

{

        int ret = 0;

        EVP_PKEY_CTX *pkctx = NULL;

        int type = do_sm2 ? NID_sm_scheme : NID_secg_scheme;

        unsigned char dgst[EVP_MAX_MD_SIZE] = "hello world";

        size_t dgstlen;

        unsigned char sig[256];

        size_t siglen;

        if (!(pkctx = EVP_PKEY_CTX_new(pkey, NULL)))   {DEAL_ERR(end);}

        /* EVP_PKEY_sign() */

        if (!EVP_PKEY_sign_init(pkctx))                                  {DEAL_ERR(end);}

        if (!EVP_PKEY_CTX_set_ec_sign_type(pkctx, type)){DEAL_ERR(end);}

        dgstlen = 32;

        memset(sig, 0, sizeof(sig));

        siglen = sizeof(sig);

        if (!EVP_PKEY_sign(pkctx, sig, &siglen, dgst, dgstlen)) {DEAL_ERR(end);}

        if (!EVP_PKEY_verify_init(pkctx)) {DEAL_ERR(end);}

        if (!EVP_PKEY_CTX_set_ec_sign_type(pkctx, type)) {DEAL_ERR(end);}

        if (EVP_PKEY_verify(pkctx, sig, siglen, dgst, dgstlen) != SM2_VERIFY_SUCCESS) {DEAL_ERR(end);}

        printf("%s(%s) passed\n", __FUNCTION__, OBJ_nid2sn(type));

        ret = 1;

end:

        EVP_PKEY_CTX_free(pkctx);

        return ret;

}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值