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"
|