背景

SM2算法基于ECC椭圆曲线算法,广泛用于区块链、HTTPS 等需要非对称加密的场景。是基于椭圆曲线数学理论实现的一种非对称加密算法。相比RSA,ECC优势是可以使用更短的密钥,来实现与RSA相当或更高的安全。

下面链接可以了解一些关于SM2的基础知识。

椭圆曲线加密算法(ECC)信息安全技术 SM2密码算法使用规范深入浅出讲解国密算法

可以看下知乎上这张图,一眼就可以看出SM1 SM2 SM3等和我们常见的国际加密算法的对应关系。

因为国产化原因,项目中需要使用国标sm2签名算法对文件进行签名和验签。OpenSSL 1.1.1版本提供了对国密SM2算法的支持,在之前的版本openssl不支持。

目前关于使用sm2算法,有两种做法,一种是采用开源库 gmssl。gmssl3已经脱离了openssl的依赖,现在是一个比较好的支持国密算法和ssl协议的三方库。

关于gmssl的使用可以参考它的源码链接,还是比较简单的。

https://gitee.com/mirrors/GmSSL国密SSL实验室

第二种是本文的做法,使用openssl1.1.1版本中的sm2的支持。

核心代码

#pragma once

#include

class Sm2Helper

{

public:

/**

* @brief 生成sm2密钥

* @param [IN] privKeyfilePath 私钥文件的完整存储路径(包含文件名),函数内部会将私钥内容写入文件

* @param [IN] pubKeyfilePath 公钥文件的完整存储路径(包含文件名),函数内部会将公钥内容写入文件

*/

static bool sm2genKey(SM2_KEY_PAIR& key_pair, const std::string& privKeyfilePath,

const std::string& pubKeyfilePath);

/**

* @brief 用私钥和公钥对文件进行签名

* @param [IN] user_id 在同一套密钥下,可以对同一个文件用不同的user_id 生成不同的签名文件

* @param [IN] msgDigest 要签名文件的摘要信息,一般可以使用文件的md5或者SM3摘要信息(具体使用哪种规则用户可以自定义,但是注意签名和验签要采用相同的方法计算摘要)

* @param [IN] msgDigest_len 摘要信息字符串长度

* @param [IN] privKeyfilePath 私钥文件

* @param [IN] pubKeyfilePath 公钥文件

* @param [OUT] sm2_sig 生成的签名信息(r||s)64字节

* @param [IN] sigfilePath 生成的签名文件,函数内部会将签名信息写入文件

*/

static bool sm2signWithFile(const std::string& user_id, const unsigned char* msgDigest,

const int msgDigest_len,

const std::string& privKeyfilePath, const std::string& pubKeyfilePath,

SM2_SIGNATURE_STRUCT& sm2_sig, const std::string& sigfilePath);

/**

* @brief 用公钥对文件进行签名验证

* @param [IN] user_id 在同一套密钥下,可以对同一个文件用不同的user_id 生成不同的签名文件

* @param [IN] pubKeyfilePath 公钥文件

* @param [IN] msgDigest 待验证文件的摘要信息,一般可以使用文件的md5或者SM3摘要信息(具体使用哪种规则用户可以自定义,但是注意验签和签名要采用相同的方法计算摘要)

* @param [IN] msgDigest_len 摘要信息字符串长度

* @param [IN] sigFilePath 签名文件

*/

static bool sm2VerifyWithFile(const std::string& user_id, const std::string& pubKeyfilePath,

const unsigned char* verifyMsgDigest, const int verifyMsgDigest_len,

const std::string& sigFilePath);

};

#include

#include

#include

#include

#include

#include

#include

#include "sm2_create_key_pair.h"

#include "sm2_sign_and_verify.h"

#include "sm2helper.h"

bool Sm2Helper::sm2genKey(SM2_KEY_PAIR& key_pair, const std::string& privKeyfilePath,

const std::string& pubKeyfilePath)

{

if (0 != sm2_create_key_pair(&key_pair)) {

qWarning("Create SM2 key pair failed!\n");

return false;

}

FILE* fd_key_priv = fopen(privKeyfilePath.data(), "wb+");

if (nullptr == fd_key_priv) {

qWarning("create file %s failed.\n", privKeyfilePath.data());

return false;

}

size_t ret_size = fwrite(key_pair.pri_key, sizeof(unsigned char), PRIVATE_KEY_SIZE, fd_key_priv);

fclose(fd_key_priv);

if (ret_size != PRIVATE_KEY_SIZE) {

qWarning("write private key to file %s error.\n", privKeyfilePath.data());

return false;

}

FILE* fd_key_pub = fopen(pubKeyfilePath.data(), "wb+");

if (nullptr == fd_key_pub) {

qWarning("create file %s failed.\n", pubKeyfilePath.data());

return false;

}

ret_size = fwrite(key_pair.pub_key, sizeof(unsigned char), PUBLIC_KEY_SIZE, fd_key_pub);

fclose(fd_key_pub);

if (ret_size != PUBLIC_KEY_SIZE) {

qWarning("write public key to file %s error.\n", pubKeyfilePath.data());

return false;

}

qDebug("writing key to file OK.\n");

return true;

}

bool Sm2Helper::sm2signWithFile(const std::string& user_id, const unsigned char* msgDigest,

const int msgDigest_len,

const std::string& privKeyfilePath,

const std::string& pubKeyfilePath,

SM2_SIGNATURE_STRUCT& sm2_sig, const std::string& sigfilePath)

{

SM2_KEY_PAIR key_pair;

FILE* fd_key_priv = fopen(privKeyfilePath.data(), "rb+");

if (nullptr == fd_key_priv) {

qDebug("read file %s failed.\n", privKeyfilePath.data());

return false;

}

size_t ret_size = fread(key_pair.pri_key, sizeof(unsigned char), PRIVATE_KEY_SIZE, fd_key_priv);

fclose(fd_key_priv);

if (ret_size != PRIVATE_KEY_SIZE) {

qDebug("read private key error.\n");

return false;

}

FILE* fd_key_pub = fopen(pubKeyfilePath.data(), "rb+");

if (nullptr == fd_key_pub) {

qDebug("read file %s failed.\n", pubKeyfilePath.data());

return false;

}

ret_size = fread(key_pair.pub_key, sizeof(unsigned char), PUBLIC_KEY_SIZE, fd_key_pub);

fclose(fd_key_pub);

if (ret_size != PUBLIC_KEY_SIZE) {

qDebug("read public key error.\n");

return false;

}

if (0 != sm2_sign_data(msgDigest,

msgDigest_len,

reinterpret_cast

(user_id.data()),

user_id.length(),

key_pair.pub_key,

key_pair.pri_key,

&sm2_sig) ) {

qWarning("Create SM2 signature failed!\n");

return false;

}

FILE* fd_sig = fopen(sigfilePath.data(), "wb+");

if (nullptr == fd_sig) {

qDebug("read file %s failed.\n", sigfilePath.data());

return false;

}

ret_size = fwrite(sm2_sig.r_coordinate, sizeof(unsigned char), SIGFILE_HALF_R_SIZE, fd_sig);

if (ret_size != SIGFILE_HALF_R_SIZE) {

qDebug("create image signature file (%s)--r_coordinate error.\n", sigfilePath.data());

fclose(fd_sig);

return false;

}

ret_size = fwrite(sm2_sig.s_coordinate, sizeof(unsigned char), SIGFILE_HALF_S_SIZE, fd_sig);

fclose(fd_sig);

if (ret_size != SIGFILE_HALF_S_SIZE) {

qDebug("create image signature file (%s)--s_coordinate error.\n", sigfilePath.data());

return false;

}

return true;

}

bool Sm2Helper::sm2VerifyWithFile(const std::string& user_id, const std::string& pubKeyfilePath,

const unsigned char* verifyMsgDigest, const int verifyMsgDigest_len,

const std::string& sigFilePath)

{

SM2_SIGNATURE_STRUCT sm2_sig2;

unsigned char pub[PUBLIC_KEY_SIZE] = {0};

FILE* fd_key_pub = fopen(pubKeyfilePath.data(), "rb+");

if (nullptr == fd_key_pub) {

qDebug("read file %s failed.\n", pubKeyfilePath.data());

return false;

}

size_t ret_size = fread(pub, sizeof(unsigned char), PUBLIC_KEY_SIZE, fd_key_pub);

fclose(fd_key_pub);

if (ret_size != PUBLIC_KEY_SIZE) {

qDebug("read public key error.\n");

return false;

}

FILE* fd_sig = fopen(sigFilePath.data(), "rb+");

if (nullptr == fd_sig) {

qDebug("read file %s failed.\n", sigFilePath.data());

return false;

}

ret_size = fread(sm2_sig2.r_coordinate, sizeof(unsigned char), SIGFILE_HALF_R_SIZE, fd_sig);

if (ret_size != SIGFILE_HALF_R_SIZE) {

qDebug("read sig file: %s error.\n", sigFilePath.data());

fclose(fd_sig);

return false;

}

ret_size = fread(sm2_sig2.s_coordinate, sizeof(unsigned char), SIGFILE_HALF_S_SIZE, fd_sig);

fclose(fd_sig);

if (ret_size != SIGFILE_HALF_S_SIZE) {

qDebug("read sig file: %s error.\n", sigFilePath.data());

return false;

}

int error_code = sm2_verify_sig(verifyMsgDigest, verifyMsgDigest_len,

reinterpret_cast

(user_id.data()), user_id.length(), pub,

&sm2_sig2);

if (0 != error_code) {

qDebug("Verify SM2 signature failed!\n");

return false;

}

qDebug("Verify SM2 signature succeeded!\n");

return true;

}

详细解释可以看代码注释。

其他代码我打包上传到csdn资源中,关注公号后在后台留言需要下载的资源,我看到后免费发给你,并可以得到我的免费解答。 原创不易,谢谢支持。

下载地址:https://download.csdn.net/download/u012534831/88628411

关注公众号 QTShared,带你探索更多QT相关知识。

推荐文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: