背景
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 <string>
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 <QDebug>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#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<const unsigned char* >
(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<const unsigned char*>
(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文章来源:https://www.toymoban.com/news/detail-821539.html
关注公众号 QTShared,带你探索更多QT相关知识。文章来源地址https://www.toymoban.com/news/detail-821539.html
到了这里,关于C++调用openssl实现国标sm2签名算法的使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!