XNSim/XNSignature/sign.cpp

253 lines
6.8 KiB
C++
Raw Normal View History

#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
/**
* @brief SHA256哈希值
* @param filePath
* @param hash 32
* @return 0-1
*/
int calculateFileHash(const char *filePath, unsigned char *hash)
{
if (!filePath || !hash) {
return -1;
}
std::ifstream file(filePath, std::ios::binary);
if (!file.is_open()) {
std::cerr << "错误:无法打开文件 " << filePath << std::endl;
return -1;
}
SHA256_CTX sha256;
SHA256_Init(&sha256);
char buffer[4096];
while (file) {
file.read(buffer, sizeof(buffer));
std::streamsize bytesRead = file.gcount();
if (bytesRead > 0) {
SHA256_Update(&sha256, buffer, bytesRead);
}
}
SHA256_Final(hash, &sha256);
file.close();
return 0;
}
/**
* @brief
* @param filePath
* @param privateKeyPath
* @param signaturePath
* @return 0-1
*/
int signFile(const char *filePath, const char *privateKeyPath, const char *signaturePath)
{
if (!filePath || !privateKeyPath || !signaturePath) {
std::cerr << "错误:参数不能为空" << std::endl;
return -1;
}
// 加载私钥
FILE *privateKeyFile = fopen(privateKeyPath, "r");
if (!privateKeyFile) {
std::cerr << "错误:无法打开私钥文件" << std::endl;
return -1;
}
EVP_PKEY *privateKey = PEM_read_PrivateKey(privateKeyFile, nullptr, nullptr, nullptr);
fclose(privateKeyFile);
if (!privateKey) {
std::cerr << "错误:无法读取私钥" << std::endl;
return -1;
}
// 计算文件哈希
unsigned char hash[SHA256_DIGEST_LENGTH];
if (calculateFileHash(filePath, hash) != 0) {
EVP_PKEY_free(privateKey);
return -1;
}
// 创建签名上下文
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
if (!ctx) {
std::cerr << "错误:无法创建签名上下文" << std::endl;
EVP_PKEY_free(privateKey);
return -1;
}
// 初始化签名
if (EVP_DigestSignInit(ctx, nullptr, EVP_sha256(), nullptr, privateKey) <= 0) {
std::cerr << "错误:无法初始化签名" << std::endl;
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(privateKey);
return -1;
}
// 计算签名长度
size_t signatureLen;
if (EVP_DigestSign(ctx, nullptr, &signatureLen, hash, SHA256_DIGEST_LENGTH) <= 0) {
std::cerr << "错误:无法计算签名长度" << std::endl;
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(privateKey);
return -1;
}
// 分配签名缓冲区
std::vector<unsigned char> signature(signatureLen);
// 执行签名
if (EVP_DigestSign(ctx, signature.data(), &signatureLen, hash, SHA256_DIGEST_LENGTH) <= 0) {
std::cerr << "错误:签名失败" << std::endl;
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(privateKey);
return -1;
}
// 保存签名到文件
std::ofstream signatureFile(signaturePath, std::ios::binary);
if (!signatureFile.is_open()) {
std::cerr << "错误:无法创建签名文件" << std::endl;
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(privateKey);
return -1;
}
signatureFile.write(reinterpret_cast<const char *>(signature.data()), signatureLen);
signatureFile.close();
// 清理资源
EVP_MD_CTX_free(ctx);
EVP_PKEY_free(privateKey);
std::cout << "文件签名成功!" << std::endl;
std::cout << "签名文件保存到: " << signaturePath << std::endl;
return 0;
}
#include <filesystem>
#include <vector>
#include <string>
/**
* @brief
* @param directory
* @return
*/
std::vector<std::string> getFilesInDirectory(const std::string &directory)
{
std::vector<std::string> files;
try {
for (const auto &entry : std::filesystem::directory_iterator(directory)) {
if (entry.is_regular_file()) {
// 跳过密钥文件和签名文件
std::string filename = entry.path().filename().string();
if (filename != "private_key.pem" && filename != "public_key.pem"
&& filename.find(".sig") == std::string::npos) {
files.push_back(entry.path().string());
}
}
}
} catch (const std::filesystem::filesystem_error &e) {
std::cerr << "错误:无法读取目录 " << directory << ": " << e.what() << std::endl;
}
return files;
}
/**
* @brief 使
*/
void showUsage(const char *programName)
{
std::cout << "用法: " << programName << " [文件路径]" << std::endl;
std::cout << "参数说明:" << std::endl;
std::cout << " 文件路径: 要签名的文件路径(可选)" << std::endl;
std::cout << " 如果不提供参数,将签名当前目录下的所有文件" << std::endl;
std::cout << "示例:" << std::endl;
std::cout << " " << programName << " # 签名所有文件" << std::endl;
std::cout << " " << programName << " document.txt # 签名指定文件" << std::endl;
}
/**
* @brief
*/
int main(int argc, char *argv[])
{
const char *privateKeyPath = "private_key.pem";
std::vector<std::string> filesToSign;
std::cout << "=== XNSignature 文件签名工具 ===" << std::endl;
if (argc == 1) {
// 没有参数,签名目录下所有文件
std::cout << "未指定文件,将签名当前目录下的所有文件..." << std::endl;
filesToSign = getFilesInDirectory(".");
if (filesToSign.empty()) {
std::cout << "当前目录下没有找到可签名的文件" << std::endl;
return 0;
}
std::cout << "找到 " << filesToSign.size() << " 个文件:" << std::endl;
for (const auto &file : filesToSign) {
std::cout << " - " << file << std::endl;
}
} else if (argc == 2) {
// 指定了单个文件
filesToSign.push_back(argv[1]);
std::cout << "将签名指定文件: " << argv[1] << std::endl;
} else {
std::cerr << "错误:参数数量不正确" << std::endl;
showUsage(argv[0]);
return -1;
}
std::cout << "私钥文件: " << privateKeyPath << std::endl;
std::cout << "正在签名文件..." << std::endl;
int successCount = 0;
int totalCount = filesToSign.size();
for (const auto &filePath : filesToSign) {
// 生成签名文件路径
std::string signaturePath = filePath + ".sig";
std::cout << "\n正在签名: " << filePath << std::endl;
std::cout << "签名文件: " << signaturePath << std::endl;
int result = signFile(filePath.c_str(), privateKeyPath, signaturePath.c_str());
if (result == 0) {
std::cout << "✓ 签名成功" << std::endl;
successCount++;
} else {
std::cout << "✗ 签名失败" << std::endl;
}
}
std::cout << "\n=== 签名完成 ===" << std::endl;
std::cout << "成功签名: " << successCount << "/" << totalCount << " 个文件" << std::endl;
if (successCount == totalCount) {
std::cout << "所有文件签名完成!" << std::endl;
return 0;
} else {
std::cerr << "部分文件签名失败!" << std::endl;
return -1;
}
}