Loading... # 引言 此代码目前属于测试阶段,不保证完全可用,但是曾经写过一个python的小工具,但是随着系统越来越大,数据越来越多,加解密速度就会变得很慢很慢,所以使用C的话,就可以发挥出机器的真实性能了。 # python和c效率对比 | 属性 | C++ | Python | | --- | --- | --- | | ZIP压缩 | 35s | 57s | | RSA加密 | 22s | 15m36s | | RSA解密 | 6m22s | 48m21s | # cmake配置 ```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) ``` # 代码 ```c++ #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; } ``` ![image.png](https://www.zunmx.top/usr/uploads/2024/03/2996556954.png) ![image.png](https://www.zunmx.top/usr/uploads/2024/03/2517071420.png) # 使用方法 服务端要修改`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 # 扩展 可以将下载远程归档也嵌入到代码中,实现自动保存备份 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏