1.src/Utils/Crypto.cpp
#include "Crypto.hpp"
#include "Logger.hpp"
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <openssl/err.h>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <stdexcept>
class DataEncryptor::Impl {
public:
Impl() {
// 初始化OpenSSL
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
}
~Impl() {
// 清理OpenSSL
EVP_cleanup();
ERR_free_strings();
}
};
DataEncryptor::DataEncryptor(const std::string& keyFile)
: pImpl_(std::make_unique<Impl>())
, keyFilePath_(keyFile) {
LOG_INFO("DataEncryptor initialized");
// 尝试加载密钥
if (!keyFile.empty()) {
loadKey(keyFile);
} else {
// 使用默认密钥文件
keyFilePath_ = "encryption_key.bin";
loadKey(keyFilePath_);
}
}
DataEncryptor::~DataEncryptor() {
LOG_INFO("DataEncryptor destroyed");
}
bool DataEncryptor::hasKey() const {
return keyLoaded_;
}
void DataEncryptor::setAlgorithm(Algorithm algorithm) {
currentAlgorithm_ = algorithm;
LOG_INFO("Encryption algorithm set to: {}", static_cast<int>(algorithm));
}
DataEncryptor::Algorithm DataEncryptor::getAlgorithm() const {
return currentAlgorithm_;
}
std::string DataEncryptor::encrypt(const std::string& plaintext) {
if (!keyLoaded_) {
LOG_ERROR("No encryption key loaded");
return "";
}
try {
std::vector<uint8_t> plaintextVec(plaintext.begin(), plaintext.end());
std::vector<uint8_t> ciphertextVec = encryptData(plaintextVec);
if (ciphertextVec.empty()) {
LOG_ERROR("Encryption failed");
return "";
}
// 转换为base64
std::string ciphertext = CryptoUtils::base64Encode(ciphertextVec);
LOG_DEBUG("Encrypted {} bytes to {} bytes (base64)",
plaintext.size(), ciphertext.size());
return ciphertext;
} catch (const std::exception& e) {
LOG_ERROR("Exception during encryption: {}", e.what());
return "";
}
}
std::string DataEncryptor::decrypt(const std::string& ciphertext) {
if (!keyLoaded_) {
LOG_ERROR("No encryption key loaded");
return "";
}
try {
// 从base64解码
std::vector<uint8_t> ciphertextVec = CryptoUtils::base64Decode(ciphertext);
if (ciphertextVec.empty()) {
LOG_ERROR("Failed to decode base64 ciphertext");
return "";
}
std::vector<uint8_t> plaintextVec = decryptData(ciphertextVec);
if (plaintextVec.empty()) {
LOG_ERROR("Decryption failed");
return "";
}
std::string plaintext(plaintextVec.begin(), plaintextVec.end());
LOG_DEBUG("Decrypted {} bytes (base64) to {} bytes",
ciphertext.size(), plaintext.size());
return plaintext;
} catch (const std::exception& e) {
LOG_ERROR("Exception during decryption: {}", e.what());
return "";
}
}
bool DataEncryptor::encryptFile(const std::string& inputFile,
const std::string& outputFile) {
try {
// 读取文件
std::ifstream inFile(inputFile, std::ios::binary);
if (!inFile.is_open()) {
LOG_ERROR("Failed to open input file: {}", inputFile);
return false;
}
std::string plaintext((std::istreambuf_iterator<char>(inFile)),
std::istreambuf_iterator<char>());
inFile.close();
// 加密
std::string ciphertext = encrypt(plaintext);
if (ciphertext.empty()) {
LOG_ERROR("Failed to encrypt file content");
return false;
}
// 写入文件
std::ofstream outFile(outputFile, std::ios::binary);
if (!outFile.is_open()) {
LOG_ERROR("Failed to open output file: {}", outputFile);
return false;
}
outFile << ciphertext;
outFile.close();
LOG_INFO("File encrypted: {} -> {} ({} bytes)",
inputFile, outputFile, ciphertext.size());
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception during file encryption: {}", e.what());
return false;
}
}
bool DataEncryptor::decryptFile(const std::string& inputFile,
const std::string& outputFile) {
try {
// 读取文件
std::ifstream inFile(inputFile, std::ios::binary);
if (!inFile.is_open()) {
LOG_ERROR("Failed to open input file: {}", inputFile);
return false;
}
std::string ciphertext((std::istreambuf_iterator<char>(inFile)),
std::istreambuf_iterator<char>());
inFile.close();
// 解密
std::string plaintext = decrypt(ciphertext);
if (plaintext.empty()) {
LOG_ERROR("Failed to decrypt file content");
return false;
}
// 写入文件
std::ofstream outFile(outputFile, std::ios::binary);
if (!outFile.is_open()) {
LOG_ERROR("Failed to open output file: {}", outputFile);
return false;
}
outFile << plaintext;
outFile.close();
LOG_INFO("File decrypted: {} -> {} ({} bytes)",
inputFile, outputFile, plaintext.size());
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception during file decryption: {}", e.what());
return false;
}
}
bool DataEncryptor::encryptAndSave(const std::string& data,
const std::string& filename) {
try {
// 加密数据
std::string encryptedData = encrypt(data);
if (encryptedData.empty()) {
LOG_ERROR("Failed to encrypt data");
return false;
}
// 添加加密信息头
std::stringstream header;
header << "ENCv" << VERSION << "\n";
header << "ALG:" << static_cast<int>(currentAlgorithm_) << "\n";
header << "SIZE:" << data.size() << "\n";
header << "\n"; // 空行分隔头部和数据
std::string finalData = header.str() + encryptedData;
// 保存文件
std::ofstream file(filename, std::ios::binary);
if (!file.is_open()) {
LOG_ERROR("Failed to open file for writing: {}", filename);
return false;
}
file << finalData;
file.close();
LOG_INFO("Encrypted data saved to: {} ({} bytes)",
filename, finalData.size());
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception in encryptAndSave: {}", e.what());
return false;
}
}
std::string DataEncryptor::loadAndDecrypt(const std::string& filename) {
try {
// 读取文件
std::ifstream file(filename, std::ios::binary);
if (!file.is_open()) {
LOG_ERROR("Failed to open file: {}", filename);
return "";
}
std::string content((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
file.close();
// 解析头部
size_t headerEnd = content.find("\n\n");
if (headerEnd == std::string::npos) {
LOG_ERROR("Invalid encrypted file format");
return "";
}
std::string header = content.substr(0, headerEnd);
std::string encryptedData = content.substr(headerEnd + 2);
// 解析版本
if (header.find("ENCv") != 0) {
LOG_ERROR("Invalid encryption header");
return "";
}
// 解密数据
std::string plaintext = decrypt(encryptedData);
LOG_INFO("Decrypted data loaded from: {} ({} bytes)",
filename, plaintext.size());
return plaintext;
} catch (const std::exception& e) {
LOG_ERROR("Exception in loadAndDecrypt: {}", e.what());
return "";
}
}
bool DataEncryptor::generateKey(const std::string& password) {
try {
// 生成随机盐值
keyInfo_.salt = generateRandom(SALT_SIZE);
// 派生密钥
if (!password.empty()) {
keyInfo_.key = deriveKey(password, keyInfo_.salt);
} else {
// 生成随机密钥
keyInfo_.key = generateRandom(KEY_SIZE);
}
// 生成随机IV
keyInfo_.iv = generateRandom(IV_SIZE);
keyInfo_.algorithm = currentAlgorithm_;
keyInfo_.version = VERSION;
keyLoaded_ = true;
LOG_INFO("Encryption key generated (algorithm: {})",
static_cast<int>(currentAlgorithm_));
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception during key generation: {}", e.what());
return false;
}
}
bool DataEncryptor::loadKey(const std::string& keyFile) {
try {
std::string filename = keyFile.empty() ? keyFilePath_ : keyFile;
std::ifstream file(filename, std::ios::binary);
if (!file.is_open()) {
LOG_WARN("Key file not found: {}", filename);
return generateKey(); // 自动生成新密钥
}
// 读取密钥文件
std::vector<uint8_t> keyData((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
file.close();
if (keyData.size() < sizeof(KeyInfo)) {
LOG_ERROR("Invalid key file size");
return false;
}
// 解析密钥信息(简化版本)
// 实际应该使用更安全的序列化方式
size_t offset = 0;
// 读取版本
uint32_t version = *reinterpret_cast<uint32_t*>(&keyData[offset]);
offset += sizeof(uint32_t);
if (version != VERSION) {
LOG_ERROR("Unsupported key file version: {}", version);
return false;
}
// 读取算法
uint32_t algorithm = *reinterpret_cast<uint32_t*>(&keyData[offset]);
offset += sizeof(uint32_t);
keyInfo_.algorithm = static_cast<Algorithm>(algorithm);
// 读取密钥大小
uint32_t keySize = *reinterpret_cast<uint32_t*>(&keyData[offset]);
offset += sizeof(uint32_t);
// 读取密钥
keyInfo_.key.resize(keySize);
std::copy(keyData.begin() + offset,
keyData.begin() + offset + keySize,
keyInfo_.key.begin());
offset += keySize;
// 读取IV大小
uint32_t ivSize = *reinterpret_cast<uint32_t*>(&keyData[offset]);
offset += sizeof(uint32_t);
// 读取IV
keyInfo_.iv.resize(ivSize);
std::copy(keyData.begin() + offset,
keyData.begin() + offset + ivSize,
keyInfo_.iv.begin());
offset += ivSize;
// 读取盐值大小
uint32_t saltSize = *reinterpret_cast<uint32_t*>(&keyData[offset]);
offset += sizeof(uint32_t);
// 读取盐值
keyInfo_.salt.resize(saltSize);
std::copy(keyData.begin() + offset,
keyData.begin() + offset + saltSize,
keyInfo_.salt.begin());
keyInfo_.version = version;
keyLoaded_ = true;
LOG_INFO("Encryption key loaded from: {}", filename);
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception during key loading: {}", e.what());
return false;
}
}
bool DataEncryptor::saveKey(const std::string& keyFile) {
try {
if (!keyLoaded_) {
LOG_ERROR("No key to save");
return false;
}
std::string filename = keyFile.empty() ? keyFilePath_ : keyFile;
std::ofstream file(filename, std::ios::binary);
if (!file.is_open()) {
LOG_ERROR("Failed to open key file for writing: {}", filename);
return false;
}
// 写入密钥信息(简化版本)
file.write(reinterpret_cast<const char*>(&keyInfo_.version), sizeof(uint32_t));
uint32_t algorithm = static_cast<uint32_t>(keyInfo_.algorithm);
file.write(reinterpret_cast<const char*>(&algorithm), sizeof(uint32_t));
uint32_t keySize = static_cast<uint32_t>(keyInfo_.key.size());
file.write(reinterpret_cast<const char*>(&keySize), sizeof(uint32_t));
file.write(reinterpret_cast<const char*>(keyInfo_.data()), keySize);
uint32_t ivSize = static_cast<uint32_t>(keyInfo_.iv.size());
file.write(reinterpret_cast<const char*>(&ivSize), sizeof(uint32_t));
file.write(reinterpret_cast<const char*>(keyInfo_.iv.data()), ivSize);
uint32_t saltSize = static_cast<uint32_t>(keyInfo_.salt.size());
file.write(reinterpret_cast<const char*>(&saltSize), sizeof(uint32_t));
file.write(reinterpret_cast<const char*>(keyInfo_.salt.data()), saltSize);
file.close();
LOG_INFO("Encryption key saved to: {}", filename);
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception during key saving: {}", e.what());
return false;
}
}
std::vector<uint8_t> DataEncryptor::deriveKey(const std::string& password,
const std::vector<uint8_t>& salt) {
std::vector<uint8_t> key(KEY_SIZE);
if (PKCS5_PBKDF2_HMAC(password.c_str(), password.length(),
salt.data(), salt.size(),
100000, // 迭代次数
EVP_sha256(),
KEY_SIZE, key.data()) != 1) {
LOG_ERROR("Failed to derive key from password");
throw std::runtime_error("Key derivation failed");
}
return key;
}
std::vector<uint8_t> DataEncryptor::generateRandom(size_t size) {
std::vector<uint8_t> randomBytes(size);
if (RAND_bytes(randomBytes.data(), size) != 1) {
LOG_ERROR("Failed to generate random bytes");
throw std::runtime_error("Random generation failed");
}
return randomBytes;
}
std::vector<uint8_t> DataEncryptor::encryptData(const std::vector<uint8_t>& plaintext) {
switch (currentAlgorithm_) {
case Algorithm::AES_256_GCM:
case Algorithm::AES_256_CBC:
return encryptAES(plaintext);
case Algorithm::CHACHA20_POLY1305:
return encryptChaCha20(plaintext);
default:
LOG_ERROR("Unsupported encryption algorithm");
return {};
}
}
std::vector<uint8_t> DataEncryptor::decryptData(const std::vector<uint8_t>& ciphertext) {
switch (currentAlgorithm_) {
case Algorithm::AES_256_GCM:
case Algorithm::AES_256_CBC:
return decryptAES(ciphertext);
case Algorithm::CHACHA20_POLY1305:
return decryptChaCha20(ciphertext);
default:
LOG_ERROR("Unsupported encryption algorithm");
return {};
}
}
std::vector<uint8_t> DataEncryptor::encryptAES(const std::vector<uint8_t>& plaintext) {
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
LOG_ERROR("Failed to create cipher context");
return {};
}
std::vector<uint8_t> ciphertext(plaintext.size() + EVP_MAX_BLOCK_LENGTH);
int len = 0;
int ciphertextLen = 0;
try {
const EVP_CIPHER* cipher = nullptr;
if (currentAlgorithm_ == Algorithm::AES_256_GCM) {
cipher = EVP_aes_256_gcm();
} else {
cipher = EVP_aes_256_cbc();
}
if (!cipher) {
throw std::runtime_error("Unsupported AES cipher");
}
if (EVP_EncryptInit_ex(ctx, cipher, nullptr,
keyInfo_.key.data(), keyInfo_.iv.data()) != 1) {
throw std::runtime_error("Encryption initialization failed");
}
if (EVP_EncryptUpdate(ctx, ciphertext.data(), &len,
plaintext.data(), plaintext.size()) != 1) {
throw std::runtime_error("Encryption update failed");
}
ciphertextLen = len;
if (EVP_EncryptFinal_ex(ctx, ciphertext.data() + len, &len) != 1) {
throw std::runtime_error("Encryption finalization failed");
}
ciphertextLen += len;
ciphertext.resize(ciphertextLen);
} catch (const std::exception& e) {
LOG_ERROR("AES encryption error: {}", e.what());
ciphertext.clear();
}
EVP_CIPHER_CTX_free(ctx);
return ciphertext;
}
std::vector<uint8_t> DataEncryptor::decryptAES(const std::vector<uint8_t>& ciphertext) {
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
if (!ctx) {
LOG_ERROR("Failed to create cipher context");
return {};
}
std::vector<uint8_t> plaintext(ciphertext.size() + EVP_MAX_BLOCK_LENGTH);
int len = 0;
int plaintextLen = 0;
try {
const EVP_CIPHER* cipher = nullptr;
if (currentAlgorithm_ == Algorithm::AES_256_GCM) {
cipher = EVP_aes_256_gcm();
} else {
cipher = EVP_aes_256_cbc();
}
if (!cipher) {
throw std::runtime_error("Unsupported AES cipher");
}
if (EVP_DecryptInit_ex(ctx, cipher, nullptr,
keyInfo_.key.data(), keyInfo_.iv.data()) != 1) {
throw std::runtime_error("Decryption initialization failed");
}
if (EVP_DecryptUpdate(ctx, plaintext.data(), &len,
ciphertext.data(), ciphertext.size()) != 1) {
throw std::runtime_error("Decryption update failed");
}
plaintextLen = len;
if (EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len) != 1) {
throw std::runtime_error("Decryption finalization failed");
}
plaintextLen += len;
plaintext.resize(plaintextLen);
} catch (const std::exception& e) {
LOG_ERROR("AES decryption error: {}", e.what());
plaintext.clear();
}
EVP_CIPHER_CTX_free(ctx);
return plaintext;
}
std::vector<uint8_t> DataEncryptor::encryptChaCha20(const std::vector<uint8_t>& plaintext) {
// 简化实现,实际应该使用OpenSSL的ChaCha20-Poly1305
LOG_WARN("ChaCha20 encryption not fully implemented");
return encryptAES(plaintext); // 临时使用AES
}
std::vector<uint8_t> DataEncryptor::decryptChaCha20(const std::vector<uint8_t>& ciphertext) {
// 简化实现,实际应该使用OpenSSL的ChaCha20-Poly1305
LOG_WARN("ChaCha20 decryption not fully implemented");
return decryptAES(ciphertext); // 临时使用AES
}
DataEncryptor::EncryptionInfo DataEncryptor::getEncryptionInfo() const {
EncryptionInfo info;
info.algorithm = currentAlgorithm_;
info.keySize = KEY_SIZE;
info.ivSize = IV_SIZE;
info.tagSize = TAG_SIZE;
info.authenticated = (currentAlgorithm_ == Algorithm::AES_256_GCM ||
currentAlgorithm_ == Algorithm::CHACHA20_POLY1305);
switch (currentAlgorithm_) {
case Algorithm::AES_256_GCM:
info.algorithmName = "AES-256-GCM";
break;
case Algorithm::CHACHA20_POLY1305:
info.algorithmName = "ChaCha20-Poly1305";
break;
case Algorithm::AES_256_CBC:
info.algorithmName = "AES-256-CBC";
break;
default:
info.algorithmName = "Unknown";
}
return info;
}
// CryptoUtils 命名空间实现
namespace CryptoUtils {
std::string sha256(const std::string& data) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, data.c_str(), data.size());
SHA256_Final(hash, &sha256);
std::stringstream ss;
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
}
return ss.str();
}
std::string sha256File(const std::string& filePath) {
std::ifstream file(filePath, std::ios::binary);
if (!file.is_open()) {
LOG_ERROR("Failed to open file for hashing: {}", filePath);
return "";
}
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
char buffer[4096];
while (file.read(buffer, sizeof(buffer))) {
SHA256_Update(&sha256, buffer, file.gcount());
}
SHA256_Final(hash, &sha256);
file.close();
std::stringstream ss;
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
}
return ss.str();
}
std::string base64Encode(const std::vector<uint8_t>& data) {
BIO* b64 = BIO_new(BIO_f_base64());
BIO* bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, data.data(), data.size());
BIO_flush(b64);
BUF_MEM* bptr;
BIO_get_mem_ptr(b64, &bptr);
std::string result(bptr->data, bptr->length - 1); // 移除换行符
BIO_free_all(b64);
return result;
}
std::vector<uint8_t> base64Decode(const std::string& encoded) {
BIO* b64 = BIO_new(BIO_f_base64());
BIO* bmem = BIO_new_mem_buf(encoded.c_str(), encoded.length());
bmem = BIO_push(b64, bmem);
std::vector<uint8_t> decoded(encoded.length());
int len = BIO_read(bmem, decoded.data(), encoded.length());
BIO_free_all(bmem);
if (len > 0) {
decoded.resize(len);
return decoded;
}
return {};
}
std::string hexEncode(const std::vector<uint8_t>& data) {
std::stringstream ss;
for (const auto& byte : data) {
ss << std::hex << std::setw(2) << std::setfill('0') << (int)byte;
}
return ss.str();
}
std::vector<uint8_t> hexDecode(const std::string& encoded) {
if (encoded.length() % 2 != 0) {
return {};
}
std::vector<uint8_t> decoded(encoded.length() / 2);
for (size_t i = 0; i < encoded.length(); i += 2) {
std::string byteString = encoded.substr(i, 2);
uint8_t byte = static_cast<uint8_t>(std::stoul(byteString, nullptr, 16));
decoded[i / 2] = byte;
}
return decoded;
}
std::string generateRandomString(size_t length) {
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
std::string result;
result.reserve(length);
for (size_t i = 0; i < length; ++i) {
result.push_back(alphanum[rand() % (sizeof(alphanum) - 1)]);
}
return result;
}
std::vector<uint8_t> generateRandomBytes(size_t count) {
std::vector<uint8_t> bytes(count);
if (RAND_bytes(bytes.data(), count) != 1) {
LOG_ERROR("Failed to generate random bytes");
throw std::runtime_error("Random generation failed");
}
return bytes;
}
bool constantTimeCompare(const std::string& a, const std::string& b) {
if (a.length() != b.length()) {
return false;
}
uint8_t result = 0;
for (size_t i = 0; i < a.length(); i++) {
result |= a[i] ^ b[i];
}
return result == 0;
}
bool constantTimeCompare(const std::vector<uint8_t>& a,
const std::vector<uint8_t>& b) {
if (a.size() != b.size()) {
return false;
}
uint8_t result = 0;
for (size_t i = 0; i < a.size(); i++) {
result |= a[i] ^ b[i];
}
return result == 0;
}
bool checkPasswordStrength(const std::string& password) {
if (password.length() < 8) {
return false;
}
bool hasLower = false;
bool hasUpper = false;
bool hasDigit = false;
bool hasSpecial = false;
for (char c : password) {
if (std::islower(c)) hasLower = true;
else if (std::isupper(c)) hasUpper = true;
else if (std::isdigit(c)) hasDigit = true;
else if (!std::isspace(c)) hasSpecial = true;
}
// 至少需要3种类型的字符
int typeCount = (hasLower ? 1 : 0) + (hasUpper ? 1 : 0) +
(hasDigit ? 1 : 0) + (hasSpecial ? 1 : 0);
return typeCount >= 3;
}
}