目录
环境部署
关于openssl的移植,在之前wifi功能移植中有过说明,或者网上大把详细步骤
一、openssl RSA加解密、 使用接口生成秘钥
命令行的方式生成证书: https://blog.csdn.net/gengxiaoming7/article/details/78505107
参考文章:https://blog.csdn.net/qq_30667875/article/details/105427943
我的具体实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <fstream>
using namespace std;
#define LOG_INFO(fmt,args...) ({printf("info: %s(%d) %s:",__FILE__, __LINE__, __func__);printf(fmt"\r\n" ,##args);})
#define LOG_ERROR(fmt,args...) ({printf("error: %s(%d) %s:",__FILE__, __LINE__, __func__);printf(fmt"\r\n" ,##args);})
#define RSA_OPENSSLKEY "./rsa_private_key.pem"
#define RSA_PUBLICKEY "./rsa_public_key.pem"
#define KEY_LENGTH 2048
//生成秘钥
void GenerateRSAKey(std::string & out_pub_key, std::string & out_pri_key);
//传入秘钥内容进行加解密
std::string RsaPriEncrypt(const std::string &clear_text, std::string &pri_key);
std::string RsaPubDecrypt(const std::string & cipher_text, const std::string & pub_key);
//通过读秘钥文件的方式进行加解密
std::string RsaPriEncryptFile(const std::string &clear_text);
std::string RsaPubDecryptFile(const std::string & cipher_text);
int main(int argc, char* argv[])
{
char *p_str="qaq1234567abcdef";
std::string encrypt_text;
std::string decrypt_text;
std::string encryptFile_text;
std::string decryptFile_text;
std::string pub_key;
std::string pri_key;
GenerateRSAKey(pub_key, pri_key);
LOG_INFO("public key:\n");
LOG_INFO("%s\n", pub_key.c_str());
LOG_INFO("private key:\n");
LOG_INFO("%s\n", pri_key.c_str());
// 直接使用秘钥信息的方式加解密
// 私钥加密-公钥解密
encrypt_text = RsaPriEncrypt(p_str, pri_key);
LOG_INFO("encrypt: len=%d\n", encrypt_text.length());
LOG_INFO("decrypt: %s\n", encrypt_text.c_str());
decrypt_text = RsaPubDecrypt(encrypt_text, pub_key);
LOG_INFO("decrypt: len=%d\n", decrypt_text.length());
LOG_INFO("decrypt: %s\n", decrypt_text.c_str());
printf("==================================\n");
// 通过读秘钥文件的方式加解密
encryptFile_text = RsaPriEncryptFile(p_str);
LOG_INFO("encrypt: len=%d\n", encryptFile_text.length());
LOG_INFO("encrypt: %s\n", encryptFile_text.c_str());
decryptFile_text = RsaPubDecryptFile(encryptFile_text);
LOG_INFO("decrypt: len=%d\n", decryptFile_text.length());
LOG_INFO("decrypt: %s\n", decryptFile_text.c_str());
return 0;
}
void GenerateRSAKey(std::string & out_pub_key, std::string & out_pri_key)
{
size_t pri_len = 0; // 私钥长度
size_t pub_len = 0; // 公钥长度
char *pri_key = nullptr; // 私钥
char *pub_key = nullptr; // 公钥
// 生成密钥对
RSA *keypair = RSA_generate_key(KEY_LENGTH, RSA_3, NULL, NULL);
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());
// 生成私钥
PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
// 注意------生成第1种格式的公钥
//PEM_write_bio_RSAPublicKey(pub, keypair);
// 注意------生成第2种格式的公钥(此处代码中使用这种)
PEM_write_bio_RSA_PUBKEY(pub, keypair);
// 获取长度
pri_len = BIO_pending(pri);
pub_len = BIO_pending(pub);
// 密钥对读取到字符串
pri_key = (char *)malloc(pri_len + 1);
pub_key = (char *)malloc(pub_len + 1);
BIO_read(pri, pri_key, pri_len);
BIO_read(pub, pub_key, pub_len);
pri_key[pri_len] = '\0';
pub_key[pub_len] = '\0';
out_pub_key = pub_key;
out_pri_key = pri_key;
// 将公钥写入文件
std::ofstream pub_file(RSA_PUBLICKEY, std::ios::out);
if (!pub_file.is_open())
{
perror("pub key file open fail:");
goto ERROR;
return;
}
pub_file << pub_key;
pub_file.close();
// 将私钥写入文件
std::ofstream pri_file(RSA_OPENSSLKEY, std::ios::out);
if (!pri_file.is_open())
{
perror("pri key file open fail:");
goto ERROR;
return;
}
pri_file << pri_key;
pri_file.close();
ERROR:
// 释放内存
RSA_free(keypair);
BIO_free_all(pub);
BIO_free_all(pri);
free(pri_key);
free(pub_key);
}
std::string RsaPriEncrypt(const std::string &clear_text, std::string &pri_key)
{
std::string encrypt_text;
BIO *keybio = BIO_new_mem_buf((unsigned char *)pri_key.c_str(), -1);
RSA* rsa = RSA_new();
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
if (!rsa)
{
BIO_free_all(keybio);
return std::string("");
}
// 获取RSA单次可以处理的数据的最大长度
int len = RSA_size(rsa);
// 申请内存:存贮加密后的密文数据
char *text = new char[len + 1];
memset(text, 0, len + 1);
// 对数据进行私钥加密(返回值是加密后数据的长度)
int ret = RSA_private_encrypt(clear_text.length(), (const unsigned char*)clear_text.c_str(), (unsigned char*)text, rsa, RSA_PKCS1_PADDING);
if (ret >= 0) {
encrypt_text = std::string(text, ret);
}
// 释放内存
delete text;
BIO_free_all(keybio);
RSA_free(rsa);
return encrypt_text;
}
std::string RsaPubDecrypt(const std::string & cipher_text, const std::string & pub_key)
{
std::string decrypt_text;
BIO *keybio = BIO_new_mem_buf((unsigned char *)pub_key.c_str(), -1);
RSA *rsa = RSA_new();
// 注意--------使用第1种格式的公钥进行解密
//rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
// 注意--------使用第2种格式的公钥进行解密(我们使用这种格式作为示例)
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
if (!rsa)
{
unsigned long err = ERR_get_error(); //获取错误号
char err_msg[1024] = { 0 };
ERR_error_string(err, err_msg); // 格式:error:errId:库:函数:原因
printf("err msg: err:%ld, msg:%s\n", err, err_msg);
BIO_free_all(keybio);
return decrypt_text;
}
int len = RSA_size(rsa);
char *text = new char[len + 1];
memset(text, 0, len + 1);
// 对密文进行解密
int ret = RSA_public_decrypt(cipher_text.length(), (const unsigned char*)cipher_text.c_str(), (unsigned char*)text, rsa, RSA_PKCS1_PADDING);
if (ret >= 0) {
decrypt_text.append(std::string(text, ret));
}
// 释放内存
delete text;
BIO_free_all(keybio);
RSA_free(rsa);
return decrypt_text;
}
std::string RsaPriEncryptFile(const std::string &clear_text)
{
std::string encrypt_text;
RSA *prikey = RSA_new();
BIO *priio;
priio = BIO_new_file(RSA_OPENSSLKEY, "rb");
prikey = PEM_read_bio_RSAPrivateKey(priio, &prikey, NULL, NULL);
if (!prikey)
{
BIO_free(priio);
return std::string("");
}
int len = RSA_size(prikey);
char *text = new char[len + 1];
memset(text, 0, len + 1);
int ret = RSA_private_encrypt(clear_text.length(), (const unsigned char*)clear_text.c_str(), (unsigned char*)text, prikey, RSA_PKCS1_PADDING);
if (ret >= 0) {
encrypt_text = std::string(text, ret);
}
delete text;
RSA_free(prikey);
BIO_free(priio);
return encrypt_text;
}
std::string RsaPubDecryptFile(const std::string & cipher_text)
{
std::string decrypt_text;
RSA *pubkey = RSA_new();
BIO *pubio;
pubio = BIO_new_file(RSA_PUBLICKEY, "rb");
pubkey = PEM_read_bio_RSA_PUBKEY(pubio, &pubkey, NULL, NULL);
if (!pubkey)
{
unsigned long err = ERR_get_error(); //获取错误号
char err_msg[1024] = { 0 };
ERR_error_string(err, err_msg); // 格式:error:errId:库:函数:原因
printf("err msg: err:%ld, msg:%s\n", err, err_msg);
BIO_free(pubio);
return decrypt_text;
}
int len = RSA_size(pubkey);
char *text = new char[len + 1];
memset(text, 0, len + 1);
int ret = RSA_public_decrypt(cipher_text.length(), (const unsigned char*)cipher_text.c_str(), (unsigned char*)text, pubkey, RSA_PKCS1_PADDING);
if (ret >= 0) {
decrypt_text.append(std::string(text, ret));
}
delete text;
RSA_free(pubkey);
BIO_free(pubio);
return decrypt_text;
}
记得编译时加上 -lssl -lcrypto
2、使用openssl对文件进行签名认证
命令行方式:
message.sign:签名文件
source_ile:目标文件
sha1:摘要算法 使用openssl dgst - 可以看到支持的列表
使用私钥对升级包进行签名
openssl dgst -sha1 -out message.sign -sign rsa_private_key.pem source_file
使用公钥验证签名
openssl dgst -sha1 -verify rsa_public_key.pem -signature message.sign source_file
代码实现
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#define SIGN_PATH "./.message.sign" //签名文件
#define SOURCE_PATH "./source_file" //源文件
#define PUBLIC_KEY_PASH "./pub_key.pem" //公钥
static EVP_PKEY *PEM_read_PublicKey(FILE *fp)
{
BIO *b;
EVP_PKEY *ret;
if ((b = BIO_new(BIO_s_file())) == NULL)
{
//PEMerr(PEM_F_PEM_READ_PRIVATEKEY, ERR_R_BUF_LIB);
return(0);
}
BIO_set_fp(b, fp, BIO_NOCLOSE);
ret = PEM_read_bio_PUBKEY(b, NULL, NULL, NULL);
BIO_free(b);
return(ret);
}
static EVP_PKEY* Read_PublicKey(char* p_KeyPath)
{
FILE *fp = NULL;
char szKeyPath[1024];
EVP_PKEY *pubRsa = NULL;
/* 打开密钥文件 */
if (NULL == (fp = fopen(p_KeyPath, "r")))
{
return NULL;
}
/* 获取私密钥 */
pubRsa = PEM_read_PublicKey(fp);
if (NULL == pubRsa)
{
fclose(fp);
return NULL;
}
fclose(fp);
return pubRsa;
}
int VerifyUpgrade(char *sign_data, int sign_len)
{
printf("sign_len = %d\n", sign_len);
int nRet = 0;
EVP_PKEY *pKey;
EVP_MD_CTX* pMdCtx = NULL;
EVP_PKEY_CTX* pKeyCtx = NULL;
/*初始化验签函数*/
pKey = Read_PublicKey(PUBLIC_KEY_PASH);
if (!pKey)
{
printf("Read_PublicKey failed!\n");
return -1;
}
pMdCtx = EVP_MD_CTX_create();
if (NULL == pMdCtx)
{
printf("EVP_MD_CTX_create failed!\n");
EVP_PKEY_free(pKey);
pKey = NULL;
return -1;
}
nRet = EVP_DigestVerifyInit(pMdCtx, &pKeyCtx, EVP_sha256(), NULL, pKey);
if (nRet <= 0)
{
printf("EVP_DigestVerifyInit failed!\n");
EVP_PKEY_free(pKey);
pKey = NULL;
EVP_MD_CTX_destroy(pMdCtx);
pMdCtx = NULL;
return -1;
}
FILE *fp = NULL;
char p_pBuf[512];
fp = fopen(SOURCE_PATH, "r");
while (feof(fp) == 0)
{
int i = fread(p_pBuf, 1, 512, fp);
EVP_DigestVerifyUpdate(pMdCtx, p_pBuf, i);
}
/*验签*/
nRet = EVP_DigestVerifyFinal(pMdCtx, (unsigned char *)sign_data, sign_len);
if (nRet <= 0)
{
printf("EVP_DigestVerifyFinal failed !!! nRet = %d \n", nRet);
EVP_PKEY_free(pKey);
pKey = NULL;
EVP_MD_CTX_destroy(pMdCtx);
pMdCtx = NULL;
fclose(fp);
printf("========================= Verify Failed ========================\n");
return -1;
}
fclose(fp);
printf("========================= Verify Success ========================\n");
return 0;
}
int main()
{
int sign_len = 0;
char *p_sign_data = NULL;
struct stat statbuf;
stat(SIGN_PATH, &statbuf);
sign_len = statbuf.st_size;
p_sign_data = (char *)malloc(sign_len);
memset(p_sign_data, 0, sign_len);
FILE *sign_fp = fopen(SIGN_PATH, "r");
if (sign_fp)
{
fread(p_sign_data, 1, sign_len, sign_fp);
}
VerifyUpgrade(p_sign_data, sign_len);
free(p_sign_data);
return 0;
}