init
This commit is contained in:
commit
70d467d052
97 files changed
+10386
No files matched your search
@@ -0,0 +1,69 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Linker files
|
||||
*.ilk
|
||||
|
||||
# Debugger Files
|
||||
*.pdb
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
*.so.*
|
||||
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Build directories
|
||||
build/
|
||||
Build/
|
||||
build-*/
|
||||
|
||||
# CMake generated files
|
||||
CMakeFiles/
|
||||
CMakeCache.txt
|
||||
cmake_install.cmake
|
||||
#Makefile
|
||||
install_manifest.txt
|
||||
compile_commands.json
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.log
|
||||
*.bak
|
||||
*.swp
|
||||
|
||||
# vcpkg
|
||||
vcpkg_installed/
|
||||
|
||||
# debug information files
|
||||
*.dwo
|
||||
|
||||
# test output & cache
|
||||
Testing/
|
||||
.cache/
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 建昌风物大顺脚本
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,45 @@
|
||||
VERSION := 0.0.1
|
||||
FRAMEWORK_NAME := us
|
||||
LIB_NAME := libus_crypt
|
||||
INSTL_TDIR := /lib
|
||||
INCLU_TDIR := /usr/include
|
||||
INCLU_SDIR := inc
|
||||
CPP := g++
|
||||
INCS := -I inc
|
||||
CPPFLAGS := --std=c++20 -O3 -pipe -Wall -Werror
|
||||
LIBS :=
|
||||
BUILD_TDIR := build
|
||||
$(shell mkdir -p $(BUILD_TDIR))
|
||||
|
||||
#--------
|
||||
all: $(BUILD_TDIR)/$(LIB_NAME).so
|
||||
|
||||
$(BUILD_TDIR)/$(LIB_NAME).so: $(BUILD_TDIR)/Crypto_Basic.o
|
||||
$(CPP) -shared $^ $(LIBS) -o $@
|
||||
|
||||
$(BUILD_TDIR)/Crypto_Basic.o: src/Crypto_Basic.cpp
|
||||
$(CPP) $(CPPFLAGS) -fPIC -c $^ $(INCS) -o $@
|
||||
|
||||
clear:
|
||||
@rm -rvf $(BUILD_TDIR)
|
||||
|
||||
install:
|
||||
@echo "install UniServe_libcrypt..."
|
||||
@mkdir -vp $(INCLU_TDIR)/$(FRAMEWORK_NAME)
|
||||
@cp -vf $(INCLU_SDIR)/$(FRAMEWORK_NAME)/Crypto_Basic.hpp $(INCLU_TDIR)/$(FRAMEWORK_NAME)/
|
||||
@cp -vf $(INCLU_SDIR)/$(FRAMEWORK_NAME)/Base64.hpp $(INCLU_TDIR)/$(FRAMEWORK_NAME)/
|
||||
@cp -vf $(INCLU_SDIR)/$(FRAMEWORK_NAME)/SHA256.hpp $(INCLU_TDIR)/$(FRAMEWORK_NAME)/
|
||||
@cp -vf $(INCLU_SDIR)/$(FRAMEWORK_NAME)/AES_CBC.hpp $(INCLU_TDIR)/$(FRAMEWORK_NAME)/
|
||||
@cp -vf $(INCLU_SDIR)/$(FRAMEWORK_NAME)/MyRSA.hpp $(INCLU_TDIR)/$(FRAMEWORK_NAME)/
|
||||
@cp -vf $(BUILD_TDIR)/$(LIB_NAME).so $(INSTL_TDIR)/
|
||||
@echo "done."
|
||||
|
||||
uninstall:
|
||||
@echo "uninstall UniServe_libcrypt..."
|
||||
@rm -vf $(INCLU_TDIR)/$(FRAMEWORK_NAME)/Crypto_Basic.hpp
|
||||
@rm -vf $(INCLU_TDIR)/$(FRAMEWORK_NAME)/Base64.hpp
|
||||
@rm -vf $(INCLU_TDIR)/$(FRAMEWORK_NAME)/SHA256.hpp
|
||||
@rm -vf $(INCLU_TDIR)/$(FRAMEWORK_NAME)/AES_CBC.hpp
|
||||
@rm -vf $(INCLU_TDIR)/$(FRAMEWORK_NAME)/MyRSA.hpp
|
||||
@rm -vf $(INSTL_TDIR)/$(LIB_NAME).so
|
||||
@echo "done."
|
||||
@@ -0,0 +1,2 @@
|
||||
# UniServe_libcrypt
|
||||
UniServe Framework Cryption Library
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
cd "$(dirname "$0")" || exit
|
||||
make clear
|
||||
make
|
||||
make install
|
||||
@@ -0,0 +1,140 @@
|
||||
#include "Crypto_Basic.hpp"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace qing {
|
||||
class AES_CBC: public qing::Crypto_Basic {
|
||||
public:
|
||||
/* 构造函数 初始化一个随即的密钥和初始化向量 */
|
||||
AES_CBC() {
|
||||
generate_key_iv(key, iv);
|
||||
}
|
||||
AES_CBC(std::vector<unsigned char> &key, std::vector<unsigned char> &iv) {
|
||||
this->key = key;
|
||||
this->iv = iv;
|
||||
}
|
||||
std::string get_key() {
|
||||
return bytes_to_hex(key);
|
||||
}
|
||||
std::string get_iv() {
|
||||
return bytes_to_hex(iv);
|
||||
}
|
||||
|
||||
std::string encrypt(std::string original_text) {
|
||||
std::vector<unsigned char> plaintext(original_text.begin(), original_text.end());
|
||||
std::vector<unsigned char> ciphertext = aes_encrypt(plaintext, key, iv);
|
||||
|
||||
// hex-bytes转换测试
|
||||
/*std::string hex = bytes_to_hex(ciphertext);
|
||||
std::vector<unsigned char> cipher2 = hex_to_bytes(hex);
|
||||
print_bytes(ciphertext);
|
||||
print_bytes(cipher2);*/
|
||||
|
||||
return bytes_to_hex(ciphertext);
|
||||
}
|
||||
|
||||
std::string decrypt(std::string cipher_hex) {
|
||||
std::vector<unsigned char> ciphertext = hex_to_bytes(cipher_hex);
|
||||
std::vector<unsigned char> decrypted = aes_decrypt(ciphertext, key, iv);
|
||||
return std::string(decrypted.begin(), decrypted.end());
|
||||
}
|
||||
|
||||
static void print_bytes(std::vector<unsigned char>& bytes) {
|
||||
for (unsigned char byte : bytes) {
|
||||
std::cerr << std::setw(2) << static_cast<int>(byte);
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<unsigned char> key;
|
||||
std::vector<unsigned char> iv;
|
||||
// 生成随机密钥和IV
|
||||
static void generate_key_iv(std::vector<unsigned char>& key,
|
||||
std::vector<unsigned char>& iv) {
|
||||
key.resize(32); // AES-256 需要 32 字节密钥
|
||||
iv.resize(16); // AES 块大小 16 字节(128-bit)
|
||||
|
||||
// 生成随即密钥
|
||||
CRYPTO_CHECK(RAND_bytes(key.data(), key.size()) == 1, "密钥生成失败");
|
||||
|
||||
// 生成随即IV
|
||||
CRYPTO_CHECK(RAND_bytes(iv.data(), iv.size()) == 1, "IV生成失败");
|
||||
}
|
||||
|
||||
// AES-256-CBC 加密
|
||||
static std::vector<unsigned char> aes_encrypt(const std::vector<unsigned char>& plaintext,
|
||||
const std::vector<unsigned char>& key,
|
||||
const std::vector<unsigned char>& iv) {
|
||||
// 创建上下文
|
||||
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
||||
CRYPTO_CHECK(ctx != nullptr, "无法创建加密上下文");
|
||||
|
||||
// 初始化加密操作
|
||||
CRYPTO_CHECK(EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr,
|
||||
key.data(), iv.data()) , "加密初始化失败");
|
||||
|
||||
// 输出缓冲区 (密文可能比明文长一个块)
|
||||
std::vector<unsigned char> ciphertext(plaintext.size() + EVP_CIPHER_CTX_block_size(ctx));
|
||||
int len = 0;
|
||||
int ciphertext_len = 0;
|
||||
|
||||
// 提供明文数据
|
||||
CRYPTO_CHECK(EVP_EncryptUpdate(ctx, ciphertext.data(), &len,
|
||||
plaintext.data(), plaintext.size()) == 1, "加载更新失败");
|
||||
ciphertext_len = len;
|
||||
|
||||
// 完成加密(处理填充)
|
||||
CRYPTO_CHECK(EVP_EncryptFinal_ex(ctx, ciphertext.data() + len, &len) == 1, "加密结束失败");
|
||||
ciphertext_len += len;
|
||||
|
||||
// 调整到实际密文长度
|
||||
ciphertext.resize(ciphertext_len);
|
||||
|
||||
// 处理上下文
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
return ciphertext;
|
||||
|
||||
}
|
||||
|
||||
// AES-256-CBC
|
||||
static std::vector<unsigned char> aes_decrypt(const std::vector<unsigned char>& ciphertext,
|
||||
const std::vector<unsigned char>& key,
|
||||
const std::vector<unsigned char>& iv) {
|
||||
// 创建上下文
|
||||
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
|
||||
CRYPTO_CHECK(ctx != nullptr, "无法创建解密上下文");
|
||||
|
||||
// 初始化解密操作
|
||||
CRYPTO_CHECK(EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr,
|
||||
key.data(), iv.data()) == 1, "解密初始化失败");
|
||||
|
||||
// 输出缓冲区(明文可能比密文短,但最大为密文长度)
|
||||
std::vector<unsigned char> plaintext(ciphertext.size());
|
||||
int len = 0;
|
||||
int plaintext_len = 0;
|
||||
|
||||
// 提供密文数据
|
||||
CRYPTO_CHECK(EVP_DecryptUpdate(ctx, plaintext.data(), &len,
|
||||
ciphertext.data(), ciphertext.size()) == 1, "解密更新失败");
|
||||
plaintext_len = len;
|
||||
|
||||
// 完成解密(处理填充)
|
||||
CRYPTO_CHECK(EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len) == 1, "解密结束失败");
|
||||
plaintext_len += len;
|
||||
|
||||
// 调整到实际明文长度
|
||||
plaintext.resize(plaintext_len);
|
||||
|
||||
// 清理上下文
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include "Crypto_Basic.hpp"
|
||||
|
||||
namespace qing {
|
||||
class Base64 : public qing::Crypto_Basic {
|
||||
public:
|
||||
/* 默认构造函数 */
|
||||
Base64() = default;
|
||||
|
||||
/* 编码:将字符串编码为Base64 */
|
||||
std::string encode(const std::string& input_text) {
|
||||
return base64_encode(input_text);
|
||||
}
|
||||
|
||||
/* 编码:将字节向量编码为Base64 */
|
||||
std::string encode(const std::vector<unsigned char>& input_bytes) {
|
||||
return base64_encode(input_bytes);
|
||||
}
|
||||
|
||||
/* 解码:将Base64字符串解码为原始字符串 */
|
||||
std::string decode_to_string(const std::string& base64_text) {
|
||||
std::vector<unsigned char> decoded = base64_decode_to_bytes(base64_text);
|
||||
return std::string(decoded.begin(), decoded.end());
|
||||
}
|
||||
|
||||
/* 解码:将Base64字符串解码为字节向量 */
|
||||
std::vector<unsigned char> decode_to_bytes(const std::string& base64_text) {
|
||||
return base64_decode_to_bytes(base64_text);
|
||||
}
|
||||
|
||||
/* 静态方法:直接编码字符串(工具函数) */
|
||||
static std::string base64_encode(const std::string& input_text) {
|
||||
std::vector<unsigned char> input(input_text.begin(), input_text.end());
|
||||
return base64_encode(input);
|
||||
}
|
||||
|
||||
/* 静态方法:直接编码字节向量(工具函数) */
|
||||
static std::string base64_encode(const std::vector<unsigned char>& input_bytes) {
|
||||
// 创建BIO链:内存BIO -> Base64 BIO
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
CRYPTO_CHECK(bio != nullptr, "无法创建内存BIO");
|
||||
|
||||
BIO* b64 = BIO_new(BIO_f_base64());
|
||||
CRYPTO_CHECK(b64 != nullptr, "无法创建Base64 BIO");
|
||||
|
||||
// 将Base64 BIO连接到内存BIO
|
||||
bio = BIO_push(b64, bio);
|
||||
|
||||
// 设置不添加换行符(默认会添加换行)
|
||||
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
// 写入数据
|
||||
int written = BIO_write(bio, input_bytes.data(), input_bytes.size());
|
||||
CRYPTO_CHECK(written == (int)input_bytes.size(), "Base64编码写入失败");
|
||||
|
||||
// 刷新缓冲区
|
||||
CRYPTO_CHECK(BIO_flush(bio) == 1, "Base64编码刷新失败");
|
||||
|
||||
// 读取编码结果
|
||||
BUF_MEM* bptr;
|
||||
BIO_get_mem_ptr(bio, &bptr);
|
||||
|
||||
// 复制结果到字符串(不包括空终止符)
|
||||
std::string result(bptr->data, bptr->length);
|
||||
|
||||
// 清理BIO
|
||||
BIO_free_all(bio);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 静态方法:直接解码为字符串(工具函数) */
|
||||
static std::string base64_decode_to_string(const std::string& base64_text) {
|
||||
std::vector<unsigned char> decoded = base64_decode_to_bytes(base64_text);
|
||||
return std::string(decoded.begin(), decoded.end());
|
||||
}
|
||||
|
||||
/* 静态方法:直接解码为字节向量(工具函数) */
|
||||
static std::vector<unsigned char> base64_decode_to_bytes(const std::string& base64_text) {
|
||||
// 创建BIO链:Base64 BIO -> 内存BIO
|
||||
BIO* bio = BIO_new_mem_buf(base64_text.c_str(), -1);
|
||||
CRYPTO_CHECK(bio != nullptr, "无法创建内存BIO");
|
||||
|
||||
BIO* b64 = BIO_new(BIO_f_base64());
|
||||
CRYPTO_CHECK(b64 != nullptr, "无法创建Base64 BIO");
|
||||
|
||||
// 将Base64 BIO连接到内存BIO
|
||||
bio = BIO_push(b64, bio);
|
||||
|
||||
// 设置不添加换行符(解码时也要匹配)
|
||||
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
|
||||
|
||||
// 准备接收缓冲区
|
||||
std::vector<unsigned char> result;
|
||||
char buffer[4096];
|
||||
int bytes_read;
|
||||
|
||||
// 循环读取解码数据
|
||||
while ((bytes_read = BIO_read(bio, buffer, sizeof(buffer))) > 0) {
|
||||
result.insert(result.end(), buffer, buffer + bytes_read);
|
||||
}
|
||||
|
||||
// 检查是否解码成功(BIO_read返回0表示结束,负值表示错误)
|
||||
CRYPTO_CHECK(bytes_read >= 0, "Base64解码失败");
|
||||
|
||||
// 清理BIO
|
||||
BIO_free_all(bio);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* 验证Base64格式是否有效 */
|
||||
static bool is_valid_base64(const std::string& base64_text) {
|
||||
// 检查是否只包含Base64字符(A-Z, a-z, 0-9, +, /, =)
|
||||
if (base64_text.empty()) return false;
|
||||
|
||||
for (char c : base64_text) {
|
||||
if (!((c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') ||
|
||||
c == '+' || c == '/' || c == '=')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 打印编码结果(调试用) */
|
||||
static void print_encoded(const std::string& encoded_text) {
|
||||
std::cerr << "Base64 Encoded: " << encoded_text << std::endl;
|
||||
}
|
||||
|
||||
/* 打印解码结果(调试用) */
|
||||
static void print_decoded(const std::vector<unsigned char>& decoded_bytes) {
|
||||
std::cerr << "Decoded bytes: ";
|
||||
for (unsigned char byte : decoded_bytes) {
|
||||
std::cerr << std::setw(2) << static_cast<int>(byte);
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
#define CRYPTO_CHECK(condition, message) \
|
||||
if (!(condition)) { \
|
||||
throw std::runtime_error(message); \
|
||||
}
|
||||
namespace qing {
|
||||
class Crypto_Basic {
|
||||
public:
|
||||
class CryptoExp: public std::runtime_error {
|
||||
public:
|
||||
CryptoExp(const std::string& msg): std::runtime_error(msg) {}
|
||||
};
|
||||
protected:
|
||||
/* 字节码转十六进制字符串 */
|
||||
static std::string bytes_to_hex(const std::vector<unsigned char>& data);
|
||||
|
||||
/* 十六进制字符串转字节码 */
|
||||
static std::vector<unsigned char> hex_to_bytes(const std::string &hex);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,578 @@
|
||||
#pragma once
|
||||
#include "Crypto_Basic.hpp"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
// 错误处理宏(打印完整错误栈,便于调试)
|
||||
#define HANDLE_SSL_ERROR() { \
|
||||
ERR_print_errors_fp(stderr); \
|
||||
}
|
||||
|
||||
// 自定义删除器用于管理OpenSSL资源
|
||||
struct EVP_PKEY_deleter {
|
||||
void operator()(EVP_PKEY* pkey) const { EVP_PKEY_free(pkey); }
|
||||
};
|
||||
using EVP_PKEY_ptr = std::unique_ptr<EVP_PKEY, EVP_PKEY_deleter>;
|
||||
|
||||
struct EVP_PKEY_CTX_deleter {
|
||||
void operator()(EVP_PKEY_CTX* ctx) const { EVP_PKEY_CTX_free(ctx); }
|
||||
};
|
||||
using EVP_PKEY_CTX_ptr = std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_deleter>;
|
||||
|
||||
struct BIO_deleter {
|
||||
void operator()(BIO* bio) const { BIO_free_all(bio); }
|
||||
};
|
||||
using BIO_ptr = std::unique_ptr<BIO, BIO_deleter>;
|
||||
|
||||
struct EVP_MD_CTX_deleter {
|
||||
void operator()(EVP_MD_CTX* ctx) const { EVP_MD_CTX_free(ctx); }
|
||||
};
|
||||
using EVP_MD_CTX_ptr = std::unique_ptr<EVP_MD_CTX, EVP_MD_CTX_deleter>;
|
||||
|
||||
namespace qing {
|
||||
// 签名填充模式枚举
|
||||
enum class RSASignaturePadding {
|
||||
PKCS1_v1_5, // 传统 PKCS#1 v1.5 填充(兼容旧系统)
|
||||
PSS // 概率签名方案(更安全,推荐)
|
||||
};
|
||||
|
||||
class MyRSA : public qing::Crypto_Basic {
|
||||
public:
|
||||
class Generator {
|
||||
public:
|
||||
Generator() {
|
||||
key = generate_rsa_key();
|
||||
}
|
||||
|
||||
// 保存私钥为 PKCS#8 格式(AES-256-CBC 加密),支持密码保护
|
||||
void save_pri_key(const std::string& filename, const char* password = nullptr) {
|
||||
if (!save_private_key(key.get(), filename, password)) {
|
||||
throw Crypto_Basic::CryptoExp("保存私钥失败。");
|
||||
}
|
||||
}
|
||||
|
||||
// 保存公钥(现代 SubjectPublicKeyInfo 格式)
|
||||
void save_pub_key(const std::string& filename) {
|
||||
if (!save_public_key(key.get(), filename)) {
|
||||
throw Crypto_Basic::CryptoExp("保存公钥失败。");
|
||||
}
|
||||
}
|
||||
|
||||
// 获取密钥(直接使用)
|
||||
EVP_PKEY* get_private_key() const { return key.get(); }
|
||||
|
||||
// 导出为 PEM 字符串(PKCS#8 格式)
|
||||
std::string get_private_key_pem(const char* password = nullptr) {
|
||||
return key_to_pem(key.get(), true, password);
|
||||
}
|
||||
|
||||
std::string get_public_key_pem() {
|
||||
return key_to_pem(key.get(), false);
|
||||
}
|
||||
|
||||
private:
|
||||
EVP_PKEY_ptr key;
|
||||
|
||||
static EVP_PKEY_ptr generate_rsa_key(size_t key_bits = 2048) {
|
||||
EVP_PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr));
|
||||
if (!ctx) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return nullptr;
|
||||
}
|
||||
if (EVP_PKEY_keygen_init(ctx.get()) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OSSL_PARAM params[] = {
|
||||
OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_BITS, &key_bits),
|
||||
OSSL_PARAM_END
|
||||
};
|
||||
|
||||
if (EVP_PKEY_CTX_set_params(ctx.get(), params) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EVP_PKEY* pkey = nullptr;
|
||||
if (EVP_PKEY_generate(ctx.get(), &pkey) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return EVP_PKEY_ptr(pkey);
|
||||
}
|
||||
|
||||
// 保存私钥为 PKCS#8 加密格式
|
||||
static bool save_private_key(EVP_PKEY* pkey, const std::string& filename,
|
||||
const char* password = nullptr) {
|
||||
BIO_ptr bio(BIO_new_file(filename.c_str(), "wb"));
|
||||
if (!bio) {
|
||||
std::cerr << "Failed to open file: " << filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const EVP_CIPHER* cipher = password ? EVP_aes_256_cbc() : nullptr;
|
||||
int ret = PEM_write_bio_PKCS8PrivateKey(bio.get(), pkey, cipher,
|
||||
(char*)password,
|
||||
password ? static_cast<int>(strlen(password)) : 0,
|
||||
nullptr, nullptr);
|
||||
if (ret != 1) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool save_public_key(EVP_PKEY* pkey, const std::string& filename) {
|
||||
BIO_ptr bio(BIO_new_file(filename.c_str(), "wb"));
|
||||
if (!bio) {
|
||||
std::cerr << "Failed to open file: " << filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
int ret = PEM_write_bio_PUBKEY(bio.get(), pkey);
|
||||
if (ret != 1) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string key_to_pem(EVP_PKEY* pkey, bool is_private,
|
||||
const char* password = nullptr) {
|
||||
BIO_ptr bio(BIO_new(BIO_s_mem()));
|
||||
if (!bio) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return "";
|
||||
}
|
||||
|
||||
int ret;
|
||||
if (is_private) {
|
||||
const EVP_CIPHER* cipher = password ? EVP_aes_256_cbc() : nullptr;
|
||||
ret = PEM_write_bio_PKCS8PrivateKey(bio.get(), pkey, cipher,
|
||||
(char*)password,
|
||||
password ? static_cast<int>(strlen(password)) : 0,
|
||||
nullptr, nullptr);
|
||||
} else {
|
||||
ret = PEM_write_bio_PUBKEY(bio.get(), pkey);
|
||||
}
|
||||
|
||||
if (ret != 1) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return "";
|
||||
}
|
||||
|
||||
char* data;
|
||||
long len = BIO_get_mem_data(bio.get(), &data);
|
||||
return std::string(data, len);
|
||||
}
|
||||
};
|
||||
|
||||
// 私钥类:支持 PKCS#1 和 PKCS#8 格式(含加密)
|
||||
class Private_Key : Crypto_Basic {
|
||||
public:
|
||||
// 从文件加载(支持密码)
|
||||
Private_Key(const std::string& fullpath, bool from_file = true,
|
||||
const char* password = nullptr) {
|
||||
if (from_file) {
|
||||
if (!(pri_key = load_private_key_from_file(fullpath, password)))
|
||||
throw Crypto_Basic::CryptoExp("读取私钥失败");
|
||||
} else {
|
||||
if (!(pri_key = load_private_key_from_string(fullpath, password)))
|
||||
throw Crypto_Basic::CryptoExp("从字符串加载私钥失败");
|
||||
}
|
||||
}
|
||||
|
||||
static Private_Key from_pem(const std::string& pem_string,
|
||||
const char* password = nullptr) {
|
||||
return Private_Key(pem_string, false, password);
|
||||
}
|
||||
|
||||
// 解密(OAEP)
|
||||
std::string Decrypt(const std::string& cipher_hex) {
|
||||
std::vector<unsigned char> ciphertext = hex_to_bytes(cipher_hex);
|
||||
std::vector<unsigned char> decrypted = rsa_decrypt(pri_key.get(), ciphertext);
|
||||
if (decrypted.empty()) throw Crypto_Basic::CryptoExp("解密失败");
|
||||
return std::string(decrypted.begin(), decrypted.end());
|
||||
}
|
||||
|
||||
// 签名(支持 PSS 和 PKCS#1 v1.5)
|
||||
std::string Sign(const std::string& message,
|
||||
RSASignaturePadding padding = RSASignaturePadding::PSS) {
|
||||
std::vector<unsigned char> msg(message.begin(), message.end());
|
||||
std::vector<unsigned char> signature = rsa_sign(pri_key.get(), msg, padding);
|
||||
if (signature.empty()) throw Crypto_Basic::CryptoExp("签名失败");
|
||||
return bytes_to_hex(signature);
|
||||
}
|
||||
|
||||
std::vector<unsigned char> SignBytes(const std::string& message,
|
||||
RSASignaturePadding padding = RSASignaturePadding::PSS) {
|
||||
std::vector<unsigned char> msg(message.begin(), message.end());
|
||||
return rsa_sign(pri_key.get(), msg, padding);
|
||||
}
|
||||
|
||||
std::string Sign(const std::vector<unsigned char>& message,
|
||||
RSASignaturePadding padding = RSASignaturePadding::PSS) {
|
||||
std::vector<unsigned char> signature = rsa_sign(pri_key.get(), message, padding);
|
||||
if (signature.empty()) throw Crypto_Basic::CryptoExp("签名失败");
|
||||
return bytes_to_hex(signature);
|
||||
}
|
||||
|
||||
std::vector<unsigned char> SignBytes(const std::vector<unsigned char>& message,
|
||||
RSASignaturePadding padding = RSASignaturePadding::PSS) {
|
||||
return rsa_sign(pri_key.get(), message, padding);
|
||||
}
|
||||
|
||||
EVP_PKEY* get() const { return pri_key.get(); }
|
||||
|
||||
private:
|
||||
EVP_PKEY_ptr pri_key;
|
||||
|
||||
static EVP_PKEY_ptr load_private_key_from_file(const std::string& filename,
|
||||
const char* password = nullptr) {
|
||||
BIO_ptr bio(BIO_new_file(filename.c_str(), "rb"));
|
||||
if (!bio) {
|
||||
std::cerr << "Failed to open file: " << filename << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pem_password_cb* cb = nullptr;
|
||||
if (password) {
|
||||
cb = [](char* buf, int size, int rwflag, void* u) -> int {
|
||||
if (!u) return 0;
|
||||
const char* pass = (const char*)u;
|
||||
int len = strlen(pass);
|
||||
if (len > size) len = size;
|
||||
memcpy(buf, pass, len);
|
||||
return len;
|
||||
};
|
||||
}
|
||||
|
||||
EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio.get(), nullptr, cb, (void*)password);
|
||||
if (!pkey) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return nullptr;
|
||||
}
|
||||
return EVP_PKEY_ptr(pkey);
|
||||
}
|
||||
|
||||
static EVP_PKEY_ptr load_private_key_from_string(const std::string& pem_string,
|
||||
const char* password = nullptr) {
|
||||
BIO_ptr bio(BIO_new_mem_buf(pem_string.c_str(), -1));
|
||||
if (!bio) {
|
||||
std::cerr << "Failed to create BIO from string" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pem_password_cb* cb = nullptr;
|
||||
if (password) {
|
||||
cb = [](char* buf, int size, int rwflag, void* u) -> int {
|
||||
if (!u) return 0;
|
||||
const char* pass = (const char*)u;
|
||||
int len = strlen(pass);
|
||||
if (len > size) len = size;
|
||||
memcpy(buf, pass, len);
|
||||
return len;
|
||||
};
|
||||
}
|
||||
|
||||
EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio.get(), nullptr, cb, (void*)password);
|
||||
if (!pkey) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return nullptr;
|
||||
}
|
||||
return EVP_PKEY_ptr(pkey);
|
||||
}
|
||||
|
||||
// RSA 解密(OAEP)
|
||||
static std::vector<unsigned char> rsa_decrypt(EVP_PKEY* private_key,
|
||||
const std::vector<unsigned char>& ciphertext) {
|
||||
EVP_PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new(private_key, nullptr));
|
||||
if (!ctx) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t outlen = 0;
|
||||
if (EVP_PKEY_decrypt(ctx.get(), nullptr, &outlen,
|
||||
ciphertext.data(), ciphertext.size()) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<unsigned char> plaintext(outlen);
|
||||
if (EVP_PKEY_decrypt(ctx.get(), plaintext.data(), &outlen,
|
||||
ciphertext.data(), ciphertext.size()) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
plaintext.resize(outlen);
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
// RSA 签名(修正了 PSS 参数顺序)
|
||||
static std::vector<unsigned char> rsa_sign(EVP_PKEY* private_key,
|
||||
const std::vector<unsigned char>& message,
|
||||
RSASignaturePadding padding) {
|
||||
EVP_MD_CTX_ptr ctx(EVP_MD_CTX_new());
|
||||
if (!ctx) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
const EVP_MD* md = EVP_sha256();
|
||||
|
||||
if (EVP_DigestSignInit(ctx.get(), nullptr, md, nullptr, private_key) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX* pkey_ctx = EVP_MD_CTX_get_pkey_ctx(ctx.get());
|
||||
if (!pkey_ctx) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
int padding_mode;
|
||||
if (padding == RSASignaturePadding::PKCS1_v1_5) {
|
||||
padding_mode = RSA_PKCS1_PADDING;
|
||||
} else {
|
||||
padding_mode = RSA_PKCS1_PSS_PADDING;
|
||||
}
|
||||
|
||||
// 先设置填充模式(关键)
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_mode) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
// 如果是 PSS,再设置盐长度
|
||||
if (padding == RSASignaturePadding::PSS) {
|
||||
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
size_t siglen = 0;
|
||||
if (EVP_DigestSign(ctx.get(), nullptr, &siglen,
|
||||
message.data(), message.size()) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<unsigned char> signature(siglen);
|
||||
if (EVP_DigestSign(ctx.get(), signature.data(), &siglen,
|
||||
message.data(), message.size()) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
signature.resize(siglen);
|
||||
return signature;
|
||||
}
|
||||
};
|
||||
|
||||
// 公钥类
|
||||
class Public_Key : public Crypto_Basic {
|
||||
public:
|
||||
Public_Key(const std::string& filename, bool from_file = true) {
|
||||
if (from_file) {
|
||||
if (!(pub_key = load_public_key_from_file(filename)))
|
||||
throw Crypto_Basic::CryptoExp("读取公钥失败");
|
||||
} else {
|
||||
if (!(pub_key = load_public_key_from_string(filename)))
|
||||
throw Crypto_Basic::CryptoExp("从字符串加载公钥失败");
|
||||
}
|
||||
}
|
||||
|
||||
static Public_Key from_pem(const std::string& pem_string) {
|
||||
return Public_Key(pem_string, false);
|
||||
}
|
||||
|
||||
// 加密(OAEP)
|
||||
std::string Encrypt(const std::string& original_text) {
|
||||
std::vector<unsigned char> plaintext(original_text.begin(), original_text.end());
|
||||
std::vector<unsigned char> ciphertext = rsa_encrypt(pub_key.get(), plaintext);
|
||||
if (ciphertext.empty()) throw Crypto_Basic::CryptoExp("加密失败");
|
||||
return bytes_to_hex(ciphertext);
|
||||
}
|
||||
|
||||
// 验证签名(支持 PSS 和 PKCS#1 v1.5)
|
||||
bool Verify(const std::string& message, const std::string& signature_hex,
|
||||
RSASignaturePadding padding = RSASignaturePadding::PSS) {
|
||||
std::vector<unsigned char> msg(message.begin(), message.end());
|
||||
std::vector<unsigned char> signature = hex_to_bytes(signature_hex);
|
||||
return rsa_verify(pub_key.get(), msg, signature, padding);
|
||||
}
|
||||
|
||||
bool Verify(const std::string& message, const std::vector<unsigned char>& signature,
|
||||
RSASignaturePadding padding = RSASignaturePadding::PSS) {
|
||||
std::vector<unsigned char> msg(message.begin(), message.end());
|
||||
return rsa_verify(pub_key.get(), msg, signature, padding);
|
||||
}
|
||||
|
||||
bool Verify(const std::vector<unsigned char>& message, const std::string& signature_hex,
|
||||
RSASignaturePadding padding = RSASignaturePadding::PSS) {
|
||||
std::vector<unsigned char> signature = hex_to_bytes(signature_hex);
|
||||
return rsa_verify(pub_key.get(), message, signature, padding);
|
||||
}
|
||||
|
||||
bool Verify(const std::vector<unsigned char>& message,
|
||||
const std::vector<unsigned char>& signature,
|
||||
RSASignaturePadding padding = RSASignaturePadding::PSS) {
|
||||
return rsa_verify(pub_key.get(), message, signature, padding);
|
||||
}
|
||||
|
||||
EVP_PKEY* get() const { return pub_key.get(); }
|
||||
|
||||
private:
|
||||
EVP_PKEY_ptr pub_key;
|
||||
|
||||
static EVP_PKEY_ptr load_public_key_from_file(const std::string& filename) {
|
||||
BIO_ptr bio(BIO_new_file(filename.c_str(), "rb"));
|
||||
if (!bio) {
|
||||
std::cerr << "Failed to open file: " << filename << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EVP_PKEY* pkey = PEM_read_bio_PUBKEY(bio.get(), nullptr, nullptr, nullptr);
|
||||
if (!pkey) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return nullptr;
|
||||
}
|
||||
return EVP_PKEY_ptr(pkey);
|
||||
}
|
||||
|
||||
static EVP_PKEY_ptr load_public_key_from_string(const std::string& pem_string) {
|
||||
BIO_ptr bio(BIO_new_mem_buf(pem_string.c_str(), -1));
|
||||
if (!bio) {
|
||||
std::cerr << "Failed to create BIO from string" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EVP_PKEY* pkey = PEM_read_bio_PUBKEY(bio.get(), nullptr, nullptr, nullptr);
|
||||
if (!pkey) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return nullptr;
|
||||
}
|
||||
return EVP_PKEY_ptr(pkey);
|
||||
}
|
||||
|
||||
static std::vector<unsigned char> rsa_encrypt(EVP_PKEY* public_key,
|
||||
const std::vector<unsigned char>& plaintext) {
|
||||
EVP_PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new(public_key, nullptr));
|
||||
if (!ctx) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
if (EVP_PKEY_encrypt_init(ctx.get()) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t outlen = 0;
|
||||
if (EVP_PKEY_encrypt(ctx.get(), nullptr, &outlen,
|
||||
plaintext.data(), plaintext.size()) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<unsigned char> ciphertext(outlen);
|
||||
if (EVP_PKEY_encrypt(ctx.get(), ciphertext.data(), &outlen,
|
||||
plaintext.data(), plaintext.size()) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return {};
|
||||
}
|
||||
|
||||
ciphertext.resize(outlen);
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
// RSA 验证(修正了 PSS 参数顺序)
|
||||
static bool rsa_verify(EVP_PKEY* public_key,
|
||||
const std::vector<unsigned char>& message,
|
||||
const std::vector<unsigned char>& signature,
|
||||
RSASignaturePadding padding) {
|
||||
EVP_MD_CTX_ptr ctx(EVP_MD_CTX_new());
|
||||
if (!ctx) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return false;
|
||||
}
|
||||
|
||||
const EVP_MD* md = EVP_sha256();
|
||||
|
||||
if (EVP_DigestVerifyInit(ctx.get(), nullptr, md, nullptr, public_key) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return false;
|
||||
}
|
||||
|
||||
EVP_PKEY_CTX* pkey_ctx = EVP_MD_CTX_get_pkey_ctx(ctx.get());
|
||||
if (!pkey_ctx) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return false;
|
||||
}
|
||||
|
||||
int padding_mode;
|
||||
if (padding == RSASignaturePadding::PKCS1_v1_5) {
|
||||
padding_mode = RSA_PKCS1_PADDING;
|
||||
} else {
|
||||
padding_mode = RSA_PKCS1_PSS_PADDING;
|
||||
}
|
||||
|
||||
// 先设置填充模式(关键)
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_mode) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果是 PSS,再设置盐长度
|
||||
if (padding == RSASignaturePadding::PSS) {
|
||||
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, -1) <= 0) {
|
||||
HANDLE_SSL_ERROR();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int result = EVP_DigestVerify(ctx.get(), signature.data(), signature.size(),
|
||||
message.data(), message.size());
|
||||
|
||||
if (result == 1) {
|
||||
return true;
|
||||
} else if (result == 0) {
|
||||
return false;
|
||||
} else {
|
||||
HANDLE_SSL_ERROR();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
} // namespace qing
|
||||
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include "us/Crypto_Basic.hpp"
|
||||
|
||||
namespace qing {
|
||||
|
||||
class SHA256: public qing::Crypto_Basic {
|
||||
|
||||
public:
|
||||
SHA256() = default;
|
||||
|
||||
/* 计算字符串的SHA-256哈希值,返回十六进制字符串 */
|
||||
std::string hash(const std::string& input_text) {
|
||||
std::vector<unsigned char> input(input_text.begin(), input_text.end());
|
||||
std::vector<unsigned char> digest = sha256_hash(input);
|
||||
return bytes_to_hex(digest);
|
||||
}
|
||||
|
||||
/* 计算字节向量的SHA-256哈希值,返回十六进制字符串 */
|
||||
std::string hash(const std::vector<unsigned char>& input_bytes) {
|
||||
std::vector<unsigned char> digest = sha256_hash(input_bytes);
|
||||
return bytes_to_hex(digest);
|
||||
}
|
||||
|
||||
/* 计算字符串的SHA-256哈希值,返回字节向量 */
|
||||
std::vector<unsigned char> hash_bytes(const std::string& input_text) {
|
||||
std::vector<unsigned char> input(input_text.begin(), input_text.end());
|
||||
return sha256_hash(input);
|
||||
}
|
||||
|
||||
/* 计算字节向量的SHA-256哈希值,返回字节向量 */
|
||||
std::vector<unsigned char> hash_bytes(const std::vector<unsigned char>& input_bytes) {
|
||||
return sha256_hash(input_bytes);
|
||||
}
|
||||
|
||||
/* 验证数据是否与给定的哈希值匹配 */
|
||||
bool verify(const std::string& input_text, const std::string& expected_hash_hex) {
|
||||
std::string computed_hash = hash(input_text);
|
||||
return computed_hash == expected_hash_hex;
|
||||
}
|
||||
|
||||
/* 验证数据是否与给定的哈希值匹配(字节向量版本) */
|
||||
bool verify(const std::vector<unsigned char>& input_bytes, const std::string& expected_hash_hex) {
|
||||
std::string computed_hash = hash(input_bytes);
|
||||
return computed_hash == expected_hash_hex;
|
||||
}
|
||||
|
||||
/* 静态方法:直接计算SHA-256哈希(工具函数) */
|
||||
static std::string sha256(const std::string& input_text) {
|
||||
SHA256 hasher;
|
||||
return hasher.hash(input_text);
|
||||
}
|
||||
|
||||
/* 静态方法:直接计算SHA-256哈希,返回字节向量 */
|
||||
static std::vector<unsigned char> sha256_bytes(const std::string& input_text) {
|
||||
SHA256 hasher;
|
||||
return hasher.hash_bytes(input_text);
|
||||
}
|
||||
|
||||
/* 打印哈希值(调试用) */
|
||||
static void print_hash(const std::vector<unsigned char>& hash_bytes) {
|
||||
std::string hex = bytes_to_hex(hash_bytes);
|
||||
std::cerr << hex << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
/* SHA-256哈希核心实现 */
|
||||
static std::vector<unsigned char> sha256_hash(const std::vector<unsigned char>& input) {
|
||||
// 创建EVP上下文
|
||||
EVP_MD_CTX* ctx = EVP_MD_CTX_new();
|
||||
CRYPTO_CHECK(ctx != nullptr, "无法创建哈希上下文");
|
||||
|
||||
// 初始化SHA-256操作
|
||||
CRYPTO_CHECK(EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr) == 1,
|
||||
"SHA-256初始化失败");
|
||||
|
||||
// 提供输入数据
|
||||
CRYPTO_CHECK(EVP_DigestUpdate(ctx, input.data(), input.size()) == 1,
|
||||
"SHA-256更新失败");
|
||||
|
||||
// 获取哈希结果
|
||||
std::vector<unsigned char> digest(EVP_MD_CTX_size(ctx)); // SHA-256输出32字节
|
||||
unsigned int digest_len = 0;
|
||||
CRYPTO_CHECK(EVP_DigestFinal_ex(ctx, digest.data(), &digest_len) == 1,
|
||||
"SHA-256完成失败");
|
||||
|
||||
// 调整到实际长度(应该是32字节)
|
||||
digest.resize(digest_len);
|
||||
|
||||
// 清理上下文
|
||||
EVP_MD_CTX_free(ctx);
|
||||
|
||||
return digest;
|
||||
}
|
||||
|
||||
/* 辅助函数:字节向量转十六进制字符串 */
|
||||
static std::string bytes_to_hex(const std::vector<unsigned char>& bytes) {
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::setfill('0');
|
||||
for (unsigned char byte : bytes) {
|
||||
ss << std::setw(2) << static_cast<int>(byte);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "us/Crypto_Basic.hpp"
|
||||
|
||||
namespace qing {
|
||||
std::string Crypto_Basic::bytes_to_hex(const std::vector<unsigned char>& data) {
|
||||
static const char hex_chars[] = "0123456789abcdef";
|
||||
std::string hex_string;
|
||||
hex_string.reserve(data.size() * 2);
|
||||
|
||||
for (unsigned char byte: data) {
|
||||
hex_string.push_back(hex_chars[byte >> 4]); // 高4位
|
||||
hex_string.push_back(hex_chars[byte & 0x0F]); // 低4位
|
||||
}
|
||||
|
||||
return hex_string;
|
||||
|
||||
}
|
||||
|
||||
std::vector<unsigned char> Crypto_Basic::hex_to_bytes(const std::string &hex) {
|
||||
// 检查长度是否为偶数
|
||||
if (hex.size() % 2 != 0) {
|
||||
throw std::invalid_argument("十六进制字符串长度必须为偶数");
|
||||
}
|
||||
|
||||
std::vector<unsigned char> bytes;
|
||||
bytes.reserve(hex.size() / 2);
|
||||
|
||||
auto char_to_nibble = [](char c) -> unsigned char {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'a' && c <= 'f') return 10 + (c - 'a');
|
||||
if (c >= 'A' && c <= 'F') return 10 + (c - 'A');
|
||||
throw std::invalid_argument("无效的十六进制字符:" + std::string(1, c));
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < hex.size(); i += 2) {
|
||||
unsigned char high = char_to_nibble(hex[i]);
|
||||
unsigned char low = char_to_nibble(hex[i + 1]);
|
||||
bytes.push_back((high << 4) | low);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user