first commit
This commit is contained in:
parent
63150cd830
commit
88837e3591
49
CMakeLists.txt
Normal file
49
CMakeLists.txt
Normal file
@ -0,0 +1,49 @@
|
||||
# CMake最低版本要求
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# 项目名称
|
||||
project(SoftwareRegistration CXX)
|
||||
|
||||
# 设置C++标准
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# 添加头文件目录
|
||||
include_directories(include lib)
|
||||
|
||||
# 添加源文件
|
||||
aux_source_directory(src SRC_FILES)
|
||||
|
||||
# --- 生成主程序 (用于生成密钥) ---
|
||||
add_executable(machine_code_generator WIN32 src/generator_gui.cpp)
|
||||
target_link_libraries(machine_code_generator PRIVATE RegistrationDLL)
|
||||
|
||||
# --- 生成DLL库 ---
|
||||
add_library(RegistrationDLL SHARED src/registration_api.cpp src/machine_code.cpp)
|
||||
target_include_directories(RegistrationDLL PRIVATE include lib)
|
||||
if(WIN32)
|
||||
target_link_libraries(RegistrationDLL PRIVATE wbemuuid ole32 oleaut32)
|
||||
endif()
|
||||
# 定义导出宏
|
||||
target_compile_definitions(RegistrationDLL PRIVATE REGISTRATION_EXPORTS)
|
||||
|
||||
# --- 生成GUI应用程序 ---
|
||||
add_executable(RegistrationApp WIN32 src/gui.cpp)
|
||||
target_link_libraries(RegistrationApp PRIVATE RegistrationDLL)
|
||||
|
||||
# --- 生成测试程序 ---
|
||||
add_executable(test_license src/test_license.cpp)
|
||||
target_link_libraries(test_license PRIVATE RegistrationDLL)
|
||||
|
||||
# --- 生成仅验证程序 ---
|
||||
add_executable(validate_only src/validate_only.cpp)
|
||||
target_link_libraries(validate_only 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)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
9
include/machine_code.h
Normal file
9
include/machine_code.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef MACHINE_CODE_H
|
||||
#define MACHINE_CODE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
// 获取机器码
|
||||
std::string getMachineCode();
|
||||
|
||||
#endif // MACHINE_CODE_H
|
49
include/registration_api.h
Normal file
49
include/registration_api.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef REGISTRATION_API_H
|
||||
#define REGISTRATION_API_H
|
||||
|
||||
#ifdef REGISTRATION_EXPORTS
|
||||
#define REGISTRATION_API __declspec(dllexport)
|
||||
#else
|
||||
#define REGISTRATION_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// 获取原始机器码
|
||||
REGISTRATION_API const char* GetMachineCode();
|
||||
|
||||
// 获取加密后的许可证密钥
|
||||
REGISTRATION_API const char* GetLicenseKey();
|
||||
|
||||
// 验证许可证密钥 (离线)
|
||||
// @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=失败
|
||||
REGISTRATION_API int GenerateLicenseFileFromCode(const char* machine_code, const char* expiration_date);
|
||||
|
||||
// 验证许可证文件
|
||||
// @return: 0=成功, 1=失败, 2=过期
|
||||
REGISTRATION_API int ValidateLicenseFile();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // REGISTRATION_API_H
|
340
lib/sha256.h
Normal file
340
lib/sha256.h
Normal file
@ -0,0 +1,340 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2017-2024 nagaDev
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef PICOSHA2_H
|
||||
#define PICOSHA2_H
|
||||
//picosha2:20140213
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <iomanip>
|
||||
|
||||
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
#include <cstdint>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
namespace picosha2
|
||||
{
|
||||
typedef unsigned char byte_t;
|
||||
typedef unsigned int word_t;
|
||||
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
typedef uint64_t bits_t;
|
||||
#else
|
||||
typedef uint64_t bits_t;
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline byte_t rotr(byte_t x, byte_t n)
|
||||
{
|
||||
return (x >> n) | (x << (8 - n));
|
||||
}
|
||||
|
||||
inline word_t rotr(word_t x, word_t n)
|
||||
{
|
||||
return (x >> n) | (x << (32 - n));
|
||||
}
|
||||
|
||||
inline word_t add(word_t i, word_t j)
|
||||
{
|
||||
return i + j;
|
||||
}
|
||||
|
||||
template<typename InIter>
|
||||
void fill_block(InIter first, InIter last, std::vector<byte_t>& block)
|
||||
{
|
||||
block.clear();
|
||||
block.reserve(std::distance(first, last));
|
||||
std::copy(first, last, std::back_inserter(block));
|
||||
}
|
||||
|
||||
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
template<typename InContainer,
|
||||
typename std::enable_if<
|
||||
!std::is_same<
|
||||
typename std::iterator_traits<typename InContainer::iterator>::iterator_category,
|
||||
std::input_iterator_tag>::value>::type* = nullptr>
|
||||
#else
|
||||
template<typename InContainer>
|
||||
#endif
|
||||
void fill_block(const InContainer& container, std::vector<byte_t>& block)
|
||||
{
|
||||
block.clear();
|
||||
block.reserve(container.size());
|
||||
std::copy(container.begin(), container.end(), std::back_inserter(block));
|
||||
}
|
||||
|
||||
class hash256_one_by_one
|
||||
{
|
||||
public:
|
||||
hash256_one_by_one()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
h_[0] = 0x6a09e667;
|
||||
h_[1] = 0xbb67ae85;
|
||||
h_[2] = 0x3c6ef372;
|
||||
h_[3] = 0xa54ff53a;
|
||||
h_[4] = 0x510e527f;
|
||||
h_[5] = 0x9b05688c;
|
||||
h_[6] = 0x1f83d9ab;
|
||||
h_[7] = 0x5be0cd19;
|
||||
|
||||
add_len_ = 0;
|
||||
buffer_idx_ = 0;
|
||||
}
|
||||
|
||||
template<typename InIter>
|
||||
void process(InIter first, InIter last)
|
||||
{
|
||||
add_len_ += std::distance(first, last);
|
||||
for (; first != last; ++first)
|
||||
{
|
||||
buffer_[buffer_idx_++] = *first;
|
||||
if (buffer_idx_ == 64)
|
||||
{
|
||||
calc_chunk();
|
||||
buffer_idx_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void finish()
|
||||
{
|
||||
bits_t len_bit_ = add_len_ * 8;
|
||||
word_t len_bit_upper = static_cast<word_t>(len_bit_ >> 32);
|
||||
word_t len_bit_lower = static_cast<word_t>(len_bit_ & 0xffffffff);
|
||||
|
||||
buffer_[buffer_idx_++] = 0x80;
|
||||
|
||||
if (buffer_idx_ > 56)
|
||||
{
|
||||
while (buffer_idx_ < 64)
|
||||
{
|
||||
buffer_[buffer_idx_++] = 0;
|
||||
}
|
||||
calc_chunk();
|
||||
buffer_idx_ = 0;
|
||||
}
|
||||
|
||||
while (buffer_idx_ < 56)
|
||||
{
|
||||
buffer_[buffer_idx_++] = 0;
|
||||
}
|
||||
|
||||
buffer_[56] = static_cast<byte_t>(len_bit_upper >> 24);
|
||||
buffer_[57] = static_cast<byte_t>(len_bit_upper >> 16);
|
||||
buffer_[58] = static_cast<byte_t>(len_bit_upper >> 8);
|
||||
buffer_[59] = static_cast<byte_t>(len_bit_upper);
|
||||
buffer_[60] = static_cast<byte_t>(len_bit_lower >> 24);
|
||||
buffer_[61] = static_cast<byte_t>(len_bit_lower >> 16);
|
||||
buffer_[62] = static_cast<byte_t>(len_bit_lower >> 8);
|
||||
buffer_[63] = static_cast<byte_t>(len_bit_lower);
|
||||
|
||||
calc_chunk();
|
||||
}
|
||||
|
||||
word_t const* get_hash() const
|
||||
{
|
||||
return h_;
|
||||
}
|
||||
|
||||
private:
|
||||
void calc_chunk()
|
||||
{
|
||||
word_t w[64];
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
w[i] = (static_cast<word_t>(buffer_[i * 4]) << 24) |
|
||||
(static_cast<word_t>(buffer_[i * 4 + 1]) << 16) |
|
||||
(static_cast<word_t>(buffer_[i * 4 + 2]) << 8) |
|
||||
(static_cast<word_t>(buffer_[i * 4 + 3]));
|
||||
}
|
||||
|
||||
for (int i = 16; i < 64; ++i)
|
||||
{
|
||||
word_t s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >> 3);
|
||||
word_t s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >> 10);
|
||||
w[i] = add(add(w[i - 16], s0), add(w[i - 7], s1));
|
||||
}
|
||||
|
||||
word_t a = h_[0];
|
||||
word_t b = h_[1];
|
||||
word_t c = h_[2];
|
||||
word_t d = h_[3];
|
||||
word_t e = h_[4];
|
||||
word_t f = h_[5];
|
||||
word_t g = h_[6];
|
||||
word_t h = h_[7];
|
||||
|
||||
static const word_t k[] = {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
};
|
||||
|
||||
for (int i = 0; i < 64; ++i)
|
||||
{
|
||||
word_t s1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
||||
word_t ch = (e & f) ^ ((~e) & g);
|
||||
word_t temp1 = add(add(h, s1), add(ch, add(k[i], w[i])));
|
||||
word_t s0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
||||
word_t maj = (a & b) ^ (a & c) ^ (b & c);
|
||||
word_t temp2 = add(s0, maj);
|
||||
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
e = add(d, temp1);
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
a = add(temp1, temp2);
|
||||
}
|
||||
|
||||
h_[0] = add(h_[0], a);
|
||||
h_[1] = add(h_[1], b);
|
||||
h_[2] = add(h_[2], c);
|
||||
h_[3] = add(h_[3], d);
|
||||
h_[4] = add(h_[4], e);
|
||||
h_[5] = add(h_[5], f);
|
||||
h_[6] = add(h_[6], g);
|
||||
h_[7] = add(h_[7], h);
|
||||
}
|
||||
|
||||
word_t h_[8];
|
||||
byte_t buffer_[64];
|
||||
size_t buffer_idx_;
|
||||
uint64_t add_len_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename InIter>
|
||||
void hash256(InIter first, InIter last, std::vector<byte_t>& hash)
|
||||
{
|
||||
detail::hash256_one_by_one hasher;
|
||||
hasher.process(first, last);
|
||||
hasher.finish();
|
||||
hash.assign(32, 0);
|
||||
word_t const* digest = hasher.get_hash();
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
hash[i * 4] = static_cast<byte_t>(digest[i] >> 24);
|
||||
hash[i * 4 + 1] = static_cast<byte_t>(digest[i] >> 16);
|
||||
hash[i * 4 + 2] = static_cast<byte_t>(digest[i] >> 8);
|
||||
hash[i * 4 + 3] = static_cast<byte_t>(digest[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename InIter>
|
||||
void hash256(InIter first, InIter last, std::string& hex_str)
|
||||
{
|
||||
std::vector<byte_t> hash(32);
|
||||
hash256(first, last, hash);
|
||||
hex_str = bytes_to_hex_string(hash.begin(), hash.end());
|
||||
}
|
||||
|
||||
template<typename InIter>
|
||||
std::string hash256_hex_string(InIter first, InIter last)
|
||||
{
|
||||
std::string hex_str;
|
||||
hash256(first, last, hex_str);
|
||||
return hex_str;
|
||||
}
|
||||
|
||||
template<typename In>
|
||||
void hash256(const In& in, std::vector<byte_t>& hash)
|
||||
{
|
||||
hash256(std::begin(in), std::end(in), hash);
|
||||
}
|
||||
|
||||
template<typename In>
|
||||
void hash256(const In& in, std::string& hex_str)
|
||||
{
|
||||
hash256(std::begin(in), std::end(in), hex_str);
|
||||
}
|
||||
|
||||
template<typename In>
|
||||
std::string hash256_hex_string(const In& in)
|
||||
{
|
||||
return hash256_hex_string(std::begin(in), std::end(in));
|
||||
}
|
||||
|
||||
template<typename InIter>
|
||||
std::string bytes_to_hex_string(InIter first, InIter last)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::hex << std::setfill('0');
|
||||
while (first != last)
|
||||
{
|
||||
ss << std::setw(2) << static_cast<int>(*first);
|
||||
++first;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template<typename In>
|
||||
std::string bytes_to_hex_string(const In& bytes)
|
||||
{
|
||||
return bytes_to_hex_string(std::begin(bytes), std::end(bytes));
|
||||
}
|
||||
|
||||
template<typename OutIter>
|
||||
void hex_string_to_bytes(const std::string& hex_str, OutIter out)
|
||||
{
|
||||
assert(hex_str.length() % 2 == 0);
|
||||
for (size_t i = 0; i < hex_str.length(); i += 2)
|
||||
{
|
||||
int val;
|
||||
std::stringstream ss;
|
||||
ss << std::hex << hex_str.substr(i, 2);
|
||||
ss >> val;
|
||||
*out = static_cast<byte_t>(val);
|
||||
++out;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename OutContainer>
|
||||
void hex_string_to_bytes(const std::string& hex_str, OutContainer& bytes)
|
||||
{
|
||||
hex_string_to_bytes(hex_str, std::back_inserter(bytes));
|
||||
}
|
||||
|
||||
} // namespace picosha2
|
||||
|
||||
#endif //PICOSHA2_H
|
28
src/generate_valid.cpp
Normal file
28
src/generate_valid.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
#include <iostream>
|
||||
#include "registration_api.h"
|
||||
#include "machine_code.h"
|
||||
|
||||
int main() {
|
||||
std::cout << "--- Generating a valid License.data file for this machine ---" << std::endl;
|
||||
|
||||
const char* machine_code = GetMachineCode();
|
||||
if (!machine_code || std::string(machine_code).empty()) {
|
||||
std::cerr << "!! ERROR: Could not get machine code." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << "Machine Code: " << machine_code << std::endl;
|
||||
|
||||
const char* future_date = "2099-12-31";
|
||||
std::cout << "Expiration Date: " << future_date << std::endl;
|
||||
|
||||
int gen_result = GenerateLicenseFileFromCode(machine_code, future_date);
|
||||
|
||||
if (gen_result == 0) {
|
||||
std::cout << ">> SUCCESS: License.data generated successfully." << std::endl;
|
||||
} else {
|
||||
std::cerr << ">> FAILURE: Failed to generate License.data." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
115
src/generator_gui.cpp
Normal file
115
src/generator_gui.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
#include <windows.h>
|
||||
#include "registration_api.h"
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
#define IDC_MACHINE_CODE_LABEL 201
|
||||
#define IDC_MACHINE_CODE_EDIT 202
|
||||
#define IDC_COPY_BUTTON 203
|
||||
|
||||
LRESULT CALLBACK GenWndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
void CopyToClipboard(HWND hwnd, const std::string& text) {
|
||||
if (!OpenClipboard(hwnd)) {
|
||||
return;
|
||||
}
|
||||
EmptyClipboard();
|
||||
HGLOBAL hg = GlobalAlloc(GMEM_MOVEABLE, text.size() + 1);
|
||||
if (!hg) {
|
||||
CloseClipboard();
|
||||
return;
|
||||
}
|
||||
memcpy(GlobalLock(hg), text.c_str(), text.size() + 1);
|
||||
GlobalUnlock(hg);
|
||||
SetClipboardData(CF_TEXT, hg);
|
||||
CloseClipboard();
|
||||
GlobalFree(hg);
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||
WNDCLASSEX wc = {0};
|
||||
wc.cbSize = sizeof(WNDCLASSEX);
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = GenWndProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = "GeneratorWindowClass";
|
||||
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
|
||||
|
||||
if (!RegisterClassEx(&wc)) {
|
||||
MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
HWND hwnd = CreateWindowEx(
|
||||
WS_EX_CLIENTEDGE,
|
||||
"GeneratorWindowClass",
|
||||
"Machine Code Generator",
|
||||
(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX),
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, 540, 150,
|
||||
NULL, NULL, hInstance, NULL);
|
||||
|
||||
if (hwnd == NULL) {
|
||||
MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ShowWindow(hwnd, nCmdShow);
|
||||
UpdateWindow(hwnd);
|
||||
|
||||
MSG Msg;
|
||||
while (GetMessage(&Msg, NULL, 0, 0) > 0) {
|
||||
TranslateMessage(&Msg);
|
||||
DispatchMessage(&Msg);
|
||||
}
|
||||
return 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);
|
||||
|
||||
// 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
|
||||
std::string machineCode = GetMachineCode();
|
||||
SetWindowText(hMachineCodeEdit, machineCode.c_str());
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_CLOSE:
|
||||
DestroyWindow(hwnd);
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
135
src/gui.cpp
Normal file
135
src/gui.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
#include <windows.h>
|
||||
#include "registration_api.h"
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
#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
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
static HWND hMachineCodeEdit, hExpirationEdit, hStatusLabel;
|
||||
|
||||
void UpdateValidationStatus(HWND hwnd) {
|
||||
int result = ValidateLicenseFile();
|
||||
std::string statusText;
|
||||
switch (result) {
|
||||
case 0:
|
||||
statusText = "License Status: VALID";
|
||||
break;
|
||||
case 1:
|
||||
statusText = "License Status: INVALID or NOT FOUND";
|
||||
break;
|
||||
case 2:
|
||||
statusText = "License Status: EXPIRED";
|
||||
break;
|
||||
}
|
||||
SetWindowText(hStatusLabel, statusText.c_str());
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||
WNDCLASSEX wc = {0};
|
||||
wc.cbSize = sizeof(WNDCLASSEX);
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = hInstance;
|
||||
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = "RegistrationWindowClass";
|
||||
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
|
||||
|
||||
if (!RegisterClassEx(&wc)) {
|
||||
MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
HWND hwnd = CreateWindowEx(
|
||||
WS_EX_CLIENTEDGE,
|
||||
"RegistrationWindowClass",
|
||||
"Software Registration",
|
||||
(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX),
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, 480, 250,
|
||||
NULL, NULL, hInstance, NULL);
|
||||
|
||||
if (hwnd == NULL) {
|
||||
MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ShowWindow(hwnd, nCmdShow);
|
||||
UpdateWindow(hwnd);
|
||||
|
||||
MSG Msg;
|
||||
while (GetMessage(&Msg, NULL, 0, 0) > 0) {
|
||||
TranslateMessage(&Msg);
|
||||
DispatchMessage(&Msg);
|
||||
}
|
||||
return Msg.wParam;
|
||||
}
|
||||
|
||||
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);
|
||||
UpdateValidationStatus(hwnd);
|
||||
|
||||
// --- 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);
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_COMMAND: {
|
||||
switch (LOWORD(wParam)) {
|
||||
case IDC_GENERATE_BUTTON: {
|
||||
char machineCode[256];
|
||||
char expirationDate[11];
|
||||
GetWindowText(hMachineCodeEdit, machineCode, 256);
|
||||
GetWindowText(hExpirationEdit, expirationDate, 11);
|
||||
|
||||
if (strlen(machineCode) == 0) {
|
||||
MessageBox(hwnd, "Please enter a machine code.", "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;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_CLOSE:
|
||||
DestroyWindow(hwnd);
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
158
src/machine_code.cpp
Normal file
158
src/machine_code.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
#include "machine_code.h"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <comdef.h>
|
||||
#include <Wbemidl.h>
|
||||
|
||||
#pragma comment(lib, "wbemuuid.lib")
|
||||
|
||||
// Helper function to query a WMI property
|
||||
std::string getWMIProperty(const wchar_t* wmiClass, const wchar_t* propertyName) {
|
||||
std::string result = "";
|
||||
HRESULT hres;
|
||||
|
||||
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
if (FAILED(hres)) {
|
||||
return "Failed to initialize COM library.";
|
||||
}
|
||||
|
||||
hres = CoInitializeSecurity(
|
||||
NULL,
|
||||
-1,
|
||||
NULL,
|
||||
NULL,
|
||||
RPC_C_AUTHN_LEVEL_DEFAULT,
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||||
NULL,
|
||||
EOAC_NONE,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (FAILED(hres)) {
|
||||
CoUninitialize();
|
||||
return "Failed to initialize security.";
|
||||
}
|
||||
|
||||
IWbemLocator* pLoc = NULL;
|
||||
hres = CoCreateInstance(
|
||||
CLSID_WbemLocator,
|
||||
0,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_IWbemLocator, (LPVOID*)&pLoc);
|
||||
|
||||
if (FAILED(hres)) {
|
||||
CoUninitialize();
|
||||
return "Failed to create IWbemLocator object.";
|
||||
}
|
||||
|
||||
IWbemServices* pSvc = NULL;
|
||||
hres = pLoc->ConnectServer(
|
||||
_bstr_t(L"ROOT\\CIMV2"),
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
&pSvc
|
||||
);
|
||||
|
||||
if (FAILED(hres)) {
|
||||
pLoc->Release();
|
||||
CoUninitialize();
|
||||
return "Could not connect to WMI server.";
|
||||
}
|
||||
|
||||
hres = CoSetProxyBlanket(
|
||||
pSvc,
|
||||
RPC_C_AUTHN_WINNT,
|
||||
RPC_C_AUTHZ_NONE,
|
||||
NULL,
|
||||
RPC_C_AUTHN_LEVEL_CALL,
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE,
|
||||
NULL,
|
||||
EOAC_NONE
|
||||
);
|
||||
|
||||
if (FAILED(hres)) {
|
||||
pSvc->Release();
|
||||
pLoc->Release();
|
||||
CoUninitialize();
|
||||
return "Could not set proxy blanket.";
|
||||
}
|
||||
|
||||
IEnumWbemClassObject* pEnumerator = NULL;
|
||||
std::wstring query = L"SELECT * FROM ";
|
||||
query += wmiClass;
|
||||
|
||||
hres = pSvc->ExecQuery(
|
||||
bstr_t("WQL"),
|
||||
bstr_t(query.c_str()),
|
||||
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
|
||||
NULL,
|
||||
&pEnumerator);
|
||||
|
||||
if (FAILED(hres)) {
|
||||
pSvc->Release();
|
||||
pLoc->Release();
|
||||
CoUninitialize();
|
||||
return "Query for hardware info failed.";
|
||||
}
|
||||
|
||||
IWbemClassObject* pclsObj = NULL;
|
||||
ULONG uReturn = 0;
|
||||
|
||||
while (pEnumerator) {
|
||||
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
|
||||
if (0 == uReturn) {
|
||||
break;
|
||||
}
|
||||
|
||||
VARIANT vtProp;
|
||||
hr = pclsObj->Get(propertyName, 0, &vtProp, 0, 0);
|
||||
if (SUCCEEDED(hr) && vtProp.vt == VT_BSTR) {
|
||||
_bstr_t bstr(vtProp.bstrVal, false);
|
||||
result = (char*)bstr;
|
||||
VariantClear(&vtProp);
|
||||
pclsObj->Release();
|
||||
// We only need the first one
|
||||
break;
|
||||
}
|
||||
VariantClear(&vtProp);
|
||||
pclsObj->Release();
|
||||
}
|
||||
|
||||
pSvc->Release();
|
||||
pLoc->Release();
|
||||
pEnumerator->Release();
|
||||
CoUninitialize();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string getCpuId() {
|
||||
return getWMIProperty(L"Win32_Processor", L"ProcessorId");
|
||||
}
|
||||
|
||||
std::string getDiskSerial() {
|
||||
return getWMIProperty(L"Win32_DiskDrive", L"SerialNumber");
|
||||
}
|
||||
|
||||
std::string getMacAddress() {
|
||||
return getWMIProperty(L"Win32_NetworkAdapterConfiguration", L"MACAddress");
|
||||
}
|
||||
|
||||
std::string getMachineCode() {
|
||||
std::string cpuId = getCpuId();
|
||||
std::string diskSerial = getDiskSerial();
|
||||
std::string macAddress = getMacAddress();
|
||||
|
||||
// Clean up strings
|
||||
cpuId.erase(std::remove_if(cpuId.begin(), cpuId.end(), isspace), cpuId.end());
|
||||
diskSerial.erase(std::remove_if(diskSerial.begin(), diskSerial.end(), isspace), diskSerial.end());
|
||||
macAddress.erase(std::remove_if(macAddress.begin(), macAddress.end(), isspace), macAddress.end());
|
||||
macAddress.erase(std::remove(macAddress.begin(), macAddress.end(), ':'), macAddress.end());
|
||||
|
||||
return cpuId + "-" + diskSerial + "-" + macAddress;
|
||||
}
|
19
src/main.cpp
Normal file
19
src/main.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include "include/machine_code.h"
|
||||
#include "lib/sha256.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int main() {
|
||||
// 1. 获取原始机器码
|
||||
std::string machineCode = getMachineCode();
|
||||
std::cout << "Original Machine Code: " << machineCode << std::endl;
|
||||
|
||||
// 2. 对机器码进行SHA-256哈希加密
|
||||
std::string hashed_machine_code = picosha2::hash256_hex_string(machineCode);
|
||||
|
||||
// 3. 生成加密后的密钥 (这里我们直接使用哈希值作为密钥)
|
||||
std::cout << "Generated License Key: " << hashed_machine_code << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
214
src/registration_api.cpp
Normal file
214
src/registration_api.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
#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; // 成功
|
||||
}
|
53
src/test_license.cpp
Normal file
53
src/test_license.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "registration_api.h"
|
||||
#include "machine_code.h"
|
||||
|
||||
// Helper function to print validation status
|
||||
void print_status(int code) {
|
||||
if (code == 0) {
|
||||
std::cout << ">> RESULT: License is valid." << std::endl;
|
||||
} else if (code == 1) {
|
||||
std::cout << ">> RESULT: License is INVALID (file not found, corrupted, or for another machine)." << std::endl;
|
||||
} else if (code == 2) {
|
||||
std::cout << ">> RESULT: License has EXPIRED." << std::endl;
|
||||
} else {
|
||||
std::cout << ">> RESULT: Unknown validation code: " << code << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
if (!machine_code || std::string(machine_code).empty()) {
|
||||
std::cerr << "!! ERROR: Could not get machine code." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << "Machine Code: " << machine_code << std::endl;
|
||||
|
||||
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);
|
||||
if (gen_result == 0) {
|
||||
std::cout << "License.data generated successfully." << std::endl;
|
||||
} else {
|
||||
std::cout << "!! ERROR: Failed to generate License.data." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// --- Step 2: Validate the generated file ---
|
||||
std::cout << "--- Step 2: Validating the newly created License.data file ---" << std::endl;
|
||||
int validation_result = ValidateLicenseFile();
|
||||
print_status(validation_result);
|
||||
|
||||
if (validation_result == 0) {
|
||||
std::cout << "\nVerification successful." << std::endl;
|
||||
} else {
|
||||
std::cout << "\nVerification failed." << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
25
src/validate_only.cpp
Normal file
25
src/validate_only.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include <iostream>
|
||||
#include "registration_api.h"
|
||||
|
||||
// Helper function to print validation status
|
||||
void print_status(int code) {
|
||||
if (code == 0) {
|
||||
std::cout << ">> RESULT: License is valid." << std::endl;
|
||||
} else if (code == 1) {
|
||||
std::cout << ">> RESULT: License is INVALID (file not found, corrupted, or for another machine)." << std::endl;
|
||||
} else if (code == 2) {
|
||||
std::cout << ">> RESULT: License has EXPIRED." << std::endl;
|
||||
} else {
|
||||
std::cout << ">> RESULT: Unknown validation code: " << code << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "--- Attempting to validate existing License.data file ---" << std::endl;
|
||||
|
||||
int validation_result = ValidateLicenseFile();
|
||||
|
||||
print_status(validation_result);
|
||||
|
||||
return validation_result;
|
||||
}
|
Loading…
Reference in New Issue
Block a user