This commit is contained in:
qing committed 2026-07-20 11:12:29 +08:00
commit 70d467d052
97 files changed
+10386

No files matched your search

+69
View File
@@ -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/
+21
View File
@@ -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.
+45
View File
@@ -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."
+2
View File
@@ -0,0 +1,2 @@
# UniServe_libcrypt
UniServe Framework Cryption Library
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
cd "$(dirname "$0")" || exit
make clear
make
make install
+140
View File
@@ -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;
}
};
}
+150
View File
@@ -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;
}
};
}
+24
View File
@@ -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);
};
}
+578
View File
@@ -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
+113
View File
@@ -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();
}
};
}
+42
View File
@@ -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;
}
}