auxiliarytool/cryp/box_rsa.cpp

299 lines
8.0 KiB
C++

#include "box_rsa.h"
#include "openssl/err.h"
#include "openssl/evp.h"
#include "openssl/pem.h"
#include <cassert>
#include <openssl/rsa.h>
#include <string>
constexpr size_t g_buffsize = 2048;
namespace cppbox {
class CRSAOperatorImp
{
public:
CRSAOperatorImp()
{
err_ = new char[g_buffsize + 1];
ioerr_ = BIO_new(BIO_s_mem());
}
~CRSAOperatorImp()
{
BIO_free(ioerr_);
delete[] err_;
}
public:
bool encrypt_pub(const HData& public_pem, const HData& data, HData& result)
{
mem_ = BIO_new_mem_buf((void*)public_pem.data, public_pem.len);
key_ = PEM_read_bio_PUBKEY(mem_, nullptr, nullptr, nullptr);
if (key_ == nullptr) {
ERR_print_errors(ioerr_);
clear();
return false;
}
ctx_ = EVP_PKEY_CTX_new(key_, nullptr);
EVP_PKEY_encrypt_init(ctx_);
if (EVP_PKEY_encrypt(ctx_, nullptr, &result.len, data.data, data.len) <= 0) {
clear();
ERR_print_errors(ioerr_);
return false;
}
alloc_data(result);
if (EVP_PKEY_encrypt(ctx_, result.data, &result.len, data.data, data.len) <= 0) {
free_data(result);
clear();
ERR_print_errors(ioerr_);
return false;
}
clear();
return true;
}
bool decrypt_pri(const HData& private_pem, const HData& data, HData& result)
{
mem_ = BIO_new_mem_buf((void*)private_pem.data, private_pem.len);
key_ = PEM_read_bio_PrivateKey(mem_, nullptr, nullptr, nullptr);
if (key_ == nullptr) {
ERR_print_errors(ioerr_);
clear();
return false;
}
ctx_ = EVP_PKEY_CTX_new(key_, nullptr);
EVP_PKEY_decrypt_init(ctx_);
if (EVP_PKEY_decrypt(ctx_, nullptr, &result.len, data.data, data.len) <= 0) {
clear();
ERR_print_errors(ioerr_);
return false;
}
alloc_data(result);
if (EVP_PKEY_decrypt(ctx_, result.data, &result.len, data.data, data.len) <= 0) {
free_data(result);
clear();
ERR_print_errors(ioerr_);
return false;
}
result.data[result.len] = '\0';
clear();
return true;
}
bool encrypt_pub(const char* pub_path, const HData& data, HData& result)
{
FILE* fp = fopen(pub_path, "r");
if (fp == nullptr) {
std::snprintf(err_, g_buffsize, "Read File %s Failed.", pub_path);
return false;
}
HData file_data{};
fseek(fp, 0, SEEK_END);
file_data.len = ftell(fp);
fseek(fp, 0, SEEK_SET);
alloc_data(file_data);
if (file_data.data == NULL) {
fclose(fp);
std::snprintf(err_, g_buffsize, "Alloc Mem Failed: %zd", file_data.len);
return false;
}
file_data.len = fread(file_data.data, 1, file_data.len, fp);
fclose(fp);
bool ret = encrypt_pub(file_data, data, result);
free(file_data.data);
return ret;
}
bool decrypt_pri(const char* pri_path, const HData& data, HData& result)
{
FILE* fp = fopen(pri_path, "r");
if (fp == nullptr) {
std::snprintf(err_, g_buffsize, "Read File %s Failed.", pri_path);
return false;
}
HData file_data{};
fseek(fp, 0, SEEK_END);
file_data.len = ftell(fp);
fseek(fp, 0, SEEK_SET);
alloc_data(file_data);
if (file_data.data == NULL) {
fclose(fp);
std::snprintf(err_, g_buffsize, "Alloc Mem Failed: %zd", file_data.len);
return false;
}
file_data.len = fread(file_data.data, 1, file_data.len, fp);
fclose(fp);
bool ret = decrypt_pri(file_data, data, result);
free(file_data.data);
return ret;
}
bool generate_keypair(const char* pub_path, const char* pri_path)
{
FILE* fp_pub = fopen(pub_path, "w");
if (fp_pub == nullptr) {
std::snprintf(err_, g_buffsize, "Open File Failed: %s", pub_path);
return false;
}
FILE* fp_pri = fopen(pri_path, "w");
if (fp_pri == nullptr) {
std::snprintf(err_, g_buffsize, "Open File Failed: %s", pri_path);
fclose(fp_pub);
return false;
}
key_ = EVP_RSA_gen(g_buffsize / 2);
if (key_ == nullptr) {
ERR_print_errors(ioerr_);
return false;
}
PEM_write_PUBKEY(fp_pub, key_);
PEM_write_PrivateKey(fp_pri, key_, nullptr, nullptr, 0, nullptr, nullptr);
clear();
fclose(fp_pub);
fclose(fp_pri);
return true;
}
bool generate_keypair(HData& pub, HData& pri)
{
key_ = EVP_RSA_gen(g_buffsize / 2);
if (key_ == nullptr) {
ERR_print_errors_fp(stderr);
return false;
}
BIO* mem_pub = BIO_new(BIO_s_mem());
if (mem_pub == nullptr) {
std::snprintf(err_, g_buffsize, "Alloc public BIO Failed.");
return false;
}
BIO* mem_pri = BIO_new(BIO_s_mem());
if (mem_pri == nullptr) {
BIO_free(mem_pub);
std::snprintf(err_, g_buffsize, "Alloc private BIO Failed.");
return false;
}
PEM_write_bio_PUBKEY(mem_pub, key_);
PEM_write_bio_PrivateKey(mem_pri, key_, nullptr, nullptr, 0, nullptr, nullptr);
pub.len = BIO_ctrl_pending(mem_pub);
pri.len = BIO_ctrl_pending(mem_pri);
alloc_data(pub);
alloc_data(pri);
pub.len = BIO_read(mem_pub, pub.data, pub.len);
pri.len = BIO_read(mem_pri, pri.data, pri.len);
clear();
return true;
}
void free_data(HData& data)
{
free(data.data);
data.len = 0;
}
void alloc_data(HData& data)
{
if (data.len < 1) {
data.data = nullptr;
return;
}
data.data = static_cast<unsigned char*>(malloc(data.len + 1));
}
void get_last_error(char* buf, int len)
{
int read_len = BIO_read(ioerr_, err_, g_buffsize);
std::snprintf(buf, len, err_, read_len);
buf[read_len] = '\0';
}
private:
void clear()
{
BIO_free(mem_);
EVP_PKEY_free(key_);
EVP_PKEY_CTX_free(ctx_);
mem_ = nullptr;
ctx_ = nullptr;
key_ = nullptr;
}
private:
EVP_PKEY* key_{};
EVP_PKEY_CTX* ctx_{};
BIO* mem_{};
BIO* ioerr_{};
char* err_{};
};
CRSAOperator::CRSAOperator()
{
imp_ = new CRSAOperatorImp();
err_ = new char[g_buffsize];
}
CRSAOperator::~CRSAOperator()
{
delete imp_;
delete[] err_;
}
bool CRSAOperator::encrypt_pub(const HData& public_pem, const HData& data, HData& result)
{
assert(imp_);
return imp_->encrypt_pub(public_pem, data, result);
}
bool CRSAOperator::encrypt_pub(const char* pub_path, const HData& data, HData& result)
{
assert(imp_);
return imp_->encrypt_pub(pub_path, data, result);
}
bool CRSAOperator::decrypt_pri(const HData& private_pem, const HData& data, HData& result)
{
assert(imp_);
return imp_->decrypt_pri(private_pem, data, result);
}
bool CRSAOperator::decrypt_pri(const char* pri_path, const HData& data, HData& result)
{
assert(imp_);
return imp_->decrypt_pri(pri_path, data, result);
}
bool CRSAOperator::generate_keypair(const char* pub_path, const char* pri_path)
{
assert(imp_);
return imp_->generate_keypair(pub_path, pri_path);
}
bool CRSAOperator::generate_keypair(HData& pub, HData& pri)
{
assert(imp_);
return imp_->generate_keypair(pub, pri);
}
const char* CRSAOperator::get_last_error() const
{
assert(imp_);
imp_->get_last_error(err_, g_buffsize);
return err_;
}
void CRSAOperator::free_hdata(HData& data)
{
assert(imp_);
imp_->free_data(data);
}
void CRSAOperator::alloc_hdata(HData& data)
{
assert(imp_);
imp_->alloc_data(data);
}
} // namespace cppbox