Files
dps_lib/include/SqrReg_RSA.hpp
2026-04-22 19:36:06 +08:00

247 lines
7.6 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.
#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include <iostream>
#include <fstream>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
// 错误信息打印函数
void print_openssl_error() {
char err_buf[256];
ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf));
std::cerr << "OpenSSL 错误: " << err_buf << std::endl;
}
// 生成 RSA 密钥对并保存到文件
// 生成 RSA 密钥对公钥X.509/PKCS#8 格式私钥PKCS#1 格式)
bool generate_rsa_key(const std::string& pub_key_path,
const std::string& pri_key_path,
int key_bits = 2048) {
// 1. 创建 RSA 对象并生成密钥对
RSA* rsa = RSA_new();
BIGNUM* bn = BN_new();
if (!rsa || !bn) {
std::cerr << "创建 RSA/BIGNUM 失败" << std::endl;
RSA_free(rsa);
BN_free(bn);
return false;
}
// 设置公钥指数65537
if (BN_set_word(bn, RSA_F4) != 1) {
std::cerr << "设置 BIGNUM 失败" << std::endl;
print_openssl_error();
RSA_free(rsa);
BN_free(bn);
return false;
}
// 生成 RSA 密钥对
if (RSA_generate_key_ex(rsa, key_bits, bn, nullptr) != 1) {
std::cerr << "生成 RSA 密钥对失败" << std::endl;
print_openssl_error();
RSA_free(rsa);
BN_free(bn);
return false;
}
// 2. 封装 RSA 到 EVP_PKEY用于生成 X.509/PKCS#8 公钥)
EVP_PKEY* evp_key = EVP_PKEY_new();
if (!evp_key || EVP_PKEY_assign_RSA(evp_key, rsa) != 1) {
std::cerr << "封装 EVP_PKEY 失败" << std::endl;
print_openssl_error();
EVP_PKEY_free(evp_key);
RSA_free(rsa);
BN_free(bn);
return false;
}
// 3. 保存 X.509/PKCS#8 格式公钥(-----BEGIN PUBLIC KEY-----
FILE* pub_file = fopen(pub_key_path.c_str(), "w");
if (!pub_file) {
std::cerr << "打开公钥文件失败: " << pub_key_path << std::endl;
EVP_PKEY_free(evp_key);
BN_free(bn);
return false;
}
if (PEM_write_PUBKEY(pub_file, evp_key) != 1) {
std::cerr << "写入 X.509 公钥失败" << std::endl;
print_openssl_error();
fclose(pub_file);
EVP_PKEY_free(evp_key);
BN_free(bn);
return false;
}
fclose(pub_file);
// 4. 保存 PKCS#1 格式私钥(-----BEGIN RSA PRIVATE KEY-----
FILE* pri_file = fopen(pri_key_path.c_str(), "w");
if (!pri_file) {
std::cerr << "打开私钥文件失败: " << pri_key_path << std::endl;
EVP_PKEY_free(evp_key);
BN_free(bn);
return false;
}
if (PEM_write_RSAPrivateKey(pri_file, rsa, nullptr, nullptr, 0, nullptr, nullptr) != 1) {
std::cerr << "写入私钥失败" << std::endl;
print_openssl_error();
fclose(pri_file);
EVP_PKEY_free(evp_key);
BN_free(bn);
return false;
}
fclose(pri_file);
// 5. 释放资源EVP_PKEY_free 会自动释放内部的 RSA 对象)
EVP_PKEY_free(evp_key);
BN_free(bn);
std::cout << "RSA 密钥生成成功!" << std::endl;
std::cout << "公钥X.509/PKCS#8 格式): " << pub_key_path << std::endl;
std::cout << "私钥PKCS#1 格式): " << pri_key_path << std::endl;
return true;
}
static SQInteger Rsa_GenerateKey(HSQUIRRELVM v)
{
// 初始化 OpenSSL 错误处理
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
// 生成 2048 位 RSA 密钥对(推荐使用 2048/4096 位)
bool ret = generate_rsa_key("public.pem", "private.pem", 2048);
// 清理 OpenSSL 资源
EVP_cleanup();
ERR_free_strings();
return 0;
}
// 从文件加载私钥PKCS#1 格式)
RSA* load_rsa_private_key(const std::string& pri_key_path) {
FILE* pri_file = fopen(pri_key_path.c_str(), "r");
if (!pri_file) {
std::cerr << "打开私钥文件失败: " << pri_key_path << std::endl;
return nullptr;
}
// 加载 PKCS#1 格式私钥
RSA* rsa = PEM_read_RSAPrivateKey(pri_file, nullptr, nullptr, nullptr);
fclose(pri_file);
if (!rsa) {
std::cerr << "加载私钥失败" << std::endl;
print_openssl_error();
}
return rsa;
}
// 新增:十六进制字符串转字节数组(核心补全)
bool hex_string_to_bytes(const std::string& hex_str, std::vector<unsigned char>& bytes) {
bytes.clear();
// 检查长度是否为偶数十六进制字符串必须2字符=1字节
if (hex_str.length() % 2 != 0) {
std::cerr << "十六进制字符串长度为奇数,无效" << std::endl;
return false;
}
for (size_t i = 0; i < hex_str.length(); i += 2) {
std::string byte_str = hex_str.substr(i, 2);
// 十六进制转字节处理0-9/a-f/A-F
unsigned char byte = static_cast<unsigned char>(strtol(byte_str.c_str(), nullptr, 16));
bytes.push_back(byte);
}
return true;
}
bool rsa_private_encrypt(const std::vector<unsigned char>& plaintext_bytes, RSA* rsa_pri, std::string& ciphertext) {
if (!rsa_pri || plaintext_bytes.empty()) return false;
int rsa_len = RSA_size(rsa_pri);
unsigned char* enc_buf = new unsigned char[rsa_len];
// 加密字节数组而非字符串的ASCII
int enc_len = RSA_private_encrypt(
plaintext_bytes.size(), // 明文长度(字节数)
plaintext_bytes.data(), // 明文字节数组
enc_buf, // 加密结果缓冲区
rsa_pri, // RSA私钥
RSA_PKCS1_PADDING // 填充方式和Java一致
);
if (enc_len > 0) {
ciphertext = std::string((char*)enc_buf, enc_len);
} else {
std::cerr << "私钥加密失败2048位RSA最多加密245字节" << std::endl;
print_openssl_error();
}
delete[] enc_buf;
return enc_len > 0;
}
static SQInteger Rsa_Private_Encrypt(HSQUIRRELVM v)
{
const SQChar* hex_str;
sq_getstring(v, 2, &hex_str); // 获取Squirrel传入的十六进制字符串
// 1. 加载RSA私钥
RSA* rsa_pri = load_rsa_private_key("privatekey.pem");
if (!rsa_pri) {
sq_pushnull(v);
return 1;
}
// 2. 核心十六进制字符串转字节数组对齐Java的toByteArray
std::vector<unsigned char> plaintext_bytes;
if (!hex_string_to_bytes(std::string(hex_str), plaintext_bytes)) {
RSA_free(rsa_pri);
sq_pushnull(v);
return 1;
}
// 3. 加密字节数组
std::string ciphertext;
bool success = rsa_private_encrypt(plaintext_bytes, rsa_pri, ciphertext);
// 4. 返回加密后的字节串Squirrel中以字符串形式承载二进制数据
if (success) {
sq_pushstring(v, ciphertext.c_str(), ciphertext.length());
} else {
sq_pushnull(v);
}
// 释放资源
RSA_free(rsa_pri);
return 1;
}
// ====================== 辅助函数 - 注册Squirrel函数 ======================
static SQInteger register_Rsa_func(HSQUIRRELVM v, SQFUNCTION f, const char* fname) {
sq_pushroottable(v);
sq_pushstring(v, fname, -1);
sq_newclosure(v, f, 0);
sq_newslot(v, -3, SQFalse);
sq_pop(v, 1); // 弹出根表
return 0;
}
// ====================== 注册所有Dio函数 ======================
static void RegisterRsa(HSQUIRRELVM v) {
register_Rsa_func(v, Rsa_GenerateKey, _SC("Sq_Rsa_GenerateKey"));
//使用私钥签名
register_Rsa_func(v, Rsa_Private_Encrypt, _SC("Sq_Rsa_Private_Encrypt"));
}