modify machine code get and enntry
This commit is contained in:
parent
cc9a5747f1
commit
0e7f56cf7c
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
95
src/gui.cpp
95
src/gui.cpp
@ -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;
|
||||
}
|
||||
|
||||
@ -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::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
58
src/test_encryption.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user