303 lines
7.8 KiB
C++
303 lines
7.8 KiB
C++
#include "XNSignature_global.h"
|
||
#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>
|
||
|
||
extern "C"
|
||
{
|
||
|
||
/**
|
||
* @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 publicKeyPath 公钥文件路径
|
||
* @param signaturePath 签名文件路径
|
||
* @return 0表示验证成功,-1表示验证失败,-2表示其他错误
|
||
*/
|
||
XNSIGNATURE_API int verifySignature(const char *filePath, const char *publicKeyPath,
|
||
const char *signaturePath)
|
||
{
|
||
if (!filePath || !publicKeyPath || !signaturePath) {
|
||
std::cerr << "错误:参数不能为空" << std::endl;
|
||
return -2;
|
||
}
|
||
|
||
// 加载公钥
|
||
FILE *publicKeyFile = fopen(publicKeyPath, "r");
|
||
if (!publicKeyFile) {
|
||
std::cerr << "错误:无法打开公钥文件" << std::endl;
|
||
return -2;
|
||
}
|
||
|
||
EVP_PKEY *publicKey = PEM_read_PUBKEY(publicKeyFile, nullptr, nullptr, nullptr);
|
||
fclose(publicKeyFile);
|
||
|
||
if (!publicKey) {
|
||
std::cerr << "错误:无法读取公钥" << std::endl;
|
||
return -2;
|
||
}
|
||
|
||
// 计算文件哈希
|
||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||
if (calculateFileHash(filePath, hash) != 0) {
|
||
EVP_PKEY_free(publicKey);
|
||
return -2;
|
||
}
|
||
|
||
// 读取签名文件
|
||
std::ifstream signatureFile(signaturePath, std::ios::binary);
|
||
if (!signatureFile.is_open()) {
|
||
std::cerr << "错误:无法打开签名文件" << std::endl;
|
||
EVP_PKEY_free(publicKey);
|
||
return -2;
|
||
}
|
||
|
||
signatureFile.seekg(0, std::ios::end);
|
||
size_t signatureSize = signatureFile.tellg();
|
||
signatureFile.seekg(0, std::ios::beg);
|
||
|
||
std::vector<unsigned char> signature(signatureSize);
|
||
signatureFile.read(reinterpret_cast<char *>(signature.data()), signatureSize);
|
||
signatureFile.close();
|
||
|
||
// 创建验证上下文
|
||
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
||
if (!ctx) {
|
||
std::cerr << "错误:无法创建验证上下文" << std::endl;
|
||
EVP_PKEY_free(publicKey);
|
||
return -2;
|
||
}
|
||
|
||
// 初始化验证
|
||
if (EVP_DigestVerifyInit(ctx, nullptr, EVP_sha256(), nullptr, publicKey) <= 0) {
|
||
std::cerr << "错误:无法初始化验证" << std::endl;
|
||
EVP_MD_CTX_free(ctx);
|
||
EVP_PKEY_free(publicKey);
|
||
return -2;
|
||
}
|
||
|
||
// 执行验证
|
||
int result =
|
||
EVP_DigestVerify(ctx, signature.data(), signature.size(), hash, SHA256_DIGEST_LENGTH);
|
||
|
||
// 清理资源
|
||
EVP_MD_CTX_free(ctx);
|
||
EVP_PKEY_free(publicKey);
|
||
|
||
if (result == 1) {
|
||
std::cout << "签名验证成功!文件完整性确认。" << std::endl;
|
||
return 0;
|
||
} else if (result == 0) {
|
||
std::cout << "签名验证失败!文件可能已被篡改。" << std::endl;
|
||
return -1;
|
||
} else {
|
||
std::cerr << "错误:验证过程中发生错误" << std::endl;
|
||
return -2;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 显示文件哈希值
|
||
* @param filePath 文件路径
|
||
* @return 0表示成功,-1表示失败
|
||
*/
|
||
int showFileHash(const char *filePath)
|
||
{
|
||
if (!filePath) {
|
||
std::cerr << "错误:文件路径不能为空" << std::endl;
|
||
return -1;
|
||
}
|
||
|
||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||
if (calculateFileHash(filePath, hash) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
std::cout << "文件 " << filePath << " 的SHA256哈希值:" << std::endl;
|
||
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
|
||
printf("%02x", hash[i]);
|
||
}
|
||
std::cout << std::endl;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取文件哈希值的十六进制字符串
|
||
* @param filePath 文件路径
|
||
* @param hashString 输出哈希字符串缓冲区(至少65字节)
|
||
* @return 0表示成功,-1表示失败
|
||
*/
|
||
int getFileHashString(const char *filePath, char *hashString)
|
||
{
|
||
if (!filePath || !hashString) {
|
||
return -1;
|
||
}
|
||
|
||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||
if (calculateFileHash(filePath, hash) != 0) {
|
||
return -1;
|
||
}
|
||
|
||
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
|
||
sprintf(hashString + i * 2, "%02x", hash[i]);
|
||
}
|
||
hashString[64] = '\0'; // 确保字符串结束
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 验证签名并返回详细结果
|
||
* @param filePath 原始文件路径
|
||
* @param publicKeyPath 公钥文件路径
|
||
* @param signaturePath 签名文件路径
|
||
* @param resultMessage 结果消息缓冲区
|
||
* @param messageSize 缓冲区大小
|
||
* @return 0表示验证成功,-1表示验证失败,-2表示其他错误
|
||
*/
|
||
int verifySignatureWithMessage(const char *filePath, const char *publicKeyPath,
|
||
const char *signaturePath, char *resultMessage, int messageSize)
|
||
{
|
||
if (!filePath || !publicKeyPath || !signaturePath || !resultMessage) {
|
||
if (resultMessage && messageSize > 0) {
|
||
snprintf(resultMessage, messageSize, "错误:参数不能为空");
|
||
}
|
||
return -2;
|
||
}
|
||
|
||
// 加载公钥
|
||
FILE *publicKeyFile = fopen(publicKeyPath, "r");
|
||
if (!publicKeyFile) {
|
||
if (messageSize > 0) {
|
||
snprintf(resultMessage, messageSize, "错误:无法打开公钥文件");
|
||
}
|
||
return -2;
|
||
}
|
||
|
||
EVP_PKEY *publicKey = PEM_read_PUBKEY(publicKeyFile, nullptr, nullptr, nullptr);
|
||
fclose(publicKeyFile);
|
||
|
||
if (!publicKey) {
|
||
if (messageSize > 0) {
|
||
snprintf(resultMessage, messageSize, "错误:无法读取公钥");
|
||
}
|
||
return -2;
|
||
}
|
||
|
||
// 计算文件哈希
|
||
unsigned char hash[SHA256_DIGEST_LENGTH];
|
||
if (calculateFileHash(filePath, hash) != 0) {
|
||
EVP_PKEY_free(publicKey);
|
||
if (messageSize > 0) {
|
||
snprintf(resultMessage, messageSize, "错误:无法计算文件哈希");
|
||
}
|
||
return -2;
|
||
}
|
||
|
||
// 读取签名文件
|
||
std::ifstream signatureFile(signaturePath, std::ios::binary);
|
||
if (!signatureFile.is_open()) {
|
||
EVP_PKEY_free(publicKey);
|
||
if (messageSize > 0) {
|
||
snprintf(resultMessage, messageSize, "错误:无法打开签名文件");
|
||
}
|
||
return -2;
|
||
}
|
||
|
||
signatureFile.seekg(0, std::ios::end);
|
||
size_t signatureSize = signatureFile.tellg();
|
||
signatureFile.seekg(0, std::ios::beg);
|
||
|
||
std::vector<unsigned char> signature(signatureSize);
|
||
signatureFile.read(reinterpret_cast<char *>(signature.data()), signatureSize);
|
||
signatureFile.close();
|
||
|
||
// 创建验证上下文
|
||
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
||
if (!ctx) {
|
||
EVP_PKEY_free(publicKey);
|
||
if (messageSize > 0) {
|
||
snprintf(resultMessage, messageSize, "错误:无法创建验证上下文");
|
||
}
|
||
return -2;
|
||
}
|
||
|
||
// 初始化验证
|
||
if (EVP_DigestVerifyInit(ctx, nullptr, EVP_sha256(), nullptr, publicKey) <= 0) {
|
||
EVP_MD_CTX_free(ctx);
|
||
EVP_PKEY_free(publicKey);
|
||
if (messageSize > 0) {
|
||
snprintf(resultMessage, messageSize, "错误:无法初始化验证");
|
||
}
|
||
return -2;
|
||
}
|
||
|
||
// 执行验证
|
||
int result =
|
||
EVP_DigestVerify(ctx, signature.data(), signature.size(), hash, SHA256_DIGEST_LENGTH);
|
||
|
||
// 清理资源
|
||
EVP_MD_CTX_free(ctx);
|
||
EVP_PKEY_free(publicKey);
|
||
|
||
if (result == 1) {
|
||
if (messageSize > 0) {
|
||
snprintf(resultMessage, messageSize, "签名验证成功!文件完整性确认。");
|
||
}
|
||
return 0;
|
||
} else if (result == 0) {
|
||
if (messageSize > 0) {
|
||
snprintf(resultMessage, messageSize, "签名验证失败!文件可能已被篡改。");
|
||
}
|
||
return -1;
|
||
} else {
|
||
if (messageSize > 0) {
|
||
snprintf(resultMessage, messageSize, "错误:验证过程中发生错误");
|
||
}
|
||
return -2;
|
||
}
|
||
}
|
||
|
||
} // extern "C"
|