215 lines
6.5 KiB
C++
215 lines
6.5 KiB
C++
#include "registration_api.h"
|
|
#include "machine_code.h"
|
|
#include "sha256.h"
|
|
#include <string>
|
|
#include <chrono>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <fstream>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
|
|
// 全局变量来存储机器码和密钥,避免重复计算
|
|
static std::string machineCode_cache;
|
|
static std::string licenseKey_cache;
|
|
static std::string expiration_date_str = "2099-12-31"; // 默认永久
|
|
|
|
// 内部函数,用于初始化缓存
|
|
void InitializeCache() {
|
|
if (machineCode_cache.empty()) {
|
|
machineCode_cache = getMachineCode();
|
|
}
|
|
if (licenseKey_cache.empty()) {
|
|
licenseKey_cache = picosha2::hash256_hex_string(machineCode_cache).substr(0, 32); // Truncate to 32 chars
|
|
}
|
|
}
|
|
|
|
// --- Encryption/Decryption Helpers ---
|
|
|
|
// Generates a key from the machine code for XOR operations
|
|
std::string generate_xor_key(const std::string& machine_code) {
|
|
return picosha2::hash256_hex_string(machine_code).substr(0, 32);
|
|
}
|
|
|
|
// XORs data with a key. Handles key repeating.
|
|
std::string xor_string(const std::string& data, const std::string& key) {
|
|
std::string output = data;
|
|
for (size_t i = 0; i < data.size(); ++i) {
|
|
output[i] = data[i] ^ key[i % key.length()];
|
|
}
|
|
return output;
|
|
}
|
|
|
|
// Converts a string to its hex representation
|
|
std::string string_to_hex(const std::string& in) {
|
|
std::stringstream ss;
|
|
ss << std::hex << std::setfill('0');
|
|
for (unsigned char c : in) {
|
|
ss << std::setw(2) << static_cast<int>(c);
|
|
}
|
|
return ss.str();
|
|
}
|
|
|
|
// Converts a hex string back to a normal string
|
|
std::string hex_to_string(const std::string& in) {
|
|
std::string output;
|
|
if (in.length() % 2 != 0) {
|
|
return ""; // Invalid hex
|
|
}
|
|
for (size_t i = 0; i < in.length(); i += 2) {
|
|
std::string byteString = in.substr(i, 2);
|
|
char byte = (char)strtol(byteString.c_str(), NULL, 16);
|
|
output.push_back(byte);
|
|
}
|
|
return output;
|
|
}
|
|
|
|
|
|
// C-style string return needs to be managed carefully.
|
|
// We use static buffers here, which is not thread-safe but simple.
|
|
// For a real-world app, consider returning std::string or managing memory better.
|
|
static char machineCode_cstr[256];
|
|
static char licenseKey_cstr[256];
|
|
|
|
const char* GetMachineCode() {
|
|
InitializeCache();
|
|
strncpy_s(machineCode_cstr, machineCode_cache.c_str(), sizeof(machineCode_cstr) - 1);
|
|
machineCode_cstr[sizeof(machineCode_cstr) - 1] = '\0';
|
|
return machineCode_cstr;
|
|
}
|
|
|
|
const char* GetLicenseKey() {
|
|
InitializeCache();
|
|
strncpy_s(licenseKey_cstr, licenseKey_cache.c_str(), sizeof(licenseKey_cstr) - 1);
|
|
licenseKey_cstr[sizeof(licenseKey_cstr) - 1] = '\0';
|
|
return licenseKey_cstr;
|
|
}
|
|
|
|
int ValidateLicenseOffline(const char* key) {
|
|
if (!key) {
|
|
return 1; // 失败
|
|
}
|
|
InitializeCache();
|
|
if (licenseKey_cache != key) {
|
|
return 1; // 失败
|
|
}
|
|
|
|
// 检查有效期
|
|
if (expiration_date_str != "2099-12-31") {
|
|
std::tm tm = {};
|
|
std::stringstream ss(expiration_date_str);
|
|
ss >> std::get_time(&tm, "%Y-%m-%d");
|
|
auto expiration_time = std::chrono::system_clock::from_time_t(std::mktime(&tm));
|
|
|
|
if (std::chrono::system_clock::now() > expiration_time) {
|
|
return 2; // 过期
|
|
}
|
|
}
|
|
|
|
return 0; // 成功
|
|
}
|
|
|
|
void SetOfflineExpiration(const char* expiration_date) {
|
|
if (expiration_date) {
|
|
expiration_date_str = expiration_date;
|
|
}
|
|
}
|
|
|
|
int GenerateLicenseFile(const char* expiration_date) {
|
|
if (!expiration_date) {
|
|
return 1; // 失败
|
|
}
|
|
|
|
InitializeCache();
|
|
std::string data_to_sign = machineCode_cache + expiration_date;
|
|
std::string signature = picosha2::hash256_hex_string(data_to_sign);
|
|
|
|
std::ofstream license_file("License.data");
|
|
if (!license_file.is_open()) {
|
|
return 1; // 失败
|
|
}
|
|
|
|
license_file << expiration_date << std::endl;
|
|
license_file << signature << std::endl;
|
|
license_file.close();
|
|
|
|
return 0; // 成功
|
|
}
|
|
|
|
int GenerateLicenseFileFromCode(const char* machine_code, const char* expiration_date) {
|
|
if (!machine_code || !expiration_date) {
|
|
return 1; // 失败
|
|
}
|
|
std::string mc_str(machine_code);
|
|
std::string exp_str(expiration_date);
|
|
|
|
// 1. Encrypt the expiration date
|
|
std::string xor_key = generate_xor_key(mc_str);
|
|
std::string encrypted_date = xor_string(exp_str, xor_key);
|
|
std::string encrypted_date_hex = string_to_hex(encrypted_date);
|
|
|
|
// 2. Create a signature of the machine code and the *encrypted* date
|
|
std::string data_to_sign = mc_str + encrypted_date_hex;
|
|
std::string signature = picosha2::hash256_hex_string(data_to_sign);
|
|
|
|
// 3. Write the encrypted date and signature to the file
|
|
std::ofstream license_file("License.data");
|
|
if (!license_file.is_open()) {
|
|
return 1; // 失败
|
|
}
|
|
|
|
license_file << encrypted_date_hex << std::endl;
|
|
license_file << signature << std::endl;
|
|
license_file.close();
|
|
|
|
return 0; // 成功
|
|
}
|
|
|
|
int ValidateLicenseFile() {
|
|
std::ifstream license_file("License.data");
|
|
if (!license_file.is_open()) {
|
|
return 1; // 失败 - 文件不存在
|
|
}
|
|
|
|
std::string file_encrypted_date_hex;
|
|
std::string file_signature;
|
|
std::getline(license_file, file_encrypted_date_hex);
|
|
std::getline(license_file, file_signature);
|
|
license_file.close();
|
|
|
|
if (file_encrypted_date_hex.empty() || file_signature.empty()) {
|
|
return 1; // 失败 - 文件格式错误
|
|
}
|
|
|
|
// 1. Verify the signature first to ensure integrity
|
|
InitializeCache(); // Loads local machine code into machineCode_cache
|
|
std::string data_to_verify = machineCode_cache + file_encrypted_date_hex;
|
|
std::string expected_signature = picosha2::hash256_hex_string(data_to_verify);
|
|
|
|
if (file_signature != expected_signature) {
|
|
return 1; // 失败 - 签名不匹配, 文件被篡改或不属于此机器
|
|
}
|
|
|
|
// 2. Decrypt the date
|
|
std::string xor_key = generate_xor_key(machineCode_cache);
|
|
std::string encrypted_date = hex_to_string(file_encrypted_date_hex);
|
|
std::string decrypted_date = xor_string(encrypted_date, xor_key);
|
|
|
|
// 3. Check the expiration date
|
|
std::tm tm = {};
|
|
std::stringstream ss(decrypted_date);
|
|
ss >> std::get_time(&tm, "%Y-%m-%d");
|
|
if (ss.fail()) {
|
|
return 1; // 失败 - 日期格式损坏
|
|
}
|
|
|
|
auto expiration_time = std::chrono::system_clock::from_time_t(std::mktime(&tm));
|
|
expiration_time += std::chrono::hours(23) + std::chrono::minutes(59) + std::chrono::seconds(59);
|
|
|
|
if (std::chrono::system_clock::now() > expiration_time) {
|
|
return 2; // 过期
|
|
}
|
|
|
|
return 0; // 成功
|
|
}
|