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