modify machine code get and enntry

This commit is contained in:
brige.long 2025-08-05 23:32:23 +08:00
parent cc9a5747f1
commit 0e7f56cf7c
7 changed files with 306 additions and 234 deletions

View File

@ -43,6 +43,10 @@ target_link_libraries(validate_only PRIVATE RegistrationDLL)
add_executable(generate_valid src/generate_valid.cpp)
target_link_libraries(generate_valid PRIVATE RegistrationDLL)
# --- ---
add_executable(generate_valid src/generate_valid.cpp)
target_link_libraries(generate_valid PRIVATE RegistrationDLL)
# build/bin
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

View File

@ -12,35 +12,34 @@
#ifdef __cplusplus
extern "C" {
#endif
// 获取原始机器码
// --- Core Functions ---
// Gets the raw machine code.
REGISTRATION_API const char* GetMachineCode();
// 获取加密后的许可证密钥
REGISTRATION_API const char* GetLicenseKey();
// Validates the license file.
// @return: 0=success, 1=failure, 2=expired.
REGISTRATION_API int ValidateLicenseFile();
// 验证许可证密钥 (离线)
// @param key: 要验证的密钥
// @return: 0=成功, 1=失败, 2=过期
REGISTRATION_API int ValidateLicenseOffline(const char* key);
// 设置离线许可证的有效期
// @param expiration_date: "YYYY-MM-DD" 格式的日期字符串
REGISTRATION_API void SetOfflineExpiration(const char* expiration_date);
// 生成许可证文件
// @param expiration_date: "YYYY-MM-DD" 格式的日期字符串
// @return: 0=成功, 1=失败
REGISTRATION_API int GenerateLicenseFile(const char* expiration_date);
// 从提供的机器码生成许可证文件
// @param machine_code: 要使用的机器码
// @param expiration_date: "YYYY-MM-DD" 格式的日期字符串
// @return: 0=成功, 1=失败
// Generates a license file from a provided machine code.
// @param machine_code: The machine code to use.
// @param expiration_date: A date string in "YYYY-MM-DD" format.
// @return: 0=success, 1=failure.
REGISTRATION_API int GenerateLicenseFileFromCode(const char* machine_code, const char* expiration_date);
// 验证许可证文件
// @return: 0=成功, 1=失败, 2=过期
REGISTRATION_API int ValidateLicenseFile();
// --- New Encryption/Decryption API ---
// Generates a dynamic, 32-character encrypted code from the machine code.
// The returned string is managed by the DLL and should not be freed by the caller.
REGISTRATION_API const char* GenerateEncryptedCode();
// Decrypts a 32-character code to get the original machine code.
// @param encrypted_code: The 32-character hex string to decrypt.
// @param decrypted_machine_code: A buffer to store the null-terminated result.
// @param buffer_size: The size of the provided buffer.
// @return: 0 on success, 1 on failure (e.g., invalid format, bad length).
REGISTRATION_API int DecryptCodeAndGetMachineCode(const char* encrypted_code, char* decrypted_machine_code, int buffer_size);
#ifdef __cplusplus
}

View File

@ -1,19 +1,7 @@
#define NOMINMAX
#include <windows.h>
#include "registration_api.h"
#include <string>
#include <algorithm>
#include <cctype>
#include <random>
#include <sstream>
#include <iomanip>
#include "sha256.h"
// 简单的MD5实现只返回32位
std::string simple_md5_32(const std::string& input) {
// 使用SHA256但只取前32位模拟MD5的32位输出
std::string full_hash = picosha2::hash256_hex_string(input);
return full_hash.substr(0, 32);
}
#define IDC_MACHINE_CODE_LABEL 201
#define IDC_MACHINE_CODE_EDIT 202
@ -22,9 +10,7 @@ std::string simple_md5_32(const std::string& input) {
LRESULT CALLBACK GenWndProc(HWND, UINT, WPARAM, LPARAM);
void CopyToClipboard(HWND hwnd, const std::string& text) {
if (!OpenClipboard(hwnd)) {
return;
}
if (!OpenClipboard(hwnd)) return;
EmptyClipboard();
HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, text.size() + 1);
if (!hg) {
@ -79,55 +65,31 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
return (int)Msg.wParam;
}
LRESULT CALLBACK GenWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
static HWND hMachineCodeEdit;
switch (msg) {
case WM_CREATE: {
// Labels
CreateWindow("STATIC", "Your Machine Code:", WS_VISIBLE | WS_CHILD, 20, 20, 150, 20, hwnd, (HMENU)IDC_MACHINE_CODE_LABEL, NULL, NULL);
CreateWindow("STATIC", "Your Encrypted Code:", WS_VISIBLE | WS_CHILD, 20, 20, 150, 20, hwnd, (HMENU)IDC_MACHINE_CODE_LABEL, NULL, NULL);
hMachineCodeEdit = CreateWindow("EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_READONLY | ES_CENTER, 180, 20, 280, 20, hwnd, (HMENU)IDC_MACHINE_CODE_EDIT, NULL, NULL);
CreateWindow("BUTTON", "Copy", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 470, 20, 50, 22, hwnd, (HMENU)IDC_COPY_BUTTON, NULL, NULL);
// Edit Controls
hMachineCodeEdit = CreateWindow("EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_READONLY | ES_CENTER, 180, 20, 330, 20, hwnd, (HMENU)IDC_MACHINE_CODE_EDIT, NULL, NULL);
// Buttons
CreateWindow("BUTTON", "Copy to Clipboard", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 180, 60, 150, 30, hwnd, (HMENU)IDC_COPY_BUTTON, NULL, NULL);
// Set machine code with encryption
std::string machineCode = GetMachineCode();
// 1. 生成一个个位的随机数 (0-9)
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 9);
int randomNum = dis(gen);
// 2. 做一次 32位 MD5 加密 加密后是32位
std::string encryptedCode = simple_md5_32(machineCode);
// 3. 把 encryptedCode 字符串减掉这个数
std::string processedCode = encryptedCode;
for (char& c : processedCode) {
c = c - randomNum;
}
// 4. 把这个数变成一个字符插入到第三位的位置 加密后是33位
char randomChar = '0' + randomNum;
processedCode.insert(2, 1, randomChar);
SetWindowText(hMachineCodeEdit, processedCode.c_str());
// --- Refactored Logic ---
// Call the new API function to get the encrypted code
const char* final_code = GenerateEncryptedCode();
SetWindowText(hMachineCodeEdit, final_code);
break;
}
case WM_COMMAND: {
switch (LOWORD(wParam)) {
case IDC_COPY_BUTTON: {
char formattedMachineCode[256];
GetWindowText(hMachineCodeEdit, formattedMachineCode, 256);
CopyToClipboard(hwnd, formattedMachineCode);
MessageBox(hwnd, "Machine code copied to clipboard!", "Success", MB_OK);
char codeToCopy[64];
GetWindowText(hMachineCodeEdit, codeToCopy, sizeof(codeToCopy));
CopyToClipboard(hwnd, codeToCopy);
MessageBox(hwnd, "Encrypted code copied to clipboard!", "Success", MB_OK);
break;
}
}
@ -143,4 +105,4 @@ LRESULT CALLBACK GenWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
}

View File

@ -1,20 +1,33 @@
#define NOMINMAX
#include <windows.h>
#include "registration_api.h"
#include <string>
#include <algorithm>
#include <cctype>
// --- Control IDs ---
#define IDC_STATUS_LABEL 101
#define IDC_MACHINE_CODE_LABEL 102
#define IDC_MACHINE_CODE_EDIT 103
#define IDC_EXPIRATION_LABEL 104
#define IDC_EXPIRATION_EDIT 105
#define IDC_GENERATE_BUTTON 106
#define IDC_GEN_GROUP 102
#define IDC_GEN_MC_LABEL 103
#define IDC_GEN_MC_EDIT 104
#define IDC_GEN_EXP_LABEL 105
#define IDC_GEN_EXP_EDIT 106
#define IDC_GEN_BUTTON 107
#define IDC_DEC_GROUP 201
#define IDC_DEC_INPUT_LABEL 202
#define IDC_DEC_INPUT_EDIT 203
#define IDC_DEC_BUTTON 204
#define IDC_DEC_OUTPUT_LABEL 205
#define IDC_DEC_OUTPUT_EDIT 206
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static HWND hMachineCodeEdit, hExpirationEdit, hStatusLabel;
// --- Global Handles for UI Controls ---
static HWND hStatusLabel;
static HWND hGenMachineCodeEdit, hGenExpirationEdit;
static HWND hDecInputEdit, hDecOutputEdit;
// --- Function to update the license status label ---
void UpdateValidationStatus(HWND hwnd) {
int result = ValidateLicenseFile();
std::string statusText;
@ -32,6 +45,7 @@ void UpdateValidationStatus(HWND hwnd) {
SetWindowText(hStatusLabel, statusText.c_str());
}
// --- Main Entry Point ---
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
@ -55,9 +69,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
HWND hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
"RegistrationWindowClass",
"Software Registration",
"Software Registration Tool",
(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX),
CW_USEDEFAULT, CW_USEDEFAULT, 480, 250,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 400, // Increased window height
NULL, NULL, hInstance, NULL);
if (hwnd == NULL) {
@ -73,52 +87,79 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
return (int)Msg.wParam;
}
// --- Window Procedure to Handle Messages ---
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE: {
// --- Top Part: Validation Status ---
hStatusLabel = CreateWindow("STATIC", "Checking license...", WS_VISIBLE | WS_CHILD | SS_CENTER, 20, 20, 420, 20, hwnd, (HMENU)IDC_STATUS_LABEL, NULL, NULL);
hStatusLabel = CreateWindow("STATIC", "Checking license...", WS_VISIBLE | WS_CHILD | SS_CENTER, 20, 15, 440, 20, hwnd, (HMENU)IDC_STATUS_LABEL, NULL, NULL);
UpdateValidationStatus(hwnd);
// --- Middle Part: Decryption ---
CreateWindow("STATIC", "Decrypt Encrypted Code", WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 10, 50, 460, 120, hwnd, (HMENU)IDC_DEC_GROUP, NULL, NULL);
CreateWindow("STATIC", "Encrypted Code:", WS_VISIBLE | WS_CHILD, 30, 80, 150, 20, hwnd, (HMENU)IDC_DEC_INPUT_LABEL, NULL, NULL);
hDecInputEdit = CreateWindow("EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER, 190, 80, 260, 20, hwnd, (HMENU)IDC_DEC_INPUT_EDIT, NULL, NULL);
CreateWindow("BUTTON", "Decrypt", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 190, 110, 120, 30, hwnd, (HMENU)IDC_DEC_BUTTON, NULL, NULL);
CreateWindow("STATIC", "Original Machine Code:", WS_VISIBLE | WS_CHILD, 30, 145, 150, 20, hwnd, (HMENU)IDC_DEC_OUTPUT_LABEL, NULL, NULL);
hDecOutputEdit = CreateWindow("EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_READONLY, 190, 145, 260, 20, hwnd, (HMENU)IDC_DEC_OUTPUT_EDIT, NULL, NULL);
// --- Bottom Part: License Generation ---
CreateWindow("STATIC", "--- License Generation ---", WS_VISIBLE | WS_CHILD | SS_CENTER, 20, 60, 420, 20, hwnd, NULL, NULL, NULL);
CreateWindow("STATIC", "Machine Code:", WS_VISIBLE | WS_CHILD, 20, 90, 150, 20, hwnd, (HMENU)IDC_MACHINE_CODE_LABEL, NULL, NULL);
hMachineCodeEdit = CreateWindow("EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER, 180, 90, 260, 20, hwnd, (HMENU)IDC_MACHINE_CODE_EDIT, NULL, NULL);
CreateWindow("STATIC", "Expiration (YYYY-MM-DD):", WS_VISIBLE | WS_CHILD, 20, 120, 150, 20, hwnd, (HMENU)IDC_EXPIRATION_LABEL, NULL, NULL);
hExpirationEdit = CreateWindow("EDIT", "2099-12-31", WS_VISIBLE | WS_CHILD | WS_BORDER, 180, 120, 120, 20, hwnd, (HMENU)IDC_EXPIRATION_EDIT, NULL, NULL);
CreateWindow("BUTTON", "Generate License File", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 180, 160, 180, 30, hwnd, (HMENU)IDC_GENERATE_BUTTON, NULL, NULL);
CreateWindow("STATIC", "Generate License File", WS_VISIBLE | WS_CHILD | BS_GROUPBOX, 10, 180, 460, 160, hwnd, (HMENU)IDC_GEN_GROUP, NULL, NULL);
CreateWindow("STATIC", "Machine Code:", WS_VISIBLE | WS_CHILD, 30, 210, 150, 20, hwnd, (HMENU)IDC_GEN_MC_LABEL, NULL, NULL);
hGenMachineCodeEdit = CreateWindow("EDIT", "", WS_VISIBLE | WS_CHILD | WS_BORDER, 190, 210, 260, 20, hwnd, (HMENU)IDC_GEN_MC_EDIT, NULL, NULL);
CreateWindow("STATIC", "Expiration (YYYY-MM-DD):", WS_VISIBLE | WS_CHILD, 30, 240, 150, 20, hwnd, (HMENU)IDC_GEN_EXP_LABEL, NULL, NULL);
hGenExpirationEdit = CreateWindow("EDIT", "2099-12-31", WS_VISIBLE | WS_CHILD | WS_BORDER, 190, 240, 120, 20, hwnd, (HMENU)IDC_GEN_EXP_EDIT, NULL, NULL);
CreateWindow("BUTTON", "Generate License File", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 190, 280, 180, 30, hwnd, (HMENU)IDC_GEN_BUTTON, NULL, NULL);
break;
}
case WM_COMMAND: {
switch (LOWORD(wParam)) {
case IDC_GENERATE_BUTTON: {
case IDC_GEN_BUTTON: {
char machineCode[256];
char expirationDate[11];
GetWindowText(hMachineCodeEdit, machineCode, 256);
GetWindowText(hExpirationEdit, expirationDate, 11);
char expirationDate[12];
GetWindowText(hGenMachineCodeEdit, machineCode, sizeof(machineCode));
GetWindowText(hGenExpirationEdit, expirationDate, sizeof(expirationDate));
if (strlen(machineCode) == 0) {
MessageBox(hwnd, "Please enter a machine code.", "Error", MB_ICONERROR);
MessageBox(hwnd, "Please enter a machine code for generation.", "Error", MB_ICONERROR);
break;
}
// Note: We are now using the function that takes the machine code as an argument
int result = GenerateLicenseFileFromCode(machineCode, expirationDate);
if (result == 0) {
MessageBox(hwnd, "License.data generated successfully!", "Success", MB_OK);
// Re-validate and update the status label
UpdateValidationStatus(hwnd);
} else {
MessageBox(hwnd, "Failed to generate license file!", "Error", MB_ICONERROR);
}
break;
}
case IDC_DEC_BUTTON: {
char encryptedCode[64];
GetWindowText(hDecInputEdit, encryptedCode, sizeof(encryptedCode));
int len = strlen(encryptedCode);
if (strlen(encryptedCode) != 30) {
MessageBox(hwnd, "Please enter a valid 32-character encrypted code.", "Error", MB_ICONERROR);
break;
}
char decryptedResult[256];
int result = DecryptCodeAndGetMachineCode(encryptedCode, decryptedResult, sizeof(decryptedResult));
if (result == 0) {
SetWindowText(hDecOutputEdit, decryptedResult);
// Also copy the result to the generation input box for convenience
SetWindowText(hGenMachineCodeEdit, decryptedResult);
} else {
SetWindowText(hDecOutputEdit, ""); // Clear previous result
MessageBox(hwnd, "Decryption failed. The code is invalid or corrupted.", "Error", MB_ICONERROR);
}
break;
}
}
break;
}
@ -132,4 +173,4 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
}

View File

@ -8,68 +8,69 @@
#include <fstream>
#include <vector>
#include <algorithm>
#include <random>
#include <cstdint>
// 全局变量来存储机器码和密钥,避免重复计算
static std::string machineCode_cache;
static std::string licenseKey_cache;
static std::string expiration_date_str = "2099-12-31"; // 默认永久
// --- START: Internal Encryption Helpers ---
// 内部函数,用于初始化缓存
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
// Helper to convert a hex string to a vector of bytes
static std::vector<unsigned char> hex_string_to_bytes(const std::string& hex) {
std::vector<unsigned char> bytes;
if (hex.length() % 2 != 0) return bytes;
for (unsigned int i = 0; i < hex.length(); i += 2) {
std::string byteString = hex.substr(i, 2);
bytes.push_back((unsigned char)strtol(byteString.c_str(), NULL, 16));
}
return bytes;
}
// --- 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) {
// Helper to convert a vector of bytes to a hex string
static std::string bytes_to_hex_string(const std::vector<unsigned char>& bytes) {
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (unsigned char c : in) {
ss << std::setw(2) << static_cast<int>(c);
ss << std::hex << std::uppercase << std::setfill('0');
for (unsigned char byte : bytes) {
ss << std::setw(2) << static_cast<int>(byte);
}
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
// Generates a pseudo-random keystream from a 16-bit seed (Nonce)
static void generate_keystream(uint16_t seed, std::vector<unsigned char>& keystream, size_t len) {
std::mt19937 gen(seed);
std::uniform_int_distribution<> distrib(0, 255);
keystream.clear();
for (size_t i = 0; i < len; ++i) {
keystream.push_back(static_cast<unsigned char>(distrib(gen)));
}
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);
}
// XORs a vector of bytes with a keystream
static std::vector<unsigned char> xor_bytes(const std::vector<unsigned char>& data, const std::vector<unsigned char>& key) {
std::vector<unsigned char> output;
size_t len = std::min(data.size(), key.size());
for (size_t i = 0; i < len; ++i) {
output.push_back(data[i] ^ key[i]);
}
return output;
}
// --- END: Internal Encryption Helpers ---
// 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.
// --- Global Caches and Buffers ---
static std::string machineCode_cache;
static char machineCode_cstr[256];
static char licenseKey_cstr[256];
static char encryptedCode_cstr[33]; // 32 chars + null terminator
static char decryptedCode_cstr[256];
// Internal function to initialize the machine code cache
void InitializeCache() {
if (machineCode_cache.empty()) {
machineCode_cache = getMachineCode();
}
}
// --- Core API Implementations ---
const char* GetMachineCode() {
InitializeCache();
@ -78,97 +79,42 @@ const char* GetMachineCode() {
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; // 失败
return 1; // Failure
}
std::string mc_str(machine_code);
std::string mc_str(machine_code);
//std::transform(mc_str.begin(), mc_str.end(), std::toupper);
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);
std::string xor_key = picosha2::hash256_hex_string(mc_str).substr(0, 32);
std::string encrypted_date;
for (size_t i = 0; i < exp_str.size(); ++i) {
encrypted_date += exp_str[i] ^ xor_key[i % xor_key.length()];
}
std::string encrypted_date_hex = bytes_to_hex_string(std::vector<unsigned char>(encrypted_date.begin(), encrypted_date.end()));
// 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; // 失败
return 1; // Failure
}
license_file << encrypted_date_hex << std::endl;
license_file << signature << std::endl;
license_file.close();
return 0; // 成功
return 0; // Success
}
int ValidateLicenseFile() {
std::ifstream license_file("License.data");
if (!license_file.is_open()) {
return 1; // 失败 - 文件不存在
return 1; // Failure - file not found
}
std::string file_encrypted_date_hex;
@ -178,37 +124,98 @@ int ValidateLicenseFile() {
license_file.close();
if (file_encrypted_date_hex.empty() || file_signature.empty()) {
return 1; // 失败 - 文件格式错误
return 1; // Failure - format error
}
// 1. Verify the signature first to ensure integrity
InitializeCache(); // Loads local machine code into machineCode_cache
InitializeCache();
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; // 失败 - 签名不匹配, 文件被篡改或不属于此机器
return 1; // Failure - signature mismatch
}
// 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);
std::string xor_key = picosha2::hash256_hex_string(machineCode_cache).substr(0, 32);
std::vector<unsigned char> encrypted_date_bytes = hex_string_to_bytes(file_encrypted_date_hex);
std::string encrypted_date(encrypted_date_bytes.begin(), encrypted_date_bytes.end());
std::string decrypted_date;
for (size_t i = 0; i < encrypted_date.size(); ++i) {
decrypted_date += encrypted_date[i] ^ xor_key[i % xor_key.length()];
}
// 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; // 失败 - 日期格式损坏
return 1; // Failure - date format corrupted
}
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 2; // Expired
}
return 0; // 成功
return 0; // Success
}
// --- New Encryption/Decryption API Implementations ---
const char* GenerateEncryptedCode() {
InitializeCache();
std::string machineCodeStr = machineCode_cache;
machineCodeStr.erase(std::remove(machineCodeStr.begin(), machineCodeStr.end(), '-'), machineCodeStr.end());
std::vector<unsigned char> mc_bytes = hex_string_to_bytes(machineCodeStr);
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<uint16_t> distrib(0, 65535);
uint16_t nonce = distrib(gen);
std::vector<unsigned char> keystream;
generate_keystream(nonce, keystream, 14);
std::vector<unsigned char> encrypted_mc = xor_bytes(mc_bytes, keystream);
std::vector<unsigned char> final_payload;
final_payload.insert(final_payload.end(), encrypted_mc.begin(), encrypted_mc.begin() + 7);
final_payload.push_back(static_cast<unsigned char>(nonce & 0xFF));
final_payload.push_back(static_cast<unsigned char>((nonce >> 8) & 0xFF));
final_payload.insert(final_payload.end(), encrypted_mc.begin() + 7, encrypted_mc.end());
std::string final_code = bytes_to_hex_string(final_payload);
strncpy_s(encryptedCode_cstr, final_code.c_str(), sizeof(encryptedCode_cstr) - 1);
encryptedCode_cstr[sizeof(encryptedCode_cstr) - 1] = '\0';
return encryptedCode_cstr;
}
int DecryptCodeAndGetMachineCode(const char* encrypted_code, char* decrypted_machine_code, int buffer_size) {
if (!encrypted_code || strlen(encrypted_code) != 32) {
return 1; // Failure: invalid input
}
std::vector<unsigned char> final_payload = hex_string_to_bytes(encrypted_code);
if (final_payload.size() != 16) {
return 1; // Failure: invalid hex string
}
uint16_t nonce = final_payload[7] | (static_cast<uint16_t>(final_payload[8]) << 8);
std::vector<unsigned char> encrypted_mc;
encrypted_mc.insert(encrypted_mc.end(), final_payload.begin(), final_payload.begin() + 7);
encrypted_mc.insert(encrypted_mc.end(), final_payload.begin() + 9, final_payload.end());
std::vector<unsigned char> keystream;
generate_keystream(nonce, keystream, 14);
std::vector<unsigned char> decrypted_mc_bytes = xor_bytes(encrypted_mc, keystream);
std::string machine_code_hex = bytes_to_hex_string(decrypted_mc_bytes);
// Return the pure hex machine code, without the hyphen.
strncpy_s(decrypted_machine_code, buffer_size, machine_code_hex.c_str(), _TRUNCATE);
return 0; // Success
}

58
src/test_encryption.cpp Normal file
View File

@ -0,0 +1,58 @@
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "registration_api.h"
// Helper function to print test results
void print_test_result(const std::string& test_name, bool success) {
std::cout << "- Test: " << test_name << "... "
<< (success ? "PASSED" : "FAILED") << std::endl;
}
int main() {
std::cout << "--- Running Encryption/Decryption API Test --- \n" << std::endl;
// --- Test 1: Get Original Machine Code ---
const char* original_mc_raw = GetMachineCode();
std::string original_mc(original_mc_raw);
std::cout << "Original Machine Code: " << original_mc << std::endl;
print_test_result("GetMachineCode() is not empty", !original_mc.empty());
std::cout << std::endl;
// --- Test 2: Generate Encrypted Code ---
const char* encrypted_code_raw = GenerateEncryptedCode();
std::string encrypted_code(encrypted_code_raw);
std::cout << "Generated Encrypted Code: " << encrypted_code << std::endl;
print_test_result("GenerateEncryptedCode() returns 32 characters", encrypted_code.length() == 32);
std::cout << std::endl;
// --- Test 3: Decrypt the Code ---
char decrypted_buffer[256];
int decryption_result = DecryptCodeAndGetMachineCode(encrypted_code.c_str(), decrypted_buffer, sizeof(decrypted_buffer));
std::string decrypted_mc(decrypted_buffer);
std::cout << "Decrypted Machine Code (no hyphen): " << decrypted_mc << std::endl;
print_test_result("DecryptCodeAndGetMachineCode() succeeds", decryption_result == 0);
std::cout << std::endl;
// --- Test 4: Compare Original and Decrypted ---
std::string original_mc_no_hyphen = original_mc;
original_mc_no_hyphen.erase(std::remove(original_mc_no_hyphen.begin(), original_mc_no_hyphen.end(), '-'), original_mc_no_hyphen.end());
std::cout << "Original (no hyphen): " << original_mc_no_hyphen << std::endl;
std::cout << "Decrypted: " << decrypted_mc << std::endl;
bool match = (original_mc_no_hyphen == decrypted_mc);
print_test_result("Decrypted code matches original", match);
std::cout << "\n--------------------------------------------------" << std::endl;
if (match) {
std::cout << "\nSUCCESS: The encryption and decryption functions are working correctly.\n" << std::endl;
return 0;
}
else {
std::cout << "\nFAILURE: The decrypted code does NOT match the original.\n" << std::endl;
return 1;
}
}

View File

@ -19,7 +19,7 @@ void print_status(int code) {
int main(int argc, char* argv[]) {
// --- Step 1: Generate a valid license file ---
std::cout << "--- Step 1: Generating a valid license file for this machine ---" << std::endl;
const char* machine_code = GetMachineCode();
const char* machine_code = GenerateEncryptedCode();
if (!machine_code || std::string(machine_code).empty()) {
std::cerr << "!! ERROR: Could not get machine code." << std::endl;
return 1;
@ -28,8 +28,9 @@ int main(int argc, char* argv[]) {
const char* future_date = "2099-12-31";
std::cout << "Generating license with expiration date: " << future_date << std::endl;
int gen_result = GenerateLicenseFileFromCode(machine_code, future_date);
char code[33] = { 0 };
DecryptCodeAndGetMachineCode(machine_code, code, 33);
int gen_result = GenerateLicenseFileFromCode(code, future_date);
if (gen_result == 0) {
std::cout << "License.data generated successfully." << std::endl;
} else {