XNSim/XNSignature/verify.cpp

303 lines
7.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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