引言
此代码目前属于测试阶段,不保证完全可用,但是曾经写过一个python的小工具,但是随着系统越来越大,数据越来越多,加解密速度就会变得很慢很慢,所以使用C的话,就可以发挥出机器的真实性能了。
python和c效率对比
| 属性 | C++ | Python |
|---|---|---|
| ZIP压缩 | 35s | 57s |
| RSA加密 | 22s | 15m36s |
| RSA解密 | 6m22s | 48m21s |
cmake配置
cmake_minimum_required(VERSION 3.27)
project(main)
set(VCPKG_TARGET_TRIPLET "x64-mingw-static" CACHE STRING "" FORCE)
set(CMAKE_CXX_STANDARD 17)
find_package(OpenSSL REQUIRED)
find_package(jsoncpp CONFIG REQUIRED)
find_package(libzip CONFIG REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main
PUBLIC
OpenSSL::SSL
OpenSSL::Crypto
)
target_link_libraries(main PRIVATE libzip::zip)
target_link_libraries(main PRIVATE JsonCpp::JsonCpp)
代码
#include <iostream>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <json/json.h>
#include <filesystem>
#include <fstream>
#include <vector>
#include <ctime>
#include <chrono>
#include <iomanip>
#include <zip.h>
#include <tchar.h>
Json::Value config;
std::string pub_key = "-----BEGIN RSA PUBLIC KEY-----\n"
"MIGJ*******\n"
"*******\n"
"*******=\n"
"-----END RSA PUBLIC KEY-----\n";
std::string priv_key = "-----BEGIN RSA PRIVATE KEY-----\n"
"MIICY*******\n"
"*******\n"
"*******\n"
"*******\n"
"*******\n"
"*******/\n"
".......\n"
"*******\n"
"-----END RSA PRIVATE KEY-----\n";
void print(const std::string &msg) {
time_t currentTime = time(nullptr);
struct tm *localTime = localtime(¤tTime);
auto now = std::chrono::system_clock::now();
auto now_civil = std::chrono::system_clock::to_time_t(now);
std::cout << "["
<< std::put_time(std::localtime(&now_civil), "%Y-%m-%d %H:%M:%S") << "] "
<< msg
<< std::endl;
}
void initialize() {
print("[i] Initializing");
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
system("CHCP 65001");
print("[i] Current OS is Windows");
#else
print("[i] Current OS is Linux");
#endif
std::locale::global(std::locale(""));
time_t currentTime = time(nullptr);
struct tm *localTime = localtime(¤tTime);
const std::chrono::time_point now = std::chrono::system_clock::now();
time_t now_civil = std::chrono::system_clock::to_time_t(now);
std::stringstream date_tmp;
date_tmp << std::put_time(std::localtime(&now_civil), "%Y%m%d_%H%M%S");
config["backup_temp_path"] = "c:/inetpub/backup";
config["web_path"] = "c:/inetpub/www/";
config["date"] = date_tmp.str();
config["db_username"] = "root";
config["db_password"] = "******";
config["db_host"] = "127.0.0.1";
config["db_port"] = 3306;
config["db_backup_db"] = "my_db";
config["pointer"] = "client";
config["backup_out_path"] = "c:/inetpub/www2/backup.rsa";
config["save_path"] = _T("F:/网站备份");
print("[i] Initialize successfully");
}
std::string get_string4config(const std::string &str) {
return config[str].asString();
}
std::string RsaPubEncrypt(const std::string &clear_text, const std::string &pub_key) {
std::string encrypt_text;
BIO *keybio = BIO_new_mem_buf((unsigned char *) pub_key.c_str(), -1);
RSA *rsa = RSA_new();
rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, nullptr, nullptr);
int key_len = RSA_size(rsa);
int block_len = key_len - 11;
char *sub_text = new char[key_len + 1];
memset(sub_text, 0, key_len + 1);
int ret = 0;
int pos = 0;
std::string sub_str;
while (pos < clear_text.length()) {
sub_str = clear_text.substr(pos, block_len);
memset(sub_text, 0, key_len + 1);
ret = RSA_public_encrypt(sub_str.length(), (const unsigned char *) sub_str.c_str(), (unsigned char *) sub_text,
rsa, RSA_PKCS1_PADDING);
if (ret >= 0) {
encrypt_text.append(std::string(sub_text, ret));
}
pos += block_len;
}
BIO_free_all(keybio);
RSA_free(rsa);
delete[] sub_text;
return encrypt_text;
}
std::string RsaPriDecrypt(const std::string &cipher_text, const std::string &pri_key) {
std::string decrypt_text;
RSA *rsa = RSA_new();
BIO *keybio;
keybio = BIO_new_mem_buf((unsigned char *) pri_key.c_str(), -1);
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, nullptr, nullptr);
if (rsa == nullptr) {
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);
return {};
}
int key_len = RSA_size(rsa);
char *sub_text = new char[key_len + 1];
memset(sub_text, 0, key_len + 1);
int ret = 0;
std::string sub_str;
int pos = 0;
// 对密文进行分段解密
while (pos < cipher_text.length()) {
sub_str = cipher_text.substr(pos, key_len);
memset(sub_text, 0, key_len + 1);
ret = RSA_private_decrypt(sub_str.length(), (const unsigned char *) sub_str.c_str(), (unsigned char *) sub_text,
rsa, RSA_PKCS1_PADDING);
if (ret >= 0) {
decrypt_text.append(std::string(sub_text, ret));
pos += key_len;
}
}
// 释放内存
delete[] sub_text;
BIO_free_all(keybio);
RSA_free(rsa);
return decrypt_text;
}
// 读文件
std::string readFile(const std::string &filePath) {
std::ifstream file(filePath, std::ios::binary);
if (!file.is_open()) {
print("[x] Open file failure " + filePath);
return {};
}
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
return content;
}
void save_file(const std::string &filePath, const std::string &content) {
std::ofstream file(filePath, std::ios::binary);
if (!file.is_open()) {
print("[x] Open file failure " + filePath);
return;
}
file.write(content.c_str(), content.length());
file.close();
}
void check_path() {
print("[i] Checking backup temp path");
if (!std::filesystem::exists(get_string4config("backup_temp_path"))) {
print("[i] Creating directory: " + get_string4config("backup_temp_path"));
std::filesystem::create_directory(get_string4config("backup_temp_path"));
} else {
print("[i] Directory exists: " + get_string4config("backup_temp_path"));
std::filesystem::remove_all(get_string4config("backup_temp_path"));
check_path();
}
}
bool compress_directory(const std::string &zip_path, const std::string &dir_path) {
int err = 0;
zip_source_t *source = nullptr;
zip_t *zip = zip_open(zip_path.c_str(), ZIP_CREATE | ZIP_TRUNCATE, &err);
if (zip == nullptr) {
std::cerr << "[x] Error creating ZIP archive: " << err << std::endl;
return false;
}
for (const auto &entry: std::filesystem::recursive_directory_iterator(dir_path)) {
if (std::filesystem::is_regular_file(entry.path())) {
const std::string &abs_path = entry.path().string();
std::ifstream file(abs_path, std::ios::binary);
source = zip_source_file(zip,
abs_path.c_str(), 0,
0);
if (source == nullptr) {
std::cerr << "[x] Error adding file to ZIP: " << abs_path << std::endl;
zip_close(zip);
return false;
}
zip_file_add(zip, abs_path.substr(dir_path.size(), abs_path.size() - dir_path.size()).c_str(), source,
ZIP_FL_OVERWRITE);
zip_source_keep(source);
zip_source_free(source);
}
}
if (zip_close(zip) != 0) {
std::cerr << "[x] Error closing ZIP archive" << std::endl;
return false;
}
return true;
}
void backup_database() {
print("[i] Backing up database");
std::string backup_path = get_string4config("backup_temp_path");
std::string command = "mysqldump -h" + get_string4config("db_host") +
" -P" + get_string4config("db_port") +
" -u" + get_string4config("db_username") +
" -p" + get_string4config("db_password") +
" -E -R --databases " + get_string4config("db_backup_db") +
" > " + get_string4config("backup_temp_path") + "/db_backup_" + get_string4config("date") +
".sql";
system(command.c_str());
if (std::filesystem::exists(backup_path + "/db_backup_" + get_string4config("date") + ".sql")) {
if (compress_directory(get_string4config("backup_temp_path") + "/db_" + get_string4config("date") + ".zip",
get_string4config("backup_temp_path") + "/")) {
print("[v] DB compressed successfully.");
std::filesystem::remove(backup_path + "/db_backup_" + get_string4config("date") + ".sql");
} else {
print("[x] Error compressing directory.");
}
} else {
print("[x]Database backup failed");
}
}
int backup_website() {
print("[i] Creating website ZIP archive");
if (compress_directory(get_string4config("backup_temp_path") + "/web_" + get_string4config("date") + ".zip",
get_string4config("web_path"))) {
print("[v] Directory compressed successfully.");
} else {
print("[x] Error compressing directory.");
}
return 0;
}
int compress_backup() {
print("[i] Creating backup ZIP archive");
if (compress_directory(get_string4config("backup_temp_path") + "/all_backup.zip",
get_string4config("backup_temp_path"))) {
print("[v] Directory compressed successfully.");
} else {
print("[x] Error compressing directory.");
}
return 0;
}
int delete_temp_file() {
print("[i] Deleting temp files");
std::filesystem::remove_all(get_string4config("backup_temp_path"));
print("[v] Deleted temp files");
return 0;
}
int encrypt_publish() {
print("[i] Encrypting");
std::string encrypt = RsaPubEncrypt(readFile(get_string4config("backup_temp_path") + "all_backup.zip"), pub_key);
save_file(get_string4config("backup_out_path"), encrypt);
print("[i] Encrypted");
return 0;
}
int decrypt_backup(const std::string &path) {
print("[i] Decrypting");
std::string decrypt = RsaPriDecrypt(readFile(path), priv_key);
print("[i] Decrypted");
save_file(get_string4config("save_path") + "/" + get_string4config("date") + ".zip", decrypt);
return 0;
}
int main(int argc, char **argv) {
initialize();
if (get_string4config("pointer") == "server") {
print("[i] CURRENT MODE: SERVER");
check_path();
backup_database();
backup_website();
compress_backup();
encrypt_publish();
delete_temp_file();
} else if (get_string4config("pointer") == "client") {
print("[i] CURRENT MODE: CLIENT");
if (argc == 2) {
std::string path = argv[1];
decrypt_backup(path);
} else {
print("[x] ERROR INPUT PARAMS");
}
}
return 0;
}


使用方法
服务端要修改config["pointer"]为"server";,这样就执行的是备份和加密操作
归档存储机器要修改config["pointer"]为"client";,这样就执行的是解密操作
⚠:示例使用的是windows服务器和windows的归档服务器其中需要手动下载归档文件到归档服务器
⚠:如果无法使用中文路径,可修改代码的编码为GBK,即可解决该问题
⚠:测试使用的均为windows机器,尚未对其它系统做测试
⚠:建议使用vcpkg进行软件包管理
⚠:建议在服务端删除掉私钥,以免程序泄露,通过反汇编获得到私钥。
ℹ:公钥加密私钥解密:是为了保证数据安全性,因为私钥可生成公钥,一旦私钥泄露,那么加密就没有任何作用了,服务端采用公钥加密,保证只有唯一的私钥才能解密。
版本
bzip2==1.0.8#5
jsoncpp==1.9.5#2
libzip==1.10.1
openssl==3.2.1#1
vcpkg-cmake-config==2022-02-06#1
vcpkg-cmake-get-vars==2023.12031
vcpkg-cmake==2023-05-04
zlib=1.3.1
扩展
可以将下载远程归档也嵌入到代码中,实现自动保存备份


评论 0
还没有评论,来说点什么吧。