OpenSSL 3.1.1 ECC 加密、解密、签名、验签(国密 sm2、sm3)
openssl 3 默认废弃了 旧版本 (opessl 1.x) 的部分api 导致部分旧ecc 代码无法使用(可以通过配置编译选项打开)
,这里展示如何使用新接口用ECC 进行加密解密。
新接口是真的方便,基本上你都不需要懂啥密码学知识,对我们这种密码白痴来说太好了
头文件
生成密钥对
导出公钥&导入公钥
公钥加密
私钥解密
私钥签名
公钥验签
工具函数
所有代码(后来改过)
头文件
小小的封装了一下
#include "openssl/crypto.h"
#include "openssl/types.h"
#include "openssl/x509.h"
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
class sm2PrivateKey;
struct EVP_CUNSTOM{
EVP_PKEY * pkey=NULL;
~EVP_CUNSTOM(){
if(pkey!=NULL){
EVP_PKEY_free(pkey);
}
}
};
class sm2PublicKey{
public:
sm2PublicKey()=default;
sm2PublicKey(const sm2PublicKey & other){
m_pkey=other.m_pkey;
}
sm2PublicKey(const std::string & pub_str);
sm2PublicKey(const unsigned char * pub_str,size_t len);
std::string Encrypt(const std::string & message,std::string & error);
bool SignatureVerification(const std::string & signature,const std::string & message,std::string & error);
std::string GetPublicString();
std::string GetPublicStringBase64();
private:
std::shared_ptr<EVP_CUNSTOM> m_pkey=nullptr;//使用shared_ptr 防止拷贝构造的时候造成内存泄漏和意外释放
};
class sm2PrivateKey{
public:
sm2PrivateKey();
sm2PrivateKey(const std::string & priv_str);
sm2PublicKey CreatePublic();
std::string Decrypt(const std::string & encoded,std::string & error);
std::string Signature(const std::string & message ,std::string & error);
std::string GetPrivateString();
private:
std::shared_ptr<EVP_CUNSTOM> M_PKEY=nullptr;
};
生成密钥对
sm2PrivateKey::sm2PrivateKey(){
EVP_PKEY *ret = NULL;
EVP_PKEY_CTX *pkctx = NULL;
pkctx = EVP_PKEY_CTX_new_id(EVP_PKEY_SM2, NULL);//创建sm2 上下文
if(pkctx==NULL){
errorL("EVP_PKEY_CTX_new_id");
return;
}
int retV=1;
retV=EVP_PKEY_keygen_init(pkctx);//初始化sm2 上下文
if (retV <= 0) {
errorL("EVP_PKEY_keygen_init:" << GetErrorStr());
EVP_PKEY_CTX_free(pkctx);
return ;
}
retV=EVP_PKEY_keygen(pkctx, &ret);//生成密钥对
if (retV <= 0) {
errorL("EVP_PKEY_keygen:" << GetErrorStr());
EVP_PKEY_CTX_free(pkctx);
return ;
}
EVP_CUNSTOM * cst=new EVP_CUNSTOM{
ret};
M_PKEY=std::shared_ptr<EVP_CUNSTOM>(cst);
EVP_PKEY_CTX_free(pkctx);
}
导出公钥和导入公钥
sm2PublicKey sm2PrivateKey::CreatePublic(){
unsigned char *buffer=nullptr;
int retV=i2d_PUBKEY(M_PKEY.get()->pkey, &buffer);//导出
if (retV <= 0) {
errorL("i2d_PUBKEY:" <<GetErrorStr());
return sm2PublicKey{
};
}
//buffer 里的是公钥二进制
sm2PublicKey pub(buffer,retV);
//OPENSSL_free(buffer);
return pub;
}
sm2PublicKey::sm2PublicKey(const unsigned char * pub_str,size_t len){
EVP_PKEY * pkey_t=NULL;
//pkey_t=d2i_PublicKey(EVP_PKEY_SM2,NULL, &pub_str, len);
pkey_t=d2i_PUBKEY(NULL, &pub_str, len);//导入
std::string error;
if(pkey_t==NULL){
error=GetErrorStr();
errorL(error);
return;
}
EVP_CUNSTOM *cst=new EVP_CUNSTOM{
pkey_t};
m_pkey=std::shared_ptr<EVP_CUNSTOM>(cst);
}
公钥加密
std::string sm2PublicKey::Encrypt(const std::string &message,std::string &error) {
std::string encodedstr;
EVP_PKEY_CTX *pkctx = NULL;
int retV=1;
if (!(pkctx = EVP_PKEY_CTX_new(m_pkey.get()->pkey, NULL))) {
//生成上下文
error=GetErrorStr();
errorL("EVP_PKEY_CTX_new:" << error);
EVP_PKEY_CTX_free(pkctx);
return "";
}
retV=EVP_PKEY_encrypt_init(pkctx);//加密初始化
if (retV <= 0) {
error=GetErrorStr();
errorL("EVP_PKEY_encrypt_init:" <<error);
EVP_PKEY_CTX_free(pkctx);
return "";
}
size_t outbuflen=0;
unsigned char * outbuf=NULL;
retV=EVP_PKEY_encrypt(pkctx, NULL, &outbuflen,
(const unsigned char *)message.c_str(), message.size());//加密 (传NULL 仅获取密文长度)
if (retV <= 0) {
error=GetErrorStr();
errorL("EVP_PKEY_encrypt:" << error );
EVP_PKEY_CTX_free(pkctx);
return "";
}
if(outbuflen==0){
errorL("EVP_PKEY_encrypt:" << "no memery");
EVP_PKEY_CTX_free(pkctx);
return "";
}
outbuf=new unsigned char[outbuflen];
retV=EVP_PKEY_encrypt(pkctx, outbuf, &outbuflen,
(const unsigned char *)message.c_str(), message.size());//加密
if (retV <= 0) {
error=GetErrorStr();
errorL("EVP_PKEY_encrypt:" << error );
EVP_PKEY_CTX_free(pkctx);
delete[] outbuf;
return "";
}
encodedstr=std::string((const char *)outbuf,outbuflen);//获取结果
delete[] outbuf;
EVP_PKEY_CTX_free(pkctx);
return encodedstr;
}
私钥解密
std