Refactor project structure

This commit is contained in:
2026-03-28 19:56:39 +11:00
parent 1d267378b2
commit 8a2e721058
511 changed files with 59 additions and 48 deletions

View File

@@ -0,0 +1,106 @@
// ============================================================================
// ANSLibsLoader.cpp — Master orchestrator for all dynamic library loading
//
// Coordinates sub-loaders in the correct dependency order:
// 1. DLL search path injection (shared directory)
// 2. OpenCV (CvLoader) — pre-loads opencv_world + companions
// 3. OpenVINO (OvLoader) — pre-loads TBB + openvino.dll
// 4. NVIDIA stack (NvDynLoader) — TRT, cuDNN, CUDA
// 5. ONNX Runtime (EPLoader) — with execution provider selection
//
// Shutdown releases everything in reverse order.
// ============================================================================
#include "ANSLibsLoader.h"
#include "DynLibUtils.h"
#include "CvLoader.h"
#include "OvLoader.h"
#include "NvDynLoader.h"
#include "EPLoader.h"
#include <iostream>
#include <mutex>
namespace ANSCENTER {
// ─────────────────────────────────────────────────────────────────────────────
// Static member definitions
// ─────────────────────────────────────────────────────────────────────────────
bool ANSLibsLoader::s_initialized = false;
static std::mutex g_masterMutex;
// ─────────────────────────────────────────────────────────────────────────────
// Initialize
// ─────────────────────────────────────────────────────────────────────────────
void ANSLibsLoader::Initialize(const std::string& shared_dir, EngineType preferred)
{
std::lock_guard<std::mutex> lock(g_masterMutex);
if (s_initialized) return;
std::cout << "==========================================================\n"
<< "ANSLibsLoader: Initializing all dynamic libraries...\n"
<< " Shared dir : " << shared_dir << "\n"
<< " Engine pref : " << static_cast<int>(preferred) << "\n"
<< "==========================================================" << std::endl;
// ── STEP 1: Inject shared dir into search path ───────────────────────────
// This must happen before any DLL loading so all libraries in the shared
// directory are discoverable.
DynLib::InjectDllSearchPath(shared_dir);
// ── STEP 2: Pre-load OpenCV ──────────────────────────────────────────────
// Must happen before consuming DLLs (ANSODEngine etc.) are loaded, because
// those are import-linked against opencv_world and need the DLL available.
CvLoader::Initialize(shared_dir);
// ── STEP 3: Pre-load OpenVINO + TBB ──────────────────────────────────────
// OpenVINO is used directly (ov::Core) by many projects (ANSODEngine,
// ANSLPR, ANSFR, etc.). Pre-loading ensures the DLLs from the shared
// directory are resolved before any import-linked consumer is loaded.
OvLoader::Initialize(shared_dir);
// ── STEP 4: Load NVIDIA stack ────────────────────────────────────────────
// Only attempt if the preferred engine is NVIDIA or AUTO_DETECT.
if (preferred == EngineType::NVIDIA_GPU ||
preferred == EngineType::AUTO_DETECT)
{
NvDynLoader::Initialize();
}
// ── STEP 5: Load ONNX Runtime + select execution provider ────────────────
EPLoader::Initialize(shared_dir, preferred);
s_initialized = true;
std::cout << "==========================================================\n"
<< "ANSLibsLoader: Initialization complete.\n"
<< "==========================================================" << std::endl;
}
// ─────────────────────────────────────────────────────────────────────────────
// Shutdown
// ─────────────────────────────────────────────────────────────────────────────
void ANSLibsLoader::Shutdown()
{
std::lock_guard<std::mutex> lock(g_masterMutex);
// Shut down in reverse initialization order.
// Each sub-loader is idempotent and safe to call even if not initialized.
EPLoader::Shutdown();
NvDynLoader::Shutdown();
OvLoader::Shutdown();
CvLoader::Shutdown();
s_initialized = false;
}
// ─────────────────────────────────────────────────────────────────────────────
// IsInitialized
// ─────────────────────────────────────────────────────────────────────────────
bool ANSLibsLoader::IsInitialized()
{
return s_initialized;
}
} // namespace ANSCENTER

View File

@@ -0,0 +1,28 @@
; ============================================================================
; ANSLibsLoader.def Module definition file
;
; Exports the extern "C" TRT / ONNX-parser factory stubs so consuming
; projects can link ANSLibsLoader.lib instead of nvinfer_XX.lib /
; nvonnxparser_XX.lib.
;
; WHY A .DEF FILE?
; ----------------
; NvInfer.h declares these functions with TENSORRTAPI, and our stub
; definitions in NvDynLoader.cpp must match that declaration exactly.
; Any mismatch in __declspec attributes or noexcept causes C2375.
; By using a .def file the linker exports the symbols without requiring
; __declspec(dllexport) in the source code at all.
; ============================================================================
LIBRARY ANSLibsLoader
EXPORTS
; TensorRT factory stubs (called by NvInfer.h inline wrappers)
createInferBuilder_INTERNAL
createInferRuntime_INTERNAL
createInferRefitter_INTERNAL
; ONNX parser factory stubs (called by NvOnnxParser.h inline wrappers)
createNvOnnxParser_INTERNAL
createNvOnnxParserRefitter_INTERNAL
getNvOnnxParserVersion

View File

@@ -0,0 +1,38 @@
# ANSLibsLoader — DLL that dynamically loads all ANS modules
add_library(ANSLibsLoader SHARED
ANSLibsLoader.cpp
CvLoader.cpp
DynLibUtils.cpp
EPLoader.cpp
NvDynLoader.cpp
OvLoader.cpp
dllmain.cpp
pch.cpp
pch.h
framework.h
include/ANSLibsLoader.h
include/CvLoader.h
include/DynLibUtils.h
include/EPLoader.h
include/NvDynLoader.h
include/OvLoader.h
)
target_include_directories(ANSLibsLoader PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
)
target_link_libraries(ANSLibsLoader
PRIVATE ANSLicensingSystem
PRIVATE labview
PRIVATE spdlog_dep
PRIVATE opencv
PRIVATE onnxruntime
PRIVATE tensorrt
PRIVATE openvino
PRIVATE CUDA::cudart_static
)
target_compile_definitions(ANSLibsLoader PRIVATE UNICODE _UNICODE ANSLIBSLOADER_EXPORTS NOMINMAX)
target_precompile_headers(ANSLibsLoader PRIVATE pch.h)

View File

@@ -0,0 +1,211 @@
// ============================================================================
// CvLoader.cpp — OpenCV DLL discovery and pre-loading
// ============================================================================
#include "CvLoader.h"
#include "DynLibUtils.h"
#include <iostream>
#include <mutex>
using namespace ANSCENTER::DynLib;
// ─────────────────────────────────────────────────────────────────────────────
// Static member definitions
// ─────────────────────────────────────────────────────────────────────────────
std::mutex CvLoader::s_mutex;
bool CvLoader::s_initialized = false;
CvInfo CvLoader::s_info;
LibHandle CvLoader::s_hCvWorld = nullptr;
LibHandle CvLoader::s_hCvImgHash = nullptr;
// ─────────────────────────────────────────────────────────────────────────────
// Helper — extract version string from version code (e.g. 4130 → "4.13.0")
// ─────────────────────────────────────────────────────────────────────────────
static std::string VersionFromCode(int code)
{
// OpenCV version encoding: XYZZ where X=major, Y=minor, ZZ=patch
// 4130 → major=4, minor=13, patch=0
// 4100 → major=4, minor=10, patch=0
// 490 → major=4, minor=9, patch=0
int major = code / 1000;
int minor = (code / 10) % 100;
int patch = code % 10;
return std::to_string(major) + "." +
std::to_string(minor) + "." +
std::to_string(patch);
}
// ─────────────────────────────────────────────────────────────────────────────
// Helper — extract version code from DLL filename
// "opencv_world4130.dll" → 4130
// "opencv_world4100.dll" → 4100
// "libopencv_world.so.413"→ 413 (Linux)
// ─────────────────────────────────────────────────────────────────────────────
static int ExtractVersionCode(const std::string& path)
{
#ifdef _WIN32
// Windows: opencv_world<XYZZ>.dll — digits between "opencv_world" and ".dll"
const std::string marker = "opencv_world";
size_t pos = path.find(marker);
if (pos == std::string::npos) return 0;
pos += marker.size();
size_t dot = path.find('.', pos);
if (dot == std::string::npos) return 0;
try { return std::stoi(path.substr(pos, dot - pos)); }
catch (...) { return 0; }
#else
// Linux: libopencv_world.so.<digits>
size_t dot = path.find_last_of('.');
if (dot == std::string::npos || dot + 1 >= path.size()) return 0;
try { return std::stoi(path.substr(dot + 1)); }
catch (...) { return 0; }
#endif
}
// ─────────────────────────────────────────────────────────────────────────────
// Candidate lists — search ANSCENTER shared dir first, then system PATH
// ─────────────────────────────────────────────────────────────────────────────
std::vector<std::string> CvLoader::CvWorldCandidates(const std::string& shared_dir)
{
std::vector<std::string> v;
// Versioned candidates, newest first (covers OpenCV 4.5 through 4.20+)
// Version codes: 4200, 4190, 4180, ..., 4130, ..., 4100, ..., 450
static const int versions[] = {
4200, 4190, 4180, 4170, 4160, 4150, 4140, 4130, 4120, 4110, 4100,
490, 480, 470, 460, 450
};
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
for (int ver : versions) {
#ifdef _WIN32
v.push_back(JoinPath(shared_dir,
"opencv_world" + std::to_string(ver) + ".dll"));
#else
v.push_back(JoinPath(shared_dir,
"libopencv_world.so." + std::to_string(ver)));
#endif
}
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
for (int ver : versions) {
#ifdef _WIN32
v.push_back("opencv_world" + std::to_string(ver) + ".dll");
#else
v.push_back("libopencv_world.so." + std::to_string(ver));
#endif
}
return v;
}
std::vector<std::string> CvLoader::CvImgHashCandidates(const std::string& shared_dir)
{
std::vector<std::string> v;
static const int versions[] = {
4200, 4190, 4180, 4170, 4160, 4150, 4140, 4130, 4120, 4110, 4100,
490, 480, 470, 460, 450
};
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
for (int ver : versions) {
#ifdef _WIN32
v.push_back(JoinPath(shared_dir,
"opencv_img_hash" + std::to_string(ver) + ".dll"));
#else
v.push_back(JoinPath(shared_dir,
"libopencv_img_hash.so." + std::to_string(ver)));
#endif
}
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
for (int ver : versions) {
#ifdef _WIN32
v.push_back("opencv_img_hash" + std::to_string(ver) + ".dll");
#else
v.push_back("libopencv_img_hash.so." + std::to_string(ver));
#endif
}
return v;
}
// ─────────────────────────────────────────────────────────────────────────────
// Initialize
// ─────────────────────────────────────────────────────────────────────────────
const CvInfo& CvLoader::Initialize(const std::string& shared_dir, bool verbose)
{
std::lock_guard<std::mutex> lock(s_mutex);
if (s_initialized) return s_info;
// Clean up any partially-loaded handles from a previous failed attempt
if (s_hCvWorld) { FreeLib(s_hCvWorld); s_hCvWorld = nullptr; }
if (s_hCvImgHash) { FreeLib(s_hCvImgHash); s_hCvImgHash = nullptr; }
if (verbose) {
std::cout << "==================================================" << std::endl;
std::cout << "[CvLoader] Discovering OpenCV libraries..." << std::endl;
std::cout << " Shared dir : " << shared_dir << std::endl;
std::cout << "==================================================" << std::endl;
}
// ── STEP 1: Inject shared dir into search path ───────────────────────────
// This ensures dependent DLLs (e.g. opencv_videoio_ffmpeg) can also be
// found when they are co-located with opencv_world in the shared dir.
InjectDllSearchPath(shared_dir);
// ── STEP 2: Pre-load opencv_world ────────────────────────────────────────
std::string worldPath;
s_hCvWorld = FindAndLoad(CvWorldCandidates(shared_dir), worldPath, verbose);
if (s_hCvWorld) {
s_info.dllPath = worldPath;
s_info.versionCode = ExtractVersionCode(worldPath);
s_info.version = VersionFromCode(s_info.versionCode);
s_info.loaded = true;
if (verbose) {
std::cout << "[CvLoader] OpenCV version = " << s_info.version
<< " (code " << s_info.versionCode << ")" << std::endl;
}
} else {
std::cout << "[CvLoader] WARNING: No opencv_world DLL found in "
<< shared_dir << " or system PATH." << std::endl;
std::cout << "[CvLoader] OpenCV will rely on import-lib resolution at load time."
<< std::endl;
}
// ── STEP 3: Pre-load companion modules ───────────────────────────────────
// These are optional — missing is a warning, not a failure.
std::string imgHashPath;
s_hCvImgHash = FindAndLoad(CvImgHashCandidates(shared_dir), imgHashPath, verbose);
if (!s_hCvImgHash && verbose) {
std::cout << "[CvLoader] opencv_img_hash not found (optional)." << std::endl;
}
s_initialized = true;
if (verbose) {
std::cout << "[CvLoader] "
<< (s_info.loaded ? "initialised successfully." : "WARNING — opencv_world not pre-loaded.")
<< std::endl;
std::cout << "==================================================" << std::endl;
}
return s_info;
}
// ─────────────────────────────────────────────────────────────────────────────
// Shutdown
// ─────────────────────────────────────────────────────────────────────────────
void CvLoader::Shutdown()
{
std::lock_guard<std::mutex> lock(s_mutex);
// Release in reverse order
if (s_hCvImgHash) { FreeLib(s_hCvImgHash); s_hCvImgHash = nullptr; }
if (s_hCvWorld) { FreeLib(s_hCvWorld); s_hCvWorld = nullptr; }
s_info = CvInfo{};
s_initialized = false;
}

View File

@@ -0,0 +1,125 @@
// ============================================================================
// DynLibUtils.cpp — Shared dynamic library loading utilities
// ============================================================================
#include "DynLibUtils.h"
#ifndef _WIN32
# include <sys/stat.h>
#endif
namespace ANSCENTER {
namespace DynLib {
// ── FileExists ───────────────────────────────────────────────────────────
bool FileExists(const std::string& path)
{
#ifdef _WIN32
DWORD attr = GetFileAttributesA(path.c_str());
return (attr != INVALID_FILE_ATTRIBUTES) &&
!(attr & FILE_ATTRIBUTE_DIRECTORY);
#else
struct stat st {};
return (::stat(path.c_str(), &st) == 0) && S_ISREG(st.st_mode);
#endif
}
// ── JoinPath ─────────────────────────────────────────────────────────────
std::string JoinPath(const std::string& base, const std::string& component)
{
#ifdef _WIN32
const char sep = '\\';
#else
const char sep = '/';
#endif
if (base.empty()) return component;
if (base.back() == sep || base.back() == '/')
return base + component;
return base + sep + component;
}
// ── InjectDllSearchPath ──────────────────────────────────────────────────
void InjectDllSearchPath(const std::string& dir)
{
#ifdef _WIN32
// Safe UTF-8 → wide-string conversion (handles non-ASCII paths correctly)
int wlen = MultiByteToWideChar(CP_UTF8, 0, dir.c_str(), -1, nullptr, 0);
std::wstring wdir(static_cast<size_t>(wlen > 0 ? wlen - 1 : 0), L'\0');
if (wlen > 0)
MultiByteToWideChar(CP_UTF8, 0, dir.c_str(), -1, wdir.data(), wlen);
DLL_DIRECTORY_COOKIE cookie = AddDllDirectory(wdir.c_str());
if (!cookie)
std::cerr << "[DynLib] WARNING: AddDllDirectory failed for: "
<< dir << " (error " << GetLastError() << ")" << std::endl;
char existing_path[32767] = {};
GetEnvironmentVariableA("PATH", existing_path, sizeof(existing_path));
std::string new_path = dir + ";" + existing_path;
if (!SetEnvironmentVariableA("PATH", new_path.c_str()))
std::cerr << "[DynLib] WARNING: SetEnvironmentVariable PATH failed."
<< std::endl;
#else
const char* existing = getenv("LD_LIBRARY_PATH");
std::string new_path = dir +
(existing ? (":" + std::string(existing)) : "");
setenv("LD_LIBRARY_PATH", new_path.c_str(), 1);
#endif
std::cout << "[DynLib] DLL search path injected: " << dir << std::endl;
}
// ── LoadLib ──────────────────────────────────────────────────────────────
LibHandle LoadLib(const std::string& path, bool globalLoad)
{
#ifdef _WIN32
(void)globalLoad;
return LoadLibraryExA(path.c_str(), nullptr,
LOAD_WITH_ALTERED_SEARCH_PATH);
#else
return globalLoad
? ::dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL)
: ::dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL);
#endif
}
// ── FreeLib ──────────────────────────────────────────────────────────────
void FreeLib(LibHandle h)
{
if (!h) return;
#ifdef _WIN32
::FreeLibrary(h);
#else
::dlclose(h);
#endif
}
// ── GetSymbol ────────────────────────────────────────────────────────────
void* GetSymbol(LibHandle h, const char* sym)
{
if (!h) return nullptr;
#ifdef _WIN32
return reinterpret_cast<void*>(::GetProcAddress(h, sym));
#else
return ::dlsym(h, sym);
#endif
}
// ── FindAndLoad ──────────────────────────────────────────────────────────
LibHandle FindAndLoad(const std::vector<std::string>& candidates,
std::string& loadedPath,
bool verbose,
bool globalLoad)
{
for (const auto& name : candidates) {
LibHandle h = LoadLib(name, globalLoad);
if (h) {
loadedPath = name;
if (verbose)
std::cout << "[DynLib] Loaded: " << name << std::endl;
return h;
}
}
return LIB_INVALID;
}
} // namespace DynLib
} // namespace ANSCENTER

View File

@@ -0,0 +1,492 @@
// EPLoader.cpp
// Dynamic ONNX Runtime EP loader.
// Loads onnxruntime.dll at runtime — no onnxruntime.lib linkage required.
//
// Moved from ONNXEngine/ to ANSLibsLoader/.
// Compile this file in EXACTLY ONE project (ANSLibsLoader.dll).
// That project MUST define ANSLIBSLOADER_EXPORTS in its Preprocessor Definitions.
//
// Windows: LoadLibraryExW + AddDllDirectory + GetProcAddress
// Linux: dlopen (RTLD_NOW | RTLD_GLOBAL) + dlsym
#include "EPLoader.h"
#include "DynLibUtils.h"
// ORT C++ headers — included ONLY in this translation unit.
// ORT_API_MANUAL_INIT must be defined project-wide (Preprocessor Definitions)
// in every project that includes ORT headers, so all translation units see
// Ort::Global<void>::api_ as an extern rather than a default-constructed object.
#include <onnxruntime_cxx_api.h>
#include <algorithm>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
#else
# include <dlfcn.h>
#endif
namespace ANSCENTER {
// ── Static member definitions ────────────────────────────────────────────
#ifdef ANSLIBSLOADER_EXPORTS
std::mutex EPLoader::s_mutex;
bool EPLoader::s_initialized = false;
EPInfo EPLoader::s_info;
# ifdef _WIN32
std::string EPLoader::s_temp_ort_path;
std::string EPLoader::s_temp_dir;
# endif
#endif
// ── File-scope state ─────────────────────────────────────────────────────
#ifdef _WIN32
static HMODULE s_ort_module = nullptr;
#else
static void* s_ort_module = nullptr;
#endif
static const OrtApi* s_ort_api = nullptr;
// ════════════════════════════════════════════════════════════════════════
// File-scope helpers (anonymous namespace — not exported)
// ════════════════════════════════════════════════════════════════════════
namespace {
// ── GetOrtApi ────────────────────────────────────────────────────────
const OrtApi* GetOrtApi()
{
if (!s_ort_module)
throw std::runtime_error(
"[EPLoader] ORT DLL not loaded — call EPLoader::Current() first.");
if (s_ort_api)
return s_ort_api;
#ifdef _WIN32
using Fn = const OrtApiBase* (ORT_API_CALL*)();
auto fn = reinterpret_cast<Fn>(
GetProcAddress(s_ort_module, "OrtGetApiBase"));
#else
using Fn = const OrtApiBase* (ORT_API_CALL*)();
auto fn = reinterpret_cast<Fn>(
dlsym(s_ort_module, "OrtGetApiBase"));
#endif
if (!fn)
throw std::runtime_error(
"[EPLoader] OrtGetApiBase symbol not found in loaded ORT DLL.");
const OrtApiBase* base = fn();
if (!base)
throw std::runtime_error(
"[EPLoader] OrtGetApiBase() returned null.");
int dllMaxApi = ORT_API_VERSION;
{
const char* verStr = base->GetVersionString();
int major = 0, minor = 0;
if (verStr && sscanf(verStr, "%d.%d", &major, &minor) == 2)
dllMaxApi = minor;
}
int targetApi = std::min(ORT_API_VERSION, dllMaxApi);
const OrtApi* api = base->GetApi(targetApi);
if (!api)
throw std::runtime_error(
"[EPLoader] No compatible ORT API version found in loaded DLL.");
s_ort_api = api;
return s_ort_api;
}
} // anonymous namespace
// ════════════════════════════════════════════════════════════════════════
// EPLoader public / private methods
// ════════════════════════════════════════════════════════════════════════
const char* OrtDllName()
{
#ifdef _WIN32
return "onnxruntime.dll";
#elif defined(__APPLE__)
return "libonnxruntime.dylib";
#else
return "libonnxruntime.so";
#endif
}
const char* EPLoader::SubdirName(EngineType type)
{
switch (type) {
case EngineType::NVIDIA_GPU: return "cuda";
case EngineType::AMD_GPU: return "directml";
case EngineType::OPENVINO_GPU: return "openvino";
case EngineType::CPU: return "cpu";
default: return "cpu";
}
}
const char* EPLoader::EngineTypeName(EngineType type)
{
switch (type) {
case EngineType::NVIDIA_GPU: return "NVIDIA_GPU";
case EngineType::AMD_GPU: return "AMD_GPU";
case EngineType::OPENVINO_GPU: return "OPENVINO_GPU";
case EngineType::CPU: return "CPU";
case EngineType::AUTO_DETECT: return "AUTO_DETECT";
default: return "UNKNOWN";
}
}
/*static*/
std::string EPLoader::ResolveEPDir(const std::string& shared_dir,
EngineType type)
{
std::string ep_base = DynLib::JoinPath(shared_dir, "ep");
std::string subdir = DynLib::JoinPath(ep_base, SubdirName(type));
std::string dll_probe = DynLib::JoinPath(subdir, OrtDllName());
if (DynLib::FileExists(dll_probe)) {
std::cout << "[EPLoader] EP subdir found: " << subdir << std::endl;
return subdir;
}
std::string flat_probe = DynLib::JoinPath(shared_dir, OrtDllName());
if (DynLib::FileExists(flat_probe)) {
std::cout << "[EPLoader] EP subdir not found — "
"using flat Shared/ (backward compat): "
<< shared_dir << std::endl;
return shared_dir;
}
std::cerr << "[EPLoader] WARNING: " << OrtDllName() << " not found in:\n"
<< " " << subdir << "\n"
<< " " << shared_dir << "\n"
<< " LoadOrtDll will fail with a clear error."
<< std::endl;
return subdir;
}
EngineType EPLoader::AutoDetect()
{
std::cout << "[EPLoader] Auto-detecting hardware..." << std::endl;
ANSLicenseHelper helper;
EngineType detected = helper.CheckHardwareInformation();
std::cout << "[EPLoader] Detected: " << EngineTypeName(detected) << std::endl;
return detected;
}
/*static*/
const EPInfo& EPLoader::Initialize(const std::string& shared_dir,
EngineType preferred)
{
if (s_initialized) return s_info;
std::lock_guard<std::mutex> lock(s_mutex);
if (s_initialized) return s_info;
std::cout << "[EPLoader] Initializing..." << std::endl;
std::cout << "[EPLoader] Shared dir : " << shared_dir << std::endl;
std::cout << "[EPLoader] Preferred EP : " << EngineTypeName(preferred) << std::endl;
EngineType type = (preferred == EngineType::AUTO_DETECT)
? AutoDetect() : preferred;
std::string ep_dir = ResolveEPDir(shared_dir, type);
// When the EP lives in a subdirectory (e.g. ep/openvino/), provider
// DLLs may depend on runtime libraries that live in the parent
// shared_dir (e.g. openvino.dll). Inject shared_dir into the DLL
// search path so Windows can resolve those dependencies.
if (ep_dir != shared_dir)
DynLib::InjectDllSearchPath(shared_dir);
LoadOrtDll(ep_dir);
s_info.type = type;
s_info.libraryDir = ep_dir;
s_info.fromSubdir = (ep_dir != shared_dir);
s_initialized = true;
std::cout << "[EPLoader] Ready. EP=" << EngineTypeName(type)
<< " dir=" << ep_dir << std::endl;
return s_info;
}
/*static*/
const EPInfo& EPLoader::Current()
{
if (!s_initialized)
return Initialize(DEFAULT_SHARED_DIR, EngineType::AUTO_DETECT);
return s_info;
}
/*static*/
bool EPLoader::IsInitialized()
{
return s_initialized;
}
void* EPLoader::GetOrtApiRaw()
{
Current();
const OrtApi* api = GetOrtApi();
if (!api)
throw std::runtime_error(
"[EPLoader] GetOrtApiRaw: OrtApi not available.");
return static_cast<void*>(const_cast<OrtApi*>(api));
}
#ifdef _WIN32
// ── MakeTempDir ──────────────────────────────────────────────────────────
static std::string MakeTempDir()
{
char tmp[MAX_PATH] = {};
GetTempPathA(MAX_PATH, tmp);
std::string dir = std::string(tmp)
+ "anscenter_ort_"
+ std::to_string(GetCurrentProcessId());
CreateDirectoryA(dir.c_str(), nullptr);
return dir;
}
// ── CopyDirToTemp ─────────────────────────────────────────────────────────
static void CopyDirToTemp(const std::string& ep_dir,
const std::string& temp_dir)
{
std::string pattern = ep_dir + "\\*.dll";
WIN32_FIND_DATAA fd{};
HANDLE hFind = FindFirstFileA(pattern.c_str(), &fd);
if (hFind == INVALID_HANDLE_VALUE) {
std::cerr << "[EPLoader] WARNING: No DLLs found in ep_dir: "
<< ep_dir << std::endl;
return;
}
int copied = 0, skipped = 0;
do {
std::string src = ep_dir + "\\" + fd.cFileName;
std::string dst = temp_dir + "\\" + fd.cFileName;
if (CopyFileA(src.c_str(), dst.c_str(), /*bFailIfExists=*/FALSE)) {
++copied;
std::cout << "[EPLoader] copied: " << fd.cFileName << std::endl;
}
else {
DWORD err = GetLastError();
if (err != ERROR_FILE_EXISTS && err != ERROR_ALREADY_EXISTS) {
std::cerr << "[EPLoader] WARNING: could not copy "
<< fd.cFileName
<< " (err=" << err << ") — skipping." << std::endl;
}
++skipped;
}
} while (FindNextFileA(hFind, &fd));
FindClose(hFind);
std::cout << "[EPLoader] Staged " << copied << " DLL(s) to temp dir"
<< (skipped ? " (" + std::to_string(skipped) + " already present)" : "")
<< std::endl;
}
// ── DeleteTempDir ─────────────────────────────────────────────────────────
static void DeleteTempDir(const std::string& dir)
{
if (dir.empty()) return;
std::string pattern = dir + "\\*";
WIN32_FIND_DATAA fd{};
HANDLE hFind = FindFirstFileA(pattern.c_str(), &fd);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (strcmp(fd.cFileName, ".") == 0 ||
strcmp(fd.cFileName, "..") == 0) continue;
std::string f = dir + "\\" + fd.cFileName;
DeleteFileA(f.c_str());
} while (FindNextFileA(hFind, &fd));
FindClose(hFind);
}
RemoveDirectoryA(dir.c_str());
std::cout << "[EPLoader] Temp staging dir deleted: " << dir << std::endl;
}
#endif // _WIN32
// ── LoadOrtDll ───────────────────────────────────────────────────────────
void EPLoader::LoadOrtDll(const std::string& ep_dir)
{
if (s_ort_module) {
std::cout << "[EPLoader] ORT DLL already loaded — skipping." << std::endl;
return;
}
// Inject ep_dir into the DLL search path so cudart64_*.dll and other
// CUDA runtime DLLs that are NOT copied to temp are still found.
DynLib::InjectDllSearchPath(ep_dir);
std::string src_path = DynLib::JoinPath(ep_dir, OrtDllName());
std::cout << "[EPLoader] ORT source : " << src_path << std::endl;
#ifdef _WIN32
// ── Windows: stage ALL ep_dir DLLs into a process-unique temp folder ────
std::string temp_dir = MakeTempDir();
std::cout << "[EPLoader] Staging dir : " << temp_dir << std::endl;
CopyDirToTemp(ep_dir, temp_dir);
std::string ort_alias = temp_dir + "\\anscenter_ort_"
+ std::to_string(GetCurrentProcessId()) + ".dll";
std::string ort_in_temp = temp_dir + "\\" + OrtDllName();
if (!CopyFileA(ort_in_temp.c_str(), ort_alias.c_str(), /*bFailIfExists=*/FALSE)) {
DWORD err = GetLastError();
if (err != ERROR_FILE_EXISTS && err != ERROR_ALREADY_EXISTS) {
throw std::runtime_error(
"[EPLoader] Failed to create ORT alias in temp dir.\n"
" src : " + ort_in_temp + "\n"
" dst : " + ort_alias + "\n"
" err : " + std::to_string(err));
}
}
std::cout << "[EPLoader] ORT alias : " << ort_alias << std::endl;
DynLib::InjectDllSearchPath(temp_dir);
HMODULE hExisting = GetModuleHandleA("onnxruntime.dll");
if (hExisting) {
char existingPath[MAX_PATH] = {};
GetModuleFileNameA(hExisting, existingPath, MAX_PATH);
std::string existingStr(existingPath);
std::transform(existingStr.begin(), existingStr.end(),
existingStr.begin(), ::tolower);
if (existingStr.find("system32") != std::string::npos ||
existingStr.find("syswow64") != std::string::npos) {
std::cerr << "[EPLoader] WARNING: System ORT is resident ("
<< existingPath << ") - our alias overrides it." << std::endl;
}
}
// Safe UTF-8 → wide-string conversion (handles non-ASCII paths correctly)
int wlen = MultiByteToWideChar(CP_UTF8, 0, ort_alias.c_str(), -1, nullptr, 0);
std::wstring walias(static_cast<size_t>(wlen > 0 ? wlen - 1 : 0), L'\0');
if (wlen > 0)
MultiByteToWideChar(CP_UTF8, 0, ort_alias.c_str(), -1, walias.data(), wlen);
s_ort_module = LoadLibraryExW(
walias.c_str(),
nullptr,
LOAD_WITH_ALTERED_SEARCH_PATH);
if (!s_ort_module) {
DWORD err = GetLastError();
DeleteTempDir(temp_dir);
throw std::runtime_error(
"[EPLoader] LoadLibraryExW failed: " + ort_alias +
"\n Windows error code: " + std::to_string(err) +
"\n Ensure all CUDA runtime DLLs (cudart64_*.dll etc.)"
"\n exist in: " + ep_dir);
}
s_temp_ort_path = ort_alias;
s_temp_dir = temp_dir;
#else
// ── Linux / macOS ─────────────────────────────────────────────────────
s_ort_module = dlopen(src_path.c_str(), RTLD_NOW | RTLD_GLOBAL);
if (!s_ort_module) {
throw std::runtime_error(
std::string("[EPLoader] dlopen failed: ") + src_path +
"\n " + dlerror());
}
#endif
// ── Bootstrap ORT C++ API ─────────────────────────────────────────────
using OrtGetApiBase_fn = const OrtApiBase* (ORT_API_CALL*)();
#ifdef _WIN32
auto fn = reinterpret_cast<OrtGetApiBase_fn>(
GetProcAddress(s_ort_module, "OrtGetApiBase"));
#else
auto fn = reinterpret_cast<OrtGetApiBase_fn>(
dlsym(s_ort_module, "OrtGetApiBase"));
#endif
if (!fn)
throw std::runtime_error(
"[EPLoader] OrtGetApiBase not exported — is this a genuine onnxruntime build?\n"
" path: " + src_path);
const OrtApiBase* base = fn();
if (!base)
throw std::runtime_error(
"[EPLoader] OrtGetApiBase() returned null from: " + src_path);
// ── Version negotiation ───────────────────────────────────────────────
int dllMaxApi = ORT_API_VERSION;
{
const char* verStr = base->GetVersionString();
int major = 0, minor = 0;
if (verStr && sscanf(verStr, "%d.%d", &major, &minor) == 2)
dllMaxApi = minor;
}
int targetApi = std::min(ORT_API_VERSION, dllMaxApi);
if (targetApi < ORT_API_VERSION) {
std::cerr << "[EPLoader] WARNING: ORT DLL version "
<< base->GetVersionString()
<< " supports up to API " << dllMaxApi
<< " but headers expect API " << ORT_API_VERSION << ".\n"
<< " Using API " << targetApi
<< ". Consider upgrading onnxruntime.dll in ep/ to match SDK headers."
<< std::endl;
}
const OrtApi* api = base->GetApi(targetApi);
if (!api)
throw std::runtime_error(
"[EPLoader] GetApi(" + std::to_string(targetApi) +
") returned null — the DLL may be corrupt.");
s_ort_api = api;
Ort::Global<void>::api_ = api;
std::cout << "[EPLoader] ORT loaded successfully." << std::endl;
std::cout << "[EPLoader] ORT DLL version : " << base->GetVersionString() << std::endl;
std::cout << "[EPLoader] ORT header API : " << ORT_API_VERSION << std::endl;
std::cout << "[EPLoader] ORT active API : " << targetApi << std::endl;
}
// ── Shutdown ──────────────────────────────────────────────────────────────
void EPLoader::Shutdown()
{
std::lock_guard<std::mutex> lock(s_mutex);
if (s_ort_module) {
std::cout << "[EPLoader] Unloading ORT DLL..." << std::endl;
#ifdef _WIN32
FreeLibrary(s_ort_module);
if (!s_temp_dir.empty()) {
DeleteTempDir(s_temp_dir);
s_temp_dir.clear();
}
s_temp_ort_path.clear();
#else
dlclose(s_ort_module);
#endif
s_ort_module = nullptr;
}
s_ort_api = nullptr;
s_initialized = false;
s_info = EPInfo{};
std::cout << "[EPLoader] Shutdown complete." << std::endl;
}
} // namespace ANSCENTER

View File

@@ -0,0 +1,646 @@
// ============================================================================
// NvDynLoader.cpp
//
// Moved from TensorRTAPI/ to ANSLibsLoader/ for centralized library management.
// Now compiled into ANSLibsLoader.dll — all extern "C" stubs are exported via
// ANSLIBS_API so consuming projects can link ANSLibsLoader.lib instead of
// nvinfer_XX.lib / nvonnxparser_XX.lib.
//
// Two responsibilities:
//
// 1. Provide extern "C" stub DEFINITIONS for every symbol that TRT / ONNX
// parser inline wrappers reference. This satisfies the linker without
// linking nvinfer_XX.lib / nvonnxparser_XX.lib. Each stub forwards the
// call through a function pointer that Initialize() populates at runtime.
//
// 2. Implement NvDynLoader::Initialize() which searches for installed NVIDIA
// DLLs (trying multiple major versions, newest first) and binds all
// required function pointers.
// ============================================================================
#include "NvDynLoader.h"
#include "DynLibUtils.h"
#include <iostream>
#include <cassert>
#include <mutex>
using namespace ANSCENTER::DynLib;
// ─────────────────────────────────────────────────────────────────────────────
// Static member definitions
// ─────────────────────────────────────────────────────────────────────────────
bool NvDynLoader::s_initialized = false;
int NvDynLoader::s_trtMajor = 0;
std::string NvDynLoader::s_trtPath;
std::string NvDynLoader::s_onnxPath;
std::string NvDynLoader::s_cudaPath;
std::string NvDynLoader::s_cudnnPath;
LibHandle NvDynLoader::s_hTrt = nullptr;
LibHandle NvDynLoader::s_hOnnx = nullptr;
LibHandle NvDynLoader::s_hCuda = nullptr;
LibHandle NvDynLoader::s_hCudnn = nullptr;
NvDynLoader::PfnBuilder* NvDynLoader::pfn_createInferBuilder_INTERNAL = nullptr;
NvDynLoader::PfnRuntime* NvDynLoader::pfn_createInferRuntime_INTERNAL = nullptr;
NvDynLoader::PfnRefitter* NvDynLoader::pfn_createInferRefitter_INTERNAL = nullptr;
NvDynLoader::PfnParser* NvDynLoader::pfn_createNvOnnxParser_INTERNAL = nullptr;
NvDynLoader::PfnParserRefitter* NvDynLoader::pfn_createNvOnnxParserRefitter_INTERNAL = nullptr;
NvDynLoader::PfnGetParserVersion* NvDynLoader::pfn_getNvOnnxParserVersion = nullptr;
#ifdef NV_DYNAMIC_CUDA
cudaError_t (*NvDynLoader::pfn_cudaGetDeviceCount) (int*) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaSetDevice) (int) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaGetDeviceProperties) (cudaDeviceProp*, int) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaDeviceSetLimit) (cudaLimit, size_t) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaDeviceSynchronize) () = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaDeviceGetStreamPriorityRange)(int*, int*) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaMalloc) (void**, size_t) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaFree) (void*) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaMemset) (void*, int, size_t) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaMemGetInfo) (size_t*, size_t*) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaMemcpy) (void*, const void*, size_t, cudaMemcpyKind) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaMemcpyAsync) (void*, const void*, size_t, cudaMemcpyKind, cudaStream_t) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaStreamCreate) (cudaStream_t*) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaStreamCreateWithPriority) (cudaStream_t*, unsigned int, int) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaStreamDestroy) (cudaStream_t) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaStreamSynchronize) (cudaStream_t) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaStreamWaitEvent) (cudaStream_t, cudaEvent_t, unsigned int) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaEventCreate) (cudaEvent_t*) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaEventCreateWithFlags) (cudaEvent_t*, unsigned int) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaEventRecord) (cudaEvent_t, cudaStream_t) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaEventDestroy) (cudaEvent_t) = nullptr;
const char* (*NvDynLoader::pfn_cudaGetErrorString) (cudaError_t) = nullptr;
cudaError_t (*NvDynLoader::pfn_cudaGetLastError) () = nullptr;
#endif // NV_DYNAMIC_CUDA
// ─────────────────────────────────────────────────────────────────────────────
// extern "C" stubs (exported from ANSLibsLoader.dll via .def file)
//
// These provide the linker symbols that TRT / ONNX-parser inline wrappers
// reference. TENSORRTAPI / NVONNXPARSER_API are overridden to empty in
// NvDynLoader.h, so the NvInfer.h / NvOnnxParser.h declarations are plain
// extern "C" (no __declspec attribute). Our definitions below are also
// plain extern "C" — no __declspec attribute — so the linkage matches.
//
// The symbols are exported from the DLL via ANSLibsLoader.def, NOT via
// __declspec(dllexport). This avoids the C2375 "different linkage" error
// that occurs when NvInfer.h and our definitions carry different attributes.
// ─────────────────────────────────────────────────────────────────────────────
extern "C" {
void* createInferBuilder_INTERNAL(void* logger, int32_t version) noexcept
{
assert(NvDynLoader::pfn_createInferBuilder_INTERNAL &&
"NvDynLoader::Initialize() has not been called before the first TRT use.");
return NvDynLoader::pfn_createInferBuilder_INTERNAL(logger, version);
}
void* createInferRuntime_INTERNAL(void* logger, int32_t version) noexcept
{
assert(NvDynLoader::pfn_createInferRuntime_INTERNAL &&
"NvDynLoader::Initialize() has not been called before the first TRT use.");
return NvDynLoader::pfn_createInferRuntime_INTERNAL(logger, version);
}
// createInferRefitter_INTERNAL — only needed if engine refitting is used;
// guarded so a missing symbol is a no-op rather than an assert failure.
void* createInferRefitter_INTERNAL(void* engine, void* logger, int32_t version) noexcept
{
if (!NvDynLoader::pfn_createInferRefitter_INTERNAL) return nullptr;
return NvDynLoader::pfn_createInferRefitter_INTERNAL(engine, logger, version);
}
void* createNvOnnxParser_INTERNAL(void* network, void* logger, int32_t version) noexcept
{
assert(NvDynLoader::pfn_createNvOnnxParser_INTERNAL &&
"NvDynLoader::Initialize() has not been called before the first ONNX-parser use.");
return NvDynLoader::pfn_createNvOnnxParser_INTERNAL(network, logger, version);
}
// createNvOnnxParserRefitter_INTERNAL — TRT 10+ symbol; absent on TRT 8/9.
// Guarded rather than asserted so older TRT versions continue to work.
void* createNvOnnxParserRefitter_INTERNAL(void* refitter, void* logger, int32_t version) noexcept
{
if (!NvDynLoader::pfn_createNvOnnxParserRefitter_INTERNAL) return nullptr;
return NvDynLoader::pfn_createNvOnnxParserRefitter_INTERNAL(refitter, logger, version);
}
// getNvOnnxParserVersion — optional version query; returns 0 if not available.
int getNvOnnxParserVersion() noexcept
{
if (!NvDynLoader::pfn_getNvOnnxParserVersion) return 0;
return NvDynLoader::pfn_getNvOnnxParserVersion();
}
} // extern "C"
// ─────────────────────────────────────────────────────────────────────────────
// CUDA stubs (only when NV_DYNAMIC_CUDA is defined)
// Removes the cudart_static.lib dependency; CUDA RT is loaded dynamically.
//
// WHY extern "C":
// cuda_runtime.h wraps every public API in `extern "C"` when compiled as C++,
// giving each function C linkage (no name mangling). Our stub DEFINITIONS
// must use the same linkage — otherwise the linker sees a C-linkage declaration
// (from the header) paired with a C++-mangled definition (from our .cpp), which
// is an unresolved-symbol error on both MSVC and GCC/Clang.
//
// WHY cudaDeviceSynchronize / cudaGetLastError are NOT in the macro list:
// CUDA_STUB_N macros require at least one parameter. These two functions take
// zero arguments; they are defined manually in the block below. Do NOT add
// them back to the macro invocation list — it would create duplicate definitions.
// ─────────────────────────────────────────────────────────────────────────────
#ifdef NV_DYNAMIC_CUDA
extern "C" { // ← must match the extern "C" in cuda_runtime.h
#define CUDA_STUB_1(ret, name, t0, a0) \
ret name(t0 a0) { \
assert(NvDynLoader::pfn_##name); return NvDynLoader::pfn_##name(a0); }
#define CUDA_STUB_2(ret, name, t0,a0, t1,a1) \
ret name(t0 a0, t1 a1) { \
assert(NvDynLoader::pfn_##name); return NvDynLoader::pfn_##name(a0,a1); }
#define CUDA_STUB_3(ret, name, t0,a0, t1,a1, t2,a2) \
ret name(t0 a0, t1 a1, t2 a2) { \
assert(NvDynLoader::pfn_##name); return NvDynLoader::pfn_##name(a0,a1,a2); }
#define CUDA_STUB_4(ret, name, t0,a0, t1,a1, t2,a2, t3,a3) \
ret name(t0 a0, t1 a1, t2 a2, t3 a3) { \
assert(NvDynLoader::pfn_##name); return NvDynLoader::pfn_##name(a0,a1,a2,a3); }
#define CUDA_STUB_5(ret, name, t0,a0, t1,a1, t2,a2, t3,a3, t4,a4) \
ret name(t0 a0, t1 a1, t2 a2, t3 a3, t4 a4) { \
assert(NvDynLoader::pfn_##name); return NvDynLoader::pfn_##name(a0,a1,a2,a3,a4); }
CUDA_STUB_1(cudaError_t, cudaGetDeviceCount, int*, count)
CUDA_STUB_1(cudaError_t, cudaSetDevice, int, dev)
CUDA_STUB_2(cudaError_t, cudaGetDeviceProperties, cudaDeviceProp*, prop, int, dev)
CUDA_STUB_2(cudaError_t, cudaDeviceSetLimit, cudaLimit, limit, size_t, value)
CUDA_STUB_2(cudaError_t, cudaDeviceGetStreamPriorityRange, int*, leastPriority, int*, greatestPriority)
CUDA_STUB_2(cudaError_t, cudaMalloc, void**, devPtr, size_t, size)
CUDA_STUB_1(cudaError_t, cudaFree, void*, devPtr)
CUDA_STUB_3(cudaError_t, cudaMemset, void*, devPtr, int, value, size_t, count)
CUDA_STUB_2(cudaError_t, cudaMemGetInfo, size_t*, free, size_t*, total)
CUDA_STUB_4(cudaError_t, cudaMemcpy, void*, dst, const void*, src, size_t, count, cudaMemcpyKind, kind)
CUDA_STUB_5(cudaError_t, cudaMemcpyAsync, void*, dst, const void*, src, size_t, count, cudaMemcpyKind, kind, cudaStream_t, stream)
CUDA_STUB_1(cudaError_t, cudaStreamCreate, cudaStream_t*, stream)
CUDA_STUB_3(cudaError_t, cudaStreamCreateWithPriority, cudaStream_t*, stream, unsigned int, flags, int, priority)
CUDA_STUB_1(cudaError_t, cudaStreamDestroy, cudaStream_t, stream)
CUDA_STUB_1(cudaError_t, cudaStreamSynchronize, cudaStream_t, stream)
CUDA_STUB_3(cudaError_t, cudaStreamWaitEvent, cudaStream_t, stream, cudaEvent_t, event, unsigned int, flags)
CUDA_STUB_1(cudaError_t, cudaEventCreate, cudaEvent_t*, event)
CUDA_STUB_2(cudaError_t, cudaEventCreateWithFlags, cudaEvent_t*, event, unsigned int, flags)
CUDA_STUB_2(cudaError_t, cudaEventRecord, cudaEvent_t, event, cudaStream_t, stream)
CUDA_STUB_1(cudaError_t, cudaEventDestroy, cudaEvent_t, event)
CUDA_STUB_1(const char*, cudaGetErrorString, cudaError_t, error)
// 0-argument stubs — defined manually; NOT in the macro list above:
cudaError_t cudaDeviceSynchronize() {
assert(NvDynLoader::pfn_cudaDeviceSynchronize);
return NvDynLoader::pfn_cudaDeviceSynchronize();
}
cudaError_t cudaGetLastError() {
assert(NvDynLoader::pfn_cudaGetLastError);
return NvDynLoader::pfn_cudaGetLastError();
}
#undef CUDA_STUB_1
#undef CUDA_STUB_2
#undef CUDA_STUB_3
#undef CUDA_STUB_4
#undef CUDA_STUB_5
} // extern "C"
#endif // NV_DYNAMIC_CUDA
// ─────────────────────────────────────────────────────────────────────────────
// Helper — shared directory path with trailing separator
// ─────────────────────────────────────────────────────────────────────────────
static std::string SharedDirWithSep()
{
std::string dir = DEFAULT_SHARED_DIR;
#ifdef _WIN32
if (!dir.empty() && dir.back() != '\\') dir += '\\';
#else
if (!dir.empty() && dir.back() != '/') dir += '/';
#endif
return dir;
}
// ─────────────────────────────────────────────────────────────────────────────
// DLL candidate lists
// Priority 1 — ANSCENTER shared directory (full absolute path, newest first)
// Priority 2 — System PATH / LD_LIBRARY_PATH fallback (bare name, newest first)
// ─────────────────────────────────────────────────────────────────────────────
std::vector<std::string> NvDynLoader::TrtCandidates()
{
const std::string ansDir = SharedDirWithSep();
std::vector<std::string> v;
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
for (int major = 20; major >= 8; --major) {
#ifdef _WIN32
v.push_back(ansDir + "nvinfer_" + std::to_string(major) + ".dll");
#else
v.push_back(ansDir + "libnvinfer.so." + std::to_string(major));
#endif
}
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
for (int major = 20; major >= 8; --major) {
#ifdef _WIN32
v.push_back("nvinfer_" + std::to_string(major) + ".dll");
#else
v.push_back("libnvinfer.so." + std::to_string(major));
#endif
}
return v;
}
std::vector<std::string> NvDynLoader::OnnxCandidates()
{
const std::string ansDir = SharedDirWithSep();
std::vector<std::string> v;
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
for (int major = 20; major >= 8; --major) {
#ifdef _WIN32
v.push_back(ansDir + "nvonnxparser_" + std::to_string(major) + ".dll");
#else
v.push_back(ansDir + "libnvonnxparser.so." + std::to_string(major));
#endif
}
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
for (int major = 20; major >= 8; --major) {
#ifdef _WIN32
v.push_back("nvonnxparser_" + std::to_string(major) + ".dll");
#else
v.push_back("libnvonnxparser.so." + std::to_string(major));
#endif
}
return v;
}
std::vector<std::string> NvDynLoader::CudnnCandidates()
{
const std::string ansDir = SharedDirWithSep();
std::vector<std::string> v;
// ── cuDNN DLL/SO naming conventions ───────────────────────────────────────
// Windows: cudnn64_<major>.dll (e.g. cudnn64_8.dll, cudnn64_9.dll)
// Linux: libcudnn.so.<major> (e.g. libcudnn.so.8, libcudnn.so.9)
//
// Note: cuDNN 9 on Windows ships as multiple split DLLs
// (cudnn_ops.dll, cudnn_cnn.dll, etc.) but cudnn64_9.dll remains the
// main entry-point / compatibility shim. The split DLLs are resolved
// automatically once the ANSCENTER directory is added to the search path
// via LOAD_WITH_ALTERED_SEARCH_PATH (Windows) or RTLD_GLOBAL (Linux).
//
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
for (int major = 12; major >= 7; --major) {
#ifdef _WIN32
v.push_back(ansDir + "cudnn64_" + std::to_string(major) + ".dll");
#else
v.push_back(ansDir + "libcudnn.so." + std::to_string(major));
#endif
}
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
for (int major = 12; major >= 7; --major) {
#ifdef _WIN32
v.push_back("cudnn64_" + std::to_string(major) + ".dll");
#else
v.push_back("libcudnn.so." + std::to_string(major));
#endif
}
return v;
}
#ifdef NV_DYNAMIC_CUDA
std::vector<std::string> NvDynLoader::CudaRtCandidates()
{
const std::string ansDir = SharedDirWithSep();
std::vector<std::string> v;
// ── CUDA runtime DLL/SO naming conventions ────────────────────────────────
//
// Windows — NVIDIA changed naming at CUDA 12:
// CUDA 11.x : cudart64_110.dll … cudart64_118.dll (major + minor digit)
// CUDA 12+ : cudart64_12.dll, cudart64_13.dll … (major-only)
//
// Linux — major-only symlink is the stable name on all versions:
// libcudart.so.11, libcudart.so.12, libcudart.so.13 …
// (major.minor symlinks also tried as fallback for CUDA 11.x)
//
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
#ifdef _WIN32
for (int major = 15; major >= 12; --major) // CUDA 12+ : major-only
v.push_back(ansDir + "cudart64_" + std::to_string(major) + ".dll");
for (int minor = 9; minor >= 0; --minor) // CUDA 11.x: major+minor
v.push_back(ansDir + "cudart64_11" + std::to_string(minor) + ".dll");
v.push_back(ansDir + "cudart64.dll"); // non-versioned alias
#else
for (int major = 15; major >= 11; --major) // all versions: major-only
v.push_back(ansDir + "libcudart.so." + std::to_string(major));
for (int minor = 9; minor >= 0; --minor) // CUDA 11.x: major.minor fallback
v.push_back(ansDir + "libcudart.so.11." + std::to_string(minor));
#endif
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
#ifdef _WIN32
for (int major = 15; major >= 12; --major)
v.push_back("cudart64_" + std::to_string(major) + ".dll");
for (int minor = 9; minor >= 0; --minor)
v.push_back("cudart64_11" + std::to_string(minor) + ".dll");
v.push_back("cudart64.dll");
#else
for (int major = 15; major >= 11; --major)
v.push_back("libcudart.so." + std::to_string(major));
for (int minor = 9; minor >= 0; --minor)
v.push_back("libcudart.so.11." + std::to_string(minor));
#endif
return v;
}
#endif
// ─────────────────────────────────────────────────────────────────────────────
// Initialize
// ─────────────────────────────────────────────────────────────────────────────
static std::mutex g_initMutex;
bool NvDynLoader::Initialize(bool verbose)
{
std::lock_guard<std::mutex> lock(g_initMutex);
if (s_initialized) return true;
const std::string ansDir = SharedDirWithSep();
// If a previous Initialize() call partially loaded some libraries before
// failing (s_initialized stays false but handles may be non-null), release
// them now so we can retry cleanly without leaking handles.
if (s_hOnnx) { FreeLib(s_hOnnx); s_hOnnx = nullptr; }
if (s_hTrt) { FreeLib(s_hTrt); s_hTrt = nullptr; }
if (s_hCudnn) { FreeLib(s_hCudnn); s_hCudnn = nullptr; }
#ifdef NV_DYNAMIC_CUDA
if (s_hCuda) { FreeLib(s_hCuda); s_hCuda = nullptr; }
#endif
bool ok = true;
if (verbose) {
std::cout << "==================================================" << std::endl;
std::cout << "NvDynLoader: discovering NVIDIA libraries..." << std::endl;
std::cout << " Shared dir : " << ansDir << std::endl;
std::cout << "==================================================" << std::endl;
}
// ── STEP 1: CUDA Runtime (NV_DYNAMIC_CUDA only) ───────────────────────────
// Loaded first so cuDNN and TRT find CUDA symbols already resident in the
// process image when they are opened.
// Linux: globalLoad=true (RTLD_GLOBAL) makes cudart symbols process-wide.
// Windows: LoadLibraryExA is always process-global; globalLoad is a no-op.
#ifdef NV_DYNAMIC_CUDA
s_hCuda = FindAndLoad(CudaRtCandidates(), s_cudaPath, verbose, /*globalLoad=*/true);
if (!s_hCuda) {
std::cout << "NvDynLoader ERROR: No CUDA runtime DLL found. "
"Searched " << ansDir << " and system PATH." << std::endl;
ok = false;
} else {
bool b = true;
b &= Bind(s_hCuda, "cudaGetDeviceCount", pfn_cudaGetDeviceCount);
b &= Bind(s_hCuda, "cudaSetDevice", pfn_cudaSetDevice);
// cudaGetDeviceProperties: CUDA 12 renamed the export to '_v2'; CUDA 11
// uses the plain name. Try the CUDA 12+ symbol first, fall back to
// the CUDA 11 name. IMPORTANT: do NOT `b &=` the first attempt before
// the fallback — that would set b=false on CUDA 11 even though the
// plain-name fallback succeeds, causing a spurious init failure.
Bind(s_hCuda, "cudaGetDeviceProperties_v2", pfn_cudaGetDeviceProperties); // CUDA 12+
if (!pfn_cudaGetDeviceProperties)
Bind(s_hCuda, "cudaGetDeviceProperties", pfn_cudaGetDeviceProperties); // CUDA 11
b &= (pfn_cudaGetDeviceProperties != nullptr);
b &= Bind(s_hCuda, "cudaDeviceSetLimit", pfn_cudaDeviceSetLimit);
b &= Bind(s_hCuda, "cudaDeviceSynchronize", pfn_cudaDeviceSynchronize);
b &= Bind(s_hCuda, "cudaDeviceGetStreamPriorityRange", pfn_cudaDeviceGetStreamPriorityRange);
b &= Bind(s_hCuda, "cudaMalloc", pfn_cudaMalloc);
b &= Bind(s_hCuda, "cudaFree", pfn_cudaFree);
b &= Bind(s_hCuda, "cudaMemset", pfn_cudaMemset);
b &= Bind(s_hCuda, "cudaMemGetInfo", pfn_cudaMemGetInfo);
b &= Bind(s_hCuda, "cudaMemcpy", pfn_cudaMemcpy);
b &= Bind(s_hCuda, "cudaMemcpyAsync", pfn_cudaMemcpyAsync);
b &= Bind(s_hCuda, "cudaStreamCreate", pfn_cudaStreamCreate);
b &= Bind(s_hCuda, "cudaStreamCreateWithPriority", pfn_cudaStreamCreateWithPriority);
b &= Bind(s_hCuda, "cudaStreamDestroy", pfn_cudaStreamDestroy);
b &= Bind(s_hCuda, "cudaStreamSynchronize", pfn_cudaStreamSynchronize);
b &= Bind(s_hCuda, "cudaStreamWaitEvent", pfn_cudaStreamWaitEvent);
b &= Bind(s_hCuda, "cudaEventCreate", pfn_cudaEventCreate);
b &= Bind(s_hCuda, "cudaEventCreateWithFlags", pfn_cudaEventCreateWithFlags);
b &= Bind(s_hCuda, "cudaEventRecord", pfn_cudaEventRecord);
b &= Bind(s_hCuda, "cudaEventDestroy", pfn_cudaEventDestroy);
b &= Bind(s_hCuda, "cudaGetErrorString", pfn_cudaGetErrorString);
b &= Bind(s_hCuda, "cudaGetLastError", pfn_cudaGetLastError);
if (!b) {
std::cout << "NvDynLoader ERROR: One or more CUDA entry points not found in "
<< s_cudaPath << std::endl;
ok = false;
}
}
#endif // NV_DYNAMIC_CUDA
// ── STEP 2: cuDNN pre-load ────────────────────────────────────────────────
// Must be loaded BEFORE TRT so the OS can resolve TRT's cuDNN dependency:
//
// Windows LoadLibraryExA + LOAD_WITH_ALTERED_SEARCH_PATH causes Windows
// to use the DLL's own directory when resolving its transitive
// dependencies. Pre-loading cuDNN from ANSCENTER dir also puts
// it in the process DLL table so TRT's import loader finds it.
//
// Linux RTLD_GLOBAL exports cuDNN symbols process-wide so TRT's
// DT_NEEDED resolution succeeds without LD_LIBRARY_PATH changes.
// cuDNN 9 also ships split DLLs (libcudnn_ops.so.9, etc.); those
// are found automatically once libcudnn.so.9 is globally loaded.
//
// Not finding cuDNN is a WARNING, not a fatal error — TRT may still locate
// it via LD_LIBRARY_PATH / system PATH at load time.
s_hCudnn = FindAndLoad(CudnnCandidates(), s_cudnnPath, verbose, /*globalLoad=*/true);
if (!s_hCudnn && verbose) {
std::cout << "NvDynLoader: WARNING — cuDNN not found in " << ansDir
<< "; TRT will search system PATH / LD_LIBRARY_PATH." << std::endl;
}
// ── STEP 3: TensorRT core ─────────────────────────────────────────────────
s_hTrt = FindAndLoad(TrtCandidates(), s_trtPath, verbose);
if (!s_hTrt) {
std::cout << "NvDynLoader ERROR: No TensorRT DLL found. "
"Searched " << ansDir << " and system PATH." << std::endl;
ok = false;
} else {
// Extract major version from the loaded library path.
// Windows : "C:\...\nvinfer_10.dll" → digits between last '_' and last '.'
// Linux : ".../libnvinfer.so.10" → digits after last '.'
#ifdef _WIN32
{
const size_t under = s_trtPath.find_last_of('_');
const size_t dot = s_trtPath.find_last_of('.');
if (under != std::string::npos && dot != std::string::npos && dot > under) {
try { s_trtMajor = std::stoi(s_trtPath.substr(under + 1, dot - under - 1)); }
catch (...) { /* non-numeric — leave s_trtMajor at 0 */ }
}
}
#else
{
const size_t dot = s_trtPath.find_last_of('.');
if (dot != std::string::npos && dot + 1 < s_trtPath.size()) {
try { s_trtMajor = std::stoi(s_trtPath.substr(dot + 1)); }
catch (...) { /* non-numeric — leave s_trtMajor at 0 */ }
}
}
#endif
bool b = true;
b &= Bind(s_hTrt, "createInferBuilder_INTERNAL", pfn_createInferBuilder_INTERNAL);
b &= Bind(s_hTrt, "createInferRuntime_INTERNAL", pfn_createInferRuntime_INTERNAL);
Bind(s_hTrt, "createInferRefitter_INTERNAL", pfn_createInferRefitter_INTERNAL); // optional
if (!b) {
std::cout << "NvDynLoader ERROR: Required TRT entry points not found in "
<< s_trtPath << std::endl;
ok = false;
} else if (verbose) {
std::cout << "NvDynLoader: TRT major version = " << s_trtMajor << std::endl;
}
}
// ── STEP 4: ONNX parser ───────────────────────────────────────────────────
s_hOnnx = FindAndLoad(OnnxCandidates(), s_onnxPath, verbose);
if (!s_hOnnx) {
std::cout << "NvDynLoader ERROR: No nvonnxparser DLL found. "
"Searched " << ansDir << " and system PATH." << std::endl;
ok = false;
} else {
if (!Bind(s_hOnnx, "createNvOnnxParser_INTERNAL", pfn_createNvOnnxParser_INTERNAL)) {
std::cout << "NvDynLoader ERROR: createNvOnnxParser_INTERNAL not found in "
<< s_onnxPath << std::endl;
ok = false;
} else {
// TRT 10+ optional symbols — absent on TRT 8/9; missing is not an error.
Bind(s_hOnnx, "createNvOnnxParserRefitter_INTERNAL", pfn_createNvOnnxParserRefitter_INTERNAL);
Bind(s_hOnnx, "getNvOnnxParserVersion", pfn_getNvOnnxParserVersion);
// Cross-check: TRT and ONNX-parser must share the same major version.
// Mismatched majors (e.g. nvinfer_10 + nvonnxparser_11) compile fine
// but crash at runtime when the ONNX parser tries to populate a TRT
// network object built by a different major version.
int onnxMajor = 0;
#ifdef _WIN32
{
const size_t under = s_onnxPath.find_last_of('_');
const size_t dot = s_onnxPath.find_last_of('.');
if (under != std::string::npos && dot != std::string::npos && dot > under)
try { onnxMajor = std::stoi(s_onnxPath.substr(under + 1, dot - under - 1)); }
catch (...) {}
}
#else
{
const size_t dot = s_onnxPath.find_last_of('.');
if (dot != std::string::npos && dot + 1 < s_onnxPath.size())
try { onnxMajor = std::stoi(s_onnxPath.substr(dot + 1)); }
catch (...) {}
}
#endif
if (onnxMajor > 0 && s_trtMajor > 0 && onnxMajor != s_trtMajor) {
std::cout << "NvDynLoader ERROR: TRT major version (" << s_trtMajor
<< ") != ONNX-parser major version (" << onnxMajor << ").\n"
<< " TRT : " << s_trtPath << "\n"
<< " ONNX : " << s_onnxPath << "\n"
<< " Replace both DLLs with matching versions in "
<< ansDir << std::endl;
ok = false;
} else if (verbose && onnxMajor > 0) {
std::cout << "NvDynLoader: ONNX-parser major version = " << onnxMajor << std::endl;
}
}
}
s_initialized = ok;
if (verbose) {
std::cout << "NvDynLoader: "
<< (ok ? "initialised successfully." : "FAILED — check errors above.")
<< std::endl;
std::cout << "==================================================" << std::endl;
}
return ok;
}
// ─────────────────────────────────────────────────────────────────────────────
// Shutdown
// ─────────────────────────────────────────────────────────────────────────────
void NvDynLoader::Shutdown()
{
std::lock_guard<std::mutex> lock(g_initMutex);
// NOTE: No early-return guard on s_initialized here.
//
// Shutdown() must always release whatever handles are currently open,
// including handles left behind by a *partially*-successful Initialize()
// call (where s_initialized == false but some DLLs were already opened).
// Every FreeLib call is guarded by if(h), so this function is safe to call
// on a fully- or partially-initialised instance, and also safe to call
// multiple times (idempotent).
// ── Null all entry-point pointers first ───────────────────────────────────
// Prevents stubs from jumping into freed library memory in the window
// between Shutdown() and a subsequent Initialize() call.
pfn_createInferBuilder_INTERNAL = nullptr;
pfn_createInferRuntime_INTERNAL = nullptr;
pfn_createInferRefitter_INTERNAL = nullptr;
pfn_createNvOnnxParser_INTERNAL = nullptr;
pfn_createNvOnnxParserRefitter_INTERNAL = nullptr;
pfn_getNvOnnxParserVersion = nullptr;
#ifdef NV_DYNAMIC_CUDA
// Null every CUDA function pointer so the assert() in each stub fires
// immediately if a CUDA call is made after Shutdown() without a new
// Initialize(), rather than silently calling into freed DLL memory.
pfn_cudaGetDeviceCount = nullptr;
pfn_cudaSetDevice = nullptr;
pfn_cudaGetDeviceProperties = nullptr;
pfn_cudaDeviceSetLimit = nullptr;
pfn_cudaDeviceSynchronize = nullptr;
pfn_cudaDeviceGetStreamPriorityRange = nullptr;
pfn_cudaMalloc = nullptr;
pfn_cudaFree = nullptr;
pfn_cudaMemset = nullptr;
pfn_cudaMemGetInfo = nullptr;
pfn_cudaMemcpy = nullptr;
pfn_cudaMemcpyAsync = nullptr;
pfn_cudaStreamCreate = nullptr;
pfn_cudaStreamCreateWithPriority = nullptr;
pfn_cudaStreamDestroy = nullptr;
pfn_cudaStreamSynchronize = nullptr;
pfn_cudaStreamWaitEvent = nullptr;
pfn_cudaEventCreate = nullptr;
pfn_cudaEventCreateWithFlags = nullptr;
pfn_cudaEventRecord = nullptr;
pfn_cudaEventDestroy = nullptr;
pfn_cudaGetErrorString = nullptr;
pfn_cudaGetLastError = nullptr;
#endif // NV_DYNAMIC_CUDA
// ── Release handles in reverse load order ─────────────────────────────────
// ONNX parser → depends on TRT
// TRT → depends on cuDNN + CUDA RT
// cuDNN → depends on CUDA RT
// CUDA RT → base dependency
if (s_hOnnx) { FreeLib(s_hOnnx); s_hOnnx = nullptr; }
if (s_hTrt) { FreeLib(s_hTrt); s_hTrt = nullptr; }
if (s_hCudnn) { FreeLib(s_hCudnn); s_hCudnn = nullptr; }
#ifdef NV_DYNAMIC_CUDA
if (s_hCuda) { FreeLib(s_hCuda); s_hCuda = nullptr; }
#endif
// ── Reset version / path state ────────────────────────────────────────────
// A subsequent Initialize() call will re-discover fresh paths and versions.
s_trtMajor = 0;
s_trtPath.clear();
s_onnxPath.clear();
s_cudaPath.clear();
s_cudnnPath.clear();
s_initialized = false;
}

View File

@@ -0,0 +1,252 @@
// ============================================================================
// OvLoader.cpp — OpenVINO DLL discovery and pre-loading
//
// Loading order (dependency chain):
// 1. Intel TBB (tbb12.dll / tbbmalloc.dll) — required by openvino.dll
// 2. openvino.dll — core runtime
// 3. openvino_c.dll — C API (optional, version query)
//
// Plugins (openvino_intel_cpu_plugin, openvino_intel_gpu_plugin, etc.) and
// frontends (openvino_ir_frontend, openvino_onnx_frontend, etc.) are loaded
// on-demand by OpenVINO's internal plugin system. They are discovered
// automatically because the shared directory is injected into the DLL
// search path by ANSLibsLoader before OvLoader::Initialize() runs.
// ============================================================================
#include "OvLoader.h"
#include "DynLibUtils.h"
#include <iostream>
#include <mutex>
using namespace ANSCENTER::DynLib;
// ─────────────────────────────────────────────────────────────────────────────
// Static member definitions
// ─────────────────────────────────────────────────────────────────────────────
std::mutex OvLoader::s_mutex;
bool OvLoader::s_initialized = false;
OvInfo OvLoader::s_info;
LibHandle OvLoader::s_hTbb = nullptr;
LibHandle OvLoader::s_hTbbMalloc = nullptr;
LibHandle OvLoader::s_hOvCore = nullptr;
LibHandle OvLoader::s_hOvC = nullptr;
// ─────────────────────────────────────────────────────────────────────────────
// Candidate lists — search ANSCENTER shared dir first, then system PATH
// ─────────────────────────────────────────────────────────────────────────────
std::vector<std::string> OvLoader::TbbCandidates(const std::string& shared_dir)
{
std::vector<std::string> v;
// ── Priority 1: ANSCENTER shared directory ────────────────────────────────
#ifdef _WIN32
v.push_back(JoinPath(shared_dir, "tbb12.dll"));
v.push_back(JoinPath(shared_dir, "tbb.dll"));
#else
v.push_back(JoinPath(shared_dir, "libtbb.so.12"));
v.push_back(JoinPath(shared_dir, "libtbb.so.2"));
v.push_back(JoinPath(shared_dir, "libtbb.so"));
#endif
// ── Priority 2: System PATH / LD_LIBRARY_PATH ─────────────────────────────
#ifdef _WIN32
v.push_back("tbb12.dll");
v.push_back("tbb.dll");
#else
v.push_back("libtbb.so.12");
v.push_back("libtbb.so.2");
v.push_back("libtbb.so");
#endif
return v;
}
std::vector<std::string> OvLoader::TbbMallocCandidates(const std::string& shared_dir)
{
std::vector<std::string> v;
#ifdef _WIN32
v.push_back(JoinPath(shared_dir, "tbbmalloc.dll"));
v.push_back("tbbmalloc.dll");
#else
v.push_back(JoinPath(shared_dir, "libtbbmalloc.so.2"));
v.push_back(JoinPath(shared_dir, "libtbbmalloc.so"));
v.push_back("libtbbmalloc.so.2");
v.push_back("libtbbmalloc.so");
#endif
return v;
}
std::vector<std::string> OvLoader::OvCoreCandidates(const std::string& shared_dir)
{
std::vector<std::string> v;
#ifdef _WIN32
v.push_back(JoinPath(shared_dir, "openvino.dll"));
v.push_back("openvino.dll");
#else
v.push_back(JoinPath(shared_dir, "libopenvino.so"));
v.push_back("libopenvino.so");
#endif
return v;
}
std::vector<std::string> OvLoader::OvCApiCandidates(const std::string& shared_dir)
{
std::vector<std::string> v;
#ifdef _WIN32
v.push_back(JoinPath(shared_dir, "openvino_c.dll"));
v.push_back("openvino_c.dll");
#else
v.push_back(JoinPath(shared_dir, "libopenvino_c.so"));
v.push_back("libopenvino_c.so");
#endif
return v;
}
// ─────────────────────────────────────────────────────────────────────────────
// Version extraction via OpenVINO C API
//
// The C API exports ov_get_openvino_version() which fills an ov_version_t
// struct with a buildNumber string (e.g. "2024.6.0-17404-4c0f47d2335").
// We replicate the struct layout locally to avoid including OpenVINO headers.
// ─────────────────────────────────────────────────────────────────────────────
std::string OvLoader::TryGetVersion(LibHandle hOvC)
{
if (!hOvC) return {};
// Replicate the ov_version_t layout from openvino/c/ov_common.h
struct ov_version_local {
const char* buildNumber;
const char* description;
};
using fn_get_version = int (*)(ov_version_local*);
using fn_free_version = void (*)(ov_version_local*);
fn_get_version pfnGet = nullptr;
fn_free_version pfnFree = nullptr;
Bind(hOvC, "ov_get_openvino_version", pfnGet);
Bind(hOvC, "ov_version_free", pfnFree);
if (!pfnGet) return {};
ov_version_local ver = {};
if (pfnGet(&ver) == 0 && ver.buildNumber) {
std::string result = ver.buildNumber;
if (pfnFree) pfnFree(&ver);
return result;
}
return {};
}
// ─────────────────────────────────────────────────────────────────────────────
// Initialize
// ─────────────────────────────────────────────────────────────────────────────
const OvInfo& OvLoader::Initialize(const std::string& shared_dir, bool verbose)
{
std::lock_guard<std::mutex> lock(s_mutex);
if (s_initialized) return s_info;
// Clean up any partially-loaded handles from a previous failed attempt
if (s_hOvC) { FreeLib(s_hOvC); s_hOvC = nullptr; }
if (s_hOvCore) { FreeLib(s_hOvCore); s_hOvCore = nullptr; }
if (s_hTbbMalloc) { FreeLib(s_hTbbMalloc); s_hTbbMalloc = nullptr; }
if (s_hTbb) { FreeLib(s_hTbb); s_hTbb = nullptr; }
if (verbose) {
std::cout << "==================================================" << std::endl;
std::cout << "[OvLoader] Discovering OpenVINO libraries..." << std::endl;
std::cout << " Shared dir : " << shared_dir << std::endl;
std::cout << "==================================================" << std::endl;
}
// ── STEP 1: Inject shared dir into search path ───────────────────────────
// Ensures plugins/frontends are discoverable by OpenVINO's internal loader.
InjectDllSearchPath(shared_dir);
// ── STEP 2: Pre-load Intel TBB (dependency of openvino.dll) ──────────────
std::string tbbPath;
s_hTbb = FindAndLoad(TbbCandidates(shared_dir), tbbPath, verbose);
if (s_hTbb) {
if (verbose)
std::cout << "[OvLoader] TBB loaded: " << tbbPath << std::endl;
} else if (verbose) {
std::cout << "[OvLoader] WARNING: TBB not found "
<< "(openvino.dll may fail to load)." << std::endl;
}
std::string tbbMallocPath;
s_hTbbMalloc = FindAndLoad(TbbMallocCandidates(shared_dir),
tbbMallocPath, verbose);
if (!s_hTbbMalloc && verbose) {
std::cout << "[OvLoader] tbbmalloc not found (optional)." << std::endl;
}
// ── STEP 3: Pre-load openvino.dll (core runtime) ─────────────────────────
std::string corePath;
s_hOvCore = FindAndLoad(OvCoreCandidates(shared_dir), corePath, verbose);
if (s_hOvCore) {
s_info.dllPath = corePath;
s_info.loaded = true;
if (verbose)
std::cout << "[OvLoader] OpenVINO core loaded: " << corePath
<< std::endl;
} else {
std::cout << "[OvLoader] WARNING: openvino.dll not found in "
<< shared_dir << " or system PATH." << std::endl;
std::cout << "[OvLoader] OpenVINO will rely on import-lib resolution "
<< "at load time." << std::endl;
}
// ── STEP 4: Pre-load openvino_c.dll + query version ──────────────────────
std::string cApiPath;
s_hOvC = FindAndLoad(OvCApiCandidates(shared_dir), cApiPath, verbose);
if (s_hOvC) {
s_info.version = TryGetVersion(s_hOvC);
if (!s_info.version.empty() && verbose) {
std::cout << "[OvLoader] OpenVINO version = " << s_info.version
<< std::endl;
}
} else if (verbose) {
std::cout << "[OvLoader] openvino_c.dll not found "
<< "(version detection skipped)." << std::endl;
}
s_initialized = true;
if (verbose) {
std::cout << "[OvLoader] "
<< (s_info.loaded
? "initialised successfully."
: "WARNING — openvino.dll not pre-loaded.")
<< std::endl;
std::cout << "==================================================" << std::endl;
}
return s_info;
}
// ─────────────────────────────────────────────────────────────────────────────
// Shutdown
// ─────────────────────────────────────────────────────────────────────────────
void OvLoader::Shutdown()
{
std::lock_guard<std::mutex> lock(s_mutex);
// Release in reverse load order
if (s_hOvC) { FreeLib(s_hOvC); s_hOvC = nullptr; }
if (s_hOvCore) { FreeLib(s_hOvCore); s_hOvCore = nullptr; }
if (s_hTbbMalloc) { FreeLib(s_hTbbMalloc); s_hTbbMalloc = nullptr; }
if (s_hTbb) { FreeLib(s_hTbb); s_hTbb = nullptr; }
s_info = OvInfo{};
s_initialized = false;
}

View File

@@ -0,0 +1,23 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#define NOMINMAX // Prevent windows.h from defining min/max macros
#include <windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

View File

@@ -0,0 +1,5 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>

View File

@@ -0,0 +1,89 @@
#pragma once
#ifndef ANSLIBSLOADER_H
#define ANSLIBSLOADER_H
// ============================================================================
// ANSLibsLoader — Centralized dynamic library loader for ANSCENTER
//
// Consolidates all runtime DLL loading:
// - ONNX Runtime (via EPLoader)
// - TensorRT / cuDNN / CUDA (via NvDynLoader)
// - OpenCV (via CvLoader)
// - OpenVINO + TBB (via OvLoader)
//
// USAGE
// -----
// // At application startup:
// ANSCENTER::ANSLibsLoader::Initialize();
//
// // At application exit (after all engine objects are destroyed):
// ANSCENTER::ANSLibsLoader::Shutdown();
//
// EXPORT MACRO
// ------------
// ANSLIBS_API replaces both ANSCORE_API and ENGINE_API for loader classes.
// Define ANSLIBSLOADER_EXPORTS when building ANSLibsLoader.dll.
// All other projects importing from ANSLibsLoader get __declspec(dllimport).
// ============================================================================
#ifdef _WIN32
# ifdef ANSLIBSLOADER_EXPORTS
# define ANSLIBS_API __declspec(dllexport)
# else
# define ANSLIBS_API __declspec(dllimport)
# endif
#else
# define ANSLIBS_API
#endif
#include "ANSLicense.h" // for ANSCENTER::EngineType enum
#include <string>
namespace ANSCENTER {
class ANSLIBS_API ANSLibsLoader
{
public:
// ── Platform defaults ────────────────────────────────────────────────
#ifdef _WIN32
static constexpr const char* DEFAULT_SHARED_DIR =
"C:\\ProgramData\\ANSCENTER\\Shared";
#else
static constexpr const char* DEFAULT_SHARED_DIR =
"/opt/anscenter/shared";
#endif
// ── Master initialization ────────────────────────────────────────────
/// Calls all sub-loaders in the correct order:
/// 1. Injects shared_dir into DLL search path
/// 2. CvLoader — pre-loads OpenCV
/// 3. OvLoader — pre-loads OpenVINO + TBB
/// 4. NvDynLoader — loads TRT / cuDNN / CUDA (if NVIDIA)
/// 5. EPLoader — loads ONNX Runtime with selected EP
///
/// Thread-safe. Subsequent calls are no-ops.
static void Initialize(
const std::string& shared_dir = DEFAULT_SHARED_DIR,
EngineType preferred = EngineType::AUTO_DETECT);
// ── Master shutdown ──────────────────────────────────────────────────
/// Shuts down all sub-loaders in reverse order.
/// Must be called AFTER all engine/session objects are destroyed.
/// Safe to call multiple times.
static void Shutdown();
// ── Status ───────────────────────────────────────────────────────────
[[nodiscard]] static bool IsInitialized();
// ── Non-copyable / non-movable ───────────────────────────────────────
ANSLibsLoader() = delete;
ANSLibsLoader(const ANSLibsLoader&) = delete;
ANSLibsLoader& operator=(const ANSLibsLoader&) = delete;
private:
static bool s_initialized;
};
} // namespace ANSCENTER
#endif // ANSLIBSLOADER_H

View File

@@ -0,0 +1,62 @@
#pragma once
// ============================================================================
// CvLoader -- Runtime discovery and pre-loading of OpenCV DLLs
//
// OpenCV is normally import-linked (opencv_world4130.lib), but the DLLs
// must be discoverable at process load time. CvLoader ensures the correct
// DLL is found by:
// 1. Searching the ANSCENTER shared directory for versioned candidates
// 2. Injecting the directory into the DLL search path
// 3. Pre-loading the DLL so dependent modules resolve it correctly
//
// Companion modules (opencv_img_hash, opencv_videoio_ffmpeg) are also
// pre-loaded when found alongside the main opencv_world DLL.
// ============================================================================
#include "ANSLibsLoader.h" // ANSLIBS_API
#include "DynLibUtils.h" // LibHandle
#include <string>
#include <vector>
#include <mutex>
// ============================================================================
struct ANSLIBS_API CvInfo
{
std::string dllPath; // Full path to loaded opencv_world DLL
std::string version; // e.g. "4.13.0"
int versionCode = 0;// e.g. 4130
bool loaded = false;
};
// ============================================================================
class ANSLIBS_API CvLoader
{
public:
/// Discover and pre-load OpenCV DLLs.
/// Safe to call multiple times -- subsequent calls are no-ops.
/// @param shared_dir Directory to search first (default: ANSCENTER shared).
/// @param verbose Print discovery results to stdout.
/// @returns Reference to the discovery result.
[[nodiscard]] static const CvInfo& Initialize(
const std::string& shared_dir = ANSCENTER::DynLib::DEFAULT_SHARED_DIR,
bool verbose = true);
/// Release pre-loaded library handles.
static void Shutdown();
/// Query current state.
[[nodiscard]] static const CvInfo& Current() noexcept { return s_info; }
[[nodiscard]] static bool IsInitialized() noexcept { return s_initialized; }
private:
/// Build candidate DLL names, newest first.
static std::vector<std::string> CvWorldCandidates(const std::string& shared_dir);
static std::vector<std::string> CvImgHashCandidates(const std::string& shared_dir);
static std::mutex s_mutex;
static bool s_initialized;
static CvInfo s_info;
static LibHandle s_hCvWorld;
static LibHandle s_hCvImgHash;
};

View File

@@ -0,0 +1,95 @@
#pragma once
#ifndef DYNLIBUTILS_H
#define DYNLIBUTILS_H
// ============================================================================
// DynLibUtils — Shared dynamic library loading utilities
//
// Common infrastructure used by EPLoader, NvDynLoader, CvLoader, OvLoader, etc.
// Consolidates duplicate utility functions that were previously in each loader.
// ============================================================================
#ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
using LibHandle = HMODULE;
# define LIB_INVALID nullptr
#else
# include <dlfcn.h>
using LibHandle = void*;
# define LIB_INVALID nullptr
#endif
#include <string>
#include <vector>
#include <iostream>
namespace ANSCENTER {
namespace DynLib {
// ── Platform defaults ────────────────────────────────────────────────────
#ifdef _WIN32
static constexpr const char* DEFAULT_SHARED_DIR =
"C:\\ProgramData\\ANSCENTER\\Shared";
#else
static constexpr const char* DEFAULT_SHARED_DIR =
"/opt/anscenter/shared";
#endif
// ── File / path helpers ──────────────────────────────────────────────────
/// Returns true if @p path is a regular file.
[[nodiscard]] bool FileExists(const std::string& path);
/// Joins base + component with the platform separator.
[[nodiscard]] std::string JoinPath(const std::string& base,
const std::string& component);
// ── DLL search-path injection ────────────────────────────────────────────
/// Adds @p dir to the DLL search path.
/// - Windows: AddDllDirectory() + prepend to %PATH%
/// - Linux: prepend to $LD_LIBRARY_PATH
void InjectDllSearchPath(const std::string& dir);
// ── Library loading ──────────────────────────────────────────────────────
/// Iterates @p candidates, returns the first successfully loaded library.
/// @param loadedPath On success, receives the path/name that was loaded.
/// @param verbose Print discovery results to stdout.
/// @param globalLoad Linux only: use RTLD_GLOBAL (ignored on Windows).
[[nodiscard]] LibHandle FindAndLoad(const std::vector<std::string>& candidates,
std::string& loadedPath,
bool verbose = true,
bool globalLoad = false);
/// Load a single library by path.
/// @param globalLoad Linux only: use RTLD_GLOBAL.
[[nodiscard]] LibHandle LoadLib(const std::string& path, bool globalLoad = false);
/// Free a loaded library handle.
void FreeLib(LibHandle h);
/// Get a symbol address from a loaded library.
[[nodiscard]] void* GetSymbol(LibHandle h, const char* sym);
// ── Type-safe symbol binding ─────────────────────────────────────────────
/// Bind a function pointer from a loaded library handle.
/// @returns true if the symbol was found and bound.
template<typename Fn>
[[nodiscard]] bool Bind(LibHandle h, const char* sym, Fn*& pfn)
{
pfn = reinterpret_cast<Fn*>(GetSymbol(h, sym));
return pfn != nullptr;
}
} // namespace DynLib
} // namespace ANSCENTER
#endif // DYNLIBUTILS_H

View File

@@ -0,0 +1,116 @@
#pragma once
#ifndef EPLOADER_H
#define EPLOADER_H
// ============================================================================
// EPLoader — Dynamic ONNX Runtime loader
//
// Moved from ONNXEngine/ to ANSLibsLoader/ for centralized library management.
// Now exported via ANSLIBS_API from ANSLibsLoader.dll.
// ============================================================================
#include "ANSLibsLoader.h" // ANSLIBS_API, EngineType
#include <string>
#include <mutex>
namespace ANSCENTER {
struct EPInfo {
EngineType type = EngineType::CPU;
std::string name; // "CUDA", "OpenVINO", "DirectML", "CPU"
std::string ortProviderName; // exact ORT provider string
std::string libraryDir; // resolved absolute path to EP DLLs
bool fromSubdir = false; // true = ep/<name>/, false = flat Shared/
};
class ANSLIBS_API EPLoader
{
public:
// ── Platform defaults ────────────────────────────────────────────────
#ifdef _WIN32
static constexpr const char* DEFAULT_SHARED_DIR =
"C:\\ProgramData\\ANSCENTER\\Shared";
#else
static constexpr const char* DEFAULT_SHARED_DIR =
"/opt/anscenter/shared";
#endif
// ── Initialize ───────────────────────────────────────────────────────
/// Call once at application startup (optional — Current() lazy-inits).
///
/// @param shared_dir Root deployment directory.
/// Expected subdirectory layout:
/// <shared_dir>/ep/cuda/onnxruntime.dll
/// <shared_dir>/ep/directml/onnxruntime.dll
/// <shared_dir>/ep/openvino/onnxruntime.dll
/// <shared_dir>/ep/cpu/onnxruntime.dll
/// Falls back to <shared_dir>/onnxruntime.dll if
/// subdirectories are absent (backward compat).
///
/// @param preferred Force a specific EP.
/// Pass EngineType::AUTO_DETECT to let AutoDetect()
/// query ANSLicenseHelper (default).
///
/// @return Const reference to the populated EPInfo.
/// Valid for the lifetime of the process.
///
/// @throws std::runtime_error if onnxruntime.dll cannot be loaded or
/// OrtGetApiBase is not found in the DLL.
[[nodiscard]] static const EPInfo& Initialize(
const std::string& shared_dir = DEFAULT_SHARED_DIR,
EngineType preferred = EngineType::AUTO_DETECT);
// ── Current ──────────────────────────────────────────────────────────
/// Returns the active EPInfo. Calls Initialize() with default arguments
/// on the first invocation (lazy auto-init). Thread-safe.
[[nodiscard]] static const EPInfo& Current();
// ── AutoDetect ───────────────────────────────────────────────────────
/// Delegates to ANSLicenseHelper::CheckHardwareInformation().
/// Priority: NVIDIA > AMD > Intel (OpenVINO) > CPU.
[[nodiscard]] static EngineType AutoDetect();
// ── IsInitialized ────────────────────────────────────────────────────
[[nodiscard]] static bool IsInitialized();
// ── EngineTypeName ───────────────────────────────────────────────────
[[nodiscard]] static const char* EngineTypeName(EngineType type);
// ── SubdirName ───────────────────────────────────────────────────────
/// Returns the ep/ subdirectory name for a given EngineType.
/// e.g. EngineType::NVIDIA_GPU → "cuda"
[[nodiscard]] static const char* SubdirName(EngineType type);
[[nodiscard]] static void* GetOrtApiRaw();
// ── Shutdown ─────────────────────────────────────────────────────────
/// Releases the onnxruntime.dll handle.
/// Call at application exit AFTER all Ort::Session objects are destroyed.
/// Safe to call multiple times.
static void Shutdown();
// ── Non-copyable / non-movable ───────────────────────────────────────
EPLoader() = delete;
EPLoader(const EPLoader&) = delete;
EPLoader& operator=(const EPLoader&) = delete;
private:
static std::string ResolveEPDir(const std::string& shared_dir,
EngineType type);
static void LoadOrtDll(const std::string& ep_dir);
// ── State ────────────────────────────────────────────────────────────
// Defined in EPLoader.cpp only when ANSLIBSLOADER_EXPORTS is set.
static std::mutex s_mutex;
static bool s_initialized;
static EPInfo s_info;
#ifdef _WIN32
static std::string s_temp_ort_path;
static std::string s_temp_dir;
#endif
};
} // namespace ANSCENTER
#endif // EPLOADER_H

View File

@@ -0,0 +1,142 @@
#pragma once
// ============================================================================
// NvDynLoader -- Runtime discovery and loading of NVIDIA TensorRT / CUDA DLLs
//
// Moved from TensorRTAPI/ to ANSLibsLoader/ for centralized library management.
// Now exported via ANSLIBS_API from ANSLibsLoader.dll.
//
// PROBLEM SOLVED
// --------------
// Linking against nvinfer_10.lib / nvonnxparser_10.lib hard-codes the major
// version into the binary's import table. Upgrading TRT 10 -> 11 then forces
// every project to update its .lib references and relink.
//
// SOLUTION
// --------
// NvDynLoader provides the three extern "C" symbols that TRT / ONNX-parser
// inline wrappers call (createInferBuilder_INTERNAL, etc.) as thin stubs
// compiled directly into ANSLibsLoader.dll. At runtime the stubs call through
// function pointers into whichever DLL version is actually installed.
//
// All C++ vtable dispatch (IBuilder, IRuntime, IParser methods) continues to
// work correctly because the objects are created by -- and owned by the vtable
// of -- the DLL that was dynamically loaded.
//
// REQUIRED PROJECT CHANGES
// ------------------------
// Consuming projects:
// REMOVE: nvinfer_10.lib / nvonnxparser_10.lib from linker input
// ADD: ANSLibsLoader.lib
// KEEP: cudart_static.lib (or use NV_DYNAMIC_CUDA for dynamic CUDA RT)
// ============================================================================
#include "ANSLibsLoader.h" // ANSLIBS_API
#include "DynLibUtils.h" // LibHandle
// -- TRT / ONNX-parser API decoration override --------------------------------
// Must appear BEFORE including NvInfer.h / NvOnnxParser.h.
// By default these macros expand to __declspec(dllimport), which would conflict
// with our extern "C" stub definitions in NvDynLoader.cpp. Setting them to
// empty makes all TRT inline-wrapper calls direct, so the linker resolves them
// against our stubs rather than against nvinfer_XX.lib.
//
// The stubs are exported from ANSLibsLoader.dll via the .def file
// (ANSLibsLoader.def), NOT via __declspec(dllexport), to avoid C2375
// linkage conflicts between the NvInfer.h declarations and our definitions.
#ifndef TENSORRTAPI
# define TENSORRTAPI
#endif
#ifndef NVONNXPARSER_API
# define NVONNXPARSER_API
#endif
#include <cuda_runtime.h> // CUDA types (cudaStream_t, cudaDeviceProp, ...)
#include <NvInfer.h> // TRT types (IBuilder, IRuntime, ...)
#include <NvOnnxParser.h> // nvonnxparser types
#include <string>
#include <vector>
// ============================================================================
class ANSLIBS_API NvDynLoader
{
public:
// -- Lifecycle -------------------------------------------------------------
/// Discover and load NVIDIA DLLs at runtime.
/// Safe to call multiple times -- subsequent calls are no-ops.
/// @param verbose Print discovery results to stdout.
/// @returns false if a critical library (TRT or CUDA) could not be loaded.
[[nodiscard]] static bool Initialize(bool verbose = true);
/// Release all loaded library handles. Call at application exit.
static void Shutdown();
[[nodiscard]] static bool IsInitialized() noexcept { return s_initialized; }
// -- Informational ---------------------------------------------------------
[[nodiscard]] static const std::string& TrtDllPath() noexcept { return s_trtPath; }
[[nodiscard]] static const std::string& OnnxDllPath() noexcept { return s_onnxPath; }
[[nodiscard]] static const std::string& CudaDllPath() noexcept { return s_cudaPath; }
[[nodiscard]] static const std::string& CudnnDllPath()noexcept { return s_cudnnPath; }
[[nodiscard]] static int TrtMajor() noexcept { return s_trtMajor; }
// -- TRT factory pointers ---------------------------------------------------
using PfnBuilder = void*(void* logger, int32_t version) noexcept;
using PfnRuntime = void*(void* logger, int32_t version) noexcept;
using PfnRefitter = void*(void* engine, void* logger, int32_t version) noexcept;
using PfnParser = void*(void* network, void* logger, int32_t version) noexcept;
using PfnParserRefitter = void*(void* refitter, void* logger, int32_t version) noexcept;
using PfnGetParserVersion = int() noexcept;
static PfnBuilder* pfn_createInferBuilder_INTERNAL;
static PfnRuntime* pfn_createInferRuntime_INTERNAL;
static PfnRefitter* pfn_createInferRefitter_INTERNAL;
static PfnParser* pfn_createNvOnnxParser_INTERNAL;
static PfnParserRefitter* pfn_createNvOnnxParserRefitter_INTERNAL;
static PfnGetParserVersion* pfn_getNvOnnxParserVersion;
// -- CUDA function pointers (populated only with NV_DYNAMIC_CUDA) -----------
#ifdef NV_DYNAMIC_CUDA
static cudaError_t (*pfn_cudaGetDeviceCount) (int*);
static cudaError_t (*pfn_cudaSetDevice) (int);
static cudaError_t (*pfn_cudaGetDeviceProperties) (cudaDeviceProp*, int);
static cudaError_t (*pfn_cudaDeviceSetLimit) (cudaLimit, size_t);
static cudaError_t (*pfn_cudaDeviceSynchronize) ();
static cudaError_t (*pfn_cudaDeviceGetStreamPriorityRange)(int*, int*);
static cudaError_t (*pfn_cudaMalloc) (void**, size_t);
static cudaError_t (*pfn_cudaFree) (void*);
static cudaError_t (*pfn_cudaMemset) (void*, int, size_t);
static cudaError_t (*pfn_cudaMemGetInfo) (size_t*, size_t*);
static cudaError_t (*pfn_cudaMemcpy) (void*, const void*, size_t, cudaMemcpyKind);
static cudaError_t (*pfn_cudaMemcpyAsync) (void*, const void*, size_t, cudaMemcpyKind, cudaStream_t);
static cudaError_t (*pfn_cudaStreamCreate) (cudaStream_t*);
static cudaError_t (*pfn_cudaStreamCreateWithPriority) (cudaStream_t*, unsigned int, int);
static cudaError_t (*pfn_cudaStreamDestroy) (cudaStream_t);
static cudaError_t (*pfn_cudaStreamSynchronize) (cudaStream_t);
static cudaError_t (*pfn_cudaStreamWaitEvent) (cudaStream_t, cudaEvent_t, unsigned int);
static cudaError_t (*pfn_cudaEventCreate) (cudaEvent_t*);
static cudaError_t (*pfn_cudaEventCreateWithFlags) (cudaEvent_t*, unsigned int);
static cudaError_t (*pfn_cudaEventRecord) (cudaEvent_t, cudaStream_t);
static cudaError_t (*pfn_cudaEventDestroy) (cudaEvent_t);
static const char* (*pfn_cudaGetErrorString) (cudaError_t);
static cudaError_t (*pfn_cudaGetLastError) ();
#endif // NV_DYNAMIC_CUDA
private:
static bool s_initialized;
static int s_trtMajor;
static std::string s_trtPath;
static std::string s_onnxPath;
static std::string s_cudaPath;
static std::string s_cudnnPath;
static LibHandle s_hTrt;
static LibHandle s_hOnnx;
static LibHandle s_hCuda;
static LibHandle s_hCudnn;
// Candidate DLL / SO name lists.
static std::vector<std::string> TrtCandidates();
static std::vector<std::string> OnnxCandidates();
static std::vector<std::string> CudnnCandidates();
static std::vector<std::string> CudaRtCandidates();
};

View File

@@ -0,0 +1,69 @@
#pragma once
// ============================================================================
// OvLoader -- Runtime discovery and pre-loading of OpenVINO DLLs
//
// OpenVINO is normally import-linked (openvino.lib), but the DLLs
// must be discoverable at process load time. OvLoader ensures the correct
// DLLs are found by:
// 1. Pre-loading Intel TBB (dependency of openvino.dll)
// 2. Pre-loading openvino.dll from the ANSCENTER shared directory
// 3. Optionally querying the OpenVINO version via the C API
//
// Plugins (CPU, GPU, NPU) and frontends (IR, ONNX, etc.) are discovered
// automatically by OpenVINO's internal plugin loader from the same directory
// once the shared directory has been injected into the DLL search path.
// ============================================================================
#include "ANSLibsLoader.h" // ANSLIBS_API
#include "DynLibUtils.h" // LibHandle
#include <string>
#include <vector>
#include <mutex>
// ============================================================================
struct ANSLIBS_API OvInfo
{
std::string dllPath; // Full path to loaded openvino.dll
std::string version; // e.g. "2024.6.0" (build number from C API)
bool loaded = false;
};
// ============================================================================
class ANSLIBS_API OvLoader
{
public:
/// Discover and pre-load OpenVINO + TBB DLLs.
/// Safe to call multiple times -- subsequent calls are no-ops.
/// @param shared_dir Directory to search first (default: ANSCENTER shared).
/// @param verbose Print discovery results to stdout.
/// @returns Reference to the discovery result.
[[nodiscard]] static const OvInfo& Initialize(
const std::string& shared_dir = ANSCENTER::DynLib::DEFAULT_SHARED_DIR,
bool verbose = true);
/// Release pre-loaded library handles.
static void Shutdown();
/// Query current state.
[[nodiscard]] static const OvInfo& Current() noexcept { return s_info; }
[[nodiscard]] static bool IsInitialized() noexcept { return s_initialized; }
private:
/// Build candidate DLL names for each component.
static std::vector<std::string> TbbCandidates(const std::string& shared_dir);
static std::vector<std::string> TbbMallocCandidates(const std::string& shared_dir);
static std::vector<std::string> OvCoreCandidates(const std::string& shared_dir);
static std::vector<std::string> OvCApiCandidates(const std::string& shared_dir);
/// Try to extract version string via the ov_get_openvino_version C API.
static std::string TryGetVersion(LibHandle hOvC);
static std::mutex s_mutex;
static bool s_initialized;
static OvInfo s_info;
static LibHandle s_hTbb;
static LibHandle s_hTbbMalloc;
static LibHandle s_hOvCore;
static LibHandle s_hOvC;
};

View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

13
core/ANSLibsLoader/pch.h Normal file
View File

@@ -0,0 +1,13 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#endif //PCH_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,395 @@
#ifndef ANSLICENSE_H
#define ANSLICENSE_H
#ifdef ANSLICENSE_EXPORTS
#define ANSLICENSE_API __declspec(dllexport)
#else
#define ANSLICENSE_API __declspec(dllimport)
#endif
#pragma once
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include <exception>
#include <iostream>
#include "anslicensing.h"
#include "LabVIEWHeader/extcode.h"
#include <mutex>
#ifdef _UNICODE
#define _T(s) L##s
#define _tprintf wprintf
#define _tcscmp wcscmp
#define _tfopen fopen
#else
#define _T(s) (s)
#define _TL(s) L##s
#define _tprintf printf
#define _tcscmp strcmp
#define _tfopen fopen
#endif
enum LicenseKeyStatus {
SUCCESS = 0,
INVALID_LICENSE_KEY = 1,
INVALID_HARDWARE_ID = 2,
LICENSE_EXPIRED = 3,
INVALID_ACTIVATION_KEY = 4,
PAYMENT_REQUIRED = 5,
INVALID_PRODUCT = 6,
UNKNOWN = 7
};
typedef struct {
int32 cnt; /* number of bytes that follow */
double value[1]; /* value of double */
} LDbl, * LDblPtr, ** LDblHandle;
namespace ANSCENTER
{
// Precision used for GPU inference
enum OCRType {
SINGLETEXT = 0,
STRUCTURE = 1
};
enum OCRLanguage {
ENGLISH = 0,
CHINESE = 1,
FRENCH = 2,
GERMANY = 3,
JAPANESE= 4,
KOREAN = 5,
CUSTOM =6
};
// Precision used for GPU inference
enum class Precision {
// Full precision floating point value
FP32,
// Half prevision floating point value
FP16,
// Int8 quantization.
// Has reduced dynamic range, may result in slight loss in accuracy.
// If INT8 is selected, must provide path to calibration dataset directory.
INT8,
};
// Options for the network
struct Options {
// Precision to use for GPU inference.
Precision precision = Precision::FP16;
// If INT8 precision is selected, must provide path to calibration dataset
// directory.
std::string calibrationDataDirectoryPath;
// The batch size to be used when computing calibration data for INT8
// inference. Should be set to as large a batch number as your GPU will
// support.
int32_t calibrationBatchSize = 128;
// The batch size which should be optimized for.
int32_t optBatchSize = 1;
// Maximum allowable batch size
int32_t maxBatchSize = 16;
// GPU device index
int deviceIndex = 0;
// Directory where the engine file should be saved
std::string engineFileDir = ".";
// Maximum allowed input width
int32_t maxInputWidth = -1; // Default to -1 --> expecting fixed input size
// Minimum allowed input width
int32_t minInputWidth = -1; // Default to -1 --> expecting fixed input size
// Optimal input width
int32_t optInputWidth = -1; // Default to -1 --> expecting fixed input size
// Maximum allowed input height
int32_t maxInputHeight = -1; // Default to -1 --> expecting fixed input size
// Minimum allowed input height
int32_t minInputHeight = -1; // Default to -1 --> expecting fixed input size
// Optimal input height
int32_t optInputHeight = -1; // Default to -1 --> expecting fixed input size
// GPU clock lock frequency in MHz.
// -1 = auto (default) — query max supported clock and lock at ~80%
// 0 = disabled — let the driver manage clocks dynamically
// >0 = lock at this specific MHz value (e.g. 2400)
// Prevents GPU power throttling that causes TensorRT timing instability
// on laptop GPUs. Requires elevated privileges; fails gracefully if not.
int32_t gpuClockLockMHz = -1;
};
enum PrecisionType {
INT8 = 0,
FP16 = 1,
FP32 = 2,
};
enum EngineType {
CPU = 0,
NVIDIA_GPU = 1,
OPENVINO_GPU = 2,
AMD_GPU = 3,
AUTO_DETECT = 99 // default: hardware auto-detection
};
enum DetectionType {
CLASSIFICATION = 0,
DETECTION = 1,
SEGMENTATION = 2,
FACEDETECTOR = 3,
FACERECOGNIZER = 4,
LICENSEPLATE = 5,
TEXTSCENSE = 6,
KEYPOINT=7,
OBB = 8 // Oriented Bounding Box
};
enum ModelType {
TENSORFLOW = 0,
YOLOV4 = 1,
YOLOV5 = 2,
YOLOV8 = 3,
TENSORRT = 4,
OPENVINO = 5,
FACEDETECT = 6,
FACERECOGNIZE = 7,
ALPR = 8,
OCR = 9,
ANOMALIB = 10,
POSE=11,
SAM=12,
ODHUBMODEL = 13,
YOLOV10RTOD = 14, // TensorRT Object Detection for Yolov10
YOLOV10OVOD = 15, // OpenVINO Object Detection for Yolov10
CUSTOMDETECTOR = 16, // Custom Detector
YOLOV12 = 17, // YoloV12 standard for yolov12
CUSTOMPY = 18, // Custom Python script model
MOTIONDETECTOR = 19, // Motion Detector,
ONNXCL =20,
ONNXPOSE=21,
RTPOSE=22,
ONNXSEG = 23,
RTSEG = 24,
ONNXOBB = 25,
RTOBB = 26,
MOVIENET=27,
ONNXSAM3=28,
RTSAM3 = 29,
ONNXYOLO = 30,
RTYOLO = 31
};
enum TrackerType {
BYTETRACK = 0,
UCMC = 1,
OCSORT = 2
};
enum ANSPRODUCTS {
ANNHUB = 1000,
DLHUB = 1001,
ODHUB = 1002,
ANSVIS = 1003,
ANS_FACERECOGNIZE = 1004,
ANS_OCR = 1005,
ANS_ALPR =1006,
ANS_CV = 1007,
ANS_TS = 1008
};
enum ANSLICENSESTATUS {
ACTIVE = 0,
EXPIRED = 1,
TRIAL=2,
UNLICENSE = 3
};
struct ModelConfig {
DetectionType detectionType;
ModelType modelType;
PrecisionType precisionType;
int inpWidth;
int inpHeight;
float modelConfThreshold;
float modelMNSThreshold;
float detectionScoreThreshold;
int numKPS; // Number of pose keypoint
float kpsThreshold;
bool autoGPUDetection;
float unknownPersonThreshold;
int gpuOptBatchSize = 1; // The batch size which should be optimized for.
int gpuMaxBatchSize = 1; // Maximum allowable batch size
int gpuDeviceIndex = 0; // GPU device index
// Maximum allowed input width
int32_t maxInputWidth = -1; // Default to -1 --> expecting fixed input size
// Minimum allowed input width
int32_t minInputWidth = -1; // Default to -1 --> expecting fixed input size
// Optimal input width
int32_t optInputWidth = -1; // Default to -1 --> expecting fixed input size
// Maximum allowed input height
int32_t maxInputHeight = -1; // Default to -1 --> expecting fixed input size
// Minimum allowed input height
int32_t minInputHeight = -1; // Default to -1 --> expecting fixed input size
// Optimal input height
int32_t optInputHeight = -1; // Default to -1 --> expecting fixed input size
};
struct ANSLicenseInfo {
std::string productName;
std::string licenseKey;
std::string activationKey;
std::string hardwareId;
ANSLICENSESTATUS licenseStatus;
int remainingDays;
int enableFeature;
};
class ANSLICENSE_API SPDLogger
{// Singleton design pattern
protected:
SPDLogger(const std::string& loggerFileName, bool consoleLoggerEnable = false)
: _loggerFileName(loggerFileName), _consoleLoggerEnable(consoleLoggerEnable) {
Init();
}
void Init();
void ConfigureLogger();
std::string _loggerFileName{};
bool _consoleLoggerEnable{true};
// Deleting copy constructor and assignment operator to ensure singleton
SPDLogger(const SPDLogger&) = delete;
SPDLogger& operator=(const SPDLogger&) = delete;
public:
bool Release();
~SPDLogger();
// Static method to get the singleton instance
static SPDLogger& GetInstance(const std::string& loggerFileName, bool consoleLoggerEnable = false) {
static SPDLogger instance(loggerFileName, consoleLoggerEnable);
return instance;
}
void Disable();
void Enable();
void LogTrace(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
void LogDebug(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
void LogInfo(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
void LogWarn(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
void LogError(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
void LogFatal(const std::string& source, const std::string& messsage, const std::string& fileSource, int lineSource);
};
class ANSLICENSE_API ANSLSHelper {
private:
LicenseTemplate* _licenseTemplate = nullptr;
License* _license = nullptr;
std::wstring _licenseFilePath = _T("");
std::wstring _licenseServiceURL = _T("");
std::wstring _sdkLicenseKey = _T("");
std::wstring _privateKey = _T("");
std::wstring _publicKey = _T("");
SPDLogger& _logger = SPDLogger::GetInstance("License");
std::string LoadLicenseContent();
void Setup5x5LicenseTemplate();// This is simple case
std::wstring GetProductId(std::string licenseKey);
public:
ANSLSHelper();
ANSLSHelper(std::string licenseServiceURL);
ANSLSHelper(std::string privateKey, std::string licenseServiceURL);
ANSLSHelper(std::string privateKey, std::string publicKey, std::string licenseServiceURL);
~ANSLSHelper();
void SetupLicenseTemplate();
[[nodiscard]] bool MatchCurrentHardwareId(std::string hwid);
[[nodiscard]] bool DectectClockmanipulation(int year, int month, int date);
[[nodiscard]] std::string GetLicenseData(std::string licenseKey);
[[nodiscard]] int ActivateLicense(std::string licenseKey, std::string registrationName, std::string& activationKey); // Always activate the license (need internet connection)
[[nodiscard]] int ActivateLicenseWithCustomHWID(std::string licenseKey, std::string registrationName, std::string hardwareId, std::string& activationKey); // Always activate the license (need internet connection)
[[nodiscard]] bool LoadLicenseTemplate(std::string templateFilePath);
[[nodiscard]] std::string SaveLicenseTemplate(std::string templateFilePath, bool savePrivateKey);
// These are the common methods to be used
void SetLicenseServiceURL(std::string licenseServiceURL);
[[nodiscard]] std::string GetCurrentHardwareId();
void LoadLicense(std::string licenseKey);
[[nodiscard]] std::string SaveLicense();
[[nodiscard]] std::string GenerateKey(int productId, std::string registrationName, int productFeature, bool trialLicense);
[[nodiscard]] std::string GenerateKey(int productId, std::string registrationName, int productFeature, int expiredYear, int expiredMonth, int expiredDate);
[[nodiscard]] bool IsLicenseKeyValid(std::string licenseKey, std::string registrationName); // Only check the license key with registration name and expiration date only. This is used when developer to use internal APIs called
[[nodiscard]] bool CheckLicenseKey(std::string licenseKey, std::string registrationName, int productId, int& enabledFeatures); // Check if the license key is valid
[[nodiscard]] int ValidateLicense(std::string licenseKey, std::string registrationName, std::string& activationKey);
[[nodiscard]] int ValidateLicenseWithCustomHWID(std::string licenseKey, std::string registrationName, std::string customHWID, std::string& activationKey);
[[nodiscard]] int GenerateOfflineActivationData(std::string licenseKey, std::string registrationName, std::string& offlineActivationData);
[[nodiscard]] int InstallOfflineLicense(std::string licenseKey, std::string registrationName, std::string activationKey);
// Utilities
[[nodiscard]] static int ExtractModelZipFile(std::string modelZipFile, std::string password, std::string modelName, std::string& extractedOutputFolder);
[[nodiscard]] static bool ZipFolerWithPassword(std::string folderPath, std::string zipFilePath, std::string password);
[[nodiscard]] static int PrepareEdgeModel(std::string modelZipFile, std::string zipFilePassword, std::string edgePassword, std::string modelName, std::string edgeSerialNumber, std::string& configFilePathName, std::string& labelMapPathName, std::string& outputModelFolder);
[[nodiscard]] static std::string GetSystemHardwareInformation();
[[nodiscard]] static bool ReleaseLogger();
};
class ANSLICENSE_API ANSLicenseHelper {
private:
[[nodiscard]] static bool deleteRecursively(const std::string& pathStr, bool safeMode);
[[nodiscard]] static bool isPathSafe(const std::string& pathStr);
public:
[[nodiscard]] static bool LicenseVerification(std::string licenseKey, int productId, std::string registrationName);
[[nodiscard]] static EngineType CheckHardwareInformation();
[[nodiscard]] static std::string ListLicenses();
[[nodiscard]] static int ActivateTrialLicense(std::string productName);
[[nodiscard]] static int DeactivateLicense(std::string productName);
[[nodiscard]] static int ActivateLicense(std::string productName, std::string licenseKey);
[[nodiscard]] static int ActivateLicenseWithCustomHWID(std::string productName, std::string licenseKey, std::string hwid, std::string& activationKey);
[[nodiscard]] static std::string DecodeValidationData(const char* validationData);
[[nodiscard]] static std::string GenerateActivationDataFile(std::string activationKey,std::string licenseKey, std::string hardwareId, std::string validationData);
[[nodiscard]] static std::string DecodeBase64(std::string base64String);
[[nodiscard]] static bool RemoveTrialLicenseKeys(std::string registrationName);
[[nodiscard]] static bool DeleleteRecursively(const std::string& pathStr) {
return deleteRecursively(pathStr, true);
}
};
}
extern "C" __declspec(dllexport) int CreateANSLSHandle(ANSCENTER::ANSLSHelper * *Handle, const char* privateKey, const char* publicKey, const char* licenseServiceURL);
extern "C" __declspec(dllexport) int Release(ANSCENTER::ANSLSHelper * *Handle);
extern "C" __declspec(dllexport) void SetLicenseServiceURL(ANSCENTER::ANSLSHelper * *Handle, const char* licenseServiceURL);
extern "C" __declspec(dllexport) int GetLicenseData(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, LStrHandle licenseData);
extern "C" __declspec(dllexport) int LoadLicenseTemplate(ANSCENTER::ANSLSHelper * *Handle, const char* templateFilePath);
extern "C" __declspec(dllexport) int GetCurrentHardwareId(ANSCENTER::ANSLSHelper * *Handle, LStrHandle currentHwID);
extern "C" __declspec(dllexport) int GenerateKey(ANSCENTER::ANSLSHelper * *Handle, int productId, const char* registrationName, int productFeature, int trialLicense, LStrHandle generatedKey);
extern "C" __declspec(dllexport) int GenerateKeyWithExpiredDate(ANSCENTER::ANSLSHelper * *Handle, int productId, const char* registrationName, int productFeature, int expiredYear, int expiredMonth, int expiredDate, LStrHandle generatedKey);
extern "C" __declspec(dllexport) int CheckLicenseKey(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, int productId);// , LStrHandle strEnableFeature); // Check if the license key is valid
extern "C" __declspec(dllexport) int ValidateLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* existingActivationKey, LStrHandle activationKey);
extern "C" __declspec(dllexport) int ActivateLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, LStrHandle activationKey); // Always activate the license (need internet connection)
extern "C" __declspec(dllexport) int ActivateLicenseWithCustomHWID(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* hardwareId, LStrHandle activationKey); // Always activate the license (need internet connection)
extern "C" __declspec(dllexport) int IsLicenseKeyValid(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName); // Only check the license key with registration name and expiration date only. This is used when developer to use internal APIs called
extern "C" __declspec(dllexport) int GenerateOfflineActivationData(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, LStrHandle offlineActivationData);
extern "C" __declspec(dllexport) int InstallOfflineLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* activationKey);
// Utilities
extern "C" __declspec(dllexport) int ExtractModelZipFile(const char* modelZipFile, const char* password, const char* modelName, LStrHandle extractedOutputFolder);
extern "C" __declspec(dllexport) int ZipFolderToZipFile(const char* modelFolderSource,const char* modelZipFileDes, const char* password);
extern "C" __declspec(dllexport) int PrepareEdgeModel(const char* modelZipFile, const char* zipFilePassword, const char* edgePassword, const char* modelName, const char* edgeSerialNumber, LStrHandle pathArray);
extern "C" __declspec(dllexport) int GetSystemHardwareInformation(LStrHandle systemHardwareInformation);
extern "C" __declspec(dllexport) int ReleaseLoggers();
extern "C" __declspec(dllexport) int ListANSLicenses(std::string &listLicense);
extern "C" __declspec(dllexport) int ListANSLicenses_LV(LStrHandle ansProductLicenses);
extern "C" __declspec(dllexport) int ActivateTrialLicense(const char* productName);
extern "C" __declspec(dllexport) int DeactivateLicense(const char* productName);
extern "C" __declspec(dllexport) int ActivateProductLicense(const char* productName, const char* licenseKey);
extern "C" __declspec(dllexport) int ActivateProductLicenseWithCustomHWID(const char* productName, const char* licenseKey, const char* hwid, LStrHandle lvActivationKey);
extern "C" __declspec(dllexport) int GetRegistrationName(const char* validationData, LStrHandle registrationName);
extern "C" __declspec(dllexport) int GenerateActivationKeyData(const char* activationKey, const char* licenseKey, const char* hardwareId, const char* validationData, LStrHandle activationData);
extern "C" __declspec(dllexport) int ANSLicenseVerification(const char* licenseKey, int productId, const char* registrationName);
extern "C" __declspec(dllexport) int ANSModelConversion(const char* zipModelFile, const char* zipModelPassword);
extern "C" __declspec(dllexport) int DeletePathRecursively(const char* pathTobeDeleted);
#endif

View File

@@ -0,0 +1,67 @@
# ANSLicensingSystem — DLL for license validation (also used by LabVIEW)
add_library(ANSLicensingSystem SHARED
ANSLicense.cpp
ANSLicense.h
Utility.cpp
Utility.h
pch.cpp
pch.h
framework.h
dllmain.cpp
)
target_include_directories(ANSLicensingSystem PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${SHARED_INCLUDE_DIR}
# These are needed by consumers because ANSLicense.h / Utility.h include them
${RESEARCH_DIR} # for LabVIEWHeader/extcode.h
${ANSLIBS_DIR}/ZLIB/include # for zlib.h (Utility.h includes it)
${VCPKG_INCLUDE_DIR} # for zip.h (Utility.h includes it)
)
target_include_directories(ANSLicensingSystem PRIVATE
${ANLS_ROOT}/ANSLIB/anszip
${RESEARCH_DIR}/ANS-HWiNFO/include
${RESEARCH_DIR}/spdlog-1.12.0/include
)
target_link_libraries(ANSLicensingSystem
PRIVATE anslicensing
PRIVATE labview
PRIVATE opencv
PRIVATE zlib_dep
PRIVATE spdlog_dep
PRIVATE boost
)
target_link_directories(ANSLicensingSystem PRIVATE
${RESEARCH_DIR}/ANS-HWiNFO/lib
${RESEARCH_DIR}/boost_lib
${VCPKG_LIB_DIR}
${ANLS_ROOT}/ANSLIB/anszip/x64/Release
)
# BASE64 class — not exported from anslicensing.dll, compile directly
target_include_directories(ANSLicensingSystem PRIVATE
${CMAKE_SOURCE_DIR}/core/anslicensing
)
target_sources(ANSLicensingSystem PRIVATE
${CMAKE_SOURCE_DIR}/core/anslicensing/base64.cpp
)
target_link_libraries(ANSLicensingSystem PRIVATE
HWiNFO.lib OpenCL.lib OpenCLExt.lib
bz2.lib zip.lib
libboost_log-vc143-mt-x64-1_82.lib
shlwapi.lib winhttp.lib
${WIN_COMMON_LIBS}
)
target_compile_definitions(ANSLicensingSystem PRIVATE
ANSLICENSE_EXPORTS
ANSLICENSINGSYSTEM_EXPORTS
UNICODE _UNICODE
_USRDLL
)
target_precompile_headers(ANSLicensingSystem PRIVATE pch.h)

View File

@@ -0,0 +1,895 @@
#include "Utility.h"
#include <ctime>
template <typename T>
T get_data(const boost::property_tree::ptree& pt, const std::string& key)
{
T ret;
if (boost::optional<T> data = pt.get_optional<T>(key))
{
ret = data.get();
}
else
{
return T();
//throw std::runtime_error("Could not read the data from ptree: [key: " + key + "]");
}
return ret;
}
// Convert file path to only the filename
std::string path_to_filename(std::string path) {
return path.substr(path.find_last_of("/\\") + 1);
}
std::string GetMainFolderDir() {
std::string loggerDir = "C:\\ProgramData\\ANSCENTER";
if (!FolderExist(loggerDir)) {
CreateDirectory(loggerDir);
}
return loggerDir;
}
std::string GetLoggerDir()
{
std::string mainFolderDir = GetMainFolderDir();
#ifdef _WIN32
const char pathSeparator = '\\'; // Windows uses backslash
#else
const char pathSeparator = '/'; // Unix-like systems use forward slash
#endif
std::string loggerDir = mainFolderDir+ pathSeparator+"Logs";
if (!FolderExist(loggerDir)) {
CreateDirectory(loggerDir);
}
return loggerDir;
}
std::string GetLicenseDir()
{
std::string mainFolderDir = GetMainFolderDir();
#ifdef _WIN32
const char pathSeparator = '\\'; // Windows uses backslash
#else
const char pathSeparator = '/'; // Unix-like systems use forward slash
#endif
std::string loggerDir = mainFolderDir + pathSeparator + "Licenses";
if (!FolderExist(loggerDir)) {
CreateDirectory(loggerDir);
}
return loggerDir;
}
std::wstring String2WString(const std::string input)
{
auto w = fs::path(input).wstring();
return w;
}
std::string WString2String(const std::wstring input)
{
auto s = fs::path(input).string();
return s;
}
std::string Dash2Underscore(std::string text)
{
std::replace(text.begin(), text.end(), '-', '_');
return text;
}
std::string Underscore2Dash(std::string text) {
std::replace(text.begin(), text.end(), '_', '-');
return text;
}
std::string Space2Underscore(std::string text) {
std::replace(text.begin(), text.end(), ' ', '_');
return text;
}
bool FileExist(const std::string& filePath) {
return fs::exists(filePath) && fs::is_regular_file(filePath);
}
bool FolderExist(const std::string& folderPath) {
return fs::is_directory(folderPath);
}
bool CreateDirectory(const std::string& folderPath) {
try {
fs::create_directory(folderPath);
return true;
}
catch (const std::exception& ex) {
std::cerr << "Creating directory: " << ex.what() << std::endl;
return false;
}
}
bool RenameFile(const std::string& oldFilePath, const std::string& newFilePath) {
try {
fs::rename(oldFilePath, newFilePath);
return true;
}
catch (const std::exception& ex) {
std::cerr << "Error renaming file: " << ex.what() << std::endl;
return false;
}
}
bool CopyFile(const std::string& sourceFilePath, const std::string& destinationFilePath) {
try {
fs::copy_file(sourceFilePath, destinationFilePath, fs::copy_options::overwrite_existing);
return true;
}
catch (const std::exception& ex) {
std::cerr << "Error copying file: " << ex.what() << std::endl;
return false;
}
}
void CopyFiles(const std::string& sourceFolder, const std::string& destinationFolder)
{
for (const auto& entry : std::filesystem::directory_iterator(sourceFolder))
{
if (entry.is_regular_file())
{
std::filesystem::copy(entry.path(), destinationFolder / entry.path().filename());
}
}
}
bool DeleteFile(const std::string& filePath) {
try {
fs::remove(filePath);
return true;
}
catch (const std::exception& ex) {
std::cerr << "Error deleting file: " << ex.what() << std::endl;
return false;
}
}
std::string FindFilePathInFileList(const std::vector<std::string>& vec, const std::string& substring)
{
auto it = std::find_if(vec.begin(), vec.end(), [&substring](const std::string& str) {
return str.find(substring) != std::string::npos;
});
return (it != vec.end()) ? *it : "";
}
bool DeleteLicenseFile(const std::string& filePath) {
try {
fs::remove(filePath);
return true;
}
catch (const std::exception& ex) {
std::cerr << "Error deleting file: " << ex.what() << std::endl;
return false;
}
}
void ToLowerCase(std::string& str) {
for (auto& c : str)
{
c = tolower(c);
}
}
std::string toLower(const std::string& str) {
std::string result = str;
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
return result;
}
std::string GetFileExtension(const std::string& filePath) {
fs::path path(filePath);
std::string extensionFile= path.extension().string();
ToLowerCase(extensionFile);
return extensionFile;
}
std::vector<std::string> ListFilesInFolder(const std::string& folderPath) {
std::vector<std::string> filePaths;
try {
for (const auto& entry : std::filesystem::directory_iterator(folderPath)) {
if (entry.is_regular_file()) {
std::string filePath = entry.path().string();
std::string fileName = GetFileNameWithoutExtension(filePath);
std::string _licenseKey, _activationKey, _validationData;
if (ReadLicenseKeyFile(filePath, _licenseKey, _activationKey, _validationData)) {
filePaths.push_back(entry.path().string());
}
}
}
}
catch (const std::exception& ex) {
std::cerr << "Error listing files in folder: " << ex.what() << std::endl;
}
return filePaths;
}
void DeleteFilesInFolderExcept(const std::string& folderPath, const std::vector<std::string>& filesToKeep) {
try {
for (const auto& entry : fs::directory_iterator(folderPath)) {
if (entry.is_regular_file()) {
std::string fileName = entry.path().filename().string();
if (std::find(filesToKeep.begin(), filesToKeep.end(), fileName) == filesToKeep.end()) {
// File is not in the list of files to keep; delete it.
fs::remove(entry.path());
std::cout << "Deleted: " << entry.path() << std::endl;
}
}
}
}
catch (const std::exception& ex) {
std::cerr << "Error deleting files in folder: " << ex.what() << std::endl;
}
}
bool DeleteFolder(const std::string& folderPath) {
try {
fs::remove_all(folderPath);
return true;
}
catch (const std::exception& ex) {
std::cerr << "Error deleting folder: " << ex.what() << std::endl;
return false;
}
}
std::string GetFileNameWithoutExtension(const std::string& filePath) {
fs::path path(filePath);
return path.stem().string();
}
std::string ReadFileContent(std::string filePath) {
std::ifstream ifs(filePath);
return std::string((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));
}
std::string ReadFileAsBinary(const std::string& filename) {
std::ifstream file(filename, std::ios::binary);
if (!file) {
std::cerr << "Failed to open file: " << filename << std::endl;
return ""; // Return an empty string to indicate failure
}
// Read the file content into a stringstream
std::stringstream buffer;
buffer << file.rdbuf();
// Convert the stringstream to a string
return buffer.str();
}
int ReadAllBytes(std::string filePath, std::vector<char>& allDataBytes) {
// Open the file in binary mode
std::ifstream file(filePath, std::ios::binary);
if (!file.is_open()) {
std::cerr << "Failed to open file." << std::endl;
return 1;
}
// Get the file size
file.seekg(0, std::ios::end);
std::streampos fileSize = file.tellg();
file.seekg(0, std::ios::beg);
// Create a vector to store the file data
std::vector<char> fileData(fileSize);
// Read the file into the vector
if (!file.read(fileData.data(), fileSize)) {
std::cerr << "Failed to read file." << std::endl;
return 1;
}
allDataBytes = fileData;
return 0;
}
// Functionto get parent folder path (C:\ParentFolder\FileName) -> C:\ParentFolder
std::string GetParentFolder(const std::string& filePath) {
size_t lastSlashPos = filePath.find_last_of("/\\"); // Handle both '/' and '\'
if (lastSlashPos != std::string::npos) {
return filePath.substr(0, lastSlashPos);
}
return ""; // Return an empty string if there is no folder
}
// Function to extract the folder name from a file path or file name
std::string ExtractFolderName(const std::string& directoryPath) {
std::filesystem::path path(directoryPath);
return path.stem().string();
}
// Function to create a file path from a folder name and a file name
std::string CreateFilePath(const std::string& folderName, const std::string& fileName) {
#ifdef _WIN32
const char pathSeparator = '\\'; // Windows uses backslash
#else
const char pathSeparator = '/'; // Unix-like systems use forward slash
#endif
std::string folder = folderName;
if (!folder.empty() && folder.back() != pathSeparator) {
folder += pathSeparator;
}
return folder + fileName;
}
std::filesystem::path GetSafeTempDirectory() {
std::filesystem::path systemTemp = std::filesystem::temp_directory_path();
std::filesystem::path fallbackTemp = "C:\\ProgramData\\Jh7O7nUe7vS\\";
// Ensure fallback directory exists
if (!std::filesystem::exists(fallbackTemp)) {
try {
std::filesystem::create_directories(fallbackTemp);
}
catch (const std::exception& e) {
std::cerr << "Failed to create fallback temp directory: " << e.what() << std::endl;
}
}
// Convert systemTemp to lowercase string for checking
std::string systemTempStr = toLower(systemTemp.string());
// Check if systemTemp does not exist or contains "c:\windows"
if (!std::filesystem::exists(systemTemp) ||
systemTempStr.find("windows") != std::string::npos) {
return fallbackTemp;
}
return systemTemp;
}
std::string GenerateOutputFolder(std::string modelFilePath, std::string modelName, bool edgeDeviceModel) {
// Get the path to the Temp folder
std::filesystem::path tempFolderPath = GetSafeTempDirectory();
std::string outputFolder = "";
outputFolder.clear();
if (std::filesystem::exists(tempFolderPath)) {
std::string strTempPath = tempFolderPath.string();
#ifdef _WIN32
const char pathSeparator = '\\'; // Windows uses backslash
#else
const char pathSeparator = '/'; // Unix-like systems use forward slash
#endif
std::string baseFolder = strTempPath + "Models";
if(!FolderExist(baseFolder)) {
CreateDirectory(baseFolder);
}
std::string EdgeModelsFolder = baseFolder + pathSeparator + "EdgeModels";
if (!FolderExist(EdgeModelsFolder)) {
CreateDirectory(EdgeModelsFolder);
}
std::string EngineModelsFolder = baseFolder + pathSeparator + "EngineModels";
if (!FolderExist(EngineModelsFolder)) {
CreateDirectory(EngineModelsFolder);
}
if(edgeDeviceModel)
outputFolder = EdgeModelsFolder + pathSeparator + modelName;
else
outputFolder = EngineModelsFolder + pathSeparator + modelName;
return outputFolder;
}
else {
return outputFolder;
}
}
bool ExtractPasswordProtectedZip(const std::string& zipFileName,
const std::string& password,
const std::string& modelName,
std::string& outputFolder,
bool edgeDeviceModel) {
outputFolder = GenerateOutputFolder(zipFileName, modelName, edgeDeviceModel);
return ExtractProtectedZipFile(zipFileName, password, modelName, outputFolder);
}
bool AddFileToZip(zip* archive, const char* filePath, const char* zipPath, const char* password) {
struct zip_source* source = zip_source_file(archive, filePath, 0, 0);
if (!source) {
std::cerr << "Failed to add file '" << filePath << "' to ZIP archive." << std::endl;
return false;
}
if (zip_file_add(archive, zipPath, source, ZIP_FL_OVERWRITE) == -1) {
std::cerr << "Failed to add file '" << filePath << "' to ZIP archive." << std::endl;
zip_source_free(source);
return false;
}
// Get the index of the added file
zip_int64_t fileIndex = zip_name_locate(archive, zipPath, 0);
if (fileIndex < 0) {
std::cerr << "Failed to locate file '" << zipPath << "' in ZIP archive." << std::endl;
zip_source_free(source);
return false;
}
// Set encryption for the added file
if (zip_file_set_encryption(archive, fileIndex, ZIP_EM_AES_256, password) == -1) {
std::cerr << "Failed to set encryption for file '" << zipPath << "' in ZIP archive." << std::endl;
zip_source_free(source);
return false;
}
return true;
}
bool AddFolderContentsToZip(zip* archive, const char* folderPath, const char* zipPath, const char* password) {
try {
fs::path dir(folderPath);
if (!fs::exists(dir) || !fs::is_directory(dir)) {
std::cerr << "Failed to open directory '" << folderPath << "'." << std::endl;
return false;
}
for (const fs::directory_entry& entry : fs::directory_iterator(dir)) {
std::string entryName = entry.path().filename().string();
std::string entryPath = (zipPath && zipPath[0] != '\0') ? std::string(zipPath) + "/" + entryName : entryName;
std::string filePath = folderPath + std::string("/") + entryName;
if (fs::is_directory(entry.status())) {
if (entryName != "." && entryName != "..") {
if (!AddFolderContentsToZip(archive, filePath.c_str(), entryPath.c_str(), password)) {
return false;
}
}
}
else {
if (!AddFileToZip(archive, filePath.c_str(), entryPath.c_str(), password)) {
return false;
}
}
}
}
catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << std::endl;
return false;
}
return true;
}
bool ZipFolderWithPassword(const char* folderPath, const char* zipFilePath, const char* password) {
zip* zipArchive;
zip_flags_t flags = ZIP_CREATE | ZIP_TRUNCATE;
//std::cout << "Open Zip File: " << zipFilePath << std::endl;
zipArchive = zip_open(zipFilePath, flags, nullptr);
if (!zipArchive) {
std::cerr << "Failed to create ZIP archive." << std::endl;
return false;
}
// Set a password for the ZIP file
if (zip_set_default_password(zipArchive, password) == -1) {
std::cerr << "Failed to set the password for the ZIP file." << std::endl;
zip_close(zipArchive);
return false;
}
// Add folder contents to the ZIP archive
if (!AddFolderContentsToZip(zipArchive, folderPath, "", password)) {
zip_close(zipArchive);
return false;
}
// Save the ZIP archive to the file
if (zip_close(zipArchive) == -1) {
std::cerr << "Failed to save the ZIP archive to the file." << std::endl;
return false;
}
return true;
}
std::string VectorToCommaSeparatedString(const std::vector<std::string>& inputVector) {
std::string result;
for (size_t i = 0; i < inputVector.size(); ++i) {
result += inputVector[i];
if (i < inputVector.size() - 1) {
result += ",";
}
}
return result;
}
std::string VectorToSeparatedString(const std::vector<std::string>& inputVector) {
std::string result;
for (size_t i = 0; i < inputVector.size(); ++i) {
result += inputVector[i];
if (i < inputVector.size() - 1) {
result += ";";
}
}
return result;
}
std::vector<std::string> Split(const std::string str, const std::string regex_str) {
std::regex regexz(regex_str);
return { std::sregex_token_iterator(str.begin(), str.end(), regexz, -1),
std::sregex_token_iterator() };
}
std::vector<std::string> GetTrialLicenseKeyFiles(std::string registrationName) {
std::vector < std::string> trialLicenseKeyFiles;
std::string trialLicenseKeyFileName = registrationName + "_Trial.lic";
if (CreateDirectory("C:\\ProgramData\\Apple")) {
std::string trialLicenseKeyFile1 = CreateFilePath("C:\\ProgramData\\Apple", trialLicenseKeyFileName);
trialLicenseKeyFiles.push_back(trialLicenseKeyFile1);
}
if (CreateDirectory("C:\\ProgramData\\Licenses")) {
std::string trialLicenseKeyFile2 = CreateFilePath("C:\\ProgramData\\Licenses", trialLicenseKeyFileName);
trialLicenseKeyFiles.push_back(trialLicenseKeyFile2);
}
if (CreateDirectory("C:\\ProgramData\\McAfee")) {
std::string trialLicenseKeyFile3 = CreateFilePath("C:\\ProgramData\\McAfee", trialLicenseKeyFileName);
trialLicenseKeyFiles.push_back(trialLicenseKeyFile3);
}
if (CreateDirectory("C:\\ProgramData\\NVIDIA")) {
std::string trialLicenseKeyFile4 = CreateFilePath("C:\\ProgramData\\NVIDIA", trialLicenseKeyFileName);
trialLicenseKeyFiles.push_back(trialLicenseKeyFile4);
}
if (CreateDirectory("C:\\ProgramData\\National Instruments")) {
std::string trialLicenseKeyFile5 = CreateFilePath("C:\\ProgramData\\National Instruments", trialLicenseKeyFileName);
trialLicenseKeyFiles.push_back(trialLicenseKeyFile5);
}
if (CreateDirectory("C:\\ProgramData\\Microsoft")) {
std::string trialLicenseKeyFile6 = CreateFilePath("C:\\ProgramData\\Microsoft", trialLicenseKeyFileName);
trialLicenseKeyFiles.push_back(trialLicenseKeyFile6);
}
return trialLicenseKeyFiles;
}
bool ReadLicenseKeyFile(std::string licenseKeyFilePath, std::string& licenseKey, std::string& activationKey, std::string& validationData) {
try {
if (!FileExist(licenseKeyFilePath))return false;
boost::property_tree::ptree pt;
boost::property_tree::read_json(licenseKeyFilePath, pt);
auto itLicenseKey = pt.get_child("license_key");
licenseKey = itLicenseKey.get_value<std::string>();
auto itActivationKey = pt.get_child("activation_key");
activationKey = itActivationKey.get_value<std::string>();
auto itRegistrationName = pt.get_child("license_key_validation_data");
validationData = itRegistrationName.get_value<std::string>();
if ((licenseKey.empty()) ||
(activationKey.empty()) ||
(validationData.empty())) return false;
return true;
}
catch (std::exception& e) {
std::cout<<"Read License key"<< e.what()<< std::endl;
return false;
}
}
std::string GetTrialLicenseKey(std::string registrationName) {
std::string trialLicenseKey;
std::vector<std::string> trialLicenseKeys;
trialLicenseKeys.clear();
// Get all licenseKeys from vavious places
std::vector < std::string> trialLicenseKeyFiles =GetTrialLicenseKeyFiles(registrationName);
size_t trialSize = trialLicenseKeyFiles.size();
for (size_t i = 0; i < trialSize; i++) {
std::string trialLicenseFile = trialLicenseKeyFiles[i];
if (FileExist(trialLicenseFile)) {
std::string trialLicenseKey = ReadFileContent(trialLicenseFile);
trialLicenseKeys.push_back(trialLicenseKey);
}
}
sort(trialLicenseKeys.begin(), trialLicenseKeys.end());
trialLicenseKeys.erase(unique(trialLicenseKeys.begin(), trialLicenseKeys.end()), trialLicenseKeys.end());
size_t lSize = trialLicenseKeys.size();
if (lSize == 1) trialLicenseKey = trialLicenseKeys[0];
return trialLicenseKey;
}
bool UpdateTrialLicenseKey(std::string trialLicenseKey, std::string registrationName) {
try {
std::vector < std::string> trialLicenseKeyFiles = GetTrialLicenseKeyFiles(registrationName);
size_t trialSize = trialLicenseKeyFiles.size();
for (size_t i = 0; i < trialSize; i++) {
try {
std::string trialLicenseFile = trialLicenseKeyFiles[i];
std::ofstream(trialLicenseFile) << trialLicenseKey;
}
catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << std::endl;
}
}
return true;
}
catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << std::endl;
return false;
}
}
bool RemoveTrialLicenseKey(std::string registrationName) {
try {
std::vector < std::string> trialLicenseKeyFiles = GetTrialLicenseKeyFiles(registrationName);
size_t trialSize = trialLicenseKeyFiles.size();
for (size_t i = 0; i < trialSize; i++) {
try {
DeleteFile(trialLicenseKeyFiles[i]);
}
catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << std::endl;
}
}
return true;
}
catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << std::endl;
return false;
}
}
int GetExpirationDate(std::string licenseData, int &productId) {
if (licenseData.empty()) return -1;
int remainDate = -1;
std::stringstream ss;
ss << licenseData;
boost::property_tree::ptree pt;
boost::property_tree::read_json(ss, pt);
auto rootNode = pt.get_child("licenseData");
auto childNode = rootNode.get_child("remaining_days");
remainDate = childNode.get_value<int>();
childNode = rootNode.get_child("valid_product_id");
productId = childNode.get_value<int>();
return remainDate;
}
std::string GetStringCurrentDateTime() {
// Get the current time
std::time_t t = std::time(nullptr);
std::tm now = {}; // Initialize to all zeros
localtime_s(&now, &t);
// Convert the time to a string
std::stringstream ss;
ss << std::put_time(&now, "%Y%m%d%H%M%S");
std::string currentDateTime = ss.str();
return currentDateTime;
}
std::string GetDateTimeString(const std::string& format) {
// Get the current time
std::time_t t = std::time(nullptr);
std::tm now = {}; // Initialize to all zeros
localtime_s(&now, &t);
// Convert the time to a string
std::stringstream ss;
ss << std::put_time(&now, format.c_str());
std::string currentDateTime = ss.str();
return currentDateTime;
}
// For traing engine
//bool ExtractProtectedZipFile(const std::string& zipFileName, const std::string& password, const std::string& modelName, const std::string outputFolder)
//{
// int error;
// if (!FileExist(zipFileName))return false;
// zip_t* archive = zip_open(zipFileName.c_str(), ZIP_RDONLY, &error);
// if (!archive) {
// std::cerr << "Error opening ZIP archive: " << zip_strerror(archive) << std::endl;
// return false;
// }
// try {
// if (!password.empty()) {
// if (zip_set_default_password(archive, password.c_str()) == -1) {
// std::cerr << "Error setting password: " << zip_strerror(archive) << std::endl;
// zip_close(archive);
// return false;
// }
// }
// int numEntries = (int)zip_get_num_entries(archive, 0);
// for (int i = 0; i < numEntries; i++) {
// zip_file_t* file = zip_fopen_index(archive, i, 0);
// if (!file) {
// std::cerr << "Error opening file in ZIP: " << zip_strerror(archive) << std::endl;
// zip_close(archive);
// return false;
// }
// // Check if the folder exists
// if (!std::filesystem::exists(outputFolder)) {
// // Folder does not exist, so create it
// try {
// std::filesystem::create_directories(outputFolder);
// }
// catch (const std::exception& ex) {
// std::cerr << "Error opening file in ZIP: " << ex.what() << std::endl;
// zip_close(archive);
// zip_fclose(file);
// return false;
// }
// }
// try {// otherwise extract to the output folder
// const char* filename = zip_get_name(archive, i, 0);
// std::string outputPath = CreateFilePath(outputFolder, filename);
//
// // Check if filename ends with '/' indicating it's a directory
// if (outputPath.back() == '/') {// Create the directory and its parents as needed
// fs::create_directories(outputPath);
// }
// else {// Proceed to extract the file
// std::ofstream output(outputPath, std::ios::binary);
// if (!output.is_open()) {
// zip_fclose(file);
// }
// else {
// const size_t buffer_size = 4096;
// unsigned char buffer[buffer_size];
// zip_int64_t bytesRead;
// while ((bytesRead = zip_fread(file, buffer, buffer_size)) > 0) {
// output.write(reinterpret_cast<char*>(buffer), bytesRead);
// }
// zip_fclose(file);
// output.close();
// }
// }
// }
// catch (const std::exception& ex) {
// std::cerr << "Error creating output file: " << ex.what() << std::endl;
// }
// }
// }
// catch (...) {
// zip_close(archive);
// return false;
// }
// zip_close(archive);
// return true;
//}
//bool ExtractProtectedZipFile(const std::string& zipFileName, const std::string& password, const std::string& modelName, const std::string outputFolder) {
// int error;
// if (!FileExist(zipFileName)) return false;
//
// zip_t* archive = zip_open(zipFileName.c_str(), ZIP_RDONLY, &error);
// if (!archive) {
// std::cerr << "Error opening ZIP archive: " << zip_strerror(archive) << std::endl;
// return false;
// }
//
// try {
// if (!password.empty()) {
// if (zip_set_default_password(archive, password.c_str()) == -1) {
// std::cerr << "Error setting password: " << zip_strerror(archive) << std::endl;
// zip_close(archive);
// return false;
// }
// }
//
// int numEntries = static_cast<int>(zip_get_num_entries(archive, 0));
// for (int i = 0; i < numEntries; i++) {
// zip_file_t* file = zip_fopen_index(archive, i, 0);
// if (!file) {
// std::cerr << "Error opening file in ZIP: " << zip_strerror(archive) << std::endl;
// zip_close(archive);
// return false;
// }
//
// // Check and create the output folder if necessary
// if (!std::filesystem::exists(outputFolder)) {
// try {
// std::filesystem::create_directories(outputFolder);
// }
// catch (const std::exception& ex) {
// std::cerr << "Error creating output directory: " << ex.what() << std::endl;
// zip_fclose(file);
// zip_close(archive);
// return false;
// }
// }
//
// try {
// const char* filename = zip_get_name(archive, i, 0);
// std::string outputPath = CreateFilePath(outputFolder, filename);
//
// // Check if the path is a directory and create it if necessary
// if (outputPath.back() == '/') {
// std::filesystem::create_directories(outputPath);
// }
// else {
// std::ofstream output(outputPath, std::ios::binary);
// if (!output.is_open()) {
// std::cerr << "Error creating output file: " << outputPath << std::endl;
// zip_fclose(file);
// zip_close(archive);
// return false;
// }
//
// const size_t buffer_size = 4096;
// unsigned char buffer[buffer_size];
// zip_int64_t bytesRead;
// while ((bytesRead = zip_fread(file, buffer, buffer_size)) > 0) {
// output.write(reinterpret_cast<char*>(buffer), bytesRead);
// }
//
// output.close();
// }
//
// zip_fclose(file);
// }
// catch (const std::exception& ex) {
// std::cerr << "Error creating output file: " << ex.what() << std::endl;
// zip_fclose(file);
// zip_close(archive);
// return false;
// }
// }
// }
// catch (...) {
// zip_close(archive);
// return false;
// }
//
// zip_close(archive);
// return true;
//}
bool ExtractProtectedZipFile(const std::string& zipFileName, const std::string& password, const std::string& modelName, const std::string outputFolder)
{
int error;
if (!FileExist(zipFileName))return false;
zip_t* archive = zip_open(zipFileName.c_str(), ZIP_RDONLY, &error);
if (!archive) {
std::cerr << "Error opening ZIP archive: " << zip_strerror(archive) << std::endl;
return false;
}
try {
if (!password.empty()) {
if (zip_set_default_password(archive, password.c_str()) == -1) {
std::cerr << "Error setting password: " << zip_strerror(archive) << std::endl;
zip_close(archive);
return false;
}
}
int numEntries = (int)zip_get_num_entries(archive, 0);
for (int i = 0; i < numEntries; i++) {
zip_file_t* file = zip_fopen_index(archive, i, 0);
if (!file) {
std::cerr << "Error opening file in ZIP: " << zip_strerror(archive) << std::endl;
zip_close(archive);
return false;
}
// Check if the folder exists
if (!std::filesystem::exists(outputFolder)) {
// Folder does not exist, so create it
try {
std::filesystem::create_directories(outputFolder);
}
catch (const std::exception& ex) {
std::cerr << "Error opening file in ZIP: " << ex.what() << std::endl;
zip_close(archive);
zip_fclose(file);
return false;
}
}
try {// otherwise extract to the output folder
const char* filename = zip_get_name(archive, i, 0);
std::string outputPath = CreateFilePath(outputFolder, filename);
// Check if filename ends with '/' indicating it's a directory
if (outputPath.back() == '/') {// Create the directory and its parents as needed
fs::create_directories(outputPath);
}
else {// Proceed to extract the file
std::ofstream output(outputPath, std::ios::binary);
if (!output.is_open()) {
zip_fclose(file);
}
else {
const size_t buffer_size = 4096;
unsigned char buffer[buffer_size];
zip_int64_t bytesRead;
while ((bytesRead = zip_fread(file, buffer, buffer_size)) > 0) {
output.write(reinterpret_cast<char*>(buffer), bytesRead);
}
zip_fclose(file);
output.close();
}
}
}
catch (const std::exception& ex) {
std::cerr << "Error creating output file: " << ex.what() << std::endl;
}
}
}
catch (...) {
zip_close(archive);
return false;
}
zip_close(archive);
return true;
}

View File

@@ -0,0 +1,92 @@
#pragma once
#ifndef UTILITY_H
#define UTILITY_H
#include "ANSLicense.h"
#include <boost/date_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include "boost/property_tree/ptree.hpp"
#include "boost/property_tree/json_parser.hpp"
#include "boost/foreach.hpp"
#include <zlib.h>
#include <zip.h>
#include <filesystem>
#include <cstring>
#include <iostream>
#include <vector>
#include <regex>
#include <stdio.h>
//namespace logging = boost::log;
//namespace attrs = boost::log::attributes;
//namespace expr = boost::log::expressions;
//namespace src = boost::log::sources;
//namespace keywords = boost::log::keywords;
//namespace sinks = boost::log::sinks;
namespace fs = std::filesystem;
#ifndef MIN
# define MIN(a,b) ((a) > (b) ? (b) : (a))
#endif
#ifndef MAX
# define MAX(a,b) ((a) < (b) ? (b) : (a))
#endif
#define DETECT_BUFFER_SIZE 0x9000
ANSLICENSE_API std::string path_to_filename(std::string path);
ANSLICENSE_API std::string GetMainFolderDir();
ANSLICENSE_API std::string GetLoggerDir();
ANSLICENSE_API std::string GetLicenseDir();
// Convert file path to only the filename
ANSLICENSE_API std::wstring String2WString(const std::string input);
ANSLICENSE_API std::string WString2String(const std::wstring input);
ANSLICENSE_API std::string Dash2Underscore(std::string text);
ANSLICENSE_API std::string Underscore2Dash(std::string text);
ANSLICENSE_API std::string Space2Underscore(std::string text);
[[nodiscard]] ANSLICENSE_API bool FileExist(const std::string& filePath);
[[nodiscard]] ANSLICENSE_API bool FolderExist(const std::string& folderPath);
[[nodiscard]] ANSLICENSE_API bool CreateDirectory(const std::string& folderPath);
[[nodiscard]] ANSLICENSE_API bool RenameFile(const std::string& oldFilePath, const std::string& newFilePath);
[[nodiscard]] ANSLICENSE_API bool CopyFile(const std::string& sourceFilePath, const std::string& destinationFilePath);
ANSLICENSE_API void CopyFiles(const std::string& sourceFolder, const std::string& destinationFolder);
[[nodiscard]] ANSLICENSE_API bool DeleteFile(const std::string& filePath);
[[nodiscard]] ANSLICENSE_API bool DeleteLicenseFile(const std::string& filePath);
[[nodiscard]] ANSLICENSE_API std::vector<std::string> ListFilesInFolder(const std::string& folderPath);
ANSLICENSE_API void DeleteFilesInFolderExcept(const std::string& folderPath, const std::vector<std::string>& filesToKeep);
[[nodiscard]] ANSLICENSE_API bool DeleteFolder(const std::string& folderPath);
ANSLICENSE_API void ToLowerCase(std::string& str);
ANSLICENSE_API std::string toLower(const std::string& str);
ANSLICENSE_API std::string GetFileExtension(const std::string& filePath);
ANSLICENSE_API std::string GetFileNameWithoutExtension(const std::string& filePath);
ANSLICENSE_API std::string FindFilePathInFileList(const std::vector<std::string>& fileList, const std::string& fileName);
ANSLICENSE_API std::string ReadFileContent(std::string filePath);
ANSLICENSE_API std::string ReadFileAsBinary(const std::string& filename);
ANSLICENSE_API int ReadAllBytes(std::string filePath, std::vector<char>& allDataBytes);
ANSLICENSE_API std::string ExtractFolderName(const std::string& filePath); // Function to extract the folder name from a file path or file name
ANSLICENSE_API std::string GetParentFolder(const std::string& directoryPath);// Function to extract the folder name from a file path or file name
ANSLICENSE_API std::string CreateFilePath(const std::string& folderName, const std::string& fileName);// Function to create a file path from a folder name and a file name
ANSLICENSE_API std::filesystem::path GetSafeTempDirectory();
ANSLICENSE_API std::string GenerateOutputFolder(std::string modelFilePath, std::string modelName, bool edgeDeviceModel=true);
ANSLICENSE_API bool ExtractPasswordProtectedZip(const std::string& zipFileName, const std::string& password, const std::string& modelName, std::string& outputFolder, bool edgeDeviceModel = true);
ANSLICENSE_API bool AddFileToZip(zip* archive, const char* filePath, const char* zipPath, const char* password);
ANSLICENSE_API bool AddFolderContentsToZip(zip* archive, const char* folderPath, const char* zipPath, const char* password);
ANSLICENSE_API bool ZipFolderWithPassword(const char* folderPath, const char* zipFilePath, const char* password);
ANSLICENSE_API std::string VectorToCommaSeparatedString(const std::vector<std::string>& inputVector);
ANSLICENSE_API std::string VectorToSeparatedString(const std::vector<std::string>& inputVector);
ANSLICENSE_API std::vector<std::string> Split(const std::string str, const std::string regex_str);
ANSLICENSE_API bool ReadLicenseKeyFile(std::string licenseKeyFilePath, std::string& licenseKey, std::string& activationKey, std::string& validationData);
ANSLICENSE_API std::vector<std::string> GetTrialLicenseKeyFiles(std::string registrationName);
ANSLICENSE_API std::string GetTrialLicenseKey(std::string registrationName);
ANSLICENSE_API bool UpdateTrialLicenseKey(std::string trialLicenseKey, std::string registrationName);
ANSLICENSE_API int GetExpirationDate(std::string licenseData, int& productId);
ANSLICENSE_API bool RemoveTrialLicenseKey(std::string registrationName);
ANSLICENSE_API std::string GetStringCurrentDateTime(); // Return current datetime in string format
ANSLICENSE_API std::string GetDateTimeString(const std::string& format);
// For training engine
//bool ExtractPasswordProtectedZipForTrainingEgnine(const std::string& zipFileName, const std::string& password, const std::string& modelName, std::string& outputFolder, bool edgeDeviceModel = true);
ANSLICENSE_API bool ExtractProtectedZipFile(const std::string& zipFileName,const std::string& password,const std::string& modelName,const std::string outputFolder);
#endif

View File

@@ -0,0 +1,554 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include "ANSLicense.h"
#include "Utility.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" __declspec(dllexport) int CreateANSLSHandle(ANSCENTER::ANSLSHelper * *Handle, const char* privateKey, const char* publicKey, const char* licenseServiceURL) {
try {
if (!Handle || !privateKey || !publicKey || !licenseServiceURL) return 0;
std::string st_privateKey = privateKey;
std::string st_publicKey = publicKey;
std::string st_licenseServiceURL = licenseServiceURL;
(*Handle) = new ANSCENTER::ANSLSHelper(st_privateKey, st_publicKey, st_licenseServiceURL);
if (*Handle == nullptr) return 0;
else return 1;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int Release(ANSCENTER::ANSLSHelper * *Handle) {
try {
if (!Handle || !(*Handle)) return 1; // already released
delete* Handle;
*Handle = nullptr;
return 1;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) void SetLicenseServiceURL(ANSCENTER::ANSLSHelper * *Handle, const char* licenseServiceURL) {
if (!Handle || !(*Handle) || !licenseServiceURL) return;
(*Handle)->SetLicenseServiceURL(licenseServiceURL);
}
extern "C" __declspec(dllexport) int GetLicenseData(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, LStrHandle licenseData) {
try {
if (!Handle || !(*Handle) || !licenseKey) return 0;
std::string st = (*Handle)->GetLicenseData(licenseKey);
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(licenseData, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*licenseData)->cnt = size;
memcpy((*licenseData)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else {
return 0;
}
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int LoadLicenseTemplate(ANSCENTER::ANSLSHelper * *Handle, const char* templateFilePath) {
try {
if (!Handle || !(*Handle) || !templateFilePath) return 0;
bool result = (*Handle)->LoadLicenseTemplate(templateFilePath);
if (result == true) return 1;
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int GetCurrentHardwareId(ANSCENTER::ANSLSHelper * *Handle, LStrHandle currentHwID) {
try {
if (!Handle || !(*Handle)) return 0;
std::string st = (*Handle)->GetCurrentHardwareId();
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(currentHwID, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*currentHwID)->cnt = size;
memcpy((*currentHwID)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int GenerateKey(ANSCENTER::ANSLSHelper * *Handle, int productId, const char* registrationName, int productFeature, int trialLicense, LStrHandle generatedKey) {
try {
if (!Handle || !(*Handle) || !registrationName) return 0;
bool enableTrialLicense = false;
if (trialLicense > 0)enableTrialLicense = true;
std::string st = (*Handle)->GenerateKey(productId, registrationName, productFeature, enableTrialLicense);
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(generatedKey, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*generatedKey)->cnt = size;
memcpy((*generatedKey)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int GenerateKeyWithExpiredDate(ANSCENTER::ANSLSHelper * *Handle, int productId, const char* registrationName, int productFeature, int expiredYear, int expiredMonth, int expiredDate, LStrHandle generatedKey) {
try {
if (!Handle || !(*Handle) || !registrationName) return 0;
std::string st = (*Handle)->GenerateKey(productId, registrationName, productFeature, expiredYear, expiredMonth, expiredDate);
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(generatedKey, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*generatedKey)->cnt = size;
memcpy((*generatedKey)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int CheckLicenseKey(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, int productId){ //, LStrHandle strEnableFeature) { // Check if the license key is valid
try {
if (!Handle || !(*Handle) || !licenseKey || !registrationName) return -1;
int enFeatures = 0;
bool result = (*Handle)->CheckLicenseKey(licenseKey, registrationName, productId, enFeatures);
if (result) return enFeatures;
else return -1;
}
catch (...) {
return -1;
}
}
extern "C" __declspec(dllexport) int ValidateLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* existingActivationKey,LStrHandle activationKey) {
try {
if (!Handle || !(*Handle) || !licenseKey || !registrationName || !existingActivationKey) return UNKNOWN;
std::string st = existingActivationKey;
int result = (*Handle)->ValidateLicense(licenseKey, registrationName, st);
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(activationKey, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*activationKey)->cnt = size;
memcpy((*activationKey)->str, st.c_str(), size);
return result;
}
else return UNKNOWN;
}
else return INVALID_LICENSE_KEY;
}
catch (...) {
return UNKNOWN;
}
}
extern "C" __declspec(dllexport) int ActivateLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, LStrHandle activationKey) { // Always activate the license (need internet connection)
try {
if (!Handle || !(*Handle) || !licenseKey || !registrationName) return UNKNOWN;
std::string st = "";
int result = (*Handle)->ActivateLicense(licenseKey, registrationName, st);
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(activationKey, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*activationKey)->cnt = size;
memcpy((*activationKey)->str, st.c_str(), size);
return result;
}
else return UNKNOWN;
}
else return INVALID_LICENSE_KEY;
}
catch (...) {
return UNKNOWN;
}
}
extern "C" __declspec(dllexport) int ActivateLicenseWithCustomHWID(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* hardwareId, LStrHandle activationKey) {
try {
if (!Handle || !(*Handle) || !licenseKey || !registrationName || !hardwareId) return UNKNOWN;
std::string st;
int result = (*Handle)->ActivateLicenseWithCustomHWID(licenseKey, registrationName, hardwareId, st);
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(activationKey, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*activationKey)->cnt = size;
memcpy((*activationKey)->str, st.c_str(), size);
return result;
}
else return UNKNOWN;
}
else return INVALID_LICENSE_KEY;
}
catch (...) {
return UNKNOWN;
}
}// Always activate the license (need internet connection)
extern "C" __declspec(dllexport) int IsLicenseKeyValid(ANSCENTER::ANSLSHelper **Handle, const char* licenseKey, const char * registrationName) { // Only check the license key with registration name and expiration date only. This is used when developer to use internal APIs called
try {
if (!Handle || !(*Handle) || !licenseKey || !registrationName) return 0;
bool result = (*Handle)->IsLicenseKeyValid(licenseKey, registrationName);
if (result) return 1;
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int GenerateOfflineActivationData(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, LStrHandle offlineActivationData) {
try {
if (!Handle || !(*Handle) || !licenseKey || !registrationName) return 0;
std::string st = "";
int result = (*Handle)->GenerateOfflineActivationData(licenseKey, registrationName, st);
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(offlineActivationData, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*offlineActivationData)->cnt = size;
memcpy((*offlineActivationData)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int InstallOfflineLicense(ANSCENTER::ANSLSHelper * *Handle, const char* licenseKey, const char* registrationName, const char* activationKey) {
try {
if (!Handle || !(*Handle) || !licenseKey || !registrationName || !activationKey) return 0;
return (*Handle)->InstallOfflineLicense(licenseKey, registrationName, activationKey);
}
catch (...) {
return 0;
}
}
//Utilities
extern "C" __declspec(dllexport) int ExtractModelZipFile(const char* modelZipFile, const char* password, const char* modelName, LStrHandle extractedOutputFolder) {
try {
std::string st = "";
int result = ANSCENTER::ANSLSHelper::ExtractModelZipFile(modelZipFile, password, modelName, st);
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(extractedOutputFolder, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*extractedOutputFolder)->cnt = size;
memcpy((*extractedOutputFolder)->str, st.c_str(), size);
return 1;
}
}
return result;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int ZipFolderToZipFile(const char* modelFolderSource, const char* modelZipFileDes, const char* password) {
try {
std::string stPass = password;
if (stPass.empty()) password = "Sh7O7nUe7vJ/417W0gWX+dSdfcP9hUqtf/fEqJGqxYL3PedvHubJag==";
bool result = ANSCENTER::ANSLSHelper::ZipFolerWithPassword(modelFolderSource, modelZipFileDes, password);
if (result == true) return 1;
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int PrepareEdgeModel(const char* modelZipFile, const char* zipFilePassword, const char* edgePassword, const char* modelName, const char* edgeSerialNumber,LStrHandle pathArray) {
try {
std::string st_configFilePathName = "";
std::string st_labelMapPathName = "";
std::string st_zipFilePathName = "";
int result = ANSCENTER::ANSLSHelper::PrepareEdgeModel(modelZipFile, zipFilePassword, edgePassword, modelName, edgeSerialNumber, st_configFilePathName, st_labelMapPathName, st_zipFilePathName);
std::string st = st_configFilePathName + ";" + st_labelMapPathName + ";" + st_zipFilePathName;
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(pathArray, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*pathArray)->cnt = size;
memcpy((*pathArray)->str, st.c_str(), size);
return 1;
}
}
return result;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int GetSystemHardwareInformation(LStrHandle systemHardwareInformation) {
try {
std::string st = ANSCENTER::ANSLSHelper::GetSystemHardwareInformation();
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(systemHardwareInformation, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*systemHardwareInformation)->cnt = size;
memcpy((*systemHardwareInformation)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int ReleaseLoggers() {
try {
bool result = ANSCENTER::ANSLSHelper::ReleaseLogger();
if (result) return 1;
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int ListANSLicenses(std::string & listLicense) {
try {
listLicense = ANSCENTER::ANSLicenseHelper::ListLicenses();
if (!listLicense.empty()) return 1;
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int ListANSLicenses_LV(LStrHandle ansProductLicenses) {
try {
std::string st = ANSCENTER::ANSLicenseHelper::ListLicenses();
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(ansProductLicenses, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*ansProductLicenses)->cnt = size;
memcpy((*ansProductLicenses)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int ActivateTrialLicense(const char* productName) {
return ANSCENTER::ANSLicenseHelper::ActivateTrialLicense(productName);
}
extern "C" __declspec(dllexport) int DeactivateLicense(const char* productName) {
return ANSCENTER::ANSLicenseHelper::DeactivateLicense(productName);
}
extern "C" __declspec(dllexport) int ActivateProductLicense(const char* productName, const char* licenseKey) {
return ANSCENTER::ANSLicenseHelper::ActivateLicense(productName,licenseKey);
}
extern "C" __declspec(dllexport) int ActivateProductLicenseWithCustomHWID(const char* productName, const char* licenseKey, const char* hwid, LStrHandle lvActivationKey) {
try {
std::string st;
int result = ANSCENTER::ANSLicenseHelper::ActivateLicenseWithCustomHWID(productName, licenseKey, hwid, st);
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(lvActivationKey, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*lvActivationKey)->cnt = size;
memcpy((*lvActivationKey)->str, st.c_str(), size);
return result;
}
else return LicenseKeyStatus::UNKNOWN;
}
else return LicenseKeyStatus::INVALID_LICENSE_KEY;
}
catch (...) {
return LicenseKeyStatus::UNKNOWN;
}
}
extern "C" __declspec(dllexport) int GetRegistrationName(const char* validationData, LStrHandle registrationName) {
try {
std::string st = ANSCENTER::ANSLicenseHelper::DecodeValidationData(validationData);
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(registrationName, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*registrationName)->cnt = size;
memcpy((*registrationName)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int GenerateActivationKeyData(const char* activationKey, const char* licenseKey, const char* hardwareId, const char* validationData, LStrHandle activationData) {
try {
std::string st = ANSCENTER::ANSLicenseHelper::GenerateActivationDataFile(activationKey, licenseKey, hardwareId, validationData);
int size = (int)st.length();
if (size > 0) {
MgErr error;
error = DSSetHandleSize(activationData, sizeof(int32) + size * sizeof(uChar));
if (error == noErr)
{
(*activationData)->cnt = size;
memcpy((*activationData)->str, st.c_str(), size);
return 1;
}
else return 0;
}
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int ANSLicenseVerification(const char* licenseKey, int productId, const char* registrationName) {
try{
bool result = ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, productId, registrationName);
if (result)return 1;
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int ANSModelConversion(const char* zipModelFile, const char* zipModelPassword) {
try {
//1. Uzip the model file to a temp location
std::string parentFolder = GetParentFolder(zipModelFile);
if (parentFolder.empty()) {
return -1; // or handle error appropriately
}
std::string modelName = GetFileNameWithoutExtension(zipModelFile) + "_converted";
const std::string outputFolder = GenerateOutputFolder(zipModelFile, modelName, true);
if (!FolderExist(outputFolder)) fs::create_directory(outputFolder);
bool extractedResult = ExtractProtectedZipFile(zipModelFile, zipModelPassword, modelName, outputFolder);
if (!extractedResult) return 0;
//2. Zip the model file to a temp location
std::string newModelZipFile = CreateFilePath(parentFolder, modelName + ".zip");
std::string newModelZipPassword = "Sh7O7nUe7vJ/417W0gWX+dSdfcP9hUqtf/fEqJGqxYL3PedvHubJag==";
//3. Read names of classes from the label map file
std::string labelMapFile = CreateFilePath(outputFolder, "classes.names");
if (labelMapFile.empty()) return 0;
std::vector<std::string> classesNames = Split(ReadFileContent(labelMapFile), "\n");
// 4. Create Categories folder
std::string categoriesFolder = outputFolder + "\\Categories";
if (FolderExist(categoriesFolder))DeleteFolder(categoriesFolder);
fs::create_directory(categoriesFolder);
for (size_t i = 0; i < classesNames.size(); ++i) {
std::ofstream outFile(categoriesFolder + "/" + classesNames[i] + "." + std::to_string(i + 1));
outFile.close();
}
bool zipResult = ZipFolderWithPassword(outputFolder.c_str(), newModelZipFile.c_str(), newModelZipPassword.c_str());
if (zipResult) {
DeleteFolder(outputFolder);
return 1;
}
else return 0;
}
catch (...) {
return 0;
}
}
extern "C" __declspec(dllexport) int DeletePathRecursively(const char* pathTobeDeleted) {
try {
bool result = ANSCENTER::ANSLicenseHelper::DeleleteRecursively(pathTobeDeleted);
if (result) return 1;
else return 0;
}
catch (...) {
return 0;
}
}

View File

@@ -0,0 +1,7 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#define NOMINMAX // Prevent windows.h from defining min/max macros
// which break std::min / std::max (C2589)
// Windows Header Files
#include <windows.h>

View File

@@ -0,0 +1,5 @@
// pch.cpp: source file corresponding to the pre-compiled header
#include "pch.h"
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.

View File

@@ -0,0 +1,13 @@
// pch.h: This is a precompiled header file.
// Files listed below are compiled only once, improving build performance for future builds.
// This also affects IntelliSense performance, including code completion and many code browsing features.
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
// Do not add files here that you will be updating frequently as this negates the performance advantage.
#ifndef PCH_H
#define PCH_H
// add headers that you want to pre-compile here
#include "framework.h"
#endif //PCH_H

View File

@@ -0,0 +1,17 @@
# anslicensing — Licensing SDK (shared library, built from source)
file(GLOB ANSLICENSING_SOURCES "*.cpp" "*.c")
file(GLOB ANSLICENSING_HEADERS "*.h")
add_library(anslicensing SHARED ${ANSLICENSING_SOURCES} ${ANSLICENSING_HEADERS})
target_include_directories(anslicensing PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${SHARED_INCLUDE_DIR}
)
target_compile_definitions(anslicensing PRIVATE ANSLICENSING_EXPORTS LICENSING_EXPORTS _USRDLL)
if(WIN32)
target_link_libraries(anslicensing PRIVATE ${WIN_COMMON_LIBS} winhttp)
else()
target_link_libraries(anslicensing PRIVATE ${UNIX_COMMON_LIBS} curl ssl crypto)
endif()

View File

@@ -0,0 +1,395 @@
#include "precomp.h"
#include <cstdlib>
#include <string>
#include <cassert>
#include "base32.h"
const char BASE32::alphabet[] = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
const char BASE32::values[] = {
/* 0 1 2 3 4 5 6 7 8 9 */ /* 0123456789 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 00 -&gt; 09 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 10 -&gt; 19 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 20 -&gt; 29 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 30 -&gt; 39 */
-1,-1,-1,-1,-1,-1,-1,-1, /* - 40 -&gt; 47 */
-1,-1,24,25,26,27,28,29,30,31, /* 0123456789 - 48 -&gt; 57 */
-1,-1,-1,-1,-1,-1,-1, 0, 1, 2, /* :;&lt;=&gt;?@ABC - 58 -&gt; 67 */
3, 4, 5, 6, 7,-1, 8, 9,10,11, /* DEFGHIJKLM - 68 -&gt; 77 */
12,-1,13,14,15,16,17,18,19,20, /* NOPQRSTUVW - 78 -&gt; 87 */
21,22,23, /* XYZ - 88 -&gt; 90 */
-1,-1,-1,-1,-1,-1, 0, 1, 2, 3, /* abcd - 91 -&gt; 100 */
4, 5, 6, 7,-1, 8, 9,10,11,12, /* efghijklmn - 101 -&gt; 110 */
-1,13,14,15,16,17,18,19,20,21, /* opqrstuvwx - 111 -&gt; 120 */
22,23,-1,-1,-1,-1,-1,-1,-1,-1, /* yz - 121 -&gt; 130 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 131 -&gt; 140 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 141 -&gt; 150 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 151 -&gt; 160 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 161 -&gt; 170 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 171 -&gt; 180 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 181 -&gt; 190 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 191 -&gt; 200 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 201 -&gt; 210 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 211 -&gt; 220 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 221 -&gt; 230 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 231 -&gt; 240 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 241 -&gt; 250 */
-1,-1,-1,-1,-1, /* - 251 -&gt; 255 */
};
BASE32::BASE32()
{
}
BASE32::~BASE32()
{
}
string BASE32::encode(unsigned char * buf, int len, bool padding)
{
int pad;
int enclen = encode_pad_length(len, &pad);
string encbuf;
if (!padding)
pad = 0;
encbuf.resize(enclen + pad + 1); /* Allow for trailing NUL */
encode_exactly(buf, len, encbuf.data(), enclen);
if (pad)
memset(encbuf.data() + enclen, '=', pad);
encbuf[enclen + pad] = '\0';
return encbuf;
}
/*
* encode_exactly
*
* Encode `len' bytes from `buf' into `enclen' bytes starting from `encbuf'.
* Caller must have ensured that there was EXACTLY the needed room in encbuf.
*/
void BASE32::encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen)
{
int i = 0; /* Input accumulator, 0 for trailing pad */
unsigned char const *ip = buf + len; /* Input pointer, one byte off end */
char *op = encbuf + enclen; /* Output pointer, one byte off end */
assert(buf);
assert(encbuf);
assert(len > 0);
assert(enclen >= len * 8 / 5);
/*
* In the following picture, we represent how the 5 bytes of input
* are split into groups of 5 bits, each group being encoded as a
* single base32 digit.
*
* input byte 0 1 2 3 4
* +--------+--------+--------+--------+--------+
* |01234012|34012340|12340123|40123401|23401234|
* +--------+--------+--------+--------+--------+
* <---><----><---><----><----><---><----><--->
* output digit 0 1 2 3 4 5 6 7
*
*
* Because of possible padding, which must be done as if the input
* was 0, and because the fractional part is at the end, we'll
* start encoding from the end. The encoding loop is unrolled for
* greater performance (using the infamous Duff's device to directly
* switch at the proper stage within the do {} while loop).
*/
switch (len % 5) {
case 0:
do {
assert(op - encbuf >= 8);
i = (unsigned char) *--ip; /* Input #4 */
*--op = alphabet[i & 0x1f]; /* Ouput #7 */
i >>= 5; /* upper <234>, input #4 */
/* FALLTHROUGH */
case 4:
i |= ((unsigned char) *--ip) << 3; /* had 3 bits in `i' */
*--op = alphabet[i & 0x1f]; /* Output #6 */
i >>= 5; /* upper <401234>, input #3 */
*--op = alphabet[i & 0x1f]; /* Output #5 */
i >>= 5; /* upper <4>, input #3 */
/* FALLTHROUGH */
case 3:
i |= ((unsigned char) *--ip) << 1; /* had 1 bits in `i' */
*--op = alphabet[i & 0x1f]; /* Output #4 */
i >>= 5; /* upper <1234>, input #2 */
/* FALLTHROUGH */
case 2:
i |= ((unsigned char) *--ip) << 4; /* had 4 bits in `i' */
*--op = alphabet[i & 0x1f]; /* Output #3 */
i >>= 5; /* upper <3401234>, input #1 */
*--op = alphabet[i & 0x1f]; /* Output #2 */
i >>= 5; /* upper <34>, input #1 */
/* FALLTHROUGH */
case 1:
i |= ((unsigned char) *--ip) << 2; /* had 2 bits in `i' */
*--op = alphabet[i & 0x1f]; /* Output #1 */
i >>= 5; /* upper <01234>, input #0 */
*--op = alphabet[i & 0x1f]; /* Output #0 */
i >>= 5; /* Holds nothing, MBZ */
assert(i == 0);
assert(op >= encbuf);
} while (op > encbuf);
}
}
/*
* encode_pad_length
*
* Compute the number of base32 digits and amount of padding necessary
* to encode `len' bytes.
*
* Returns the number of base32 digits necessary.
* Furthermore, if `pad' is a non-NULL pointer, it is filled with the amount
* of padding chars that would be necessary.
*/
int BASE32::encode_pad_length(int len, int *pad)
{
int ndigits; /* Base32 digits necessary */
int npad = 0; /* Final padding chars necessary */
int qcount; /* Amount of full quintets */
int remainder; /* Amount of input bytes in final quintet */
assert(len > 0);
qcount = len / 5;
remainder = len - (qcount * 5);
assert(remainder >= 0);
switch (remainder) {
case 0: npad = 0; break;
case 1: npad = 6; break;
case 2: npad = 4; break;
case 3: npad = 3; break;
case 4: npad = 1; break;
default: assert(0); /* Not possible */
}
ndigits = qcount * 8; /* Each full quintet encoded on 8 bytes */
if (npad != 0)
ndigits += (8 - npad);
if (pad)
*pad = npad;
return ndigits;
}
vector<unsigned char> BASE32::decode( const char * buf, int len, int * outlen )
{
int declen;
vector<unsigned char> decbuf;
int decoded;
if (len == 0 || (len & 0x7)) /* Empty, or padding bytes missing */
{
decbuf.clear();
return decbuf;
}
declen = (len >> 3) * 5;
decbuf.resize(declen);
decoded = decode_into(buf, len, decbuf.data(), declen);
if (decoded == 0)
decbuf.clear();
if (outlen != NULL)
*outlen = decoded;
return decbuf;
}
/*
* decode_into
*
* Decode `len' bytes from `buf' into `declen' bytes starting from `decbuf',
* faking the necessary amount of padding if necessary.
* Caller must have ensured that there was sufficient room in decbuf.
*
* Returns the amount of bytes decoded (without trailing padding) if successful,
* 0 if the input was not valid base32.
*/
int BASE32::decode_into(const char *buf, int len, unsigned char *decbuf, int declen)
{
int padding = 0;
if (len & 0x7)
padding = 8 - (len & 0x7);
return decode_alphabet(values, buf, len + padding, decbuf, declen, padding);
}
/*
* decode_alphabet
*
* Decode `len' bytes from `buf' into `declen' bytes starting from `decbuf'.
* Caller must have ensured that there was sufficient room in decbuf.
* Uses the specified decoding alphabet.
*
* `padding', when non-zero, is the amount of padding that is missing from
* the input buffer and which we must assume.
*
* Return decoded bytes if successful, 0 if the input was not valid base32.
*/
int BASE32::decode_alphabet(const char valmap[],
const char *buf, int len, unsigned char *decbuf, int declen, int padding)
{
int i = 0; /* Input accumulator, 0 for trailing pad */
char const *ip = buf + len; /* Input pointer, one byte off end */
int dlen = (len >> 3) * 5; /* Exact decoded length */
unsigned char *op; /* Output pointer, one byte off end */
int bytes; /* bytes decoded without padding */
char v;
assert(padding >= 0);
assert(buf);
assert(decbuf);
assert(len > 0);
assert((len & 0x7) == 0); /* `len' is a multiple of 8 bytes */
//assert(declen >= dlen);
/*
* If the last byte of input is '=', there is padding and we need to
* zero the tail of the decoding buffer.
*
* Likewise, when `padding' is non-zero, act as if the '=' were there.
*/
if (buf[len-1] == '=' || padding > 0) {
int pad = 0;
int n = 0; /* Amount of bytes to zero */
int s = 0; /* Amount of bytes to zero */
/*
* Remove and count trailing input padding bytes.
*/
if (padding == 0) {
while (*--ip == '=')
pad++;
ip++; /* Points one byte after real non-padding input */
} else {
pad = padding;
ip -= padding;
}
switch (pad) {
case 1: n = 1; s = 0; break;
case 3: n = 2; s = 1; break;
case 4: n = 3; s = 2; break;
case 6: n = 4; s = 3; break;
default:
return 0; /* Cannot be valid base32 */
}
memset(decbuf + (dlen - n), 0, n);
op = decbuf + (dlen - s);
bytes = dlen - n;
} else {
op = decbuf + dlen;
bytes = dlen;
}
/*
* In the following picture, we represent how the 8 bytes of input,
* each consisting of only 5 bits of information forming a base32 digit,
* are concatenated back into 5 bytes of binary information.
*
* input digit 0 1 2 3 4 5 6 7
* <---><----><---><----><----><---><----><--->
* +--------+--------+--------+--------+--------+
* |01234012|34012340|12340123|40123401|23401234|
* +--------+--------+--------+--------+--------+
* output byte 0 1 2 3 4
*
*
* Because of possible padding, which must be done as if the input
* was 0, and because the fractional part is at the end, we'll
* start decoding from the end. The decoding loop is unrolled for
* greater performance (using the infamous Duff's device to directly
* switch at the proper stage within the do {} while loop).
*/
switch ((ip - buf) % 8) {
case 0:
do {
i = valmap[(unsigned char) *--ip]; /* Input #7 */
if (i < 0)
return 0;
/* FALLTHROUGH */
case 7:
v = valmap[(unsigned char) *--ip]; /* Input #6 */
if (v < 0)
return 0;
i |= v << 5; /* had 5 bits */
*--op = i & 0xff; /* Output #4 */
i >>= 8; /* lower <01> of output #3 */
/* FALLTHROUGH */
case 6:
v = valmap[(unsigned char) *--ip]; /* Input #5 */
if (v < 0)
return 0;
i |= v << 2; /* had 2 bits */
/* FALLTHROUGH */
case 5:
v = valmap[(unsigned char) *--ip]; /* Input #4 */
if (v < 0)
return 0;
i |= v << 7; /* had 7 bits */
*--op = i & 0xff; /* Output #3 */
i >>= 8; /* lower <0123> of output #2 */
/* FALLTHROUGH */
case 4:
v = valmap[(unsigned char) *--ip]; /* Input #3 */
if (v < 0)
return 0;
i |= v << 4; /* had 4 bits */
*--op = i & 0xff; /* Output #2 */
i >>= 8; /* lower <0> of output #1 */
/* FALLTHROUGH */
case 3:
v = valmap[(unsigned char) *--ip]; /* Input #2 */
if (v < 0)
return 0;
i |= v << 1; /* had 1 bit */
/* FALLTHROUGH */
case 2:
v = valmap[(unsigned char) *--ip]; /* Input #1 */
if (v < 0)
return 0;
i |= v << 6; /* had 6 bits */
*--op = i & 0xff; /* Output #1 */
i >>= 8; /* lower <012> of output #0 */
/* FALLTHROUGH */
case 1:
v = valmap[(unsigned char) *--ip]; /* Input #0 */
if (v < 0)
return 0;
i |= v << 3; /* had 3 bits */
*--op = i & 0xff; /* Output #0 */
i >>= 8; /* Holds nothing, MBZ */
assert(i == 0);
assert(op >= decbuf);
} while (op > decbuf);
}
return bytes;
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include <string>
#include <vector>
using namespace std;
class BASE32 {
public:
BASE32();
~BASE32();
string encode(unsigned char * input, int len, bool padding = false);
vector<unsigned char> decode(const char * input, int len, int * outlen);
int encode_pad_length(int len, int *pad);
private:
void encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen);
int decode_into(const char *buf, int len, unsigned char *decbuf, int declen);
int decode_alphabet(const char valmap[], const char *buf, int len, unsigned char *decbuf, int declen, int padding);
static const char values[];
static const char alphabet[];
};

View File

@@ -0,0 +1,378 @@
#include "precomp.h"
#include <cstdlib>
#include <string>
#include <cassert>
#include "base64.h"
using namespace std;
/*
* The Base 64 Alphabet
*
* Value Encoding Value Encoding Value Encoding Value Encoding
* 0 A 17 R 34 i 51 z
* 1 B 18 S 35 j 52 0
* 2 C 19 T 36 k 53 1
* 3 D 20 U 37 l 54 2
* 4 E 21 V 38 m 55 3
* 5 F 22 W 39 n 56 4
* 6 G 23 X 40 o 57 5
* 7 H 24 Y 41 p 58 6
* 8 I 25 Z 42 q 59 7
* 9 J 26 a 43 r 60 8
* 10 K 27 b 44 s 61 9
* 11 L 28 c 45 t 62 +
* 12 M 29 d 46 u 63 /
* 13 N 30 e 47 v
* 14 O 31 f 48 w (pad) =
* 15 P 32 g 49 x
* 16 Q 33 h 50 y
*/
const char BASE64::alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const char BASE64::values[] = {
/* 0 1 2 3 4 5 6 7 8 9 */ /* 0123456789 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 00 -> 09 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 10 -> 19 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 20 -> 29 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 30 -> 39 */
-1,-1,-1,62,-1,-1,-1,63, /* ()*+'-./ - 40 -> 47 */
52,53,54,55,56,57,58,59,60,61, /* 0123456789 - 48 -> 57 */
-1,-1,-1,-1,-1,-1,-1, 0, 1, 2, /* :;<=>?@ABC - 58 -> 67 */
3, 4, 5, 6, 7, 8, 9,10,11,12, /* DEFGHIJKLM - 68 -> 77 */
13,14,15,16,17,18,19,20,21,22, /* NOPQRSTUVW - 78 -> 87 */
23,24,25,-1,-1,-1,-1,-1,-1,26, /* XYZ[\]^_`a - 88 -> 97 */
27,28,29,30,31,32,33,34,35,36, /* bcdefghijk - 98 -> 107 */
37,38,39,40,41,42,43,44,45,46, /* lmnopqrstu - 108 -> 117 */
47,48,49,50,51, /* vwxyz - 118 -> 122 */
-1,-1,-1,-1,-1,-1,-1,-1, /* - 123 -> 130 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 131 -> 140 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 141 -> 150 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 151 -> 160 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 161 -> 170 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 171 -> 180 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 181 -> 190 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 191 -> 200 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 201 -> 210 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 211 -> 220 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 221 -> 230 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 231 -> 240 */
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* - 241 -> 250 */
-1,-1,-1,-1,-1, /* - 251 -> 255 */
};
BASE64::BASE64()
{
}
BASE64::~BASE64()
{
}
string BASE64::encode(unsigned char * buf, int len, bool padding)
{
int pad;
int enclen = encode_pad_length(len, &pad);
string encbuf;
if (!padding)
pad = 0;
encbuf.resize(enclen + pad); /* Allow for trailing NUL */
encode_exactly(buf, len, encbuf.data(), enclen);
if (pad)
memset(encbuf.data() + enclen, '=', pad);
return encbuf;
}
/**
* encode_exactly
*
* Encode `len' bytes from `buf' unsignedo `enclen' bytes starting from `encbuf'.
* Caller must have ensured that there was EXACTLY the needed room in encbuf.
*/
void BASE64::encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen)
{
int i = 0; /* Input accumulator, 0 for trailing pad */
unsigned char const *ip = buf + len; /* Input pounsigneder, one byte off end */
char *op = encbuf + enclen; /* Output pounsigneder, one byte off end */
assert(buf);
assert(encbuf);
assert(len > 0);
assert(enclen >= len * 4 / 3);
/*
* In the following picture, we represent how the 3 bytes of input
* are split unsignedo groups of 6 bits, each group being encoded as a
* single base64 digit.
*
* input byte 0 1 2
* +--------+--------+--------+
* |01234501|23450123|45012345|
* +--------+--------+--------+
* <----><-----><-----><---->
* output digit 0 1 2 3
*
*
* Because of possible padding, which must be done as if the input
* was 0, and because the fractional part is at the end, we'll
* start encoding from the end. The encoding loop is unrolled for
* greater performance (using the infamous Duff's device to directly
* switch at the proper stage within the do {} while loop).
*/
switch (len % 3) {
case 0:
do {
assert(op - encbuf >= 4);
i = (unsigned char) *--ip; /* Input #2 */
*--op = alphabet[i & 0x3f]; /* Ouput #3 */
i >>= 6; /* upper <45>, input #2 */
/* FALLTHROUGH */
case 2:
i |= ((unsigned char) *--ip) << 2; /* had 2 bits in `i' */
*--op = alphabet[i & 0x3f]; /* Output #2 */
i >>= 6; /* upper <2345>, input #1 */
/* FALLTHROUGH */
case 1:
i |= ((unsigned char) *--ip) << 4; /* had 4 bits in `i' */
*--op = alphabet[i & 0x3f]; /* Output #1 */
i >>= 6; /* upper <012345>, input #0 */
*--op = alphabet[i & 0x3f]; /* Output #0 */
i >>= 6; /* Holds nothing, MBZ */
assert(i == 0);
assert(op >= encbuf);
} while (op > encbuf);
}
}
/**
* encode_pad_length
*
* Compute the number of base64 digits and amount of padding necessary
* to encode `len' bytes.
*
* Returns the number of base64 digits necessary.
* Furthermore, if `pad' is a non-NULL pounsigneder, it is filled with the amount
* of padding chars that would be necessary.
*/
int BASE64::encode_pad_length(int len, int *pad)
{
int ndigits; /* Base64 digits necessary */
int npad = 0; /* Final padding chars necessary */
int tcount; /* Amount of full triplets */
int remainder; /* Amount of input bytes in final triplet */
assert(len > 0);
tcount = len / 3;
remainder = len - (tcount * 3);
assert((unsigned) remainder >= 0);
switch (remainder) {
case 0: npad = 0; break;
case 1: npad = 2; break;
case 2: npad = 1; break;
default: assert(0); /* Not possible */
}
ndigits = tcount * 4; /* Each full triplet encoded on 4 bytes */
if (npad != 0)
ndigits += (4 - npad);
if (pad)
*pad = npad;
return ndigits;
}
/**
* base64_decode
*
* Decode `len' bytes starting at `buf' unsignedo new allocated buffer.
*
* Returns the new decoded buffer, or NULL if the input was not valid base64
* encoding. The caller knows the length of the returned buffer: it's the
* size of the input divided by 4 and multiplied by 3. If `outlen' is non-NULL,
* it is filled with the amount of bytes decoded unsignedo the buffer (without
* trailing padding).
*/
vector<unsigned char> BASE64::decode(const char * buf, int len, int * outlen)
{
int declen;
vector<unsigned char> decbuf;
int decoded;
if (len == -1)
len = strlen(buf);
// if (len == 0 || (len & 0x3)) /* Empty, or padding bytes missing */
// return NULL;
declen = (len >> 2) * 3;
decbuf.resize(declen * sizeof(unsigned char));
decoded = decode_into(buf, len, decbuf.data(), declen);
if (decoded == 0)
decbuf.clear();
if (outlen)
*outlen = decoded;
return decbuf;
}
/**
* decode_into
*
* Decode `len' bytes from `buf' unsignedo `declen' bytes starting from `decbuf',
* faking the necessary amount of padding if necessary.
* Caller must have ensured that there was sufficient room in decbuf.
*
* Returns the amount of bytes decoded (without trailing padding) if successful,
* 0 if the input was not valid base32.
*/
int BASE64::decode_into(const char *buf, int len, unsigned char *decbuf, int declen)
{
int padding = 0;
if (len & 0x3)
padding = 4 - (len & 0x3);
return decode_alphabet(values, buf, len + padding, decbuf, declen, padding);
}
/*
* decode_alphabet
*
* Decode `len' bytes from `buf' unsignedo `declen' bytes starting from `decbuf'.
* Caller must have ensured that there was sufficient room in decbuf.
* Uses the specified decoding alphabet.
*
* `padding', when non-zero, is the amount of padding that is missing from
* the input buffer and which we must assume.
*
* Return decoded bytes if successful, 0 if the input was not valid base32.
*/
int BASE64::decode_alphabet(const char valmap[],
const char *buf, int len, unsigned char *decbuf, int declen, int padding)
{
int i = 0; /* Input accumulator, 0 for trailing pad */
char const *ip = buf + len; /* Input pounsigneder, one byte off end */
int dlen = (len >> 2) * 3; /* Exact decoded length */
unsigned char *op; /* Output pounsigneder, one byte off end */
int bytes; /* Bytes decoded without padding */
char v;
assert(buf);
assert(decbuf);
assert(len > 0);
assert((len & 0x3) == 0); /* `len' is a multiple of 4 bytes */
//assert(declen >= dlen);
/*
* If the last byte of input is '=', there is padding and we need to
* zero the tail of the decoding buffer.
*
* Likewise, when `padding' is non-zero, act as if the '=' were there.
*/
if (buf[len-1] == '=' || padding > 0) {
int pad = 0;
int n = 0; /* Amount of bytes to zero */
int s = 0; /* Amount of bytes to zero */
/*
* Remove and count trailing input padding bytes.
*/
if (padding == 0) {
while (*--ip == '=')
pad++;
ip++; /* Pounsigneds one byte after real non-padding input */
} else {
pad = padding;
ip -= padding;
}
switch (pad) {
case 1: n = 1; s = 0; break;
case 2: n = 2; s = 1; break;
default:
return 0; /* Cannot be valid base64 */
}
memset(decbuf + (dlen - n), 0, n);
op = decbuf + (dlen - s);
bytes = dlen - n;
} else {
op = decbuf + dlen;
bytes = dlen;
}
/*
* In the following picture, we represent how the 4 bytes of input,
* each consisting of only 6 bits of information forming a base64 digit,
* are concatenated back unsignedo 3 bytes of binary information.
*
* input digit 0 1 2 3
* <----><-----><-----><---->
* +--------+--------+--------+
* |01234501|23450123|45012345|
* +--------+--------+--------+
* output byte 0 1 2
*
* Because of possible padding, which must be done as if the input
* was 0, and because the fractional part is at the end, we'll
* start decoding from the end. The decoding loop is unrolled for
* greater performance (using the infamous Duff's device to directly
* switch at the proper stage within the do {} while loop).
*/
switch ((ip - buf) % 4) {
case 0:
do {
v = valmap[(unsigned char) *--ip]; /* Input #3 */
if (v < 0) return 0;
i = v;
/* FALLTHROUGH */
case 3:
v = valmap[(unsigned char) *--ip]; /* Input #2 */
if (v < 0) return 0;
i |= v << 6; /* had 6 bits */
*--op = i & 0xff; /* Output #2 */
i >>= 8; /* lower <0123> of output #1 */
/* FALLTHROUGH */
case 2:
v = valmap[(unsigned char) *--ip]; /* Input #1 */
if (v < 0) return 0;
i |= v << 4; /* had 4 bits */
*--op = i & 0xff; /* Output #1 */
i >>= 8; /* lower <01> of output #0 */
/* FALLTHROUGH */
case 1:
v = valmap[(unsigned char) *--ip]; /* Input #0 */
if (v < 0) return 0;
i |= v << 2; /* had 2 bits */
*--op = i & 0xff; /* Output #0 */
i >>= 8; /* Holds nothing, MBZ */
assert(i == 0);
assert(op >= decbuf);
} while (op > decbuf);
}
return bytes;
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include <string>
#include <vector>
using namespace std;
class BASE64 {
public:
BASE64();
~BASE64();
string encode(unsigned char * input, int len, bool padding = false);
vector<unsigned char> decode(const char * input, int len = -1, int * outlen = nullptr);
int encode_pad_length(int len, int *pad);
private:
void encode_exactly(const unsigned char *buf, int len, char *encbuf, int enclen);
int decode_into(const char *buf, int len, unsigned char *decbuf, int declen);
int decode_alphabet(const char valmap[], const char *buf, int len, unsigned char *decbuf, int declen, int padding);
static const char values[];
static const char alphabet[];
};

1000
core/anslicensing/bigint.cpp Normal file

File diff suppressed because it is too large Load Diff

130
core/anslicensing/bigint.h Normal file
View File

@@ -0,0 +1,130 @@
#ifndef __BIGINT_H
#define __BIGINT_H
class bigint;
class bigint_value;
class bigint_unit // Provides storage allocation and index checking
{
friend class bigint_value;
friend class bigint;
public:
bigint_unit();
~bigint_unit();
public:
void clear(); // set n to zero
unsigned get( unsigned i ) const; // get ith unsigned
void set( unsigned i, unsigned x ); // set ith unsigned
void reserve( unsigned x ); // storage hint
void fast_mul( bigint_unit & x, bigint_unit & y, unsigned n ); // Time critical routine
private:
unsigned n; // used units (read-only)
unsigned * a; // array of units
unsigned z; // units allocated
};
class bigint_value : public bigint_unit
{
friend class bigint;
public:
bigint_value();
public:
int is_zero() const;
unsigned bit( unsigned i ) const;
void setbit( unsigned i );
void clearbit( unsigned i );
unsigned bits() const;
int cf( bigint_value& x ) const;
int product( bigint_value &x ) const;
void shl();
int shr(); // result is carry
void shr( unsigned n );
void add( bigint_value& x );
void _xor( bigint_value& x );
void _and( bigint_value& x );
void subtract( bigint_value& x );
void init( unsigned x );
void copy( bigint_value& x );
unsigned to_unsigned(); // Unsafe conversion to unsigned
void mul( bigint_value& x, bigint_value& y );
void divide( bigint_value& x, bigint_value& y, bigint_value& rem );
private:
unsigned share; // share count, used by bigint to delay physical copying
};
class bigint // very long integer - can be used like long
{
public:
// Construction and
bigint ( unsigned x = 0 );
bigint ( const bigint & x );
~bigint();
public:
// Standard arithmetic operators
friend bigint operator +( const bigint& x, const bigint& y );
friend bigint operator -( const bigint& x, const bigint& y );
friend bigint operator *( const bigint& x, const bigint& y );
friend bigint operator /( const bigint& x, const bigint& y );
friend bigint operator %( const bigint& x, const bigint& y );
friend bigint operator ^( const bigint& x, const bigint& y );
friend bigint pow2( unsigned n );
friend bigint operator &( const bigint& x, const bigint& y );
friend bigint operator <<( const bigint& x, unsigned n );
bigint & operator +=( const bigint& x );
bigint & operator -=( const bigint& x );
bigint & operator >>=( unsigned n );
// Standard comparison operators
friend int operator !=( const bigint& x, const bigint& y );
friend int operator ==( const bigint& x, const bigint& y );
friend int operator >=( const bigint& x, const bigint& y );
friend int operator <=( const bigint& x, const bigint& y );
friend int operator > ( const bigint& x, const bigint& y );
friend int operator < ( const bigint& x, const bigint& y );
// Absolute value
friend bigint abs( const bigint & x );
// conversion operations
friend unsigned to_unsigned( const bigint &x );
bigint & operator =(const bigint& x);
// Bit operations
unsigned bits() const;
unsigned bit(unsigned i) const;
void setbit(unsigned i);
void clearbit(unsigned i);
bigint & operator ^=( const bigint& x );
bigint & operator &=( const bigint& x );
bigint & ror( unsigned n ); // single bit rotate
bigint & rol( unsigned n ); // single bit rotate
friend int product( const bigint & x, const bigint & y ); // parity of x&y
void load( const unsigned * a, unsigned n ); // load value, a[0] is lsw
void store( unsigned * a, unsigned n ) const; // low level save, a[0] is lsw
private:
bigint_value * value;
int negative;
int cf( const bigint & x ) const;
void docopy();
friend class monty;
};
bigint modexp( const bigint & x, const bigint & e, const bigint & m ); // m must be odd
bigint gcd( const bigint & X, const bigint & Y ); // greatest common denominator
bigint modinv( const bigint & a, const bigint & m ); // modular inverse
bigint lucas ( const bigint & P, const bigint & Z, const bigint & k, const bigint & p ); // P^2 - 4Z != 0
bigint sqrt( const bigint & g, const bigint & p ); // square root mod p
bigint pow2( unsigned n );
#endif

View File

@@ -0,0 +1,232 @@
//
// Copyright (c) ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#include <tchar.h>
#endif
#include "bitstream.h"
using namespace std;
BitStream::BitStream(int bitSize)
{
Create(bitSize);
}
BitStream::BitStream(vector<unsigned char>& buf, int bufBits)
{
Attach(buf, bufBits);
}
bool BitStream::Create(int bitCount)
{
m_bufBits = bitCount;
m_currentBitIndex = 0;
if (!bitCount)
{
m_buf.clear();
return true;
}
m_buf.resize((bitCount + 7) >> 3);
Clear();
return true;
}
void BitStream::Attach(vector<unsigned char>& buf, int bufBits)
{
m_buf = std::move(buf);
m_bufBits = bufBits;
m_currentBitIndex = 0;
}
int BitStream::Read(void *bitPtr, int bitCount)
{
if(bitCount + m_currentBitIndex > m_bufBits)
{
bitCount = m_bufBits - m_currentBitIndex;
}
if(!bitCount)
{
return 0;
}
int readBitCount = bitCount;
unsigned char lastByteMask = (unsigned char)((1 << (readBitCount & 7)) - 1);
unsigned char * sourcePtr = m_buf.data() + (m_currentBitIndex >> 3);
int byteCount = (bitCount + 7) >> 3;
unsigned char * destPtr = (unsigned char *)bitPtr;
int downShift = m_currentBitIndex & 0x7;
int upShift = 8 - downShift;
if (!downShift)
{
while(byteCount--)
*destPtr++ = *sourcePtr++;
m_currentBitIndex += bitCount;
if (lastByteMask > 0)
((unsigned char *)bitPtr)[readBitCount >> 3] &= lastByteMask;
return readBitCount;
}
unsigned char sourceByte = *sourcePtr >> downShift;
m_currentBitIndex += bitCount;
for (; bitCount > 8; bitCount -= 8)
{
unsigned char nextByte = *++sourcePtr;
*destPtr++ = sourceByte | (nextByte << upShift);
sourceByte = nextByte >> downShift;
}
if (bitCount)
{
if (bitCount <= upShift)
{
*destPtr = sourceByte;
return readBitCount;
}
*destPtr = sourceByte | ( (*++sourcePtr) << upShift);
}
if (lastByteMask > 0)
((unsigned char *)bitPtr)[readBitCount >> 3] &= lastByteMask;
return readBitCount;
}
int BitStream::Write(const void * bitPtr, int bitCount)
{
int maxBits = ((m_bufBits + 7) >> 3) << 3;
if (bitCount + m_currentBitIndex > maxBits)
{
bitCount = maxBits - m_currentBitIndex;
}
if(!bitCount)
return 0;
int writeBitCount = bitCount;
int upShift = m_currentBitIndex & 0x7;
int downShift = 8 - upShift;
const unsigned char * sourcePtr = (unsigned char *)bitPtr;
unsigned char * destPtr = m_buf.data() + (m_currentBitIndex >> 3);
// if this write is for <= 1 byte, and it will all fit in the
// first dest byte, then do some special masking.
if (downShift >= bitCount)
{
unsigned char mask = (unsigned char)(((1 << bitCount) - 1) << upShift);
*destPtr = (*destPtr & ~mask) | ((*sourcePtr << upShift) & mask);
m_currentBitIndex += bitCount;
return writeBitCount;
}
// check for byte aligned writes -- this will be
// much faster than the shifting writes.
if(!upShift)
{
m_currentBitIndex += bitCount;
for(; bitCount >= 8; bitCount -= 8)
*destPtr++ = *sourcePtr++;
if(bitCount)
{
unsigned char mask = (unsigned char)((1 << bitCount) - 1);
*destPtr = (*sourcePtr & mask) | (*destPtr & ~mask);
}
return writeBitCount;
}
// the write destination is not byte aligned.
unsigned char sourceByte;
unsigned char destByte = *destPtr & (0xFF >> downShift);
unsigned char lastMask = (unsigned char)(0xFF >> (7 - ((m_currentBitIndex + bitCount - 1) & 0x7)));
m_currentBitIndex += bitCount;
for(;bitCount >= 8; bitCount -= 8)
{
sourceByte = *sourcePtr++;
*destPtr++ = destByte | (sourceByte << upShift);
destByte = sourceByte >> downShift;
}
if(bitCount == 0)
{
*destPtr = (*destPtr & ~lastMask) | (destByte & lastMask);
return writeBitCount;
}
if(bitCount <= downShift)
{
*destPtr = (*destPtr & ~lastMask) | ((destByte | (*sourcePtr << upShift)) & lastMask);
return writeBitCount;
}
sourceByte = *sourcePtr;
*destPtr++ = destByte | (sourceByte << upShift);
*destPtr = (*destPtr & ~lastMask) | ((sourceByte >> downShift) & lastMask);
return writeBitCount;
}
void BitStream::ZeroPadToNextByte()
{
unsigned char zero = 0;
if(m_currentBitIndex & 0x7)
Write(&zero, 8 - (m_currentBitIndex & 0x7));
}
int BitStream::Seek(int offset, bool relative)
{
unsigned oldIndex = m_currentBitIndex;
m_currentBitIndex = (relative) ? m_currentBitIndex + offset : offset;
return oldIndex;
}
int BitStream::GetSize()
{
return m_bufBits;
}
void * BitStream::GetBuffer(int * sizeInBits)
{
if (sizeInBits != NULL)
*sizeInBits = m_bufBits;
return m_buf.data();
}
void BitStream::ReleaseBuffer(int bitCount)
{
m_currentBitIndex = bitCount;
}
void BitStream::Clear()
{
memset(m_buf.data(), 0, m_buf.size());
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <vector>
using namespace std;
class BitStream
{
public:
BitStream(int bitSize = 0);
BitStream(vector<unsigned char>& buf, int bitSize);
bool Create(int sizeInBits);
void Attach(vector<unsigned char>& buf, int sizeInBits);
int Read(void *bitPtr, int countInBits);
int Write(const void * bitPtr, int countInBits);
int Seek(int offset, bool relative = false);
int GetSize();
void ZeroPadToNextByte();
void * GetBuffer(int * sizeInBits = NULL);
void ReleaseBuffer(int bitCount);
void Clear();
protected:
vector<unsigned char> m_buf;
int m_bufBits;
int m_currentBitIndex;
};

View File

@@ -0,0 +1,125 @@
#include "precomp.h"
#include <stdlib.h>
#include <string.h>
#include "bitstream2.h"
const unsigned char BitStream2::hiMask[] = { 0, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
BitStream2::BitStream2() :
ownMemory(false),
currentBit(0),
currentByte(0),
buffer(NULL)
{
}
BitStream2::BitStream2(int bitCount)
{
currentBit = 0;
currentByte = 0;
Create(bitCount);
}
BitStream2::~BitStream2()
{
if (ownMemory)
delete buffer;
}
void BitStream2::Create(int bitCount)
{
bufSize = (bitCount + 7) >> 3;
buffer = new unsigned char[(bitCount + 7) >> 3];
ownMemory = true;
memset(buffer, 0, bufSize);
}
void BitStream2::Attach(void * buf, int bitCount)
{
buffer = (unsigned char *)buf;
}
int BitStream2::Write(const unsigned char * buf, int bitCount)
{
unsigned char destByte;
int leftBits = currentBit & 7;
int rightBits = 8 - leftBits;
int i = 0;
int count = bitCount;
while (count > 0)
{
destByte = (unsigned char)((buffer[currentByte] & hiMask[leftBits]) | (buf[i] >> leftBits));
buffer[currentByte] = destByte;
count = (count > rightBits) ? count - rightBits : 0;
if (count > 0)
{
currentByte++;
buffer[currentByte] = (unsigned char)(buf[i] << rightBits);
count = (count > leftBits) ? count - leftBits : 0;
}
i++;
}
currentBit += bitCount;
return bitCount;
}
int BitStream2::WriteUInt16(unsigned short val)
{
unsigned char split[2]; split[0] = (unsigned char)(val >> 8); split[1] = (unsigned char)(val & 0xFF);
return Write(split, 16);
}
int BitStream2::Read(unsigned char * buf, int bitCount)
{
unsigned char destByte;
int rightBits = 8 - (currentBit & 7);
int leftBits = 8 - rightBits;
int count = bitCount;
int i = 0;
while (count > 0)
{
buf[i] = (unsigned char)(buffer[currentByte] << leftBits);
count = (count > rightBits) ? count - rightBits : 0;
if (count > 0)
{
currentByte++;
destByte = buf[i];
destByte = (unsigned char)(destByte | (buffer[currentByte] >> rightBits));
buf[i] = destByte;
count = (count > leftBits) ? count - leftBits : 0;
}
i++;
}
currentBit += bitCount;
return bitCount;
}
int BitStream2::ReadUInt16(unsigned short * val)
{
unsigned char split[2];
int result = Read(split, 16);
*val = (unsigned short)(((unsigned short)split[0] << 8) | (unsigned short)split[1]);
return result;
}
unsigned char * BitStream2::GetBuffer()
{
return buffer;
}

View File

@@ -0,0 +1,24 @@
#pragma once
class BitStream2
{
public:
BitStream2();
BitStream2(int bitCount);
~BitStream2();
void Create(int bitCount);
void Attach(void * buf, int bitCount);
int Write(const unsigned char * buf, int bitCount);
int WriteUInt16(unsigned short val);
int Read(unsigned char * buf, int bitCount);
int ReadUInt16(unsigned short * val);
unsigned char * GetBuffer();
protected:
bool ownMemory;
unsigned char * buffer;
int bufSize;
int currentBit, currentByte;
static const unsigned char hiMask[];
};

View File

@@ -0,0 +1,144 @@
#include "precomp.h"
#include <stdlib.h>
#include <string.h>
#include "bitstream3.h"
const unsigned char BitStream3::hiMask[] = { 0, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
BitStream3::BitStream3() :
ownMemory(false),
currentBit(0),
currentByte(0),
buffer(NULL)
{
}
BitStream3::BitStream3(int bitCount)
{
currentBit = 0;
currentByte = 0;
Create(bitCount);
}
BitStream3::~BitStream3()
{
if (ownMemory)
free(buffer);
}
void BitStream3::Create(int bitCount)
{
bufSize = (bitCount + 7) >> 3;
bitSize = bitCount;
buffer = (unsigned char*)malloc((bitCount + 7) >> 3);
ownMemory = true;
memset(buffer, 0, bufSize);
}
void BitStream3::Attach(void * buf, int bitCount)
{
buffer = (unsigned char *)buf;
bitSize = bitCount;
currentBit = 0;
currentByte = 0;
}
int BitStream3::Write(const unsigned char * buf, int bitCount)
{
int i = 0, gap = 8 - (currentBit & 7);
if (bitCount >= gap)
{
if ((gap & 7) != 0)
{
buffer[currentByte] = (unsigned char)((buffer[currentByte] << gap) | (buf[0] >> (bitCount < 8 ? bitCount - gap : 8 - gap)));
currentBit += gap; bitCount -= gap; currentByte++;
for (; bitCount >= 8; i++, currentByte++, currentBit += 8, bitCount -= 8)
buffer[currentByte] = (unsigned char)((buf[i] << gap) | (buf[i + 1] >> (8 - gap)));
}
else
for (; bitCount >= 8; currentByte++, i++, currentBit += 8, bitCount -= 8)
buffer[currentByte] = buf[i];
}
if (bitCount > 0)
{
buffer[currentByte] = (unsigned char)((buffer[currentByte] << bitCount) | (buf[i] & ((1 << bitCount) - 1)));
currentBit += bitCount;
}
return bitCount;
}
int BitStream3::WriteUInt16(unsigned short val)
{
unsigned char split[2]; split[0] = (unsigned char)(val >> 8); split[1] = (unsigned char)(val & 0xFF);
return Write(split, 16);
}
int BitStream3::Read(unsigned char * readBuf, int bitCount)
{
int i = 0, gap = currentBit & 7;
if ((gap & 7) != 0)
{
for (; bitCount >= 8 + 8 - gap; bitCount -= 8, currentByte++, currentBit += 8, i++)
readBuf[i] = (unsigned char)((buffer[currentByte] << gap) | (buffer[currentByte + 1] >> (8 - gap)));
// byte align
if (bitCount > 0)
{
if (bitCount < 8 - gap)
{
readBuf[i] = (unsigned char)((buffer[currentByte] >> (8 - gap - bitCount)) & ((1 << bitCount) - 1));
currentBit += bitCount;
bitCount = 0;
}
else
{
readBuf[i] = (unsigned char)(buffer[currentByte] & ((1 << (8 - gap)) - 1));
bitCount -= (8 - gap);
currentBit += (8 - gap);
currentByte++;
readBuf[i] <<= (bitCount < gap ? bitCount : gap);
}
}
}
else
for (; bitCount >= 8; bitCount -= 8, currentByte++, currentBit += 8, i++)
readBuf[i] = buffer[currentByte];
// already aligned
if (bitCount > 0)
{
if (currentBit + 8 <= bitSize) // not last byte
readBuf[i] |= (unsigned char)((buffer[currentByte] >> (8 - bitCount)) & ((1 << bitCount) - 1));
else // last byte
readBuf[i] = (unsigned char)((buffer[currentByte] >> ((bitSize & 7) - bitCount)) & ((1 << bitCount) - 1));
currentBit += bitCount;
}
return bitCount;
}
int BitStream3::ReadUInt16(unsigned short * val)
{
unsigned char split[2];
int result = Read(split, 16);
*val = (unsigned short)(((unsigned short)split[0] << 8) | (unsigned short)split[1]);
return result;
}
unsigned char * BitStream3::GetBuffer()
{
return buffer;
}

View File

@@ -0,0 +1,24 @@
#pragma once
class BitStream3
{
public:
BitStream3();
BitStream3(int bitCount);
~BitStream3();
void Create(int bitCount);
void Attach(void * buf, int bitCount);
int Write(const unsigned char * buf, int bitCount);
int WriteUInt16(unsigned short val);
int Read(unsigned char * buf, int bitCount);
int ReadUInt16(unsigned short * val);
unsigned char * GetBuffer();
protected:
bool ownMemory;
unsigned char * buffer;
int bufSize, bitSize;
int currentBit, currentByte;
static const unsigned char hiMask[];
};

View File

@@ -0,0 +1,4 @@
#include "precomp.h"
#include "bitstruct.h"

View File

@@ -0,0 +1,378 @@
#pragma once
#include <memory>
#include <map>
#include "bitstream.h"
#include "uniconv.h"
#include "except.h"
#ifndef _WIN32
#include <alloca.h>
#else
#include <malloc.h>
#endif
using namespace std;
class BitStruct {
public:
enum FIELD_TYPE
{
RAW,
INTEGER,
STRING,
DATE14,
DATE13,
DATE16,
};
private:
class Field {
public:
Field():
m_fieldType(FIELD_TYPE::INTEGER),
m_offset(0),
m_size(0)
{
}
Field(FIELD_TYPE fieldType, int offset, int size)
{
m_fieldType = fieldType;
m_offset = offset;
m_size = size;
}
public:
FIELD_TYPE m_fieldType;
int m_offset;
int m_size;
};
typedef std::map<string, Field> FieldMap;
public:
BitStruct(int bitSize = 0) :
m_bits(bitSize)
{
}
BitStruct(vector<unsigned char>& buf, int bitSize):
m_bits(buf, bitSize)
{
}
void Create(int bitSize = 0)
{
m_bits.Create(bitSize);
}
void Attach(vector<unsigned char>& buf, int bitSize)
{
m_bits.Attach(buf, bitSize);
}
void AddField(const char * fieldName, FIELD_TYPE fieldType, int fieldBitSize, int offset = -1 )
{
if (offset == -1)
offset = currentFieldOffset;
m_fieldMap.insert(FieldMap::value_type(fieldName, Field(fieldType, offset, fieldBitSize)));
currentFieldOffset = offset + fieldBitSize;
}
bool GetField(const char * fieldName, FIELD_TYPE * fieldType, int * fieldSize, int * fieldOffset) const
{
FieldMap::const_iterator iter = m_fieldMap.find(fieldName);
if (iter == m_fieldMap.end())
return false;
*fieldType = iter->second.m_fieldType;
*fieldSize = iter->second.m_size;
*fieldOffset = iter->second.m_offset;
return true;
}
bool EnumFields(void **enumHandle, const char **fieldName, FIELD_TYPE * fieldType, int * fieldSize, int * offset)
{
FieldMap::iterator * pIter;
static string name;
if (*enumHandle == NULL)
{
pIter = new FieldMap::iterator(m_fieldMap.begin());
if (!pIter)
return false;
}
else
pIter = (FieldMap::iterator *)(*enumHandle);
if (*pIter == m_fieldMap.end())
{
delete pIter;
return false;
}
name = (*pIter)->first;
*fieldName = name.c_str();
*fieldType = (*pIter)->second.m_fieldType;
*fieldSize = (*pIter)->second.m_size;
*offset = (*pIter)->second.m_offset;
pIter->operator ++(); // *Iter++ does not work. Think why :)
*enumHandle = pIter;
return true;
}
void Set(const char * fieldName, const void * buf, unsigned len)
{
int offset = 0, size = m_bits.GetSize();
if (fieldName)
{
FieldMap::iterator iter;
iter = m_fieldMap.find(fieldName);
if (iter == m_fieldMap.end())
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
offset = iter->second.m_offset;
size = iter->second.m_size;
}
m_bits.Seek(offset);
int bitlen = len << 3;
if (bitlen >= size)
m_bits.Write(buf, size);
else
{
int bits = size - bitlen;
unsigned char * zeroes = (unsigned char *)_alloca((bits + 7) >> 3);
memset(zeroes, 0, (bits + 7) >> 3);
m_bits.Write(buf, bitlen);
m_bits.Write(zeroes, bits);
}
}
void Set(const char * fieldName, const char * data)
{
Set(fieldName, data, (unsigned)strlen(data));
}
void Set(const char * fieldName, int data)
{
#ifndef LICENSING_BIG_ENDIAN
Set(fieldName, &data, sizeof(data));
#else
unsigned char buf[sizeof(int)] = { 0, 0, 0, 0 };
buf[0] = (unsigned char)(data & 0xFF);
buf[1] = (unsigned char)((data >> 8) & 0xFF);
buf[2] = (unsigned char)((data >> 16) & 0xFF);
buf[3] = (unsigned char)((data >> 24) & 0xFF);
Set(fieldName, buf, sizeof(data));
#endif
}
void Set(const char * fieldName, int year, int month, int day)
{
FieldMap::iterator iter;
iter = m_fieldMap.find(fieldName);
if (iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
int date;
switch (iter->second.m_fieldType)
{
case FIELD_TYPE_DATE13:
date = PackDate13(year, month, day);
break;
case FIELD_TYPE_DATE14:
date = PackDate14(year, month, day);
break;
case FIELD_TYPE_DATE16:
date = PackDate16(year, month, day);
break;
default:
throw new LicensingException(STATUS_INVALID_PARAM, "A data value is being set to a non-date field");
}
Set(fieldName, date);
}
void Get(const char * dataField, void * buf, int * len)
{
if (dataField)
{
FieldMap::const_iterator iter;
iter = m_fieldMap.find(dataField);
if ( iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
if ( *len < ( iter->second.m_size + 7 ) >> 3 )
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
m_bits.Seek(iter->second.m_offset);
m_bits.Read(buf, iter->second.m_size);
*len = (iter->second.m_size + 7) >> 3;
} else
{
int validationDataLen = (m_bits.GetSize() + 7) >> 3;
if (*len < validationDataLen)
{
*len = validationDataLen;
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
}
memcpy(buf, m_bits.GetBuffer(), validationDataLen);
*len = validationDataLen;
}
}
int GetInt(const char * dataField)
{
FieldMap::const_iterator iter;
iter = m_fieldMap.find(dataField);
if ( iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
unsigned char buf[sizeof(int)] = {0, 0, 0, 0};
if ( sizeof(buf) < ( iter->second.m_size + 7 ) >> 3 )
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
m_bits.Seek(iter->second.m_offset);
m_bits.Read(buf, iter->second.m_size);
#ifndef LICENSING_BIG_ENDIAN
return *(int *)buf;
#else
return ((int)buf[3] << 24) | ((int)buf[2] << 16) | ((int)buf[1] << 8) | (int)buf[0];
#endif
}
void GetDate(const char * dataField, int * year, int * month, int * day)
{
FieldMap::const_iterator iter;
iter = m_fieldMap.find(dataField);
if ( iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
unsigned short packedDate = (unsigned short)GetInt(dataField);
switch (iter->second.m_fieldType)
{
case FIELD_TYPE_DATE13:
UnpackDate13(packedDate, year, month, day);
break;
case FIELD_TYPE_DATE14:
UnpackDate14(packedDate, year, month, day);
break;
case FIELD_TYPE_DATE16:
UnpackDate16(packedDate, year, month, day);
break;
default:
throw new LicensingException(STATUS_INVALID_PARAM, "An attempt was made to query a date from a non-date field");
}
}
void * GetBuffer(int * sizeInBits = NULL)
{
return m_bits.GetBuffer(sizeInBits);
}
BitStream& GetBitStream()
{
return m_bits;
}
int GetCurrentFieldOffset()
{
return currentFieldOffset;
}
void ResetFieldOffset()
{
currentFieldOffset = 0;
}
int GetSize()
{
return m_bits.GetSize();
}
private:
unsigned short PackDate13(int year, int month, int day)
{
if (year < 2012 || year > 2027)
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 13-bit date. Allowed values are 2012-2027");
return (unsigned short)(((month - 1) << 9) | ((day - 1) << 4) | (year - 2012));
}
void UnpackDate13(unsigned short packedDate, int * year, int * month, int * day)
{
*year = 2012 + (packedDate & 0x0F);
*month = 1 + (packedDate >> 9);
*day = 1 + ((packedDate >> 4) & 0x1F);
}
unsigned short PackDate14(int year, int month, int day)
{
if (year < 2010 || year > 2041)
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 14-bit date. Allowed values are 2010-2041");
return (unsigned short)(((month - 1) << 10) | ((day - 1) << 5) | (year - 2010));
}
void UnpackDate14(unsigned short packedDate, int * year, int * month, int * day)
{
*year = 2010 + (packedDate & 0x1F);
*month = 1 + (packedDate >> 10);
*day = 1 + ((packedDate >> 5) & 0x1F);
}
unsigned short PackDate16(int year, int month, int day)
{
if (year < 2000 || year > 2127)
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 16-bit date. Allowed values are 2010-2127");
return (unsigned short)(((year - 2000) << 9) | (month << 5) | day);
}
void UnpackDate16(unsigned short packedDate, int * year, int * month, int * day)
{
*year = 2000 + (packedDate >> 9);
*month = (packedDate & 0x01FF) >> 5;
*day = packedDate & 0x001F;
}
FieldMap m_fieldMap;
BitStream m_bits;
int currentFieldOffset;
};

View File

@@ -0,0 +1,2 @@
#include "precomp.h"
#include "certificate.h"

View File

@@ -0,0 +1,451 @@
#ifndef __CERTIFICATE_H
#define __CERTIFICATE_H
#include "ecc.h"
#include "bitstruct.h"
#include "except.h"
#include "base64.h"
#include "sdkregistration.h"
#include "download.h"
#include <time.h>
using namespace ECC;
class Certificate
{
public:
Certificate()
{
}
Certificate(const char * base64Certificate)
{
BASE64 base64;
int len;
auto buf = base64.decode(base64Certificate, strlen(base64Certificate), &len);
if (buf.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 encoding for certificate");
Attach(buf, len);
}
Certificate(vector<unsigned char>& buf, int len)
{
Attach(buf, len);
}
void* GetBuffer(int * len)
{
int size;
void * buf = m_certBits.GetBuffer(&size);
size = (size + 7) >> 3;
*len = size;
return buf;
}
const char * ToString()
{
BASE64 base64;
int len;
static string base64cert;
unsigned char * buf = (unsigned char *)m_certBits.GetBuffer(&len);
len = (len + 7) >> 3;
auto base64Buf = base64.encode(buf, len, true);
if (base64Buf.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "could not encode buffer to base64");
base64cert = base64Buf.c_str();
return base64cert.c_str();
}
/*
static Certificate * Generate(int signatureSize, time_t expirationDate = 0)
{
return Generate(signatureSize, (ECC::Key *)NULL, NULL, NULL, NULL, expirationDate);
}
static Certificate * Generate(int signatureSize, Certificate * signingCertificate, time_t expirationDate = 0)
{
return Generate(signatureSize, NULL, NULL, signingCertificate, NULL, expirationDate);
}
static Certificate * Generate(int signatureSize, const char * certificateAuthorityUrl, time_t expirationDate = 0)
{
return Generate(signatureSize, (ECC::Key *)NULL, NULL, NULL, certificateAuthorityUrl, expirationDate);
}
*/
static bool VerifySignature(Certificate * cert, Certificate * validationCert)
{
unsigned char rawPublicKey[256]; int rawPublicKeyLen = 256;
if (validationCert == NULL || cert->m_certBits.GetInt("IsSelfSigned") != 0)
cert->m_certBits.Get("PublicKey", rawPublicKey, &rawPublicKeyLen);
else
validationCert->m_certBits.Get("PublicKey", rawPublicKey, &rawPublicKeyLen);
Key key(rawPublicKey, rawPublicKeyLen);
Verifier verifier;
verifier.SetPublicKey(&key);
unsigned char * certBuffer = (unsigned char *)cert->m_certBits.GetBuffer();
int signedPartLen = 4 + cert->m_certBits.GetInt("PublicKeyLen"),
signatureOffset = 2 + signedPartLen,
signatureBitLen = cert->m_certBits.GetInt("SignatureSizeBits");
if (!verifier.Verify(certBuffer, signedPartLen, certBuffer + signatureOffset, (signatureBitLen + 7) >> 3, signatureBitLen))
return false;
return true;
}
void GetPublicKey(void * buf, int * len)
{
m_certBits.Get("PublicKey", buf, len);
}
static Certificate * Generate(int signatureSize, const char * base64PrivateKey, const char * base64PublicKey, const char * base64SigningPrivateKey, const char * base64SigningCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
{
Key * privateKey = NULL,
* publicKey = NULL,
* privateSigningKey;
Certificate * signingCertificate = NULL;
Certificate * result;
try {
if (base64PublicKey != NULL)
publicKey = new Key(base64PublicKey);
if (base64PrivateKey != NULL)
privateKey = new Key(base64PrivateKey);
if (base64SigningPrivateKey != NULL)
privateSigningKey = new Key(base64SigningPrivateKey);
if (base64SigningCertificate != NULL)
signingCertificate = new Certificate(base64SigningCertificate);
result = Generate(signatureSize, privateKey, publicKey, privateSigningKey, signingCertificate, certificateAuthorityUrl, expirationDate);
} catch (...)
{
if (privateKey) delete privateKey;
if (publicKey) delete publicKey;
if (privateSigningKey) delete privateSigningKey;
if (signingCertificate) delete signingCertificate;
throw;
}
if (privateKey) delete privateKey;
if (publicKey) delete publicKey;
if (privateSigningKey) delete privateSigningKey;
if (signingCertificate) delete signingCertificate;
return result;
}
static Certificate * Generate(int signatureSize, Key * privateKey, Key * publicKey, Key * signingPrivateKey, Certificate * signingCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
{
if (publicKey == NULL)
{
throw new LicensingException(STATUS_GENERIC_ERROR, "public key must be provided for the certificate");
}
Key * signingKey = NULL;
bool selfSigned;
if (signingPrivateKey == NULL && certificateAuthorityUrl == NULL)
{
selfSigned = true;
signingKey = privateKey;
}
else
{
selfSigned = false;
if (signingPrivateKey != NULL)
signingKey = signingPrivateKey;
// else use certificate authority url for signing
}
unsigned char rawPublicKey[256]; int rawPublicKeyLen = 256;
publicKey->Store(rawPublicKey, &rawPublicKeyLen);
// unsigned char rawPrivateKey[256]; int rawPrivateKeyLen = 256;
// signingKey->Store(rawPrivateKey, &rawPrivateKeyLen);
int certBitsLen = 4 * 8 + rawPublicKeyLen * 8;
BitStruct certBits(certBitsLen);
certBits.ResetFieldOffset();
certBits.AddField("Version", BitStruct::INTEGER, 4);
certBits.AddField("IsSelfSigned", BitStruct::INTEGER, 1);
certBits.AddField("ReservedFlags", BitStruct::INTEGER, 3);
certBits.AddField("ExpirationDate", BitStruct::DATE16, 16);
certBits.AddField("PublicKeyLen", BitStruct::INTEGER, 8);
certBits.AddField("PublicKey", BitStruct::RAW, rawPublicKeyLen * 8);
certBits.Set("Version", 0);
certBits.Set("IsSelfSigned", (selfSigned) ? 1 : 0);
certBits.Set("ReservedFlags", 0);
expirationDate = time(NULL);
struct tm * t = gmtime(&expirationDate);
certBits.Set("ExpirationDate", t->tm_year + 1900, t->tm_mon, t->tm_mday);
certBits.Set("PublicKeyLen", rawPublicKeyLen);
certBits.Set("PublicKey", rawPublicKey, rawPublicKeyLen);
unsigned char certSignature[256];
int sigSizeBytes = 256;
int sigSizeBits;
if (signingKey != NULL)
{
Signer signer;
signer.SetPrivateKey(signingKey);
signer.Sign(certBits.GetBuffer(), (certBitsLen + 7) >> 3, certSignature, &sigSizeBytes, &sigSizeBits);
}
else
{
#ifndef LICENSING_NO_NETWORKING
if (!certificateAuthorityUrl)
throw new LicensingException(STATUS_GENERIC_ERROR, "no means for certificate signing were provided");
string certificateAuthorityRequest(certificateAuthorityUrl);
certificateAuthorityRequest.append("?csr=");
BASE64 base64;
int len = 4096;
char buffer[4096];
auto base64csr = base64.encode((unsigned char *)certBits.GetBuffer(), (certBits.GetSize() + 7) >> 3, true);
string escapedBase64csr(base64csr.c_str());
StrReplace(escapedBase64csr, "+", "%2B");
StrReplace(escapedBase64csr, "/", "%2F");
StrReplace(escapedBase64csr, "=", "%3D");
certificateAuthorityRequest.append(escapedBase64csr);
const char * sdkLicenseKey = SDKRegistrationImpl::GetLicenseKey();
if (sdkLicenseKey && strlen(sdkLicenseKey) > 0)
{
certificateAuthorityRequest.append("&sdklicensekey=");
certificateAuthorityRequest.append(sdkLicenseKey);
}
UrlDownloadToString(certificateAuthorityRequest.c_str(), buffer, &len);
auto rawBuffer = base64.decode(buffer, len, &len);
if (rawBuffer.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 string");
auto certBuffer = rawBuffer;
unique_ptr<Certificate> issuedCert = std::make_unique<Certificate>(certBuffer, len);
sigSizeBits = issuedCert->m_certBits.GetInt("SignatureSizeBits");
sigSizeBytes = (sigSizeBits + 7) >> 3;
issuedCert->m_certBits.Get("Signature", certSignature, &sigSizeBytes);
memcpy(certBits.GetBuffer(), rawBuffer.data(), 4 + rawPublicKeyLen);
#else
throw new LicensingException(STATUS_GENERIC_ERROR, "certificate signing private key not provided");
#endif
}
int certBufLen = ((certBitsLen + 7) >> 3) // header + public key
+ 2 // signature size in bits
+ ((sigSizeBits + 7) >> 3); // signature
vector<unsigned char> certBuf;
certBuf.resize(certBufLen);
memcpy(certBuf.data(), certBits.GetBuffer(), (certBitsLen + 7) >> 3);
certBits.Attach(certBuf, certBufLen * 8);
certBits.AddField("SignatureSizeBits", BitStruct::INTEGER, 16);
certBits.AddField("Signature", BitStruct::RAW, ((sigSizeBits + 7) >> 3) << 3);
certBits.Set("SignatureSizeBits", sigSizeBits);
certBits.Set("Signature", certSignature, (sigSizeBits + 7) >> 3);
Certificate * cert = new Certificate();
cert->m_certBits = std::move(certBits);
return cert;
}
static const char * Sign(const char * csr, const char * privateKey, const char * signingPrivateKey, const char * signingCertificate, const char * certificateAuthorityUrl, int expYear, int expMonth, int expDay)
{
Certificate * _csr = new Certificate(csr);
Key * _privateKey = (privateKey) ? new Key(privateKey) : NULL;
Key * _signingPrivateKey = (signingPrivateKey) ? new Key(signingPrivateKey) : NULL;
Certificate * _signingCertificate = (signingCertificate) ? new Certificate(signingCertificate) : NULL;
struct tm _expTm;
time_t _expTime = 0;
if (expYear >= 1900 && expMonth >= 1 && expMonth <= 12 && expDay >= 1 && expDay <= 31)
{
memset(&_expTm, 0, sizeof(_expTm));
_expTm.tm_year = expYear - 1900;
_expTm.tm_mon = expMonth - 1;
_expTm.tm_mday = expDay;
_expTime = mktime(&_expTm);
}
else
if (expYear != 0 || expMonth != 0 || expDay != 0)
throw new LicensingException(STATUS_GENERIC_ERROR, "Invalid certificate expiration date");
Certificate * _signedCert = Sign(_csr, _privateKey, _signingPrivateKey, _signingCertificate, certificateAuthorityUrl, 0);
if (_csr) delete _csr;
if (_privateKey) delete _privateKey;
if (_signingPrivateKey) delete _signingPrivateKey;
if (_signingCertificate) delete _signingCertificate;
const char * signedCert = _signedCert->ToString();
delete _signedCert;
return signedCert;
}
static Certificate * Sign(Certificate * csr, Key * privateKey, Key * signingPrivateKey, Certificate * signingCertificate, const char * certificateAuthorityUrl, time_t expirationDate)
{
unsigned char buf[1024];
int len = 1024;
Key * publicKey;
csr->GetPublicKey(buf, &len);
publicKey = new Key(buf, len);
Certificate * cert = Certificate::Generate(0, privateKey, publicKey, signingPrivateKey, signingCertificate, certificateAuthorityUrl, expirationDate);
delete publicKey;
return cert;
}
private:
void Attach(vector<unsigned char>& buf, int len)
{
m_certBits.Attach(buf, len << 3);
m_certBits.ResetFieldOffset();
m_certBits.AddField("Version", BitStruct::INTEGER, 4);
m_certBits.AddField("IsSelfSigned", BitStruct::INTEGER, 1);
m_certBits.AddField("ReservedFlags", BitStruct::INTEGER, 3);
m_certBits.AddField("ExpirationDate", BitStruct::DATE16, 16);
m_certBits.AddField("PublicKeyLen", BitStruct::INTEGER, 8);
m_certBits.AddField("PublicKey", BitStruct::RAW, m_certBits.GetInt("PublicKeyLen") * 8);
int signedPartLen = (m_certBits.GetCurrentFieldOffset() + 7) >> 3;
if (len <= signedPartLen)
return;
m_certBits.AddField("SignatureSizeBits", BitStruct::INTEGER, 16);
int signatureBitLen = m_certBits.GetInt("SignatureSizeBits");
int signatureLen = (signatureBitLen + 7) >> 3;
int signatureOffset = m_certBits.GetCurrentFieldOffset() >> 3;
m_certBits.AddField("Signature", BitStruct::RAW, signatureLen << 3);
}
static ECC::KEY_TYPE GetKeyType(int sigSize)
{
if (sigSize < 76 || sigSize > 322)
throw new LicensingException(STATUS_INVALID_SIGNATURE_SIZE);
ECC::KEY_TYPE keyType;
int keySize;
if (sigSize <= 108)
{
keyType = ECC::ECC_54;
keySize = 54;
} else
if (sigSize <= 146)
{
keyType = ECC::ECC_73;
keySize = 73;
} else
if (sigSize <= 158)
{
keyType = ECC::ECC_79;
keySize = 79;
} else
if (sigSize <= 182)
{
keyType = ECC::ECC_91;
keySize = 91;
} else
if (sigSize <= 200)
{
keyType = ECC::ECC_100;
keySize = 100;
} else
if (sigSize <= 240)
{
keyType = ECC::ECC_120;
keySize = 120;
} else
if (sigSize <= 262)
{
keyType = ECC::ECC_131;
keySize = 131;
} else
if (sigSize <= 282)
{
keyType = ECC::ECC_141;
keySize = 141;
} else
{
keyType = ECC::ECC_161;
keySize = 161;
}
return keyType;
}
static void StrReplace(string& str, const string& oldStr, const string& newStr)
{
size_t pos = 0;
while((pos = str.find(oldStr, pos)) != std::string::npos)
{
str.replace(pos, oldStr.length(), newStr);
pos += newStr.length();
}
}
BitStruct m_certBits;
};
#endif

View File

@@ -0,0 +1,69 @@
#include "precomp.h"
#include "crc32.h"
const unsigned int Crc32::crcTable[256] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
0x2D02EF8D
};
unsigned int Crc32::Compute(const unsigned char * buffer, int count)
{
unsigned int crc = 0xFFFFFFFF;
while (count--)
crc = (crc >> 8) ^ crcTable[(crc ^ *buffer++) & 0xFF];
return crc ^ 0xFFFFFFFF;
}

10
core/anslicensing/crc32.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
class Crc32
{
public:
static unsigned int Compute(const unsigned char * buffer, int count);
private:
static const unsigned int crcTable[256];
};

2616
core/anslicensing/cwrap.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,211 @@
#include "precomp.h"
#include <iostream>
#include <string>
#include "download.h"
#include "uniconv.h"
#include "except.h"
#ifdef _WIN32
#include <winhttp.h>
#include <malloc.h>
#else
#include <curl/curl.h>
#endif
#ifndef _WIN32
class CurlWriteBuffer
{
public:
CurlWriteBuffer(void * buffer, size_t size)
{
this->buffer = (char *)buffer;
this->size = size;
offset = 0;
}
int Append(void * buffer, size_t size)
{
if (this->offset + size > this->size)
size = this->size - offset;
if (size > 0)
{
memcpy(this->buffer + offset, buffer, size);
offset += size;
}
return size;
}
static size_t
Callback(void *contents, size_t size, size_t nmemb, void *userp)
{
return ((CurlWriteBuffer *)userp)->Append(contents, size * nmemb);
}
size_t offset;
size_t size;
char * buffer;
};
#endif
void UrlDownloadToString(const char * url, char * buffer, int * len)
{
#ifndef LICENSING_NO_NETWORKING
#ifdef _WIN32
HRESULT result = ERROR_SUCCESS;
URL_COMPONENTS urlComponents;
do {
ZeroMemory(&urlComponents, sizeof(urlComponents));
urlComponents.dwStructSize = sizeof(urlComponents);
urlComponents.dwHostNameLength = (DWORD)-1;
urlComponents.dwUrlPathLength = (DWORD)-1;
auto urlw = s2w(url);
if (!WinHttpCrackUrl(urlw.c_str(), urlw.size(), 0L, &urlComponents))
{
result = GetLastError();
break;
}
wstring hostName(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> internet_ptr(WinHttpOpen(L"ANSCENTER Licensing SDK", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0L), WinHttpCloseHandle);
if (!internet_ptr)
{
result = GetLastError();
break;
}
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> connection_ptr(WinHttpConnect(internet_ptr.get(), hostName.c_str(), urlComponents.nPort, 0L), WinHttpCloseHandle);
if (connection_ptr == NULL)
{
result = GetLastError();
break;
}
wstring objectPath(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
DWORD requestFlags = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS)
requestFlags |= WINHTTP_FLAG_SECURE;
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> request_ptr(WinHttpOpenRequest(connection_ptr.get(), L"GET", objectPath.c_str(), NULL, NULL, NULL, requestFlags), WinHttpCloseHandle);
if (!request_ptr)
{
result = GetLastError();
break;
}
if (!WinHttpSendRequest(request_ptr.get(), NULL, 0L, NULL, 0, 0L, NULL))
{
result = GetLastError();
break;
}
if (!WinHttpReceiveResponse(request_ptr.get(), NULL))
{
result = GetLastError();
break;
}
DWORD status;
DWORD statusSize = sizeof(DWORD);
if (!WinHttpQueryHeaders(request_ptr.get(), WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status, &statusSize, WINHTTP_NO_HEADER_INDEX))
{
result = GetLastError();
break;
}
if (status != HTTP_STATUS_OK)
{
WCHAR buffer[1024];
DWORD bufferSize = 1024;
if (!WinHttpQueryHeaders(request_ptr.get(), WINHTTP_QUERY_STATUS_TEXT, WINHTTP_HEADER_NAME_BY_INDEX, buffer, &bufferSize, WINHTTP_NO_HEADER_INDEX))
{
result = GetLastError();
break;
}
result = ERROR_WINHTTP_INVALID_URL;
break;
}
if (status != HTTP_STATUS_OK)
{
result = GetLastError();
break;
}
DWORD offset = 0, count;
char lbuf[0x100];
do {
if (WinHttpReadData(request_ptr.get(), lbuf, 0x100, &count))
{
if (count == 0)
{
*len = offset;
break;
}
if (offset + count > *len)
{
result = ERROR_INSUFFICIENT_BUFFER;
break;
}
memcpy(buffer + offset, lbuf, count);
offset += count;
} else
{
result = GetLastError();
break;
}
} while (true);
} while (false);
if (result != ERROR_SUCCESS)
throw new LicensingException(result, "networking error while downloading url contents");
#else
CURL *curl;
CURLcode res;
if ((curl = curl_easy_init()) == NULL)
throw new LicensingException(STATUS_NET_ERROR, "cURL initalization failed");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
CurlWriteBuffer curlBuffer(buffer, *len);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteBuffer::Callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &curlBuffer);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
{
curl_easy_cleanup(curl);
throw new LicensingException(STATUS_NET_ERROR, curl_easy_strerror(res));
}
*len = curlBuffer.offset;
curl_easy_cleanup(curl);
#endif
#else // !LICENSING_NO_NETWORKING
throw new LicensingException(STATUS_GENERIC_ERROR, "networking support not built in");
#endif
}

View File

@@ -0,0 +1,6 @@
#ifndef __DOWNLOAD_H
#define __DOWNLOAD_H
void UrlDownloadToString(const char * url, char * buffer, int * len);
#endif

1473
core/anslicensing/ec2m.cpp Normal file

File diff suppressed because it is too large Load Diff

256
core/anslicensing/ec2m.h Normal file
View File

@@ -0,0 +1,256 @@
// elliptic curves over GF(2^(L*K))
#pragma once
#define MAXL 16
#define MAXK 193
class field;
class field_element;
class curve;
class full_curve_parameter;
class small_field
{
friend class field;
#if MAXL > 16 // assumes that unsigned short is at least 16 bits
typedef unsigned lunit;
#else
#if MAXL > 8
typedef unsigned short lunit;
#else
typedef unsigned char lunit;
#endif
#endif
// construction
public:
small_field( unsigned L, unsigned root );
~small_field();
// methods
public:
unsigned * curve_order();
// properties
public:
lunit * const alog; // index range is [0..(BASE-2)]
lunit * const log; // index range is [1..(BASE-1)], but log[0] is set to (BASE-1)
const unsigned L, BASE, BASE_M1;
};
// elements are polynomials with coefficients in small_field
class field : public small_field
{
friend class curve;
friend class field_element;
friend class full_curve_parameter;
// construction
public:
field( class full_curve_parameter & a );
virtual unsigned rand( unsigned base );
// methods
private:
typedef unsigned poly[ 2 * MAXK ];
static void add( const poly a, const poly b, poly c );
static void copy ( const poly a, poly b );
static int equal( const poly a, const poly b );
void div( poly a, unsigned b );
void set_random( poly a );
int set_K( unsigned K, unsigned T );
void reduce( poly a );
void mul( const poly a, const poly b, poly c );
void square( const poly a, poly b );
void inverse( const poly a, poly b );
int trace( const poly a );
int slow_trace( const poly a );
void quad_solve( const poly a, poly b );
void sqrt( const poly a, poly b );
void addmul( poly a, unsigned alpha, unsigned j, const poly b );
friend field_element sqrt( const field_element x );
void unpack( const bigint & x, poly a );
bigint pack( const poly a );
// properties
private:
const unsigned M, K, T;
unsigned prng;
poly nzt; // element with non-zero trace
poly tm; // trace mask ( trace(x) is number of bits in x & tm )
};
class field_element
{
friend class field;
friend class curve;
friend class point;
friend field_element sqrt( const field_element x );
// construction
public:
field_element( const field_element & x );
field_element( field * F );
field_element();
// methods
public:
int operator == ( const field_element & x ) const;
int operator == ( unsigned x ) const;
field_element operator + ( const field_element & x ) const;
field_element operator * ( const field_element & x ) const;
field_element operator / ( const field_element & x ) const;
field_element & operator = ( const field_element & x );
// properties
private:
field * f;
field::poly v;
};
class point
{
friend class curve;
friend class ec_crypt;
friend point operator * ( const bigint & k, const point & P );
// construction
public:
point();
point( const point & P );
point( curve * C );
// methods
public:
point & operator = ( const point & P );
point operator + ( const point & P ) const;
point operator - ( const point & P ) const;
// properties
private:
curve * c;
field_element x, y;
};
struct curve_parameter
{
unsigned L;
unsigned K;
unsigned T;
unsigned root;
unsigned b;
unsigned nso;
unsigned ntf;
};
class full_curve_parameter : public curve_parameter
{
// construction
public:
full_curve_parameter( const curve_parameter & bp );
// properties
public:
bigint tm, p0, P0;
};
class curve : public field
{
friend class curve_factory;
friend class point;
friend point operator * ( const bigint & k, const point & P );
// construction
public:
curve( full_curve_parameter & a );
// methods
public:
point random_point();
static bigint pack( const point & P );
point unpack( const bigint & X );
static bigint to_vlong( const point & P );
// methods
private:
void add( const point & P, const point & Q, point & R );
void sub( const point & P, const point & Q, point & R );
void mul( const point & P, const bigint & x, point & Q );
int calc_y( point & R, unsigned ybit=0 );
static int MOV( unsigned B, const bigint & q, const bigint & r );
static bigint small_lucas( bigint P, bigint Z, unsigned ik );
static unsigned ybit( const field_element & x );
static field_element sq( const field_element & x );
// properties
public:
point PP; // point with prime order
bigint p; // prime order of P
// properties
private:
field_element b;
};
class curve_factory // Used for calculating curve_parameter but in practice
// use pre-calculated table ncdata.hpp or equivalent
{
// construction
public:
curve_factory( unsigned L ); // can take a long time
~curve_factory();
// methods
public:
int find( unsigned K, curve_parameter & result );
// properties
private:
unsigned L;
unsigned root;
unsigned so_min;
unsigned so_max;
unsigned *so_set;
bigint comp;
};
struct bigint_pair
{
bigint r;
bigint s;
};
class ECC_BASE : private curve
{
// construction
public:
ECC_BASE( full_curve_parameter & a );
~ECC_BASE();
// methods
public:
virtual unsigned rand( unsigned base );
bigint create_private_key();
bigint create_public_key( const bigint & private_key );
bigint encrypt( const bigint & public_key, bigint & message );
bigint decrypt( const bigint & private_key, const bigint & message );
bigint_pair schnorr_sign( const bigint & msg, const bigint & private_key, bigint (*hash)(const bigint &, const bigint &) = 0, unsigned hashbits = 1 );
bool schnorr_verify( const bigint & msg, const bigint_pair & sig, const bigint & public_key, bigint (*hash)(const bigint &, const bigint &) = 0, unsigned hashbits = 1 );
bigint_pair dsa_sign( const bigint & msg, const bigint & private_key, bigint (*hash)(const bigint &, const bigint &));
bool dsa_verify( const bigint & msg, const bigint_pair & sig, const bigint & public_key, bigint (*hash)(const bigint &, const bigint &));
// properties
public:
const unsigned bits; // number of bits in prime order
#ifdef WIN32
HCRYPTPROV m_cryptProv;
#endif
};

596
core/anslicensing/ecc.cpp Normal file
View File

@@ -0,0 +1,596 @@
//
// Copyright (c) 2014 ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include "ecc.h"
#include "bigint.h"
#include "ec2m.h"
#include "sha1.h"
#include "except.h"
#include "base64.h"
#include "uniconv.h"
#ifndef _WIN32
#include <alloca.h>
#else
#include <malloc.h>
#endif
namespace ECC {
#if 0
void biPrint( bigint & data )
{
int n;
unsigned * u;
n = ( data.bits() + 31 ) / 32;
u = new unsigned[ n ];
data.store( u, n );
printf( "%d ", data.bits() );
for ( int i = n - 1; i >= 0; i-- )
{
printf( "%08X ", u[i] );
}
printf("\n");
delete [] u;
}
#endif
static const curve_parameter eccCurveTable[ 10 ] = { { 9, 7, 1, 17, 43, 48, 1},
{ 12, 7, 1, 83, 2049, 10, 1 },
{ 13, 7, 1, 27, 124, 52, 1},
{ 15, 7, 1, 3, 977, 110, 1},
{ 16, 7, 1, 45, 2902, 6, 1},
{ 10, 11, 2, 9, 139, 34, 1},
{ 12, 11, 2, 83, 2083, 66, 1},
{ 13, 11, 2, 27, 773, 48, 1},
{ 14, 11, 2, 43, 146, 40, 1},
{ 10, 17, 3, 9, 48, 28, 1} };
static void UintArrayToByteArray(unsigned * srcArray, int bitCount, unsigned char * dstArray)
{
int dstLength = ((int)bitCount + 7) >> 3;
int srcLength = (dstLength + 3) >> 2;
int i = 0;
int j = 0;
unsigned currentUint;
if (dstLength > 3)
{
while (i < dstLength - 3)
{
currentUint = (j < srcLength) ? srcArray[j] : 0;
dstArray[i + 3] = (unsigned char)(currentUint >> 24);
dstArray[i + 2] = (unsigned char)((currentUint >> 16) & 0xFF);
dstArray[i + 1] = (unsigned char)((currentUint >> 8) & 0xFF);
dstArray[i] = (unsigned char)(currentUint & 0xFF);
i += 4;
j += 1;
}
}
currentUint = (j < srcLength) ? srcArray[j] : 0;
if (i < dstLength) dstArray[i] = (unsigned char)(currentUint & 0xFF); i++;
if (i < dstLength) dstArray[i] = (unsigned char)((currentUint >> 8) & 0xFF); i++;
if (i < dstLength) dstArray[i] = (unsigned char)((currentUint >> 16) & 0xFF);
}
static void ByteArrayToUintArray(unsigned char * srcArray, int srcLength, unsigned * dstArray)
{
int roundedLen = (srcLength + sizeof(unsigned) - 1) / sizeof(unsigned);
int i = 0;
int j = 0;
while (i < roundedLen - 1)
{
dstArray[i] = (unsigned)(((unsigned)srcArray[j + 3] << 24) | ((unsigned)srcArray[j + 2] << 16) | ((unsigned)srcArray[j + 1] << 8) | (unsigned)srcArray[j]);
i += 1;
j += 4;
}
dstArray[roundedLen - 1] = 0;
if (j < srcLength) dstArray[roundedLen - 1] = (unsigned)(srcArray[j]); j++;
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 8); j++;
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 16); j++;
if (j < srcLength) dstArray[roundedLen - 1] |= (unsigned)((unsigned)srcArray[j] << 24);
}
class KeyImpl {
friend class Key;
friend class SignerImpl;
friend class VerifierImpl;
friend void GenerateKeyPair(KEY_TYPE keyType, Key **privKey, Key **pubKey);
private:
KeyImpl()
{
}
KeyImpl(const void * keyBuf, int bufLen, KEY_TYPE keyType = ECC)
{
Load(keyBuf, bufLen, keyType);
}
KeyImpl(const char * base64Key, KEY_TYPE keyType = ECC)
{
BASE64 base64;
int len;
auto buf = base64.decode(base64Key, strlen(base64Key), &len);
if (buf.empty())
throw new LicensingException(STATUS_INVALID_PARAM, "invalid base64 key");
Load(buf.data(), len, keyType);
}
void Load(const void * keyBuf, int bufLen, KEY_TYPE keyType = ECC)
{
if (keyType == ECC)
{
unsigned char * keyBytes = (unsigned char *)keyBuf;
if ((keyBytes[0] >> 5) != 0)
throw new LicensingException(STATUS_INVALID_PARAM, "unsupported key version");
if (keyBytes[1] + 2 != bufLen)
throw new LicensingException(STATUS_INVALID_PARAM, "invalid key size");
isPrivate = ((keyBytes[0] & 0x10) != 0);
SetKeyType((KEY_TYPE)(keyBytes[0] & 0x0F));
int roundedLen = sizeof(unsigned) * ((bufLen - 2 + sizeof(unsigned) - 1) / sizeof(unsigned));
unsigned * buf = (unsigned *)calloc(roundedLen, 1);
if (!buf) return;
ByteArrayToUintArray(keyBytes + 2, bufLen - 2, buf);
m_key.load(buf, (unsigned)(roundedLen / sizeof(unsigned)));
free(buf);
} else
{
SetKeyType(keyType);
int roundedLen = sizeof(unsigned) * ((bufLen + sizeof(unsigned) - 1) / sizeof(unsigned));
unsigned * buf = (unsigned *)calloc(roundedLen, 1);
if (!buf) return;
ByteArrayToUintArray((unsigned char *)keyBuf, bufLen, buf);
m_key.load(buf, (unsigned)(roundedLen / sizeof(unsigned)));
free(buf);
}
}
bool Store(void * buf, int * bufLen)
{
unsigned char * keyBytes = (unsigned char *)buf;
int numBits = m_key.bits();
int numBytes = (numBits + 7) >> 3;
if (*bufLen < 2 + numBytes)
return false;
keyBytes[0] &= 0x1F; // set first 3 bits to 0 - version 1
if (isPrivate) keyBytes[0] |= 0x10; else keyBytes[0] &= 0xEF; // the 4th bit is 1 if it's a private key
keyBytes[0] = (keyBytes[0] & 0xF0) | (((unsigned char)m_keyType) & 0x0F); // the next 4 bits from 1st byte are the key type
keyBytes[1] = numBytes; // the second byte specifies the key size
int numUints = (numBytes + sizeof(unsigned) - 1) / sizeof(unsigned);
unsigned * temp = (unsigned int *)_alloca(numUints * sizeof(unsigned));
m_key.store(temp, numUints);
UintArrayToByteArray(temp, numBits, keyBytes + 2);
*bufLen = numBytes + 2;
return true;
}
void SetKeyType(KEY_TYPE keyType)
{
m_keyType = keyType;
switch (keyType)
{
case ECC_54: m_keySize = 54;break;
case ECC_73: m_keySize = 73;break;
case ECC_79: m_keySize = 79;break;
case ECC_91: m_keySize = 91;break;
case ECC_97: m_keySize = 97;break;
case ECC_100: m_keySize = 100;break;
case ECC_120: m_keySize = 120;break;
case ECC_131: m_keySize = 131;break;
case ECC_141: m_keySize = 141;break;
case ECC_161: m_keySize = 161;break;
}
}
KEY_TYPE GetKeyType()
{
return m_keyType;
}
KEY_TYPE m_keyType;
int m_keySize;
bigint m_key;
bool isPrivate;
};
class SignerImpl {
public:
SignerImpl()
{
m_hashBits = 0; // thus select ECDSA as the signing algorithm
}
~SignerImpl()
{
}
static bigint Hash(const bigint & x, const bigint & p)
{
unsigned int n = ( x.bits() + ( ( sizeof(unsigned) << 3 ) - 1 ) ) / ( sizeof( unsigned ) << 3 );
unsigned int * a = (unsigned *)_alloca(n * sizeof(unsigned));
unsigned int h[ 5 ];
x.store(a, n);
SHA1 sha;
#ifndef LICENSING_BIG_ENDIAN
sha.Update((unsigned char *)a, (x.bits() + 7) >> 3);
#else
int nb = (x.bits() + 7) >> 3;
unsigned char * buf = (unsigned char *)_alloca(nb);
UintArrayToByteArray(a, x.bits(), buf);
sha.Update(buf, nb);
#endif
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)h);
#else
unsigned char bh[20];
sha.GetHash(bh);
ByteArrayToUintArray(bh, 20, h);
#endif
bigint r;
r.load( h, 5 );
return r % p;
}
void SetHashSize(int hashBits)
{
m_hashBits = hashBits;
}
void SetPrivateKey(const KeyImpl & privKey)
{
m_privateKey = privKey;
}
void Sign(const void * msg, int msgLen, void * sigBuf, int * sigLen, int * sigLenBits)
{
full_curve_parameter param(eccCurveTable[ m_privateKey.m_keyType ]);
ECC_BASE ecc(param);
bigint message;
bigint temp;
bigint_pair signature;
*sigLenBits = (m_hashBits && m_hashBits < m_privateKey.m_keySize) ? m_hashBits + m_privateKey.m_keySize : m_privateKey.m_keySize << 1;
*sigLen = (*sigLenBits + 7) >> 3;
unsigned * buf = (unsigned *)_alloca(msgLen + *sigLen + sizeof(unsigned) - 1);
// take care of endianess here, do not do just a memcpy()
memcpy(buf, msg, msgLen);
memset((char *)buf + msgLen, 0, sizeof(unsigned) - 1);
unsigned msgHash[5];
SHA1 sha;
sha.Update((unsigned char *)msg, msgLen);
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)msgHash);
#else
unsigned char msgHashBuf[20];
sha.GetHash(msgHashBuf);
ByteArrayToUintArray(msgHashBuf, 20, msgHash);
#endif
message.load(msgHash, 5);
signature = (m_hashBits && m_hashBits < m_privateKey.m_keySize) ? ecc.schnorr_sign(message, m_privateKey.m_key, Hash, m_hashBits) : ecc.dsa_sign(message, m_privateKey.m_key, Hash);
temp = (signature.r << m_privateKey.m_keySize); temp += signature.s;
unsigned int n = (unsigned)((*sigLen + sizeof(unsigned) - 1) / sizeof(unsigned));
temp.store(buf, n);
#ifndef LICENSING_BIG_ENDIAN
// take care of endianess here
memcpy(sigBuf, buf, *sigLen);
#else
UintArrayToByteArray(buf, *sigLenBits, (unsigned char *)sigBuf);
#endif
}
private:
KeyImpl m_privateKey;
int m_hashBits;
};
class VerifierImpl {
public:
VerifierImpl()
{
m_hashBits = 0;
}
~VerifierImpl()
{
}
static bigint Hash(const bigint & x, const bigint & p)
{
int n = ( x.bits() + ( ( sizeof(unsigned) << 3 ) - 1 ) ) / ( sizeof( unsigned ) << 3 );
unsigned int * a = (unsigned *)_alloca(n * sizeof(unsigned));
unsigned int h[ 5 ];
x.store(a, n);
SHA1 sha;
#ifndef LICENSING_BIG_ENDIAN
sha.Update((unsigned char *)a, (x.bits() + 7) >> 3);
#else
int nb = (x.bits() + 7) >> 3;
unsigned char * buf = (unsigned char *)_alloca(nb);
UintArrayToByteArray(a, x.bits(), buf);
sha.Update(buf, nb);
#endif
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)h);
#else
unsigned char bh[20];
sha.GetHash(bh);
ByteArrayToUintArray(bh, 20, h);
#endif
bigint r;
r.load( h, 5 );
return r % p;
}
void SetHashSize(int hashBits)
{
m_hashBits = hashBits;
}
void SetPublicKey(const KeyImpl & pubKey)
{
m_publicKey = pubKey;
}
bool Verify(const void * msg, int msgLen, const void * sig, int sigLen, int sigLenBits)
{
full_curve_parameter param(eccCurveTable[ m_publicKey.m_keyType ]);
ECC_BASE ecc(param);
bigint message;
bigint_pair signature;
int msgBufLen = (msgLen + sizeof(unsigned) - 1) / sizeof(unsigned);
int sigBufLen = (sigLen + sizeof(unsigned) - 1) / sizeof(unsigned);
unsigned * msgBuf = (unsigned *)_alloca(msgBufLen * sizeof(unsigned));
unsigned * sigBuf = (unsigned *)_alloca(sigBufLen * sizeof(unsigned));
#ifndef LICENSING_BIG_ENDIAN
memset(msgBuf, 0, msgBufLen * sizeof(unsigned));
memcpy(msgBuf, msg, msgLen);
memset(sigBuf, 0, sigBufLen * sizeof(unsigned));
memcpy(sigBuf, sig, sigLen);
#else
ByteArrayToUintArray((unsigned char *)msg, msgLen, msgBuf);
ByteArrayToUintArray((unsigned char *)sig, sigLen, sigBuf);
#endif
unsigned int msgHash[5];
SHA1 sha;
sha.Update((unsigned char *)msg, msgLen);
sha.Final();
#ifndef LICENSING_BIG_ENDIAN
sha.GetHash((unsigned char *)msgHash);
#else
unsigned char byteHash[20];
sha.GetHash(byteHash);
ByteArrayToUintArray(byteHash, 20, msgHash);
#endif
message.load(msgHash, 5);
signature.r.load(sigBuf, sigBufLen);
signature.r >>= m_publicKey.m_keySize; signature.r &= (pow2((unsigned)(sigLenBits - m_publicKey.m_keySize)) - 1);
signature.s.load(sigBuf, sigBufLen);
signature.s &= (pow2(m_publicKey.m_keySize) - 1);
return (m_hashBits && m_hashBits < m_publicKey.m_keySize) ? ecc.schnorr_verify(message, signature, m_publicKey.m_key, Hash, m_hashBits) : ecc.dsa_verify(message, signature, m_publicKey.m_key, Hash);
}
private:
int m_hashBits;
KeyImpl m_publicKey;
};
void GenerateKeyPair(KEY_TYPE keyType, Key **privKey, Key **pubKey)
{
full_curve_parameter param(eccCurveTable[ keyType ]);
ECC_BASE ecc(param);
Key * privateKey = new Key(),
* publicKey = new Key();
privateKey->m_Impl.m_key = ecc.create_private_key();
privateKey->m_Impl.SetKeyType(keyType);
privateKey->m_Impl.isPrivate = true;
publicKey->m_Impl.m_key = ecc.create_public_key(privateKey->m_Impl.m_key);
publicKey->m_Impl.SetKeyType(keyType);
*privKey = privateKey;
*pubKey = publicKey;
}
Key::Key():
m_Impl( *new KeyImpl() )
{
}
Key::Key(const void * keyBuf, int bufLen, KEY_TYPE keyType):
m_Impl( *new KeyImpl(keyBuf, bufLen, keyType) )
{
}
Key::Key(const char * base64Key, KEY_TYPE keyType):
m_Impl( *new KeyImpl(base64Key, keyType))
{
}
Key::~Key()
{
delete & m_Impl;
}
void Key::Load(const void * keyData, int keyLen, KEY_TYPE keyType)
{
m_Impl.Load(keyData, keyLen, keyType);
}
bool Key::Store(void * buf, int * bufLen) const
{
return m_Impl.Store(buf, bufLen);
}
const char * Key::ToString()
{
static string base64key;
int len = 2 + ((m_Impl.m_key.bits() + 7) >> 3);
unsigned char * buf = (unsigned char *)_alloca(len);
Store(buf, &len);
BASE64 base64;
auto base64Buf = base64.encode(buf, len, true);
if (base64Buf.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "could not encode buffer to base64");
base64key = base64Buf.c_str();
return base64key.c_str();
}
KEY_TYPE Key::GetKeyType()
{
return m_Impl.GetKeyType();
}
const Key & Key::operator = (const Key & key)
{
m_Impl = key.m_Impl;
return (const Key &)(*this);
}
Signer::Signer():
m_Impl(*new SignerImpl())
{
}
Signer::~Signer()
{
delete & m_Impl;
}
void Signer::SetHashSize(int hashBits)
{
m_Impl.SetHashSize(hashBits);
}
void Signer::SetPrivateKey(const Key * privKey)
{
m_Impl.SetPrivateKey(privKey->m_Impl);
}
void Signer::Sign(const void * msg, int msgLen, void * sigBuf, int * sigLen, int * sigLenBits)
{
m_Impl.Sign(msg, msgLen, sigBuf, sigLen, sigLenBits);
}
Verifier::Verifier():
m_Impl( *new VerifierImpl() )
{
}
Verifier::~Verifier()
{
delete & m_Impl;
}
void Verifier::SetHashSize(int hashBits)
{
m_Impl.SetHashSize(hashBits);
}
void Verifier::SetPublicKey(const Key * pubKey)
{
m_Impl.SetPublicKey(pubKey->m_Impl);
}
bool Verifier::Verify(const void * msg, int msgLen, const void * sig, int sigLen, int sigLenBits)
{
return m_Impl.Verify(msg, msgLen, sig, sigLen, sigLenBits);
}
}

80
core/anslicensing/ecc.h Normal file
View File

@@ -0,0 +1,80 @@
#ifndef __ECC_H
#define __ECC_H
namespace ECC {
enum KEY_TYPE {
ECC_54,
ECC_73,
ECC_79,
ECC_91,
ECC_97,
ECC_100,
ECC_120,
ECC_131,
ECC_141,
ECC_161,
ECC
};
class KeyImpl;
class Key {
public:
Key();
Key(const void * keyData, int keyLen, KEY_TYPE keyType = ECC);
Key(const char * base64Key, KEY_TYPE keyType = ECC);
~Key();
void Load(const void * keyData, int keyLen, KEY_TYPE keyType = ECC);
bool Store(void * buf, int * bufLen) const;
const char * ToString();
KEY_TYPE GetKeyType();
const Key & operator = (const Key & key);
public:
KeyImpl & m_Impl;
};
typedef unsigned (*HashFunction)(const void *, int, void *, unsigned *);
class SignerImpl;
class Signer
{
public:
Signer();
~Signer();
void SetPrivateKey(const Key * privKey);
void SetHashSize(int hashBits);
void Sign(const void * msg, int msgLen, void * sigBuf, int * sigLen, int *sigLenInBits = (int *)0);
private:
SignerImpl & m_Impl;
};
class VerifierImpl;
class Verifier {
public:
Verifier();
~Verifier();
void SetPublicKey(const Key * pubKey);
void SetHashSize(int hashBits);
bool Verify(const void * msg, int msgLen, const void * sig, int sigLen, int sigLenInBits = 0);
private:
VerifierImpl & m_Impl;
};
void GenerateKeyPair(KEY_TYPE keyType, Key **privKey, Key **pubKey);
};
#endif

View File

@@ -0,0 +1,3 @@
#include "precomp.h"
#include "except.h"

View File

@@ -0,0 +1,31 @@
#ifndef __EXCEPT_H
#define __EXCEPT_H
#include <string>
#include "anslicensing.h"
using namespace std;
class LicensingException : public ANSCENTER::Licensing::Exception {
public:
LicensingException( int code, const char * message = NULL)
{
SetCode(code);
if (message)
SetMessage(message);
}
virtual ~LicensingException() {}
virtual int GetCode() { return m_code; }
virtual const char * GetExceptionMessage() { return m_message.c_str(); }
virtual void Destroy() { delete this; }
void SetCode(int code) { m_code = code; }
void SetMessage(const char * message) { m_message = message; }
protected:
int m_code;
string m_message;
};
#endif

View File

@@ -0,0 +1,207 @@
//
// Copyright (c) 2014 ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include "anslicensing.h"
#include "template.h"
#include "base32.h"
#include "base64.h"
#include "sha1.h"
#include "except.h"
#include "bitstream.h"
#include "uniconv.h"
#include "generator.h"
namespace ANSCENTER {
namespace Licensing {
template<>
KeyGeneratorT<char>::KeyGeneratorT():
m_Impl( *new KeyGeneratorImpl())
{
}
template<>
KeyGeneratorT<wchar_t>::KeyGeneratorT():
m_Impl( *new KeyGeneratorImpl())
{
}
template<>
KeyGeneratorT<char>::KeyGeneratorT(const LicenseTemplateT<char> * templ):
m_Impl( *new KeyGeneratorImpl(&templ->m_Impl) )
{
}
template<>
KeyGeneratorT<wchar_t>::KeyGeneratorT(const LicenseTemplateT<wchar_t> * templ):
m_Impl( *new KeyGeneratorImpl(&templ->m_Impl) )
{
}
template<>
KeyGeneratorT<char>::~KeyGeneratorT()
{
delete & m_Impl;
}
template<>
KeyGeneratorT<wchar_t>::~KeyGeneratorT()
{
delete & m_Impl;
}
template<>
KeyGeneratorT<char> * KeyGeneratorT<char>::Create()
{
return new KeyGeneratorT<char>();
}
template<>
KeyGeneratorT<wchar_t> * KeyGeneratorT<wchar_t>::Create()
{
return new KeyGeneratorT<wchar_t>();
}
template<>
void KeyGeneratorT<char>::Destroy(KeyGeneratorT<char> * obj)
{
delete obj;
}
template<>
void KeyGeneratorT<wchar_t>::Destroy(KeyGeneratorT<wchar_t> * obj)
{
delete obj;
}
template<>
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, const void * buf, int len)
{
m_Impl.KeyGeneratorImpl::SetKeyData(fieldName, buf, len);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, const void * buf, int len)
{
m_Impl.KeyGeneratorImpl::SetKeyData(w2s(fieldName).c_str(), buf, len);
}
template<>
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, int data)
{
m_Impl.SetKeyData(fieldName, data);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, int data)
{
m_Impl.SetKeyData(w2s(fieldName).c_str(), data);
}
template<>
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, const char * data)
{
m_Impl.SetKeyData(fieldName, data);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, const wchar_t * data)
{
m_Impl.SetKeyData(w2s(fieldName).c_str(), w2s(data).c_str());
}
template<>
void KeyGeneratorT<char>::SetKeyData(const char * fieldName, int year, int month, int day)
{
m_Impl.SetKeyData(fieldName, year, month, day);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyData(const wchar_t * fieldName, int year, int month, int day)
{
m_Impl.SetKeyData(w2s(fieldName).c_str(), year, month, day);
}
template<>
void KeyGeneratorT<char>::SetValidationData(const char * fieldName, const void * buf, int len)
{
m_Impl.SetValidationData(fieldName, buf, len);
}
template<>
void KeyGeneratorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const void * buf, int len)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), buf, len);
}
template<>
void KeyGeneratorT<char>::SetValidationData(const char * fieldName, int data)
{
m_Impl.SetValidationData(fieldName, data);
}
template<>
void KeyGeneratorT<wchar_t>::SetValidationData(const wchar_t * fieldName, int data)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), data);
}
template<>
void KeyGeneratorT<char>::SetValidationData(const char * fieldName, const char * data)
{
m_Impl.SetValidationData(fieldName, data);
}
template<>
void KeyGeneratorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const wchar_t * data)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), w2s(data).c_str());
}
template<>
void KeyGeneratorT<char>::SetKeyTemplate(const LicenseTemplateT<char> & templ)
{
m_Impl.SetKeyTemplate(&templ.m_Impl);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyTemplate(const LicenseTemplateT<wchar_t> & templ)
{
m_Impl.SetKeyTemplate(&templ.m_Impl);
}
template<>
void KeyGeneratorT<char>::SetKeyTemplate(const LicenseTemplateT<char> * templ)
{
m_Impl.SetKeyTemplate(&templ->m_Impl);
}
template<>
void KeyGeneratorT<wchar_t>::SetKeyTemplate(const LicenseTemplateT<wchar_t> * templ)
{
m_Impl.SetKeyTemplate(&templ->m_Impl);
}
template<>
const char * KeyGeneratorT<char>::GenerateKey()
{
return m_Impl.GenerateKey();
}
template<>
const wchar_t * KeyGeneratorT<wchar_t>::GenerateKey()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GenerateKey());
return wstr1.c_str();
}
};
};

View File

@@ -0,0 +1,423 @@
#pragma once
#include "bitstream.h"
#include "base32.h"
#include "base64.h"
#include <map>
#ifndef LICENSING_NO_NETWORKING
#ifdef _WIN32
#include <winhttp.h>
#include <tchar.h>
#else
#include <curl/curl.h>
#endif
#endif
using namespace std;
class KeyGeneratorImpl {
public:
KeyGeneratorImpl():
m_signingServiceStatusCode(-1)
{
}
KeyGeneratorImpl(const LicenseTemplateImpl * templ):
KeyGeneratorImpl()
{
SetKeyTemplate(templ);
}
void SetKeyTemplate(const LicenseTemplateImpl * templ)
{
m_keyTemplate = templ;
m_keyData.Create(m_keyTemplate->m_numGroups * m_keyTemplate->m_charsPerGroup * m_keyTemplate->m_keyEncoding);
m_keyData.GetBitStream().Clear();
for (const auto& field : m_keyTemplate->m_dataFields)
m_keyData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
if (m_keyTemplate->m_validationDataSize)
{
m_validationData.Create(m_keyTemplate->m_validationDataSize);
m_validationData.GetBitStream().Clear();
for (const auto& field : m_keyTemplate->m_validationFields)
m_validationData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
}
}
void SetKeyData(const char * fieldName, const void * buf, int len)
{
m_keyData.Set(fieldName, buf, len);
}
void SetKeyData(const char * fieldName, const char * data)
{
m_keyData.Set(fieldName, data);
}
void SetKeyData(const char * fieldName, int data)
{
m_keyData.Set(fieldName, data);
}
void SetKeyData(const char * fieldName, int year, int month, int day)
{
m_keyData.Set(fieldName, year, month, day);
}
void SetValidationData(const char * fieldName, const void * buf, int len)
{
m_validationData.Set(fieldName, buf, len);
}
void SetValidationData(const char * fieldName, const char * data)
{
m_validationData.Set(fieldName, data);
}
void SetValidationData(const char * fieldName, int data)
{
m_validationData.Set(fieldName, data);
}
#ifndef _WIN32
static size_t
CurlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
KeyGeneratorImpl * pthis = (KeyGeneratorImpl *)userp;
size_t realsize = size * nmemb;
if (realsize > 1024 || pthis->m_keyBuffer.length() > 1024)
return realsize - 1; // signal error
if (realsize > 0)
pthis->m_keyBuffer.append((char *)contents, realsize);
return realsize;
}
#endif
const char * GenerateKey()
{
BitStream signedData;
BitStream signature;
ECC::Signer signer;
int sigLen, sigLenBits;
#ifndef LICENSING_NO_NETWORKING
if (m_keyTemplate->m_signingKey == NULL)
{
m_signingServiceStatusCode = -1;
string activationQuery("Activate.ashx?");
//if (activationQuery[m_keyTemplate->m_signingServiceUrl.length() - 1] != '/')
// activationQuery.append(1, '/');
//activationQuery.append("Activate.ashx?");
unsigned char * buf = (unsigned char *)_alloca(1 + ((m_validationData.GetSize() + 7) >> 3));
void * enumHandle = NULL;
const char * name;
BitStruct::FIELD_TYPE type;
int size, offset;
while (m_keyTemplate->EnumValidationFields(&enumHandle, &name, (int*)&type, &size, &offset))
{
m_validationData.GetBitStream().Seek(offset);
m_validationData.GetBitStream().Read(buf, size);
activationQuery.append(name);
activationQuery.append("=");
if ((int)type == FIELD_TYPE_STRING)
{
buf[(size + 7) >> 3] = '\0';
activationQuery.append((char *)buf);
} else
{
BASE64 base64;
string base64Value = base64.encode(buf, (size + 7) >> 3, true);
replace_all(base64Value, "+", "%2B");
replace_all(base64Value, "/", "%2F");
replace_all(base64Value, "=", "%3D");
activationQuery.append(base64Value.c_str());
}
activationQuery.append("&");
}
if (m_keyTemplate->m_licensingServiceParameters.length() > 0)
{
activationQuery.append(m_keyTemplate->m_licensingServiceParameters);
activationQuery.append("&");
}
activationQuery.erase(activationQuery.length() - 1, 1);
m_keyBuffer.clear();
#ifdef _WIN32
URL_COMPONENTS urlComponents;
ZeroMemory(&urlComponents, sizeof(urlComponents));
urlComponents.dwStructSize = sizeof(urlComponents);
urlComponents.dwHostNameLength = (DWORD)-1;
urlComponents.dwUrlPathLength = (DWORD)-1;
auto licensingServiceUrl = s2w(m_keyTemplate->m_licensingServiceUrl);
if (!WinHttpCrackUrl(licensingServiceUrl.c_str(), m_keyTemplate->m_licensingServiceUrl.length(), 0L, &urlComponents))
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (1)"));
std::wstring hostName(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> internet_ptr(WinHttpOpen(L"ANSCENTER Licensing SDK 2.0", WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, 0L), WinHttpCloseHandle);
if (!internet_ptr)
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (2)"));
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> connection_ptr(WinHttpConnect(internet_ptr.get(), hostName.c_str(), urlComponents.nPort, 0L), WinHttpCloseHandle);
if (!connection_ptr)
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (3)"));
activationQuery.insert(0, w2s(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength));
DWORD requestFlags = WINHTTP_FLAG_BYPASS_PROXY_CACHE;
if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS)
requestFlags |= WINHTTP_FLAG_SECURE;
unique_ptr<VOID, decltype(&WinHttpCloseHandle)> request_ptr(WinHttpOpenRequest(connection_ptr.get(), L"GET", s2w(activationQuery).c_str(), NULL, NULL, NULL, requestFlags), WinHttpCloseHandle);
if (!request_ptr)
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (4)"));
if (!WinHttpSendRequest(request_ptr.get(), NULL, 0L, NULL, 0L, 0L, 0L))
{
DWORD result = GetLastError();
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (5)"));
}
if (!WinHttpReceiveResponse(request_ptr.get(), NULL))
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (6)"));
DWORD status;
DWORD statusSize = sizeof(DWORD);
if (!WinHttpQueryHeaders(request_ptr.get(), WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status, &statusSize, WINHTTP_NO_HEADER_INDEX))
throw new LicensingException(STATUS_NET_ERROR, _T("networking error (7)"));
m_signingServiceStatusCode = status;
if (status != HTTP_STATUS_OK && status != HTTP_STATUS_ACCEPTED && status != HTTP_STATUS_CREATED)
{
WCHAR buffer[1024];
DWORD bufferSize = 1024;
if (!WinHttpQueryHeaders(request_ptr.get(), WINHTTP_QUERY_STATUS_TEXT, WINHTTP_HEADER_NAME_BY_INDEX, buffer, &bufferSize, WINHTTP_NO_HEADER_INDEX))
throw new LicensingException(STATUS_NET_ERROR, "networking error (8)");
throw new LicensingException(STATUS_NET_ERROR, w2s(buffer).c_str());
}
DWORD dataSize, count;
char buffer[0x100];
do {
if (!WinHttpQueryDataAvailable(request_ptr.get(), &dataSize))
break;
if (size > 0x100)
size = 0x100;
if (WinHttpReadData(request_ptr.get(), buffer, dataSize, &count))
m_keyBuffer.append(buffer, count);
} while (dataSize > 0);
#else
CURL *curl;
CURLcode res;
if ((curl = curl_easy_init()) == NULL)
throw new LicensingException(STATUS_NET_ERROR, "cURL initalization failed");
if (*(m_keyTemplate->m_licensingServiceUrl.rbegin()) != '/')
activationQuery.insert(0, "/");
activationQuery.insert(0, m_keyTemplate->m_licensingServiceUrl);
curl_easy_setopt(curl, CURLOPT_URL, activationQuery.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
throw new LicensingException(STATUS_NET_ERROR, curl_easy_strerror(res));
curl_easy_cleanup(curl);
#endif
m_key = m_keyBuffer.c_str();
return m_key.c_str();
}
#else
if (m_keyTemplate->m_signingKey == NULL)
{
throw new LicensingException(STATUS_NET_ERROR, "private key not provided");
}
#endif
// signed data is license key data followed by validation data
signedData.Create(m_keyTemplate->m_dataSize + m_keyTemplate->m_validationDataSize);
if (m_keyTemplate->m_dataSize)
signedData.Write(m_keyData.GetBuffer(), m_keyTemplate->m_dataSize);
if (m_keyTemplate->m_validationDataSize)
signedData.Write(m_validationData.GetBuffer(), m_keyTemplate->m_validationDataSize);
signedData.ZeroPadToNextByte();
// create a bit stream to hold the signature
signature.Create(m_keyTemplate->m_signatureSize);
// sign data
// we use a different algorithm than ECDSA when the signature size must be smaller than twice the key size
if (m_keyTemplate->m_signatureSize < (m_keyTemplate->m_signatureKeySize << 1))
signer.SetHashSize(m_keyTemplate->m_signatureSize - m_keyTemplate->m_signatureKeySize);
else
signer.SetHashSize(0);
signer.SetPrivateKey(m_keyTemplate->m_signingKey.get());
signer.Sign(signedData.GetBuffer(), (signedData.GetSize() + 7) >> 3,
signature.GetBuffer(), &sigLen, &sigLenBits);
signature.ReleaseBuffer(sigLenBits);
// write the signature at the end of key data
m_keyData.GetBitStream().Seek(m_keyTemplate->m_dataSize);
m_keyData.GetBitStream().Write(signature.GetBuffer(), m_keyTemplate->m_signatureSize);
// text-encode the license key
EncodeKey();
// success
return m_key.c_str();
}
int GetSigningServiceStatusCode()
{
return m_signingServiceStatusCode;
}
void EncodeKey()
{
string buf;
// set all bits to 0 until the next byte boundary
//m_rawKey.ZeroPadToNextByte();
// reverse last byte from the stream,
// so that we will not lose significant bits in the padless, truncated BAS32/64 encoding
unsigned char * lastBytePtr = (unsigned char *)m_keyData.GetBuffer() + ((m_keyData.GetSize() + 7) >> 3) - 1;
*lastBytePtr = (unsigned char)(((*lastBytePtr * 0x0802LU & 0x22110LU) | (*lastBytePtr * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
switch (m_keyTemplate->m_keyEncoding)
{
case ENCODING_BASE32X:
{
BASE32 base32;
buf = base32.encode((unsigned char *)m_keyData.GetBuffer(), (m_keyData.GetSize() + 7) >> 3, true);
}
break;
case ENCODING_BASE64X:
{
BASE64 base64;
buf = base64.encode((unsigned char *)m_keyData.GetBuffer(), (m_keyData.GetSize() + 7) >> 3, false);
}
break;
default:
throw new LicensingException(STATUS_INVALID_KEY_ENCODING);
}
if (buf.empty())
throw new LicensingException(STATUS_OUT_OF_MEMORY);
m_key = buf.c_str();
if ((int)m_key.length() > m_keyTemplate->m_numGroups * m_keyTemplate->m_charsPerGroup)
m_key.resize(m_keyTemplate->m_numGroups * m_keyTemplate->m_charsPerGroup);
int i;
int insertPos;
// separate character groups
for (i = 0, insertPos = m_keyTemplate->m_charsPerGroup; i < m_keyTemplate->m_numGroups - 1; i++)
{
m_key.insert(insertPos, m_keyTemplate->m_groupSeparator);
insertPos += (unsigned)( m_keyTemplate->m_groupSeparator.length() + m_keyTemplate->m_charsPerGroup );
}
// add header and footer (if any)
if (!m_keyTemplate->m_header.empty())
m_key.insert(0, m_keyTemplate->m_header + "\r\n");
if (!m_keyTemplate->m_footer.empty())
m_key.append("\r\n" + m_keyTemplate->m_footer);
}
std::size_t replace_all(std::string& inout, std::string_view what, std::string_view with)
{
std::size_t count{};
for (std::string::size_type pos{};
inout.npos != (pos = inout.find(what.data(), pos, what.length()));
pos += with.length(), ++count) {
inout.replace(pos, what.length(), with.data(), with.length());
}
return count;
}
void StrReplaceA(std::string& str, const std::string& oldStr, const std::string& newStr)
{
size_t pos = 0;
while((pos = str.find(oldStr, pos)) != std::string::npos)
{
str.replace(pos, oldStr.length(), newStr);
pos += newStr.length();
}
}
private:
const LicenseTemplateImpl* m_keyTemplate;
string m_keyBuffer;
string m_key;
BitStruct m_keyData;
BitStruct m_validationData;
int m_signingServiceStatusCode;
};

View File

@@ -0,0 +1,169 @@
//
// Copyright (c) 2014 ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include <list>
#include <string>
#ifdef _WIN32
#include "wmihelper.h"
#endif
#include "anslicensing.h"
#include "uniconv.h"
#include "except.h"
#include "hwid.h"
#include "base64.h"
class KeyHelperImpl {
friend class KeyHelperT<char>;
friend class KeyHelperT<wchar_t>;
private:
static const char * GetCurrentHardwareId()
{
return HardwareId::GetCurrentHardwareId();
}
static bool MatchCurrentHardwareId(const char * hwid)
{
return HardwareId::MatchCurrentHardwareId(hwid);
}
static bool DetectClockManipulation(int year, int month, int day)
{
#ifdef _WIN32
FILETIME thresholdTime;
SYSTEMTIME st;
TCHAR path[MAX_PATH];
ZeroMemory(&st, sizeof(st));
st.wYear = year;
st.wMonth = month;
st.wDay = day;
st.wHour = 23;
st.wMinute = 59;
st.wSecond = 59;
if (!SystemTimeToFileTime(&st, &thresholdTime))
return false;
if (GetTempPath(MAX_PATH, path) > 0)
{
_tcsncat_s<MAX_PATH>(path, "*.*", _TRUNCATE);
WIN32_FIND_DATA findData;
HANDLE findHandle = FindFirstFile(path, &findData);
if (findHandle != INVALID_HANDLE_VALUE)
{
while (FindNextFile(findHandle, &findData))
{
if (CompareFileTime(&findData.ftLastWriteTime, &thresholdTime) > 0)
return true;
}
FindClose(findHandle);
}
}
WmiHelper wmi;
list<string> propList;
char dmtfTime[100];
char query[MAX_PATH];
_snprintf_s(query, MAX_PATH, _TRUNCATE, "SELECT EventIdentifier FROM Win32_NTLogEvent WHERE LogFile='system' AND TimeGenerated > '%04d%02d%02d000000.000000-000'", st.wYear, st.wMonth, st.wDay);
wmi.GetPropertyList(query, "EventIdentifier", &propList);
if (propList.size() > 0)
return true;
#endif
return false;
}
};
namespace ANSCENTER
{
namespace Licensing
{
template<>
const char * KeyHelperT<char>::GetCurrentHardwareId()
{
return KeyHelperImpl::GetCurrentHardwareId();
}
template<>
const wchar_t * KeyHelperT<wchar_t>::GetCurrentHardwareId()
{
static wstring wstr1;
wstr1 = s2w(KeyHelperImpl::GetCurrentHardwareId());
return wstr1.c_str();
}
template<>
bool KeyHelperT<char>::MatchCurrentHardwareId(const char * hwid)
{
return KeyHelperImpl::MatchCurrentHardwareId(hwid);
}
template<>
bool KeyHelperT<wchar_t>::MatchCurrentHardwareId(const wchar_t * hwid)
{
return KeyHelperImpl::MatchCurrentHardwareId(w2s(hwid).c_str());
}
template<>
bool KeyHelperT<char>::DetectClockManipulation(int thresholdYear, int thresholdMonth, int thresholdDay)
{
return KeyHelperImpl::DetectClockManipulation(thresholdYear, thresholdMonth, thresholdDay);
}
template<>
bool KeyHelperT<wchar_t>::DetectClockManipulation(int thresholdYear, int thresholdMonth, int thresholdDay)
{
return KeyHelperImpl::DetectClockManipulation(thresholdYear, thresholdMonth, thresholdDay);
}
};
};
namespace ANSCENTER
{
namespace Licensing
{
const char* ANSUtility::WString2String(const wchar_t * inputString) {
string result = w2s(inputString);
return result.c_str();
}
const wchar_t* ANSUtility::String2WString(const char* inputString) {
wstring result = s2w(inputString);
return result.c_str();
}
const char* ANSUtility::EncodeBase64Utility(unsigned char* buf, int len, bool padding) {
BASE64 base64;
string result= base64.encode(buf, len,padding);
return result.c_str();
}
const char* ANSUtility::DecodeBase64Utility(const char* input, int len, int* outlen) {
BASE64 base64;
vector<unsigned char> result = base64.decode(input, len, nullptr);
string str(result.begin(), result.end());
return str.c_str();
}
}
}

562
core/anslicensing/hwid.cpp Normal file
View File

@@ -0,0 +1,562 @@
//
// Copyright (c) 2014 ANSCENTER. All rights reserved.
//
#include "precomp.h"
#ifdef _WIN32
#include "wmihelper.h"
#else // !_WIN32
#if defined(__i386__) || defined(__amd64__)
#include <cpuid.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <net/if.h>
#ifdef __linux__
# include <sys/ioctl.h>
# include <netinet/in.h>
# include <unistd.h>
# include <string.h>
// Match Linux to FreeBSD
# define AF_LINK AF_PACKET
#else
# include <net/if_dl.h>
#endif
#endif
#include <list>
#include <string>
#include <functional>
#include <algorithm>
#include <cctype>
#include <stdio.h>
#include <set>
#include "bitstream2.h"
#include "bitstream3.h"
#include "base32.h"
#include "crc32.h"
#include "hwid.h"
#include "except.h"
#include "uniconv.h"
using namespace std;
string HardwareId::hardwareId;
#ifndef _WIN32
const sockaddr_in* castToIP4(const sockaddr* addr) {
if (addr == NULL) {
return NULL;
}
else if (addr->sa_family == AF_INET) {
// An IPv4 address
return reinterpret_cast<const sockaddr_in*>(addr);
}
else {
// Not an IPv4 address
return NULL;
}
}
void GetCPUIDPropertyList(std::list<std::string>* propList)
{
unsigned int level = 1, eax = 0, ebx, ecx, edx = 0;
#if defined(__i386__) || defined(__amd64__)
__get_cpuid(level, &eax, &ebx, &ecx, &edx);
#endif
char buf[17];
sprintf(buf, "%08X%08X", edx, eax);
propList->push_back(buf);
}
void GetMACPropertyList(std::list<std::string>* propList, int maxCount)
{
// Head of the interface address linked list
ifaddrs* ifap = NULL;
int r = getifaddrs(&ifap);
if (r != 0) {
return;
}
ifaddrs* current = ifap;
if (current == NULL) {
return;
}
while (current != NULL && maxCount > 0) {
const sockaddr_in* interfaceAddress = castToIP4(current->ifa_addr);
const sockaddr_in* broadcastAddress = castToIP4(current->ifa_dstaddr);
const sockaddr_in* subnetMask = castToIP4(current->ifa_netmask);
if ((current->ifa_addr != NULL) && (current->ifa_addr->sa_family == AF_LINK)) {
#ifdef __linux__
struct ifreq ifr;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
ifr.ifr_addr.sa_family = AF_INET;
strcpy(ifr.ifr_name, current->ifa_name);
ioctl(fd, SIOCGIFHWADDR, &ifr);
close(fd);
uint8_t* MAC = reinterpret_cast<uint8_t*>(ifr.ifr_hwaddr.sa_data);
#else // Posix/FreeBSD/Mac OS
sockaddr_dl* sdl = (struct sockaddr_dl*)current->ifa_addr;
uint8_t* MAC = reinterpret_cast<uint8_t*>(LLADDR(sdl));
#endif
if (MAC[0] != 0 || MAC[1] != 0 || MAC[2] != 0 || MAC[3] != 0 || MAC[4] != 0 || MAC[5] != 0)
{
char buf[18];
sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]);
propList->push_back(buf);
maxCount--;
}
}
current = current->ifa_next;
}
freeifaddrs(ifap);
ifap = NULL;
}
void GetHDDPropertyList(std::list<std::string>* propList, int maxCount)
{
}
#endif
unsigned short HardwareId::HashString(const char* str)
{
unsigned int crc = Crc32::Compute((const unsigned char*)str, strlen(str));
return (unsigned short)(crc >> 16);
}
unsigned short HardwareId::HashInt(int val)
{
unsigned char buf[4] = { (unsigned char)(val >> 24), (unsigned char)(val >> 16), (unsigned char)(val >> 8), (unsigned char)(val & 0xFF) };
unsigned int crc = Crc32::Compute(buf, 4);
return (unsigned short)(crc >> 16);
}
// LOCALE-INDEPENDENT trim from start (in place)
static inline void ltrim(std::string& s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r' && ch != 0xA0;
}));
}
// LOCALE-INDEPENDENT trim from end (in place)
static inline void rtrim(std::string& s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r' && ch != 0xA0;
}).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string& s) {
ltrim(s);
rtrim(s);
}
// LOCALE-INDEPENDENT uppercase conversion
static inline void toUpperInvariant(std::string& s) {
for (char& c : s) {
if (c >= 'a' && c <= 'z') {
c = c - 32;
}
}
}
// Normalize hardware string for consistent hashing
static std::string NormalizeHardwareString(const std::string& input) {
std::string s = input;
// Trim all types of whitespace
trim(s);
// Remove all remaining whitespace characters
s.erase(std::remove_if(s.begin(), s.end(), [](unsigned char c) {
return c <= 32 || c == 0xA0; // Remove control chars and non-breaking space
}), s.end());
// Locale-independent uppercase for ASCII
toUpperInvariant(s);
// Remove non-ASCII characters (Korean text, etc.)
s.erase(std::remove_if(s.begin(), s.end(), [](unsigned char c) {
return c > 127;
}), s.end());
return s;
}
const char* HardwareId::GetCurrentHardwareId()
{
#ifdef _WIN32
WmiHelper wmi;
#endif
BitStream3 bits(125);
list<string> propList;
unsigned char version = 1;
unsigned short hash1, hash2, hash3, hash4;
unsigned short h0 = HashInt(0);
bits.Write(&version, 3);
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT * FROM Win32_ComputerSystemProduct", "UUID", &propList);
hash1 = h0;
string s;
for (list<string>::iterator iter = propList.begin(); iter != propList.end(); iter++)
{
s = NormalizeHardwareString(*iter);
if ((s.length() > 1)
&& (s != "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
&& (s != "00000000000000000000000000000000"))
{
hash1 = HashString(s.c_str());
}
}
#else
propList.push_back("4294967296");
#endif
bits.WriteUInt16(hash1);
// CPU IDs - get up to 4 for better resilience
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT ProcessorId FROM Win32_Processor", "ProcessorId", &propList, 4);
#else
GetCPUIDPropertyList(&propList);
#endif
// Normalize CPU IDs
for (auto& cpu : propList) {
cpu = NormalizeHardwareString(cpu);
}
hash1 = (propList.size() > 0) ? HashString(propList.front().c_str()) : h0;
hash2 = (propList.size() > 1) ? HashString(propList.back().c_str()) : h0;
bits.WriteUInt16(hash1);
bits.WriteUInt16(hash2);
// MAC Addresses - get MORE adapters and sort for consistency
propList.clear();
#ifdef _WIN32
// Try physical PCI adapters first
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%PCI%\"", "MACAddress", &propList, 6);
// Fallback to VMBUS for VMs
if (propList.size() == 0)
{
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%VMBUS%\"", "MACAddress", &propList, 6);
}
#else
GetMACPropertyList(&propList, 6);
#endif
// Normalize and sort MAC addresses for consistent ordering
for (auto& mac : propList) {
mac = NormalizeHardwareString(mac);
}
propList.sort();
// Store up to 4 MAC hashes
auto macIter = propList.begin();
hash1 = (propList.size() > 0 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
hash2 = (propList.size() > 1 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
hash3 = (propList.size() > 2 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
hash4 = (propList.size() > 3 && macIter != propList.end()) ? HashString((macIter++)->c_str()) : h0;
bits.WriteUInt16(hash1);
bits.WriteUInt16(hash2);
bits.WriteUInt16(hash3);
bits.WriteUInt16(hash4);
// HDD Serial Numbers - get more drives and sort
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT SerialNumber FROM Win32_PhysicalMedia WHERE SerialNumber IS NOT NULL", "SerialNumber", &propList, 4);
#else
GetHDDPropertyList(&propList, 4);
#endif
// Normalize and sort HDD serials
for (auto& serial : propList) {
serial = NormalizeHardwareString(serial);
}
propList.sort();
auto hddIter = propList.begin();
hash1 = (propList.size() > 0 && hddIter != propList.end()) ? HashString((hddIter++)->c_str()) : h0;
hash2 = (propList.size() > 1 && hddIter != propList.end()) ? HashString((hddIter++)->c_str()) : h0;
bits.WriteUInt16(hash1);
bits.WriteUInt16(hash2);
unsigned char* rawHwid = bits.GetBuffer();
BASE32 base32;
auto encHwid = base32.encode(rawHwid, 16);
hardwareId = encHwid.c_str();
hardwareId.erase(hardwareId.length() - 1);
unsigned i;
unsigned insertPos;
// separate character groups
for (i = 0, insertPos = 5; i < 4; i++)
{
hardwareId.insert(insertPos, "-");
insertPos += 6;
}
return hardwareId.c_str();
}
bool HardwareId::MatchCurrentHardwareId(const char* hwid)
{
#ifdef _WIN32
WmiHelper wmi;
#endif
unsigned short h0 = HashInt(0);
string hardwareId((char*)hwid);
for (int i = 0, erasePos = 0; i < 4; i++)
{
erasePos += 5;
hardwareId.erase(erasePos, 1);
}
BASE32 base32;
int bufLen;
int padLen;
int len = base32.encode_pad_length(((int)hardwareId.length() * 5 + 7) >> 3, &padLen);
if (len > (int)hardwareId.length())
hardwareId.append(len - hardwareId.length(), 'A');
if (padLen)
hardwareId.append(padLen, '=');
auto buf = base32.decode(hardwareId.c_str(), hardwareId.length(), &bufLen);
BitStream3 bits;
bits.Attach(buf.data(), 125);
unsigned char version = 0;
bits.Read(&version, 3);
if ((version & 0x7) > 1)
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid hardware id version");
list<string> propList;
set<unsigned short> storedHashes; // Store all hashes from license
unsigned short hash1, hash2, hash3, hash4;
// Use a points-based matching system for resilience
int matchPoints = 0;
const int REQUIRED_POINTS = 2; // Need at least 2 components to match
// Read UUID hash
bits.ReadUInt16(&hash1);
if (version == 0)
{
// Legacy version 0 support (memory size based)
if (hash1 != h0)
{
unsigned long long memSize = 0;
#ifdef _WIN32
wmi.GetPropertyList("SELECT Capacity FROM Win32_PhysicalMemory", "Capacity", &propList);
#else
propList.push_back("4294967296");
#endif
if (propList.size() > 0)
{
for (list<string>::iterator iter = propList.begin(); iter != propList.end(); iter++)
{
memSize += _atoi64(iter->c_str());
}
memSize = memSize / (1024 * 1024);
if (hash1 != HashInt((int)memSize))
return false;
}
}
matchPoints += 2; // UUID/Memory match gives 2 points
}
else
{
// Version 1+ - UUID based
#ifdef _WIN32
wmi.GetPropertyList("SELECT * FROM Win32_ComputerSystemProduct", "UUID", &propList);
#endif
if (propList.size() > 0)
{
string s = NormalizeHardwareString(propList.front());
if ((s.length() > 1)
&& (s != "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
&& (s != "00000000000000000000000000000000"))
{
if (hash1 != h0 && hash1 == HashString(s.c_str()))
{
matchPoints += 2; // UUID match is worth 2 points (most stable)
}
}
}
}
// Read CPU hashes
bits.ReadUInt16(&hash1);
bits.ReadUInt16(&hash2);
storedHashes.clear();
if (hash1 != h0) storedHashes.insert(hash1);
if (hash2 != h0) storedHashes.insert(hash2);
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT ProcessorId FROM Win32_Processor", "ProcessorId", &propList, 4);
#else
GetCPUIDPropertyList(&propList);
#endif
// Check if ANY current CPU matches stored hashes
int cpuMatches = 0;
for (auto& cpu : propList) {
string s = NormalizeHardwareString(cpu);
unsigned short currentHash = HashString(s.c_str());
if (storedHashes.find(currentHash) != storedHashes.end()) {
cpuMatches++;
}
}
if (cpuMatches > 0) {
matchPoints += 1; // CPU match is worth 1 point
}
// Read MAC hashes (now 4 hashes for better resilience)
bits.ReadUInt16(&hash1);
bits.ReadUInt16(&hash2);
bits.ReadUInt16(&hash3);
bits.ReadUInt16(&hash4);
storedHashes.clear();
if (hash1 != h0) storedHashes.insert(hash1);
if (hash2 != h0) storedHashes.insert(hash2);
if (hash3 != h0) storedHashes.insert(hash3);
if (hash4 != h0) storedHashes.insert(hash4);
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%PCI%\"", "MACAddress", &propList, 10);
if (propList.size() == 0)
{
wmi.GetPropertyList("SELECT MACAddress FROM Win32_NetworkAdapter WHERE (AdapterType = \"Ethernet 802.3\") AND (MACAddress IS NOT NULL) AND PNPDeviceId LIKE \"%VMBUS%\"", "MACAddress", &propList, 10);
}
#else
GetMACPropertyList(&propList, 10);
#endif
// Check if ANY current MAC address matches stored hashes
int macMatches = 0;
for (auto& mac : propList) {
string s = NormalizeHardwareString(mac);
unsigned short currentHash = HashString(s.c_str());
if (storedHashes.find(currentHash) != storedHashes.end()) {
macMatches++;
}
}
if (macMatches > 0) {
matchPoints += 1; // MAC match is worth 1 point
}
// Read HDD hashes
bits.ReadUInt16(&hash1);
bits.ReadUInt16(&hash2);
storedHashes.clear();
if (hash1 != h0) storedHashes.insert(hash1);
if (hash2 != h0) storedHashes.insert(hash2);
propList.clear();
#ifdef _WIN32
wmi.GetPropertyList("SELECT SerialNumber FROM Win32_PhysicalMedia WHERE SerialNumber IS NOT NULL", "SerialNumber", &propList, 10);
#else
GetHDDPropertyList(&propList, 10);
#endif
// Check if ANY current HDD serial matches stored hashes
int hddMatches = 0;
for (auto& serial : propList) {
string s = NormalizeHardwareString(serial);
unsigned short currentHash = HashString(s.c_str());
if (storedHashes.find(currentHash) != storedHashes.end()) {
hddMatches++;
}
}
if (hddMatches > 0) {
matchPoints += 1; // HDD match is worth 1 point
}
// Validation passes if we have enough matching points
// Typical valid scenarios:
// - UUID (2) + CPU (1) = 3 points ✓
// - UUID (2) + MAC (1) = 3 points ✓
// - UUID (2) + HDD (1) = 3 points ✓
// - CPU (1) + MAC (1) + HDD (1) = 3 points ✓ (if UUID changed but hardware same)
return matchPoints >= REQUIRED_POINTS;
}

16
core/anslicensing/hwid.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef __HARDWARE_ID_H
#define __HARDWARE_ID_H
class HardwareId
{
public:
static const char * GetCurrentHardwareId();
static bool MatchCurrentHardwareId(const char * hwid);
private:
static unsigned short HashString(const char * str);
static unsigned short HashInt(int val);
static string hardwareId;
};
#endif

View File

@@ -0,0 +1,360 @@
#include "precomp.h"
#include "anslicensing.h"
#include "license.h"
#include "uniconv.h"
#include "except.h"
#include "tinyxml2.h"
#include "picojson.h"
#include "base64.h"
void LicenseImpl::LoadXml(const char * xmlTemplate)
{
tinyxml2::XMLDocument xml;
tinyxml2::XMLElement * rootElement, *element;
const char * attr;
int version = 1;
if (xml.Parse(xmlTemplate) != tinyxml2::XML_NO_ERROR)
throw new LicensingException(STATUS_INVALID_XML);
if ((element = rootElement = xml.FirstChildElement()) == NULL)
throw new LicensingException(STATUS_INVALID_XML);
if ((attr = element->Attribute("version")) != NULL)
version = atoi(attr);
if (version > 1)
throw new LicensingException(STATUS_GENERIC_ERROR, "unsupported license version");
bool isLease = false;
if ((attr = element->Attribute("isLease")) != NULL)
isLease = (_stricmp(attr, "1") == 0 || _stricmp(attr, "true") == 0);
m_isLease = isLease;
if ((element = rootElement->FirstChildElement("LicenseKey")) == NULL)
throw new LicensingException(STATUS_GENERIC_ERROR, "license key not found");
m_licenseKey = element->GetText();
if ((element = rootElement->FirstChildElement("LicenseKeyValidationData")) != NULL)
{
BASE64 base64;
m_licenseKeyValidationData = base64.decode(element->GetText(), strlen(element->GetText()), nullptr);
if (!m_licenseKeyValidationData.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid BASE64 string");
}
if ((element = rootElement->FirstChildElement("ActivationKey")) == NULL)
throw new LicensingException(STATUS_GENERIC_ERROR, "license key not found");
m_activationKey = element->GetText();
if ((element = rootElement->FirstChildElement("HardwareId")) == NULL)
throw new LicensingException(STATUS_GENERIC_ERROR, "license key not found");
m_hardwareId = element->GetText();
}
#ifndef MAX_XML_BUFFER_SIZE
#define MAX_XML_BUFFER_SIZE 4096
#endif
const char * LicenseImpl::SaveXml()
{
BASE64 base64;
char buffer[MAX_XML_BUFFER_SIZE];
m_xmlLicense.resize(0);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"); m_xmlLicense.append(buffer);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "<License version=\"%d\" isLease=\"%d\">\n", m_version, (m_isLease) ? 1 : 0); m_xmlLicense.append(buffer);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<LicenseKey>%s</LicenseKey>\n", m_licenseKey.c_str()); m_xmlLicense.append(buffer);
if (!m_licenseKeyValidationData.empty())
{
BASE64 base64;
auto enc = base64.encode(m_licenseKeyValidationData.data(), m_licenseKeyValidationData.size(), true);
if (!enc.empty())
{
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<LicenseKeyValidationData>"); m_xmlLicense.append(buffer);
m_xmlLicense.append(enc);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "</LicenseKeyValidationData>\n"); m_xmlLicense.append(buffer);
}
else
throw new LicensingException(STATUS_OUT_OF_MEMORY);
}
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<ActivationKey>%s</ActivationKey>\n", m_activationKey.c_str()); m_xmlLicense.append(buffer);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "\t<HardwareId>%s</HardwareId>\n", m_hardwareId.c_str()); m_xmlLicense.append(buffer);
snprintf(buffer, MAX_XML_BUFFER_SIZE, "</License>"); m_xmlLicense.append(buffer);
return m_xmlLicense.c_str();
}
void LicenseImpl::LoadJson(const char * jsonLicense)
{
picojson::value json;
auto err = picojson::parse(json, jsonLicense);
if (!err.empty())
throw new LicensingException(STATUS_INVALID_PARAM);
picojson::object license = json.get<picojson::object>();
auto version = license["version"].get<double>();
if (version > 1)
throw new LicensingException(STATUS_GENERIC_ERROR, "unsupported license version");
m_isLease = license.count("is_lease") ? license["is_lease"].get<bool>() : false;
m_licenseKey = license["license_key"].get<string>();
if (license.count("license_key_validation_data"))
{
BASE64 base64;
m_licenseKeyValidationData = base64.decode(license["license_key_validation_data"].get<string>().c_str());
}
m_activationKey = license["activation_key"].get<string>();
m_hardwareId = license["hardware_id"].get<string>();
}
#ifndef MAX_JSON_BUFFER_SIZE
#define MAX_JSON_BUFFER_SIZE 4096
#endif
const char * LicenseImpl::SaveJson()
{
picojson::object license;
BASE64 base64;
license["version"] = picojson::value((double)1);
license["is_lease"] = picojson::value(m_isLease);
license["license_key"] = picojson::value(m_licenseKey);
license["hardware_id"] = picojson::value(m_hardwareId);
license["activation_key"] = picojson::value(m_activationKey);
if (!m_licenseKeyValidationData.empty())
license["license_key_validation_data"] = picojson::value(base64.encode(m_licenseKeyValidationData.data(), m_licenseKeyValidationData.size(), true));
m_jsonLicense = picojson::value(license).serialize(true);
return m_jsonLicense.c_str();
}
namespace ANSCENTER {
namespace Licensing {
template<>
LicenseT<char>::LicenseT() :
m_Impl(*new LicenseImpl())
{
}
template<>
LicenseT<wchar_t>::LicenseT() :
m_Impl(*new LicenseImpl())
{
}
template<>
LicenseT<char>::~LicenseT()
{
delete& m_Impl;
}
template<>
LicenseT<wchar_t>::~LicenseT()
{
delete& m_Impl;
}
template<>
const char* LicenseT<char>::SaveXml()
{
return m_Impl.SaveXml();
}
template<>
const char* LicenseT<wchar_t>::SaveXml()
{
return m_Impl.SaveXml();
}
template<>
void LicenseT<char>::LoadXml(const char* xml)
{
m_Impl.LoadXml(xml);
}
template<>
void LicenseT<wchar_t>::LoadXml(const char* xml)
{
m_Impl.LoadXml(xml);
}
template<>
const char* LicenseT<char>::SaveJson()
{
return m_Impl.SaveJson();
}
template<>
const char* LicenseT<wchar_t>::SaveJson()
{
return m_Impl.SaveJson();
}
template<>
void LicenseT<char>::LoadJson(const char* xml)
{
m_Impl.LoadJson(xml);
}
template<>
void LicenseT<wchar_t>::LoadJson(const char* xml)
{
m_Impl.LoadJson(xml);
}
template<>
void LicenseT<char>::SetLicenseKey(const char* licenseKey)
{
m_Impl.SetLicenseKey(licenseKey);
}
template<>
void LicenseT<wchar_t>::SetLicenseKey(const wchar_t* licenseKey)
{
m_Impl.SetLicenseKey(w2s(licenseKey).c_str());
}
template<>
void LicenseT<char>::SetLicenseKeyValidationData(void* validationData, int validationDataLen)
{
m_Impl.SetLicenseKeyValidationData((const unsigned char*)validationData, validationDataLen);
}
template<>
void LicenseT<wchar_t>::SetLicenseKeyValidationData(void* validationData, int validationDataLen)
{
m_Impl.SetLicenseKeyValidationData((const unsigned char*)validationData, validationDataLen);
}
template<>
void LicenseT<char>::GetLicenseKeyValidationData(void** buf, int* len)
{
m_Impl.GetLicenseKeyValidationData((const void**)buf, len);
}
template<>
void LicenseT<wchar_t>::GetLicenseKeyValidationData(void** buf, int* len)
{
m_Impl.GetLicenseKeyValidationData((const void**)buf, len);
}
template<>
const char* LicenseT<char>::GetLicenseKey()
{
return m_Impl.GetLicenseKey();
}
template<>
const wchar_t* LicenseT<wchar_t>::GetLicenseKey()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetLicenseKey());
return wstr1.c_str();
}
template<>
void LicenseT<char>::SetActivationKey(const char* activationKey)
{
m_Impl.SetActivationKey(activationKey);
}
template<>
void LicenseT<wchar_t>::SetActivationKey(const wchar_t* activationKey)
{
m_Impl.SetActivationKey(w2s(activationKey).c_str());
}
template<>
const char* LicenseT<char>::GetActivationKey()
{
return m_Impl.GetActivationKey();
}
template<>
const wchar_t* LicenseT<wchar_t>::GetActivationKey()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetActivationKey());
return wstr1.c_str();
}
template<>
void LicenseT<char>::SetHardwareId(const char* hardwareId)
{
m_Impl.SetHardwareId(hardwareId);
}
template<>
void LicenseT<wchar_t>::SetHardwareId(const wchar_t* hardwareId)
{
m_Impl.SetHardwareId(w2s(hardwareId).c_str());
}
template<>
const char* LicenseT<char>::GetHardwareId()
{
return m_Impl.GetHardwareId();
}
template<>
const wchar_t* LicenseT<wchar_t>::GetHardwareId()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetHardwareId());
return wstr1.c_str();
}
template<>
void LicenseT<char>::SetLease(bool isLease)
{
m_Impl.SetLease(isLease);
}
template<>
void LicenseT<wchar_t>::SetLease(bool isLease)
{
m_Impl.SetLease(isLease);
}
template<>
bool LicenseT<char>::IsLease()
{
return m_Impl.IsLease();
}
template<>
bool LicenseT<wchar_t>::IsLease()
{
return m_Impl.IsLease();
}
};
}

104
core/anslicensing/license.h Normal file
View File

@@ -0,0 +1,104 @@
#pragma once
#include <vector>
#include "except.h"
using namespace std;
class LicenseImpl {
friend class LicenseValidationResultT<char>;
friend class LicenseValidationResultT<wchar_t>;
public:
LicenseImpl():
m_isLease(false)
{
}
void CopyFrom(const LicenseImpl * src)
{
m_activationKey = src->m_activationKey;
m_hardwareId = src->m_hardwareId;
m_isLease = src->m_isLease;
m_licenseKey = src->m_licenseKey;
m_xmlLicense = src->m_xmlLicense;
SetLicenseKeyValidationData(src->m_licenseKeyValidationData.data(), src->m_licenseKeyValidationData.size());
}
void LoadXml(const char * xml);
const char * SaveXml();
void LoadJson(const char * json);
const char * SaveJson();
const char * GetLicenseKey() const
{
return m_licenseKey.c_str();
}
void SetLicenseKey(const char * licenseKey)
{
m_licenseKey = licenseKey;
}
void GetLicenseKeyValidationData(const void ** buf, int * len) const
{
*buf = m_licenseKeyValidationData.data();
*len = m_licenseKeyValidationData.size();
}
void SetLicenseKeyValidationData(const void* buf, int len)
{
if (buf && len > 0)
{
m_licenseKeyValidationData.resize(len);
memcpy(m_licenseKeyValidationData.data(), buf, len);
}
else
{
m_licenseKeyValidationData.clear();
}
}
const char * GetActivationKey() const
{
return m_activationKey.c_str();
}
void SetActivationKey(const char * activationKey)
{
m_activationKey = activationKey;
}
const char * GetHardwareId() const
{
return m_hardwareId.c_str();
}
void SetHardwareId(const char * hardwareId)
{
m_hardwareId = hardwareId;
}
bool IsLease() const
{
return m_isLease;
}
void SetLease(bool isLease)
{
m_isLease = isLease;
}
private:
string m_licenseKey;
string m_activationKey;
string m_hardwareId;
vector<unsigned char> m_licenseKeyValidationData;
bool m_isLease;
string m_xmlLicense;
string m_jsonLicense;
static const int m_version = 1;
};

View File

@@ -0,0 +1,108 @@
#include "precomp.h"
#include "anslicensing.h"
#include "license.h"
#include "uniconv.h"
#include "licensevalidationargs.h"
namespace ANSCENTER {
namespace Licensing {
template<>
LicenseValidationArgsT<char>::LicenseValidationArgsT():
m_Impl(*new LicenseValidationArgsImpl())
{
}
template<>
LicenseValidationArgsT<wchar_t>::LicenseValidationArgsT() :
m_Impl(*new LicenseValidationArgsImpl())
{
}
template<>
LicenseValidationArgsT<char>::~LicenseValidationArgsT()
{
delete & m_Impl;
}
template<>
LicenseValidationArgsT<wchar_t>::~LicenseValidationArgsT()
{
delete & m_Impl;
}
template<>
void LicenseValidationArgsT<char>::SetLicenseKey(const char * licenseKey)
{
m_Impl.SetLicenseKey(licenseKey);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicenseKey(const wchar_t * licenseKey)
{
m_Impl.SetLicenseKey(w2s(licenseKey).c_str());
}
template<>
void LicenseValidationArgsT<char>::SetLicense(const LicenseT<char> * license)
{
m_Impl.SetLicense(&license->m_Impl);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicense(const LicenseT<wchar_t> * license)
{
m_Impl.SetLicense(&license->m_Impl);
}
template<>
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, int fieldValue)
{
m_Impl.SetLicenseKeyValidationData(fieldName, fieldValue);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, int fieldValue)
{
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), fieldValue);
}
template<>
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, const char * fieldValue)
{
m_Impl.SetLicenseKeyValidationData(fieldName, fieldValue);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, const wchar_t * fieldValue)
{
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), w2s(fieldValue).c_str());
}
template<>
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, int year, int month, int day)
{
m_Impl.SetLicenseKeyValidationData(fieldName, year, month, day);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, int year, int month, int day)
{
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), year, month, day);
}
template<>
void LicenseValidationArgsT<char>::SetLicenseKeyValidationData(const char * fieldName, void * data, int len)
{
m_Impl.SetLicenseKeyValidationData(fieldName, data, len);
}
template<>
void LicenseValidationArgsT<wchar_t>::SetLicenseKeyValidationData(const wchar_t * fieldName, void * data, int len)
{
m_Impl.SetLicenseKeyValidationData(w2s(fieldName).c_str(), data, len);
}
};
};

View File

@@ -0,0 +1,109 @@
#pragma once
#include "license.h"
#include <string>
#include <vector>
#include <list>
using namespace std;
struct NameValuePair {
public:
NameValuePair(const char* _name, const char* _value):
name(_name),
stringValue(_value)
{
}
NameValuePair(const char* _name, int _value):
name(_name),
intValue(_value)
{
}
NameValuePair(const char* _name, int _year, int _month, int _day):
name(_name),
dateValue { _year, _month, _day }
{
}
NameValuePair(const char* _name, const unsigned char* _value, int _len):
name(_name),
binaryValue(_value, _value + _len)
{
}
string name;
int intValue;
string stringValue;
struct {
int year, month, day;
} dateValue;
vector<unsigned char> binaryValue;
};
class LicenseValidationArgsImpl
{
friend LicensingClient;
public:
LicenseValidationArgsImpl():
m_license(nullptr)
{
}
void SetLicense(LicenseImpl * license)
{
m_license = license;
}
const LicenseImpl * GetLicense()
{
return m_license;
}
void SetLicenseKey(const char * licenseKey, int validationDataSize = 0)
{
m_licenseKey = licenseKey;
}
void SetLicenseKeyValidationData(const char * fieldName, const char * fieldValue)
{
m_licenseKeyValidationData.emplace_back(fieldName, fieldValue);
}
void SetLicenseKeyValidationData(const char * fieldName, int fieldValue)
{
m_licenseKeyValidationData.emplace_back(fieldName, fieldValue);
}
void SetLicenseKeyValidationData(const char * fieldName, int year, int month, int day)
{
m_licenseKeyValidationData.emplace_back(fieldName, year, month, day);
}
void SetLicenseKeyValidationData(const char * fieldName, void * data, int len)
{
m_licenseKeyValidationData.emplace_back(fieldName, (unsigned char*)data, len);
}
const char * GetLicenseKey()
{
return m_licenseKey.c_str();
}
public:
const LicenseImpl* m_license;
int m_validationDataSize;
string m_licenseKey;
list<NameValuePair> m_licenseKeyValidationData;
};

View File

@@ -0,0 +1,111 @@
#include "precomp.h"
#include "anslicensing.h"
#include "uniconv.h"
#include "licensevalidationresult.h"
namespace ANSCENTER {
namespace Licensing {
template<>
LicenseValidationResultT<char>::LicenseValidationResultT() :
m_Impl(*new LicenseValidationResultImpl())
{
}
template<>
LicenseValidationResultT<wchar_t>::LicenseValidationResultT() :
m_Impl(*new LicenseValidationResultImpl())
{
}
template<>
LicenseValidationResultT<char>::~LicenseValidationResultT()
{
delete & m_Impl;
}
template<>
LicenseValidationResultT<wchar_t>::~LicenseValidationResultT()
{
delete & m_Impl;
}
template<>
LicenseT<char> * LicenseValidationResultT<char>::GetLicense()
{
static LicenseT<char> result;
LicenseImpl * resultImpl = m_Impl.GetLicense();
if (!resultImpl) return NULL;
result.m_Impl.CopyFrom(resultImpl);
return &result;
}
template<>
LicenseT<wchar_t> * LicenseValidationResultT<wchar_t>::GetLicense()
{
static LicenseT<wchar_t> result;
LicenseImpl * resultImpl = m_Impl.GetLicense();
if (!resultImpl) return NULL;
result.m_Impl.CopyFrom(resultImpl);
return &result;
}
template<>
bool LicenseValidationResultT<char>::IsLicenseExpired()
{
return m_Impl.IsLicenseExpired();
}
template<>
bool LicenseValidationResultT<wchar_t>::IsLicenseExpired()
{
return m_Impl.IsLicenseExpired();
}
template<>
bool LicenseValidationResultT<char>::IsPaymentRequired()
{
return m_Impl.IsPaymentRequired();
}
template<>
bool LicenseValidationResultT<wchar_t>::IsPaymentRequired()
{
return m_Impl.IsPaymentRequired();
}
template<>
int LicenseValidationResultT<char>::GetLicenseValidityDays()
{
return m_Impl.GetLicenseValidityDays();
}
template<>
int LicenseValidationResultT<wchar_t>::GetLicenseValidityDays()
{
return m_Impl.GetLicenseValidityDays();
}
template<>
void LicenseValidationResultT<char>::GetLicenseExpirationDate(int * year, int * month, int * day)
{
m_Impl.GetLicenseExpirationDate(year, month, day);
}
template<>
void LicenseValidationResultT<wchar_t>::GetLicenseExpirationDate(int * year, int * month, int * day)
{
m_Impl.GetLicenseExpirationDate(year, month, day);
}
};
};

View File

@@ -0,0 +1,118 @@
#ifndef __LICENSEVALIDATIONRESULT_H
#define __LICENSEVALIDATIONRESULT_H
#include <memory>
#include "license.h"
using namespace std;
class LicensingClientImpl;
class LicenseValidationResultImpl
{
//friend class LicensingClientT<char>;
//friend class LicensingClientT<wchar_t>;
friend class LicensingClientImpl;
friend class LicenseValidationResultT<char>;
friend class LicenseValidationResultT<wchar_t>;
public:
LicenseValidationResultImpl()
{
m_isLicenseExpired = false;
m_isPaymentRequired = false;
m_licenseValidityDays = 0;
m_licenseExpirationYear = m_licenseExpirationMonth = m_licenseExpirationDay = 0;
}
~LicenseValidationResultImpl()
{
}
void MoveFrom(LicenseValidationResultImpl& src)
{
m_isLicenseExpired = src.m_isLicenseExpired;
m_isLicenseValid = src.m_isLicenseValid;
m_isPaymentRequired = src.m_isPaymentRequired;
m_license = std::move(src.m_license);
m_licenseValidityDays = src.m_licenseValidityDays;
m_licenseExpirationDay = src.m_licenseExpirationDay;
m_licenseExpirationMonth = src.m_licenseExpirationMonth;
m_licenseExpirationYear = src.m_licenseExpirationYear;
}
LicenseImpl * GetLicense()
{
return m_license.get();
}
void SetLicense(LicenseImpl * lic)
{
m_license.reset(lic);
}
bool IsLicenseValid()
{
return m_isLicenseValid;
}
void SetLicenseValid(bool isValid)
{
m_isLicenseValid = isValid;
}
bool IsLicenseExpired()
{
return m_isLicenseExpired;
}
void SetLicenseExpired(bool licenseExpired)
{
m_isLicenseExpired = licenseExpired;
}
bool IsPaymentRequired()
{
return m_isPaymentRequired;
}
void SetPaymentRequired(bool paymentRequired)
{
m_isPaymentRequired = paymentRequired;
}
int GetLicenseValidityDays()
{
return m_licenseValidityDays;
}
void SetLicenseValidityDays(int days)
{
m_licenseValidityDays = days;
}
void GetLicenseExpirationDate(int * year, int * month, int * day)
{
*year = m_licenseExpirationYear;
*month = m_licenseExpirationMonth;
*day = m_licenseExpirationDay;
}
void SetLicenseExpirationDate(int year, int month, int day)
{
m_licenseExpirationYear = year;
m_licenseExpirationMonth = month;
m_licenseExpirationDay = day;
}
private:
bool m_isLicenseValid;
bool m_isLicenseExpired;
bool m_isPaymentRequired;
int m_licenseValidityDays;
int m_licenseExpirationYear, m_licenseExpirationMonth, m_licenseExpirationDay;
unique_ptr<LicenseImpl> m_license;
};
#endif

View File

@@ -0,0 +1,289 @@
#include "precomp.h"
#include <memory>
#include "licensingclient.h"
#include "licensevalidationargs.h"
#include "licensevalidationresult.h"
using namespace std;
namespace ANSCENTER {
namespace Licensing {
template<>
LicensingClientT<wchar_t>::LicensingClientT():
m_Impl(*(new LicensingClientImpl(this, true)))
{
}
template<>
LicensingClientT<char>::LicensingClientT():
m_Impl(*(new LicensingClientImpl(this, false)))
{
}
template<>
LicensingClientT<char>::~LicensingClientT()
{
delete & m_Impl;
}
template<>
LicensingClientT<wchar_t>::~LicensingClientT()
{
delete & m_Impl;
}
template<>
void LicensingClientT<char>::SetLicenseTemplate(LicenseTemplateT<char> * tmpl)
{
m_Impl.SetLicenseTemplate(&tmpl->m_Impl);
}
template<>
void LicensingClientT<wchar_t>::SetLicenseTemplate(LicenseTemplateT<wchar_t> * tmpl)
{
m_Impl.SetLicenseTemplate(&tmpl->m_Impl);
}
template<>
void LicensingClientT<char>::SetLicenseKey(const char * key)
{
m_Impl.SetLicenseKey(key);
}
template<>
void LicensingClientT<wchar_t>::SetLicenseKey(const wchar_t * key)
{
m_Impl.SetLicenseKey(w2s(key).c_str());
}
template<>
void LicensingClientT<char>::SetActivationKey(const char * key)
{
m_Impl.SetActivationKey(key);
}
template<>
void LicensingClientT<wchar_t>::SetActivationKey(const wchar_t * key)
{
m_Impl.SetActivationKey(w2s(key).c_str());
}
template<>
const char * LicensingClientT<char>::GetActivationKey()
{
return m_Impl.GetActivationKey();
}
template<>
const wchar_t * LicensingClientT<wchar_t>::GetActivationKey()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetActivationKey());
return wstr1.c_str();
}
template<>
void LicensingClientT<char>::SetHardwareId(const char * hwid)
{
m_Impl.SetHardwareId(hwid);
}
template<>
void LicensingClientT<wchar_t>::SetHardwareId(const wchar_t * hwid)
{
m_Impl.SetHardwareId(w2s(hwid).c_str());
}
template<>
const char * LicensingClientT<char>::GetHardwareId()
{
return m_Impl.GetHardwareId();
}
template<>
const wchar_t * LicensingClientT<wchar_t>::GetHardwareId()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetHardwareId());
return wstr1.c_str();
}
template<>
const wchar_t * LicensingClientT<wchar_t>::GetCurrentHardwareId()
{
static wstring wstr1;
wstr1 = s2w(m_Impl.GetCurrentHardwareId());
return wstr1.c_str();
}
template<>
const char * LicensingClientT<char>::GetCurrentHardwareId()
{
return m_Impl.GetCurrentHardwareId();
}
template<>
bool LicensingClientT<char>::MatchCurrentHardwareId(const char * hwid)
{
return m_Impl.MatchCurrentHardwareId(hwid);
}
template<>
bool LicensingClientT<wchar_t>::MatchCurrentHardwareId(const wchar_t * hwid)
{
return m_Impl.MatchCurrentHardwareId(w2s(hwid).c_str());
}
template<>
void LicensingClientT<char>::SetLicensingServiceUrl(const char * url)
{
m_Impl.SetLicensingServiceUrl(url);
}
template<>
void LicensingClientT<wchar_t>::SetLicensingServiceUrl(const wchar_t * url)
{
m_Impl.SetLicensingServiceUrl(w2s(url).c_str());
}
template<>
void LicensingClientT<char>::SetLicenseTemplateId(const char * templateId)
{
m_Impl.SetLicenseTemplateId(templateId);
}
template<>
void LicensingClientT<wchar_t>::SetLicenseTemplateId(const wchar_t * templateId)
{
m_Impl.SetLicenseTemplateId(w2s(templateId).c_str());
}
template<>
void LicensingClientT<char>::AcquireLicense()
{
m_Impl.AcquireLicense();
}
template<>
void LicensingClientT<wchar_t>::AcquireLicense()
{
m_Impl.AcquireLicense();
}
template<>
bool LicensingClientT<char>::IsLicenseValid()
{
return m_Impl.IsLicenseValid();
}
template<>
bool LicensingClientT<wchar_t>::IsLicenseValid()
{
return m_Impl.IsLicenseValid();
}
template<>
LicenseValidationResultT<char> * LicensingClientT<char>::ValidateLicense(LicenseValidationArgsT<char> * args)
{
static LicenseValidationResultT<char> result;
auto& resultImpl = m_Impl.ValidateLicense(&args->m_Impl);
result.m_Impl.MoveFrom(resultImpl);
return &result;
}
template<>
LicenseValidationResultT<wchar_t> * LicensingClientT<wchar_t>::ValidateLicense(LicenseValidationArgsT<wchar_t> * args)
{
static LicenseValidationResultT<wchar_t> result;
auto& resultImpl = m_Impl.ValidateLicense(&args->m_Impl);
result.m_Impl.MoveFrom(resultImpl);
return &result;
}
template<>
void LicensingClientT<char>::SetLicenseKeyValidationData(void * data, int len)
{
return m_Impl.SetLicenseKeyValidationData(data, len);
}
template<>
void LicensingClientT<wchar_t>::SetLicenseKeyValidationData(void * data, int len)
{
return m_Impl.SetLicenseKeyValidationData(data, len);
}
template<>
int LicensingClientT<char>::GetLicenseActivationStatus()
{
return m_Impl.GetLicenseActivationStatus();
}
template<>
int LicensingClientT<wchar_t>::GetLicenseActivationStatus()
{
return m_Impl.GetLicenseActivationStatus();
}
template<>
void LicensingClientT<char>::GetLicenseExpirationDate(int * year, int * month, int * day)
{
m_Impl.GetLicenseExpirationDate(year, month, day);
}
template<>
void LicensingClientT<wchar_t>::GetLicenseExpirationDate(int * year, int * month, int * day)
{
m_Impl.GetLicenseExpirationDate(year, month, day);
}
template<>
void LicensingClientT<char>::SetTimeValidationMethod(int method)
{
return m_Impl.SetTimeValidationMethod(method);
}
template<>
void LicensingClientT<wchar_t>::SetTimeValidationMethod(int method)
{
return m_Impl.SetTimeValidationMethod(method);
}
};
};
const wchar_t * GetCurrentHardwareIdW(void * licensingClient)
{
static std::wstring result = ((ANSCENTER::Licensing::LicensingClientT<wchar_t> *)licensingClient)->GetCurrentHardwareId();
return result.c_str();
}
const char * GetCurrentHardwareIdA(void * licensingClient)
{
return ((ANSCENTER::Licensing::LicensingClientT<char> *)licensingClient)->GetCurrentHardwareId();
}
bool MatchCurrentHardwareIdW(void * licensingClient, const wchar_t * hwid)
{
return ((ANSCENTER::Licensing::LicensingClientT<wchar_t> *)licensingClient)->MatchCurrentHardwareId(hwid);
}
bool MatchCurrentHardwareIdA(void * licensingClient, const char * hwid)
{
return ((ANSCENTER::Licensing::LicensingClientT<char> *)licensingClient)->MatchCurrentHardwareId(hwid);
}

View File

@@ -0,0 +1,602 @@
#pragma once
#include <memory>
#include <vector>
#include "except.h"
#include "template.h"
#include "generator.h"
#include "validator.h"
#include "ntpclient.h"
#include "uniconv.h"
#include "license.h"
#include "licensevalidationargs.h"
#include "licensevalidationresult.h"
#include <time.h>
#ifdef _WIN32
#include <winhttp.h>
#include <tchar.h>
#else
#include <curl/curl.h>
#endif
using namespace std;
// these methods are compiler workarounds to eliminate circular references.
// They only call the corresponding LicensingClient::... methods
// GCC complains of cross-references between LicensingClientImpl and LicensingClientT
const wchar_t * GetCurrentHardwareIdW(void *);
const char * GetCurrentHardwareIdA(void *);
bool MatchCurrentHardwareIdW(void *, const wchar_t *);
bool MatchCurrentHardwareIdA(void *, const char *);
class LicensingClientImpl
{
public:
LicensingClientImpl(void * licensingClient, bool usesWideChar)
{
licenseKeyValidationDataLen = 0;
licenseTemplateId.clear();
parentLicensingClient = licensingClient;
parentUsesWideChar = usesWideChar;
timeValidationMethod = PREFER_INTERNET_TIME;
m_licenseValidityDays = 0;
// GetCurrentHardwareIdCallback = GetCurrentHardwareId;
// MatchCurrentHardwareIdCallback = MatchCurrentHardwareId;
}
void SetLicenseTemplate(const LicenseTemplateImpl* tmpl)
{
licenseTemplate = tmpl;
}
void SetLicenseKey(const char * key)
{
licenseKey = key;
}
void SetActivationKey(const char * key)
{
activationKey = key;
}
const char * GetActivationKey()
{
return activationKey.c_str();
}
void SetHardwareId(const char * hwid)
{
hardwareId = hwid;
}
const char * GetHardwareId()
{
return hardwareId.c_str();
}
void SetLicenseTemplateId(const char * templateId)
{
licenseTemplateId = templateId;
}
const char * GetLicenseTemplateId()
{
return licenseTemplateId.c_str();
}
void SetLicenseKeyValidationData(const void* data, unsigned len)
{
licenseKeyValidationData.resize(len);
memcpy(licenseKeyValidationData.data(), data, len);
licenseKeyValidationDataLen = len;
}
LicenseTemplateImpl * CreateActivationTemplate()
{
LicenseTemplateImpl * tmpl = new LicenseTemplateImpl();
tmpl->SetCharactersPerGroup(licenseTemplate->GetCharactersPerGroup());
tmpl->SetNumberOfGroups(licenseTemplate->GetNumberOfGroups());
tmpl->SetGroupSeparator(licenseTemplate->GetGroupSeparator());
//activationKeyTemplate.SetDataSize(t.GetDataSize());
tmpl->SetSignatureSize(licenseTemplate->GetSignatureSize());
tmpl->SetEncoding(licenseTemplate->GetEncoding());
tmpl->SetPublicKeyCertificate(licenseTemplate->GetPublicKeyCertificate());
int keyLen = tmpl->GetNumberOfGroups() * tmpl->GetCharactersPerGroup()
+ (tmpl->GetNumberOfGroups() - 1) * strlen(tmpl->GetGroupSeparator());
int hwidLen = 29;
if (hardwareId.length() > 0)
hwidLen = hardwareId.length();
tmpl->SetDataSize(tmpl->GetCharactersPerGroup() * tmpl->GetNumberOfGroups() * tmpl->GetEncoding() - tmpl->GetSignatureSize());
tmpl->SetValidationDataSize((keyLen + hwidLen ) * 8 + licenseTemplate->GetValidationDataSize());
tmpl->AddDataField("ExpirationDate", FIELD_TYPE_RAW, 16, 0);
tmpl->AddValidationField("LicenseKey", FIELD_TYPE_STRING, keyLen * 8, 0);
tmpl->AddValidationField("HardwareId", FIELD_TYPE_STRING, hwidLen * 8, keyLen * 8);
if (!licenseKeyValidationData.empty())
{
tmpl->AddValidationField("LicenseKeyValidationData", FIELD_TYPE_RAW, licenseKeyValidationDataLen * 8, (keyLen + hwidLen) * 8);
}
if (licensingServiceUrl.empty())
tmpl->SetLicensingServiceUrl(licenseTemplate->GetLicensingServiceUrl());
else
tmpl->SetLicensingServiceUrl(licensingServiceUrl.c_str());
if (licenseTemplateId.empty())
tmpl->SetTemplateId(licenseTemplate->GetTemplateId());
else
tmpl->SetTemplateId(licenseTemplateId.c_str());
return tmpl;
}
bool ValidateHardwareId()
{
if (!MatchCurrentHardwareIdCallback(hardwareId.c_str()))
{
activationStatus = STATUS_INVALID_HARDWARE_ID;
return false;
}
return true;
}
bool ValidateActivationKey(LicenseTemplateImpl* activationTemplate = nullptr, bool validateExpirationDate = true)
{
bool ownActivationTemplate = false;
try {
if (!activationTemplate)
{
activationTemplate = CreateActivationTemplate();
ownActivationTemplate = true;
}
KeyValidatorImpl validator(activationTemplate);
validator.SetValidationData("LicenseKey", licenseKey.c_str());
validator.SetValidationData("HardwareId", hardwareId.c_str());
if (!licenseKeyValidationData.empty())
validator.SetValidationData("LicenseKeyValidationData", licenseKeyValidationData.data(), (activationTemplate->GetValidationDataSize() + 7) >> 3);
try
{
validator.SetKey(activationKey.c_str());
}
catch (Exception * ex)
{
ex->Destroy();
activationStatus = STATUS_INVALID_ACTIVATION_KEY;
if (ownActivationTemplate) delete activationTemplate;
return false;
}
if (!validator.IsKeyValid())
{
activationStatus = STATUS_INVALID_ACTIVATION_KEY;
if (ownActivationTemplate) delete activationTemplate;
return false;
}
unsigned char rawKeyData[2];
int rawKeyDataBits = 16;
validator.QueryKeyData("ExpirationDate", rawKeyData, &rawKeyDataBits);
unsigned short keyData = (unsigned short)(((unsigned short)rawKeyData[0]) << 8 | rawKeyData[1]);
memset(&licenseExpirationTime, 0, sizeof(licenseExpirationTime));
if (keyData != 0)
{
licenseExpirationTime.tm_year = (2000 + (keyData >> 9)) - 1900;
licenseExpirationTime.tm_mon = ((keyData & 0x01FF) >> 5) - 1;
licenseExpirationTime.tm_mday = keyData & 0x001F;
if (!validateExpirationDate)
{
if (ownActivationTemplate) delete activationTemplate;
return true;
}
time_t currentTime;
if (timeValidationMethod != USE_LOCAL_TIME)
{
currentTime = NTPClient::GetCurrentTimeUTC();
if (currentTime == 0) // if couldn't obtain internet time
{
if (timeValidationMethod == USE_INTERNET_TIME) // internet time was mandatory
{
activationStatus = STATUS_NET_ERROR;
if (ownActivationTemplate) delete activationTemplate;
return false;
}
// fallback to local time
currentTime = time(NULL);
}
}
else
currentTime = time(NULL);
double diffSeconds = difftime(mktime(&licenseExpirationTime), currentTime);
if (diffSeconds < 0)
{
m_licenseValidityDays = licenseTemplate->GetLicenseGracePeriod() - (int)(((time_t)(-diffSeconds) + 86400 - 1) / 86400);
if (m_licenseValidityDays < 0)
m_licenseValidityDays = 0;
activationStatus = STATUS_LICENSE_EXPIRED;
if (ownActivationTemplate) delete activationTemplate;
return false;
} else
m_licenseValidityDays = licenseTemplate->GetLicenseGracePeriod() + (int)(((time_t)diffSeconds + 86400 - 1) / 86400);
}
else
m_licenseValidityDays = -1;
if (ownActivationTemplate) delete activationTemplate;
return true;
}
catch (...)
{
if (ownActivationTemplate && activationTemplate)
delete activationTemplate;
throw;
}
}
bool IsLicenseValid()
{
activationStatus = STATUS_GENERIC_ERROR;
try
{
if (ValidateHardwareId() && ValidateActivationKey())
{
activationStatus = STATUS_SUCCESS;
return true;
}
else
return false;
}
catch (Exception * ex)
{
ex->Destroy();
activationStatus = STATUS_GENERIC_ERROR;
return false;
}
catch (...)
{
activationStatus = STATUS_GENERIC_ERROR;
return false;
}
}
LicenseValidationResultImpl& ValidateLicense(LicenseValidationArgsImpl * args)
{
const LicenseImpl * license = args->GetLicense();
const char * lk = args->GetLicenseKey();
licenseKey = (lk) ? lk : "";
if (license == NULL && licenseKey.length() == 0)
throw new LicensingException(STATUS_GENERIC_ERROR, "either a license or a license key must be provided");
if (license == NULL)
{
try {
KeyValidatorImpl keyValidator;
keyValidator.SetKeyTemplate(licenseTemplate);
keyValidator.SetKey(lk);
if (licenseTemplate->GetValidationDataSize() > 0)
{
int fieldType, fieldSize, fieldOffset;
for (std::list<NameValuePair>::iterator iter = args->m_licenseKeyValidationData.begin(); iter != args->m_licenseKeyValidationData.end(); iter++)
{
if (!licenseTemplate->GetValidationField(iter->name.c_str(), &fieldType, &fieldSize, &fieldOffset))
throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "license key validation data is invalid");
switch (fieldType)
{
case FIELD_TYPE_INTEGER:
keyValidator.SetValidationData(iter->name.c_str(), iter->intValue);
break;
case FIELD_TYPE_STRING:
keyValidator.SetValidationData(iter->name.c_str(), iter->stringValue.c_str());
break;
case FIELD_TYPE_DATE13:
case FIELD_TYPE_DATE14:
case FIELD_TYPE_DATE16:
keyValidator.SetValidationData(iter->name.c_str(), iter->dateValue.year, iter->dateValue.month, iter->dateValue.day);
break;
case FIELD_TYPE_RAW:
// keyValidator.SetValidationData(iter->name.c_str(), &(iter->value.binaryValue[0]), iter->value.binaryValue.size);
break;
default:
break;
}
}
licenseKeyValidationDataLen = (licenseTemplate->GetValidationDataSize() + 7) >> 3;
licenseKeyValidationData.resize(licenseKeyValidationDataLen);
keyValidator.QueryValidationData(NULL, licenseKeyValidationData.data(), &licenseKeyValidationDataLen);
}
if (!keyValidator.IsKeyValid())
{
throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "license key is not valid");
}
AcquireLicense();
}
catch (LicensingException * ex)
{
if (ex->GetCode() == STATUS_PAYMENT_REQUIRED)
{
m_licenseValidationResult.SetPaymentRequired(true);
ex->Destroy();
}
else
throw;
}
}
else
{
licenseKey = license->GetLicenseKey();
hardwareId = license->GetHardwareId();
activationKey = license->GetActivationKey();
const void* buf; int len;
license->GetLicenseKeyValidationData(&buf, &len);
if (buf && (len > 0))
SetLicenseKeyValidationData(buf, (unsigned int)len);
if (ValidateActivationKey(NULL, true))
{
m_licenseValidationResult.SetLicenseValid(true);
m_licenseValidationResult.SetPaymentRequired(false);
m_licenseValidationResult.SetLicenseExpired(false);
m_licenseValidationResult.SetLicense(NULL);
return m_licenseValidationResult;
}
else
{
if (activationStatus == STATUS_LICENSE_EXPIRED)
{
m_licenseValidationResult.SetLicenseExpired(true);
}
if ((activationStatus == STATUS_LICENSE_EXPIRED) && (m_licenseValidityDays > 0) && license->IsLease())
{
try
{
AcquireLicense();
m_licenseValidationResult.SetLicenseExpired(false);
}
catch (LicensingException * ex)
{
if (ex->GetCode() == STATUS_PAYMENT_REQUIRED)
{
m_licenseValidationResult.SetPaymentRequired(true);
ex->Destroy();
}
else
throw;
}
}
}
}
if (licenseExpirationTime.tm_year > 0)
{
m_licenseValidationResult.SetLicenseExpirationDate(
1900 + licenseExpirationTime.tm_year,
1 + licenseExpirationTime.tm_mon,
licenseExpirationTime.tm_mday);
}
else
{
m_licenseValidationResult.SetLicenseExpirationDate(0, 0, 0);
}
return m_licenseValidationResult;
}
void AcquireLicense()
{
if (hardwareId.empty())
hardwareId = (parentLicensingClient) ? GetCurrentHardwareIdCallback() : GetCurrentHardwareId();
unique_ptr<LicenseTemplateImpl> activationTemplate(CreateActivationTemplate());
const char * templateId = activationTemplate->GetTemplateId();
if (templateId != NULL && templateId[0] != '\0')
{
char params[64] = "ProductId=";
sprintf(params + sizeof("ProductId"), "%s", activationTemplate->GetTemplateId());
activationTemplate->SetLicensingServiceParameters(params);
}
KeyGeneratorImpl generator(activationTemplate.get());
generator.SetKeyData("ExpirationDate", (int)0);
generator.SetValidationData("LicenseKey", licenseKey.c_str());
generator.SetValidationData("HardwareId", hardwareId.c_str());
if (!licenseKeyValidationData.empty())
{
generator.SetValidationData("LicenseKeyValidationData", licenseKeyValidationData.data(), licenseKeyValidationDataLen * 8);
}
try {
activationKey = generator.GenerateKey();
}
catch (LicensingException * ex)
{
if ((ex->GetCode() == STATUS_NET_ERROR) && (generator.GetSigningServiceStatusCode() == 406))
{
m_licenseValidationResult.SetPaymentRequired(true);
ex->Destroy();
}
else
throw;
}
if (ValidateActivationKey(activationTemplate.get(), false))
{
activationStatus = STATUS_SUCCESS;
}
else
throw new LicensingException(STATUS_GENERIC_ERROR, "internal error - invalid returned activation key");
m_licenseValidationResult.m_license = std::make_unique<LicenseImpl>();
m_licenseValidationResult.m_license->SetHardwareId(hardwareId.c_str());
m_licenseValidationResult.m_license->SetActivationKey(activationKey.c_str());
m_licenseValidationResult.m_license->SetLicenseKey(licenseKey.c_str());
m_licenseValidationResult.m_license->SetLicenseKeyValidationData(licenseKeyValidationData.data(), licenseKeyValidationDataLen);
int status = generator.GetSigningServiceStatusCode();
if (status == 200 /* HTTP OK */)
m_licenseValidationResult.m_license->SetLease(false);
else
if (status == 201 || status == 202)
m_licenseValidationResult.m_license->SetLease(true);
m_licenseValidationResult.SetLicenseValid(true);
}
void SetLicensingServiceUrl(const char * url)
{
licensingServiceUrl = url;
}
int GetLicenseActivationStatus()
{
return activationStatus;
}
void GetLicenseExpirationDate(int * year, int * month, int * day)
{
if (licenseExpirationTime.tm_year > 0)
{
*year = 1900 + licenseExpirationTime.tm_year;
*month = 1 + licenseExpirationTime.tm_mon;
*day = licenseExpirationTime.tm_mday;
} else
{
*year = 0;
*month = 0;
*day = 0;
}
}
const char * GetCurrentHardwareIdCallback()
{
if (parentUsesWideChar)
{
static string hwid = w2s(GetCurrentHardwareIdW(parentLicensingClient));
return hwid.c_str();
}
else
{
return GetCurrentHardwareIdA(parentLicensingClient);
}
}
bool MatchCurrentHardwareIdCallback(const char * hwid)
{
if (parentUsesWideChar)
{
return MatchCurrentHardwareIdW(parentLicensingClient, s2w(hwid).c_str());
}
else
return MatchCurrentHardwareIdA(parentLicensingClient, hwid);
}
static const char * GetCurrentHardwareId()
{
return KeyHelper::GetCurrentHardwareId();
}
static bool MatchCurrentHardwareId(const char * hwid)
{
return KeyHelper::MatchCurrentHardwareId(hwid);
}
void SetTimeValidationMethod(int method)
{
timeValidationMethod = method;
}
private:
void StrReplaceA(std::string& str, const std::string& oldStr, const std::string& newStr)
{
size_t pos = 0;
while ((pos = str.find(oldStr, pos)) != std::string::npos)
{
str.replace(pos, oldStr.length(), newStr);
pos += newStr.length();
}
}
private:
const LicenseTemplateImpl* licenseTemplate;
LicenseValidationResultImpl m_licenseValidationResult;
struct tm licenseExpirationTime;
string licenseKey;
string activationKey;
string hardwareId;
string licensingServiceUrl;
vector<unsigned char> licenseKeyValidationData;
int licenseKeyValidationDataLen;
int activationStatus;
string licenseTemplateId;
void * parentLicensingClient;
bool parentUsesWideChar;
int timeValidationMethod;
int m_licenseValidityDays;
//const char * (*GetCurrentHardwareIdCallback)(void * callerContext);
//bool (*MatchCurrentHardwareIdCallback)(void * callerContext, const char * hwid);
};

View File

@@ -0,0 +1,2 @@
#include "precomp.h"
#include "ntpclient.h"

View File

@@ -0,0 +1,113 @@
#pragma once
#ifndef _WIN32
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#define INVALID_SOCKET (-1)
#define SOCKET int
#define SOCKET_ERROR (-1)
#define closesocket close
#endif
#include <time.h>
class NTPClient
{
public:
static time_t GetCurrentTimeUTC(const char * ntpserver = NULL)
{
#ifdef _WIN32
WSADATA w;
int remote_length;
#else
socklen_t remote_length;
#endif
SOCKET sd = INVALID_SOCKET;
char ntp_buffer[48];
time_t current_time = 0;
struct hostent *hp;
struct sockaddr_in remote;
struct sockaddr_in local;
char host_name[256];
hostent * host = NULL;
do {
#ifdef _WIN32
if (WSAStartup(MAKEWORD(2, 2), &w) != 0)
return 0;
#endif
if ((sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET)
break;
memset((void *)&remote, '\0', sizeof(struct sockaddr_in));
remote.sin_family = AF_INET;
remote.sin_port = htons(123);
if ((host = gethostbyname((ntpserver) ? ntpserver : "time.windows.com")) == NULL)
break;
remote.sin_addr.s_addr = *(u_long *)host->h_addr_list[0];
memset((void *)&local, '\0', sizeof(local));
local.sin_family = AF_INET;
local.sin_port = htons(0);
local.sin_addr.s_addr = htonl(INADDR_ANY);
if (::bind(sd, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR)
break;
memset(ntp_buffer, 0, sizeof(ntp_buffer));
ntp_buffer[0] = 0x1B;
remote_length = sizeof(struct sockaddr_in);
if (sendto(sd, ntp_buffer, sizeof(ntp_buffer), 0, (struct sockaddr *)&remote, remote_length) == -1)
break;
fd_set fds;
FD_ZERO(&fds);
FD_SET(sd, &fds);
timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
if (select(1, &fds, NULL, NULL, &timeout) != 1)
break;
if (recvfrom(sd, ntp_buffer, sizeof(ntp_buffer), 0, (struct sockaddr *)&remote, &remote_length) < 0)
break;
unsigned int int_part = *(unsigned int *)(ntp_buffer + 40);
unsigned int fract_part = *(unsigned int *)(ntp_buffer + 44);
int_part = SwapEndianness(int_part);
current_time = (time_t)(int_part -= 2208988800U);
}
while (0);
if (sd != INVALID_SOCKET)
closesocket(sd);
#ifdef _WIN32
WSACleanup();
#endif
return current_time;
}
static unsigned int SwapEndianness(unsigned int x)
{
return (unsigned int)(((x & 0x000000ff) << 24) +
((x & 0x0000ff00) << 8) +
((x & 0x00ff0000) >> 8) +
((x & 0xff000000) >> 24));
}
};

1200
core/anslicensing/picojson.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,6 @@
//
// Copyright (c) ANSCENTER. All rights reserved.
//
#include "precomp.h"

View File

@@ -0,0 +1,32 @@
#pragma once
#include "anslicensing.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h> /* memset(), memcpy() */
#include <assert.h>
#include <string>
#ifdef _WIN32
#define _WIN32_WINNT 0x0501
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <WinSock2.h>
#include <windows.h>
#include <tchar.h>
#include <malloc.h>
#endif
#ifndef _WIN32
#define _alloca alloca
#define _stricmp strcasecmp
#define _snprintf snprintf
#define _atoi64(s) strtoull(s, NULL, 10)
#endif

285
core/anslicensing/prime.cpp Normal file
View File

@@ -0,0 +1,285 @@
//
// Copyright (c) ANSCENTER. All rights reserved.
//
// prime factory implementation
#include "precomp.h"
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include "bigint.h"
#include "prime.h"
extern void print( bigint x );
static int maybe_prime( const bigint & p )
{
return modexp( 2, p - 1, p ) == 1;
}
static int fermat_is_probable_prime( const bigint & p )
{
// Test based on Fermats theorem a**(p-1) = 1 mod p for prime p
// For 1000 bit numbers this can take quite a while
const int rep = 4;
const unsigned any[ rep ] = { 2,3,5,7 /*,11,13,17,19,23,29,31,37..*/ };
for ( unsigned i = 0; i < rep; i += 1 )
if ( modexp( any[ i ], p - 1, p ) != 1 )
return 0;
return 1;
}
static bigint random( const bigint & n )
{
bigint x = 0;
while ( x < n )
x = x * RAND_MAX + rand();
return x % n;
}
static int miller_rabin_is_probable_prime( const bigint & n )
{
unsigned T = 100;
unsigned v = 0;
bigint w = n - 1;
srand( (unsigned) time( 0 ) );
while ( w % 2 != 0 )
{
v += 1;
w = w / 2;
}
for ( unsigned j = 1; j <= T; j += 1 )
{
bigint a = 1 + random( n );
bigint b = modexp( a, w, n );
if ( b != 1 && b != n - 1 )
{
unsigned i = 1;
while ( 1 )
{
if ( i == v )
return 0;
b = ( b * b ) % n;
if ( b == n - 1 )
break;
if ( b == 1 )
return 0;
i += 1;
}
}
}
return 1;
}
int is_probable_prime( const bigint & n )
{
return fermat_is_probable_prime( n )
&& miller_rabin_is_probable_prime( n );
}
prime_factory::prime_factory( unsigned MP )
{
// Initialise pl
unsigned p = 2;
char * b = new char[ MP + 1 ]; // one extra to stop search
for ( unsigned i = 0; i <= MP; i += 1 )
b[ i ] = 1;
np = 0;
while ( 1 )
{
// skip composites
while ( b[ p ] == 0 )
p += 1;
if ( p == MP )
break;
np += 1;
// cross off multiples
unsigned c = p * 2;
while ( c < MP )
{
b[ c ] = 0;
c += p;
}
p += 1;
}
pl = new unsigned[ np ];
np = 0;
for ( p = 2; p < MP; p += 1 )
if ( b[ p ] )
{
pl[ np ] = p;
np += 1;
}
delete [] b;
}
prime_factory::~prime_factory()
{
delete [] pl;
}
bigint prime_factory::find_prime( bigint start )
{
unsigned SS = 1000; // should be enough unless we are unlucky
char * b = new char[ SS ]; // bitset of candidate primes
while ( 1 )
{
unsigned i;
for ( i = 0; i < SS; i += 1 )
b[ i ] = 1;
for ( i = 0; i < np; i += 1 )
{
unsigned p = pl[ i ];
unsigned r = to_unsigned( start % p ); // not as fast as it should be - could do with special routine
if ( r )
r = p - r;
// cross off multiples of p
while ( r < SS )
{
b[ r ] = 0;
r += p;
}
}
// now test candidates
for ( i = 0; i < SS; i+=1 )
{
if ( b[ i ] )
{
if ( is_probable_prime( start ) )
{
delete [] b;
return start;
}
}
start += 1;
}
}
}
bigint prime_factory::find_special( bigint start, bigint base )
{
// Returns a (probable) prime number x > start such that
// x and x*2+1 are both probable primes,
// i.e. x is a probable Sophie-Germain prime
unsigned SS = 40000; // should be enough unless we are unlucky
char * b1 = new char[ SS ]; // bitset of candidate primes
char * b2 = new char[ 2 * SS ];
while ( 1 )
{
unsigned i;
for ( i = 0; i < SS; i += 1 )
b1[ i ] = 1;
for ( i = 0; i < 2 * SS; i += 1 )
b2[ i ] = 1;
for ( i = 0; i < np; i += 1 )
{
unsigned p = pl[ i ];
unsigned r = to_unsigned( start % p ); // not as fast as it should be - could do with special routine
if ( r )
r = p - r;
// cross off multiples of p
while ( r < SS )
{
b1[ r ] = 0;
r += p;
}
r = to_unsigned( ( start * 2 + 1 ) % p );
if ( r )
r = p - r;
while ( r < 2 * SS )
{
b2[ r ] = 0;
r += p;
}
}
// now test candidates
for ( i = 0; i < SS; i += 1 )
{
if ( b1[ i ] && b2[ i * 2 ] )
{
printf("D=%u\n", to_unsigned( start * 2 + 1 - base ) );
if ( maybe_prime( start )
&& maybe_prime( start * 2 + 1 )
&& is_probable_prime( start )
&& is_probable_prime( start * 2 + 1 )
)
{
delete [] b1;
delete [] b2;
return start;
}
}
start += 1;
}
}
}
int prime_factory::make_prime( bigint & r, bigint & k, const bigint & min_p )
// Divide out small factors or r
{
k = 1;
for ( unsigned i = 0; i < np; i += 1 )
{
unsigned p = pl[ i ];
// maybe pre-computing product of several primes
// and then GCD(r,p) would be faster ?
while ( r % p == 0 )
{
if ( r == p )
return 1; // can only happen if min_p is small
r = r / p;
k = k * p;
if ( r < min_p )
return 0;
}
}
return is_probable_prime( r );
}

25
core/anslicensing/prime.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef __PRIME_H
#define __PRIME_H
class prime_factory
{
// construction
public:
prime_factory( unsigned MP = 2000 ); // sieve size
~prime_factory();
// methods
public:
bigint find_prime( bigint start );
int make_prime( bigint & r, bigint &k, const bigint & rmin );
bigint find_special( bigint start, bigint base=0 );
// properties
public:
unsigned np;
unsigned *pl;
};
int is_probable_prime( const bigint &p );
#endif

View File

@@ -0,0 +1,353 @@
#pragma once
#include "precomp.h"
#include "uniconv.h"
#include "tinyxml2.h"
#include "picojson.h"
#include <map>
#include <list>
#ifndef MAX_XML_BUFFER_SIZE
#define MAX_XML_BUFFER_SIZE 4096
#endif
class PathEntry
{
friend class PropertyCollection;
public:
PathEntry()
{
processed = false;
}
PathEntry(const PathEntry & copy)
{
processed = false;
path = copy.path;
nameValueCollection = copy.nameValueCollection;
}
PathEntry(const PathEntry * copy)
{
processed = false;
path = copy->path;
nameValueCollection = copy->nameValueCollection;
}
private:
string path;
std::map<string, string> nameValueCollection;
bool processed;
};
class PropertyCollection
{
public:
PropertyCollection()
{
}
void SetProperty(const char * path, const char * name, const char * value)
{
string propName = (name != NULL) ? name : "";
std::map<string, PathEntry>::iterator entry;
if ((entry = m_properties.find(path)) == m_properties.end())
{
PathEntry entry;
entry.path = path;
entry.nameValueCollection.insert(std::map<string, string>::value_type(propName, value));
m_properties.insert(std::map<string, PathEntry>::value_type(path, entry));
} else
entry->second.nameValueCollection.insert(std::map<string, string>::value_type(propName, value));
}
const char * GetProperty(const char * path, const char * name) const
{
std::map<string, PathEntry>::const_iterator entry = m_properties.find(path);
if (entry == m_properties.end())
return NULL;
std::map<string, string>::const_iterator nv = entry->second.nameValueCollection.find((name != NULL) ? name : "");
if (nv == entry->second.nameValueCollection.end())
return NULL;
return nv->second.c_str();
}
void LoadXml(tinyxml2::XMLElement * src)
{
XmlToPathList("", src);
}
void SaveXml(std::string & xml)
{
PathListToXml("/", &m_properties, xml, 1);
}
void LoadJson(picojson::object & json)
{
string path;
size_t pos;
for (picojson::object::iterator iter = json.begin(); iter != json.end(); iter++)
{
path = iter->first.c_str();
if ((pos = path.find_last_of('#')) == string::npos)
SetProperty(path.c_str(), NULL, iter->second.get<std::string>().c_str());
else
{
SetProperty(path.substr(0, pos).c_str(), path.substr(pos + 1).c_str(), iter->second.get<std::string>().c_str());
}
}
}
void SaveJson(std::string & json, const char * indent = "")
{
bool first = true;
json.append("{");
for (std::map<string, PathEntry>::const_iterator item = m_properties.begin(); item != m_properties.end(); item++)
{
for (std::map<string, string>::const_iterator innerItem = item->second.nameValueCollection.begin(); innerItem != item->second.nameValueCollection.end(); innerItem++)
{
if (!first) json.append(",");
json.append("\n");
json.append(indent);
json.append("\t");
json.append("\"");
json.append(item->first.c_str());
if (innerItem->first.length() > 0)
{
json.append("#"); json.append(innerItem->first.c_str());
}
json.append("\":\""); json.append(innerItem->second.c_str()); json.append("\"");
first = false;
}
}
json.append("\n"); json.append(indent); json.append("}");
}
size_t GetSize() const
{
return m_properties.size();
}
private:
std::map<string, PathEntry> m_properties;
void XmlToPathList(const std::string prefix, const tinyxml2::XMLElement * node)
{
const char * text = node->GetText();
if (text != NULL)
SetProperty(prefix.c_str(), "", text);
const tinyxml2::XMLAttribute * attr = node->FirstAttribute();
// risk of stack overflow because _alloca is called in loop. However the current number of properties
// is very low so it is acceptable
while (attr)
{
SetProperty(prefix.c_str(), attr->Name(), attr->Value());
attr = attr->Next();
}
tinyxml2::XMLElement * child;
for (child = (tinyxml2::XMLElement *)node->FirstChildElement(); child != NULL; child = child->NextSiblingElement())
{
XmlToPathList(prefix + "/" + child->Name(), child);
}
}
void PathListToXml(const std::string pathPrefix, std::map<string, PathEntry> * sortedPathList, std::string & xml, int indent)
{
std::string elementValue;
bool startElementClosed = false;
if (pathPrefix != "/")
{
if (indent > 0)
xml.append(indent, '\t');
xml.append("<"); xml.append(1 + strrchr(pathPrefix.c_str(), '/'));
}
for (std::map<string, PathEntry>::const_iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
{
if (strcmp(item->second.path.c_str(), pathPrefix.c_str()) == 0)
{
for (std::map<string, string>::const_iterator nvItem = item->second.nameValueCollection.begin();
nvItem != item->second.nameValueCollection.end();
nvItem++)
{
if (nvItem->first.length() == 0)
{
elementValue = nvItem->second.c_str();
} else
{
xml.append(" ");
xml.append(nvItem->first.c_str());
xml.append("=\"");
xml.append(nvItem->second.c_str());
xml.append("\"");
}
}
}
}
if (pathPrefix != "/")
{
xml.append(">");
if (elementValue.length() > 0)
{
xml.append(elementValue);
} else
if (indent >= 0)
xml.append("\n");
}
bool finished = false;
while (!finished)
{
finished = true;
std::string firstUnprocessedPrefix;
std::map<string, PathEntry> innerPathList;
for (std::map<string, PathEntry>::iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
{
if (!item->second.processed && item->second.path.length() > pathPrefix.length() && (firstUnprocessedPrefix.empty() || strncmp(item->second.path.c_str(), firstUnprocessedPrefix.c_str(), firstUnprocessedPrefix.length()) == 0))
{
if (firstUnprocessedPrefix.empty())
{
int nextSep = item->second.path.find('/', pathPrefix.length() + 1);
firstUnprocessedPrefix = item->second.path.substr(0, (nextSep >= 0) ? nextSep : item->second.path.length()).c_str();
}
innerPathList.insert(std::map<string, PathEntry>::value_type(item->first, item->second));
item->second.processed = true;
finished = false;
}
}
if (!finished)
PathListToXml(firstUnprocessedPrefix, &innerPathList, xml, (indent >= 0) ? indent + 1 : indent);
}
if (pathPrefix != "/")
{
if (indent > 0 && elementValue.length() == 0)
xml.append(indent, '\t');
xml.append("</"); xml.append(1 + strrchr(pathPrefix.c_str(), '/')); xml.append(">");
if (indent >= 0) xml.append("\n");
}
}
void PathListToJson(const std::string pathPrefix, std::map<string, PathEntry> * sortedPathList, std::string & xml, int indent)
{
std::string elementValue;
bool startElementClosed = false;
if (pathPrefix != "/")
{
if (indent > 0)
xml.append(indent, '\t');
xml.append("\""); xml.append(1 + strrchr(pathPrefix.c_str(), '/')); xml.append("\":");
}
for (std::map<string, PathEntry>::const_iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
{
if (strcmp(item->second.path.c_str(), pathPrefix.c_str()) == 0)
{
for (std::map<string, string>::const_iterator nvItem = item->second.nameValueCollection.begin();
nvItem != item->second.nameValueCollection.end();
nvItem++)
{
if (nvItem->first.length() == 0)
{
elementValue = nvItem->second.c_str();
}
else
{
xml.append(" ");
xml.append(nvItem->first.c_str());
xml.append("=\"");
xml.append(nvItem->second.c_str());
xml.append("\"");
}
}
}
}
if (pathPrefix != "/")
{
xml.append(">");
if (elementValue.length() > 0)
{
xml.append(elementValue);
}
else
if (indent >= 0)
xml.append("\n");
}
bool finished = false;
while (!finished)
{
finished = true;
std::string firstUnprocessedPrefix;
std::map<string, PathEntry> innerPathList;
for (std::map<string, PathEntry>::iterator item = sortedPathList->begin(); item != sortedPathList->end(); item++)
{
if (!item->second.processed && item->second.path.length() > pathPrefix.length() && (firstUnprocessedPrefix.empty() || strncmp(item->second.path.c_str(), firstUnprocessedPrefix.c_str(), firstUnprocessedPrefix.length()) == 0))
{
if (firstUnprocessedPrefix.empty())
{
int nextSep = item->second.path.find('/', pathPrefix.length() + 1);
firstUnprocessedPrefix = item->second.path.substr(0, (nextSep >= 0) ? nextSep : item->second.path.length()).c_str();
}
innerPathList.insert(std::map<string, PathEntry>::value_type(item->first, item->second));
item->second.processed = true;
finished = false;
}
}
if (!finished)
PathListToXml(firstUnprocessedPrefix, &innerPathList, xml, (indent >= 0) ? indent + 1 : indent);
}
if (pathPrefix != "/")
{
if (indent > 0 && elementValue.length() == 0)
xml.append(indent, '\t');
xml.append("}");
if (indent >= 0) xml.append("\n");
}
}
};

View File

@@ -0,0 +1,66 @@
#include "precomp.h"
#include "bigint.h"
#include "rand.h"
#ifdef _WIN32
#include <windows.h>
#include <wincrypt.h>
#endif
#include <stdlib.h>
random::random()
{
#ifdef _WIN32
if ( !CryptAcquireContext( (HCRYPTPROV *)&m_hCryptProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) )
m_hCryptProv = NULL;
#else
::srand(time(NULL));
#endif
}
random::~random()
{
#ifdef _WIN32
if ( m_hCryptProv )
CryptReleaseContext( (HCRYPTPROV)m_hCryptProv, 0L );
#endif
}
unsigned random::rand( unsigned max )
{
unsigned rnd;
#ifdef _WIN32
if ( m_hCryptProv )
CryptGenRandom( (HCRYPTPROV)m_hCryptProv, sizeof( unsigned ), (BYTE *)&rnd );
#else
rnd = ::rand();
#endif
return rnd % max;
}
bigint random::rand( bigint & max )
{
unsigned n = ( max.bits() + ( ( sizeof( unsigned ) << 3 ) - 1 ) ) / ( sizeof( unsigned ) << 3 );
unsigned * buf = (unsigned*)malloc(n * sizeof(unsigned));
if ( !buf ) return max - 1;
bigint rnd;
#ifdef _WIN32
if ( m_hCryptProv )
CryptGenRandom( (HCRYPTPROV)m_hCryptProv, n * sizeof( unsigned ), (BYTE *)buf );
#else
for (unsigned i = 0; i < n; i++)
*((unsigned *)buf + i) = ::rand();
#endif
rnd.load( buf, n );
free(buf);
return rnd % max;
}

18
core/anslicensing/rand.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef __RAND_H
#define __RAND_H
#include "bigint.h"
class random {
public:
random();
~random();
unsigned rand( unsigned max );
bigint rand( bigint & max );
protected:
void * m_hCryptProv;
};
#endif

View File

@@ -0,0 +1,14 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by licensing.rc
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,49 @@
#include "precomp.h"
#include "uniconv.h"
#include "template.h"
#include "validator.h"
#include "sdkregistration.h"
#include "version.h"
#include <time.h>
bool SDKRegistrationImpl::isRegistered = true;
bool SDKRegistrationImpl::isExpired = false;
string SDKRegistrationImpl::licenseKey;
void SDKRegistrationImpl::SetLicenseKey(const char * key)
{
licenseKey = key;
}
bool SDKRegistrationImpl::IsRegistered()
{
return true;
}
bool SDKRegistrationImpl::IsExpired()
{
return false;
}
const char * SDKRegistrationImpl::GetLicenseKey()
{
return licenseKey.c_str();
}
namespace ANSCENTER {
namespace Licensing {
template<>
void SDKRegistrationT<char>::SetLicenseKey(const char * key)
{
SDKRegistrationImpl::SetLicenseKey(key);
}
template<>
void SDKRegistrationT<wchar_t>::SetLicenseKey(const wchar_t * key)
{
string wkey = w2s(key);
SDKRegistrationImpl::SetLicenseKey(wkey.c_str());
}
};
};

View File

@@ -0,0 +1,21 @@
#ifndef __SDKREGISTRATION_H__
#define __SDKREGISTRATION_H__
class SDKRegistrationImpl
{
public:
static void SetLicenseKey(const char * key);
static const char * GetLicenseKey();
static bool IsRegistered();
static bool IsExpired();
private:
static bool isRegistered;
static bool isExpired;
static string licenseKey;
};
#endif

160
core/anslicensing/sha1.cpp Normal file
View File

@@ -0,0 +1,160 @@
#include "precomp.h"
#include "sha1.h"
#define MAX_FILE_READ_BUFFER 8000
// Rotate x bits to the left
#ifndef ROL32
#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))
#endif
#ifdef SHA1_LITTLE_ENDIAN
#define SHABLK0(i) (m_block->l[i] = \
(ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
#else
#define SHABLK0(i) (m_block->l[i])
#endif
#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \
^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
// SHA-1 rounds
#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }
#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }
#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }
SHA1::SHA1()
{
m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
Reset();
}
SHA1::~SHA1()
{
Reset();
}
void SHA1::Reset()
{
// SHA1 initialization constants
m_state[0] = 0x67452301;
m_state[1] = 0xEFCDAB89;
m_state[2] = 0x98BADCFE;
m_state[3] = 0x10325476;
m_state[4] = 0xC3D2E1F0;
m_count[0] = 0;
m_count[1] = 0;
}
void SHA1::Transform(unsigned int state[5], unsigned char buffer[64])
{
unsigned int a = 0, b = 0, c = 0, d = 0, e = 0;
memcpy(m_block, buffer, 64);
// Copy state[] to working vars
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
// 4 rounds of 20 operations each. Loop unrolled.
_R0(a,b,c,d,e, 0); _R0(e,a,b,c,d, 1); _R0(d,e,a,b,c, 2); _R0(c,d,e,a,b, 3);
_R0(b,c,d,e,a, 4); _R0(a,b,c,d,e, 5); _R0(e,a,b,c,d, 6); _R0(d,e,a,b,c, 7);
_R0(c,d,e,a,b, 8); _R0(b,c,d,e,a, 9); _R0(a,b,c,d,e,10); _R0(e,a,b,c,d,11);
_R0(d,e,a,b,c,12); _R0(c,d,e,a,b,13); _R0(b,c,d,e,a,14); _R0(a,b,c,d,e,15);
_R1(e,a,b,c,d,16); _R1(d,e,a,b,c,17); _R1(c,d,e,a,b,18); _R1(b,c,d,e,a,19);
_R2(a,b,c,d,e,20); _R2(e,a,b,c,d,21); _R2(d,e,a,b,c,22); _R2(c,d,e,a,b,23);
_R2(b,c,d,e,a,24); _R2(a,b,c,d,e,25); _R2(e,a,b,c,d,26); _R2(d,e,a,b,c,27);
_R2(c,d,e,a,b,28); _R2(b,c,d,e,a,29); _R2(a,b,c,d,e,30); _R2(e,a,b,c,d,31);
_R2(d,e,a,b,c,32); _R2(c,d,e,a,b,33); _R2(b,c,d,e,a,34); _R2(a,b,c,d,e,35);
_R2(e,a,b,c,d,36); _R2(d,e,a,b,c,37); _R2(c,d,e,a,b,38); _R2(b,c,d,e,a,39);
_R3(a,b,c,d,e,40); _R3(e,a,b,c,d,41); _R3(d,e,a,b,c,42); _R3(c,d,e,a,b,43);
_R3(b,c,d,e,a,44); _R3(a,b,c,d,e,45); _R3(e,a,b,c,d,46); _R3(d,e,a,b,c,47);
_R3(c,d,e,a,b,48); _R3(b,c,d,e,a,49); _R3(a,b,c,d,e,50); _R3(e,a,b,c,d,51);
_R3(d,e,a,b,c,52); _R3(c,d,e,a,b,53); _R3(b,c,d,e,a,54); _R3(a,b,c,d,e,55);
_R3(e,a,b,c,d,56); _R3(d,e,a,b,c,57); _R3(c,d,e,a,b,58); _R3(b,c,d,e,a,59);
_R4(a,b,c,d,e,60); _R4(e,a,b,c,d,61); _R4(d,e,a,b,c,62); _R4(c,d,e,a,b,63);
_R4(b,c,d,e,a,64); _R4(a,b,c,d,e,65); _R4(e,a,b,c,d,66); _R4(d,e,a,b,c,67);
_R4(c,d,e,a,b,68); _R4(b,c,d,e,a,69); _R4(a,b,c,d,e,70); _R4(e,a,b,c,d,71);
_R4(d,e,a,b,c,72); _R4(c,d,e,a,b,73); _R4(b,c,d,e,a,74); _R4(a,b,c,d,e,75);
_R4(e,a,b,c,d,76); _R4(d,e,a,b,c,77); _R4(c,d,e,a,b,78); _R4(b,c,d,e,a,79);
// Add the working vars back into state[]
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
// Wipe variables
a = b = c = d = e = 0;
}
// Use this function to hash in binary data and strings
void SHA1::Update(unsigned char *data, unsigned int len)
{
unsigned int i = 0, j;
j = (m_count[0] >> 3) & 63;
if((m_count[0] += len << 3) < (len << 3)) m_count[1]++;
m_count[1] += (len >> 29);
if((j + len) > 63)
{
memcpy(&m_buffer[j], data, (i = 64 - j));
Transform(m_state, m_buffer);
for (; i+63 < len; i += 64)
Transform(m_state, &data[i]);
j = 0;
}
else i = 0;
memcpy(&m_buffer[j], &data[i], len - i);
}
void SHA1::Final()
{
unsigned int i = 0;
unsigned char finalcount[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
for (i = 0; i < 8; i++)
finalcount[i] = (unsigned char)((m_count[(i >= 4 ? 0 : 1)]
>> ((3 - (i & 3)) * 8) ) & 255); // Endian independent
Update((unsigned char *)"\200", 1);
while ((m_count[0] & 504) != 448)
Update((unsigned char *)"\0", 1);
Update(finalcount, 8); // Cause a SHA1Transform()
for (i = 0; i < 20; i++)
{
m_digest[i] = (unsigned char)((m_state[i >> 2] >> ((3 - (i & 3)) * 8) ) & 255);
}
// Wipe variables for security reasons
i = 0;
memset(m_buffer, 0, 64);
memset(m_state, 0, 20);
memset(m_count, 0, 8);
memset(finalcount, 0, 8);
Transform(m_state, m_buffer);
}
// Get the raw message digest
void SHA1::GetHash(unsigned char *uDest)
{
memcpy(uDest, m_digest, 20);
}

58
core/anslicensing/sha1.h Normal file
View File

@@ -0,0 +1,58 @@
#ifndef ___SHA1_H___
#define ___SHA1_H___
#include <stdio.h> // Needed for file access
#include <memory.h> // Needed for memset and memcpy
#include <string.h> // Needed for strcat and strcpy
#define SHA1_LITTLE_ENDIAN
#ifdef LICENSING_BIG_ENDIAN
// If you're compiling big endian, just comment out the following line
#undef SHA1_LITTLE_ENDIAN
#endif
typedef union
{
unsigned char c[64];
unsigned int l[16];
} SHA1_WORKSPACE_BLOCK;
class SHA1
{
public:
// Two different formats for ReportHash(...)
enum
{
REPORT_HEX = 0,
REPORT_DIGIT = 1
};
// Constructor and Destructor
SHA1();
virtual ~SHA1();
unsigned int m_state[5];
unsigned int m_count[2];
unsigned char m_buffer[64];
unsigned char m_digest[20];
void Reset();
// Update the hash value
void Update(unsigned char *data, unsigned int len);
// Finalize hash and report
void Final();
void GetHash(unsigned char *uDest);
private:
// Private SHA-1 transformation
void Transform(unsigned int state[5], unsigned char buffer[64]);
// Member variables
unsigned char m_workspace[64];
SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,528 @@
#pragma once
#include <memory>
#include <map>
#include "ecc.h"
#include "base64.h"
#include "uniconv.h"
#include "except.h"
#include "sdkregistration.h"
#include "certificate.h"
#include "propertycollection.h"
using namespace std;
class LicenseTemplateImpl {
friend LicenseTemplate;
struct FieldInfo
{
FieldInfo(int _type, int _size, int _offset)
{
type = (BitStruct::FIELD_TYPE)_type;
size = _size;
offset = _offset;
}
BitStruct::FIELD_TYPE type;
int size;
int offset;
};
public:
LicenseTemplateImpl(const char * xmlTemplate = NULL):
m_defaultDataOffset(0),
m_defaultValidationOffset(0)
{
Init();
if (xmlTemplate)
LoadXml(xmlTemplate);
}
void SetVersion(int version)
{
if (version > 3)
throw new LicensingException(STATUS_UNSUPPORTED_VERSION);
m_version = version;
}
unsigned GetVersion() const
{
return m_version;
}
void SetNumberOfGroups(int numGroups)
{
m_numGroups = numGroups;
}
unsigned GetNumberOfGroups() const
{
return m_numGroups;
}
void SetCharactersPerGroup(int charsPerGroup)
{
m_charsPerGroup = charsPerGroup;
}
unsigned GetCharactersPerGroup() const
{
return m_charsPerGroup;
}
void SetGroupSeparator(const char * groupSep)
{
m_groupSeparator = groupSep;
}
const char * GetGroupSeparator() const
{
return m_groupSeparator.c_str();
}
void SetEncoding(int encoding)
{
m_keyEncoding = encoding;
}
int GetEncoding() const
{
return m_keyEncoding;
}
void SetHeader(const char * header)
{
m_header = header;
}
const char * GetHeader() const
{
return m_header.c_str();
}
void SetFooter(const char * footer)
{
m_footer = footer;
}
const char * GetFooter() const
{
return m_footer.c_str();
}
void SetDataSize(int sizeInBits)
{
m_dataSize = sizeInBits;
}
unsigned GetDataSize() const
{
return m_dataSize;
}
void AddDataField(const char * fieldName, int fieldType, int fieldSizeInBits, int fieldOffset = -1)
{
if (fieldOffset < 0)
fieldOffset = m_defaultDataOffset;
m_dataFields.emplace(std::piecewise_construct, forward_as_tuple(fieldName), forward_as_tuple(fieldType, fieldSizeInBits, fieldOffset));
m_defaultDataOffset += fieldSizeInBits;
}
bool GetDataField(const char * fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const
{
auto info = m_dataFields.find(fieldName);
if (info == m_dataFields.end())
return false;
*fieldType = info->second.type;
*fieldSizeInBits = info->second.size;
*fieldOffset = info->second.offset;
return true;
}
bool EnumDataFields(void **enumHandle, const char **fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const
{
map<string, FieldInfo>::const_iterator* pIter;
static string name;
if (*enumHandle == NULL)
{
pIter = new map<string, FieldInfo>::const_iterator(m_dataFields.begin());
if (!pIter)
return false;
}
else
pIter = (map<string, FieldInfo>::const_iterator*)(*enumHandle);
if (*pIter == m_dataFields.end())
{
delete pIter;
return false;
}
name = (*pIter)->first;
*fieldName = name.c_str();
*fieldType = (*pIter)->second.type;
*fieldSizeInBits = (*pIter)->second.size;
*fieldOffset = (*pIter)->second.offset;
pIter->operator ++(); // *Iter++ does not work. Think why :)
*enumHandle = pIter;
return true;
}
void SetValidationDataSize(int sizeInBits)
{
m_validationDataSize = sizeInBits;
}
unsigned GetValidationDataSize() const
{
return m_validationDataSize;
}
void AddValidationField(const char * fieldName, int fieldType, int fieldBitSize, int fieldOffset = 0)
{
if (fieldOffset < 0)
fieldOffset = m_defaultValidationOffset;
m_validationFields.emplace(piecewise_construct, forward_as_tuple(fieldName), forward_as_tuple(fieldType, fieldBitSize, fieldOffset));
m_defaultValidationOffset += fieldBitSize;
}
bool GetValidationField(const char * fieldName, int * fieldType, int * fieldSizeInBits, int * fieldOffset) const
{
auto info = m_validationFields.find(fieldName);
if (info == m_validationFields.end())
return false;
*fieldType = info->second.type;
*fieldSizeInBits = info->second.size;
*fieldOffset = info->second.offset;
return true;
}
bool EnumValidationFields(void **enumHandle, const char **fieldName, int * fieldType, int * fieldSize, int * fieldOffset) const
{
map<string, FieldInfo>::const_iterator* pIter;
static string name;
if (*enumHandle == NULL)
{
pIter = new map<string, FieldInfo>::const_iterator(m_validationFields.begin());
if (!pIter)
return false;
}
else
pIter = (map<string, FieldInfo>::const_iterator*)(*enumHandle);
if (*pIter == m_validationFields.end())
{
delete pIter;
return false;
}
name = (*pIter)->first;
*fieldName = name.c_str();
*fieldType = (*pIter)->second.type;
*fieldSize = (*pIter)->second.size;
*fieldOffset = (*pIter)->second.offset;
pIter->operator ++(); // *Iter++ does not work. Think why :)
*enumHandle = pIter;
return true;
}
void SetSignatureSize(int sizeInBits)
{
if (sizeInBits < 76 || sizeInBits > 322)
throw new LicensingException(STATUS_INVALID_SIGNATURE_SIZE);
m_signatureSize = sizeInBits;
if (sizeInBits <= 108)
{
m_signatureKeyType = ECC::ECC_54;
m_signatureKeySize = 54;
} else
if (sizeInBits <= 146)
{
m_signatureKeyType = ECC::ECC_73;
m_signatureKeySize = 73;
} else
if (sizeInBits <= 158)
{
m_signatureKeyType = ECC::ECC_79;
m_signatureKeySize = 79;
} else
if (sizeInBits <= 182)
{
m_signatureKeyType = ECC::ECC_91;
m_signatureKeySize = 91;
} else
if (sizeInBits <= 200)
{
m_signatureKeyType = ECC::ECC_100;
m_signatureKeySize = 100;
} else
if (sizeInBits <= 240)
{
m_signatureKeyType = ECC::ECC_120;
m_signatureKeySize = 120;
} else
if (sizeInBits <= 262)
{
m_signatureKeyType = ECC::ECC_131;
m_signatureKeySize = 131;
} else
if (sizeInBits <= 282)
{
m_signatureKeyType = ECC::ECC_141;
m_signatureKeySize = 141;
} else
{
m_signatureKeyType = ECC::ECC_161;
m_signatureKeySize = 161;
}
}
unsigned GetSignatureSize() const
{
return m_signatureSize;
}
void LoadXml(const char * xmlTemplate);
const char * SaveXml(bool savePrivateKey);
void LoadJson(const char * jsonTemplate);
const char * SaveJson(bool savePrivateKey);
void SetLicensingServiceUrl(const char * url)
{
m_licensingServiceUrl = url;
}
const char * GetLicensingServiceUrl() const
{
return m_licensingServiceUrl.c_str();
}
void SetTemplateId(const char * templateId)
{
m_templateId = templateId;
}
const char * GetTemplateId() const
{
return m_templateId.c_str();
}
void SetLicensingServiceParameters(const char * params)
{
m_licensingServiceParameters = params;
}
void SetLicenseGracePeriod(int days)
{
m_licenseGracePeriod = days;
}
int GetLicenseGracePeriod() const
{
return m_licenseGracePeriod;
}
void SetPublicKeyCertificate(const char * base64Certificate)
{
m_certificate = make_unique<Certificate>(base64Certificate);
ValidateCertificate();
unsigned char keyBuf[256]; int keyLen = 256;
m_certificate->GetPublicKey(keyBuf, &keyLen);
m_verificationKey = make_unique<ECC::Key>(keyBuf, keyLen);
}
const char * GetPublicKeyCertificate() const
{
if (!m_certificate)
throw new LicensingException(STATUS_GENERIC_ERROR, "the key template does not contain a certificate");
return m_certificate->ToString();
}
void SetPrivateKey(const char * base64Key)
{
BASE64 base64;
int keyLen;
int keyLenSizeT;
auto keyData = base64.decode(base64Key, (unsigned)strlen(base64Key), &keyLenSizeT);
if (keyData.empty())
throw new LicensingException(STATUS_GENERIC_ERROR, "invalid base64 private key");
keyLen = (unsigned)keyLenSizeT;
SetPrivateKey(keyData.data(), keyLen);
}
const char * GetPrivateKey() const
{
if (!m_signingKey)
throw new LicensingException(STATUS_GENERIC_ERROR, "the key template does not contain a private key");
return m_signingKey->ToString();
}
void GenerateSigningKeyPair()
{
Key * privateKey = NULL,
* publicKey = NULL;
if (!SDKRegistrationImpl::IsRegistered())
{
privateKey = new Key(); privateKey->Load(&m_demoPrivateKeys[m_signatureKeyType][1], m_demoPrivateKeys[m_signatureKeyType][0], m_signatureKeyType);
publicKey = new Key(); publicKey->Load(&m_demoPublicKeys[m_signatureKeyType][1], m_demoPublicKeys[m_signatureKeyType][0], m_signatureKeyType);
} else
{
ECC::GenerateKeyPair(m_signatureKeyType, &privateKey, &publicKey);
}
m_certificate.reset(Certificate::Generate(m_signatureSize, privateKey, publicKey, NULL, NULL, NULL, 0));
ValidateCertificate();
m_signingKey.reset(privateKey);
m_verificationKey.reset(publicKey);
}
void SetProperty(const char * path, const char * name, const char * value)
{
m_properties.SetProperty(path, name, value);
}
const char * GetProperty(const char * path, const char * name) const
{
return m_properties.GetProperty(path, name);
}
public:
// general
int m_version;
// key format
int m_numGroups;
int m_charsPerGroup;
int m_keyEncoding;
string m_groupSeparator;
string m_header;
string m_footer;
string m_licensingServiceUrl;
string m_templateId;
string m_licensingServiceParameters;
map<string, FieldInfo> m_dataFields;
int m_defaultDataOffset;
map<string, FieldInfo> m_validationFields;
int m_defaultValidationOffset;
// key signature
unique_ptr<ECC::Key> m_verificationKey;
unique_ptr<ECC::Key> m_signingKey;
unique_ptr<Certificate> m_certificate;
bool m_hasPrivateKey;
ECC::KEY_TYPE m_signatureKeyType;
int m_signatureKeySize;
int m_signatureSize;
int m_dataSize;
int m_validationDataSize;
// buffer used to hold the xml representation of the template
string m_xmlTemplate;
// other stuff
int m_licenseGracePeriod;
PropertyCollection m_properties;
protected:
static const unsigned char m_demoPublicKeys[10][23];
static const unsigned char m_demoPrivateKeys[10][23];
private:
void Init()
{
SetVersion(3);
SetLicenseGracePeriod(0);
SetGroupSeparator("-");
SetNumberOfGroups(6);
SetCharactersPerGroup(6);
SetEncoding(ENCODING_BASE32X);
SetSignatureSize(158);
SetDataSize(22); // 6 groups * 6 chars per group * 5 bits per char - 158 signature size = 22 data size
SetValidationDataSize(0);
m_hasPrivateKey = false;
}
void SetPrivateKey(const void * keyBuf, int keyLen)
{
ValidatePrivateKey(keyBuf, keyLen);
m_signingKey.reset(new Key(keyBuf, keyLen));
m_hasPrivateKey = true;
}
void ValidatePrivateKey(const void * keyBuf, int keyLen)
{
if (keyLen <= 2)
{
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid private key length");
}
keyLen -= 2;
keyBuf = (unsigned char *)keyBuf + 2;
if (!SDKRegistrationImpl::IsRegistered())
{
if (keyLen != m_demoPrivateKeys[m_signatureKeyType][0] || memcmp(keyBuf, &m_demoPrivateKeys[m_signatureKeyType][1], keyLen) != 0)
{
m_signingKey.reset();
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid public/private key. The SDK is in DEMO mode because a SDK license key was not set. In this mode, only certain public/private keys can be set. Did you set a valid SDK license key via ANSCENTER::Licensing::SDKRegistration::SetLicenseKey() ?");
}
}
}
void ValidateCertificate()
{
unique_ptr<Certificate> validationCertificate = make_unique<Certificate>("AE4vDQELjMGgCJew5QSVMBWSAN2PaBa0zzYpjSYe0rcu88lYggE=");
if (!Certificate::VerifySignature(m_certificate.get(), validationCertificate.get()))
throw new LicensingException(STATUS_GENERIC_ERROR, "certificate signature is not valid");
}
};

File diff suppressed because it is too large Load Diff

1968
core/anslicensing/tinyxml2.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
#pragma once
#include <stdexcept>
#include <string>
using namespace std;
#ifdef _WIN32
inline wstring s2w(const char* str, size_t size = -1)
{
if (size == -1)
size = strlen(str);
if (size == 0)
return wstring();
size_t req_size = ::MultiByteToWideChar(CP_UTF8, 0,
str, (int)size, NULL, 0);
if (req_size == 0)
throw runtime_error("Failed converting UTF-8 string to UTF-16");
wstring wstr(req_size, 0);
int conv_size = ::MultiByteToWideChar(CP_UTF8, 0,
str, (int)size, wstr.data(), req_size);
if (conv_size == 0)
throw runtime_error("Failed converting UTF-8 string to UTF-16");
return wstr;
}
inline wstring s2w(const string& str)
{
return s2w(str.data(), str.size());
}
inline string w2s(const wchar_t* wstr, size_t size = -1)
{
size_t req_size = WideCharToMultiByte(CP_UTF8, 0, wstr, size, nullptr, 0, nullptr, nullptr);
if (!req_size)
throw runtime_error("wide to multibyte conversion failed");
string str(req_size, 0);
int conv_size = WideCharToMultiByte(CP_UTF8, 0L, wstr, size, str.data(), req_size, nullptr, nullptr);
if (!conv_size)
throw runtime_error("wide to multibyte conversion failed");
return str;
}
inline string w2s(const wstring& wstr)
{
return w2s(wstr.data(), wstr.size());
}
#else
inline wstring s2w(const char* str, size_t size = -1)
{
throw runtime_error("not implemented");
}
inline wstring s2w(const string& str)
{
return s2w(str.data(), str.size());
}
inline string w2s(const wchar_t* wstr, size_t size = -1)
{
throw runtime_error("not implemented");
}
inline string w2s(const wstring& wstr)
{
return w2s(wstr.data(), wstr.size());
}
#endif

View File

@@ -0,0 +1,205 @@
//
// Copyright (c) ANSCENTER. All rights reserved.
//
#include "precomp.h"
#include "anslicensing.h"
#include "template.h"
#include "bitstream.h"
#include "base32.h"
#include "base64.h"
#include "sha1.h"
#include "except.h"
#include "uniconv.h"
#include "validator.h"
namespace ANSCENTER {
namespace Licensing {
template<>
KeyValidatorT<char>::KeyValidatorT():
m_Impl( *new KeyValidatorImpl() )
{
}
template<>
KeyValidatorT<wchar_t>::KeyValidatorT():
m_Impl( *new KeyValidatorImpl() )
{
}
template<>
KeyValidatorT<char>::KeyValidatorT(const LicenseTemplateT<char> * keyTemplate):
m_Impl( *new KeyValidatorImpl(&keyTemplate->m_Impl) )
{
}
template<>
KeyValidatorT<wchar_t>::KeyValidatorT(const LicenseTemplateT<wchar_t> * keyTemplate):
m_Impl( *new KeyValidatorImpl(&keyTemplate->m_Impl) )
{
}
template<>
KeyValidatorT<char>::~KeyValidatorT()
{
delete & m_Impl;
}
template<>
KeyValidatorT<wchar_t>::~KeyValidatorT()
{
delete & m_Impl;
}
template<>
KeyValidatorT<char> * KeyValidatorT<char>::Create()
{
return new KeyValidatorT<char>();
}
template<>
KeyValidatorT<wchar_t> * KeyValidatorT<wchar_t>::Create()
{
return new KeyValidatorT<wchar_t>();
}
template<>
void KeyValidatorT<char>::Destroy(KeyValidatorT<char> * obj)
{
delete obj;
}
template<>
void KeyValidatorT<wchar_t>::Destroy(KeyValidatorT<wchar_t> * obj)
{
delete obj;
}
template<>
void KeyValidatorT<char>::SetKeyTemplate(const LicenseTemplateT<char> * templ)
{
m_Impl.SetKeyTemplate(&templ->m_Impl);
}
template<>
void KeyValidatorT<wchar_t>::SetKeyTemplate(const LicenseTemplateT<wchar_t> * templ)
{
m_Impl.SetKeyTemplate(&templ->m_Impl);
}
template<>
void KeyValidatorT<char>::SetValidationData(const char * fieldName, const void * buf, int len)
{
m_Impl.SetValidationData(fieldName, buf, len);
}
template<>
void KeyValidatorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const void * buf, int len)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), buf, len);
}
template<>
void KeyValidatorT<char>::SetValidationData(const char * fieldName, const char * data)
{
m_Impl.SetValidationData(fieldName, data);
}
template<>
void KeyValidatorT<wchar_t>::SetValidationData(const wchar_t * fieldName, const wchar_t * data)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), w2s(data).c_str());
}
template<>
void KeyValidatorT<char>::SetValidationData(const char * fieldName, int data)
{
m_Impl.SetValidationData(fieldName, data);
}
template<>
void KeyValidatorT<wchar_t>::SetValidationData(const wchar_t * fieldName, int data)
{
m_Impl.SetValidationData(w2s(fieldName).c_str(), data);
}
template<>
void KeyValidatorT<char>::SetKey(const char * key)
{
m_Impl.SetKey(key);
}
template<>
void KeyValidatorT<wchar_t>::SetKey(const wchar_t * key)
{
m_Impl.SetKey(w2s(key).c_str());
}
template<>
bool KeyValidatorT<char>::IsKeyValid()
{
return m_Impl.IsKeyValid();
}
template<>
bool KeyValidatorT<wchar_t>::IsKeyValid()
{
return m_Impl.IsKeyValid();
}
template<>
void KeyValidatorT<char>::QueryKeyData(const char * dataField, void * buf, int * len)
{
m_Impl.QueryKeyData(dataField, buf, len);
}
template<>
void KeyValidatorT<wchar_t>::QueryKeyData(const wchar_t * dataField, void * buf, int * len)
{
m_Impl.QueryKeyData(w2s(dataField).c_str(), buf, len);
}
template<>
int KeyValidatorT<char>::QueryIntKeyData(const char * dataField)
{
return m_Impl.QueryIntKeyData(dataField);
}
template<>
int KeyValidatorT<wchar_t>::QueryIntKeyData(const wchar_t * dataField)
{
return m_Impl.QueryIntKeyData(w2s(dataField).c_str());
}
template<>
void KeyValidatorT<char>::QueryDateKeyData(const char * dataField, int * year, int * month, int * day)
{
m_Impl.QueryDateKeyData(dataField, year, month, day);
}
template<>
void KeyValidatorT<wchar_t>::QueryDateKeyData(const wchar_t * dataField, int * year, int * month, int * day)
{
m_Impl.QueryDateKeyData(w2s(dataField).c_str(), year, month, day);
}
template<>
void KeyValidatorT<char>::QueryValidationData(const char * dataField, void * buf, int * len)
{
m_Impl.QueryValidationData(dataField, buf, len);
}
template<>
void KeyValidatorT<wchar_t>::QueryValidationData(const wchar_t * dataField, void * buf, int * len)
{
m_Impl.QueryValidationData((dataField) ? w2s(dataField).c_str() : NULL, buf, len);
}
};
};

View File

@@ -0,0 +1,224 @@
#pragma once
#include <memory>
#include "bitstream.h"
#include "base64.h"
#include "base32.h"
#ifdef _WIN32
#include <tchar.h>
#endif
using namespace std;
class KeyValidatorImpl {
public:
KeyValidatorImpl()
{
}
KeyValidatorImpl(const LicenseTemplateImpl* templ, const char * key = NULL)
{
SetKeyTemplate(templ);
if (key)
SetKey(key);
}
~KeyValidatorImpl()
{
}
void SetKeyTemplate(const LicenseTemplateImpl* templ)
{
m_keyTemplate = templ;
if (templ->m_validationDataSize)
{
m_validationData.Create(templ->m_validationDataSize);
for (const auto& field : m_keyTemplate->m_validationFields)
m_validationData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
}
else
m_validationData.Create(0);
}
void SetValidationData(const char * fieldName, const void * buf, int len)
{
m_validationData.Set(fieldName, buf, len);
}
void SetValidationData(const char * fieldName, const char * data)
{
m_validationData.Set(fieldName, data);
}
void SetValidationData(const char * fieldName, int data)
{
m_validationData.Set(fieldName, data);
}
void SetValidationData(const char * fieldName, int year, int month, int day)
{
m_validationData.Set(fieldName, year, month, day);
}
void SetKey(const char * licKey)
{
if (!licKey)
throw new LicensingException(STATUS_INVALID_PARAM, "invalid license key");
string key(licKey);
if (key.length() < m_keyTemplate->GetCharactersPerGroup() * m_keyTemplate->GetNumberOfGroups() +
strlen(m_keyTemplate->GetHeader()) +
strlen(m_keyTemplate->GetFooter()) +
strlen(m_keyTemplate->GetGroupSeparator()) * (m_keyTemplate->GetNumberOfGroups() - 1))
{
throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "invalid license key (too short)");
}
// remove header and footer (if any)
if (!m_keyTemplate->m_header.empty())
{
key.erase(0, m_keyTemplate->m_header.length() + 2);
}
if (!m_keyTemplate->m_footer.empty())
{
key.erase(key.length() - m_keyTemplate->m_footer.length() - 2, m_keyTemplate->m_footer.length() + 2);
}
// ungroup license key
for (int i = 0, erasePos = 0; i < m_keyTemplate->m_numGroups - 1; i++)
{
erasePos += m_keyTemplate->m_charsPerGroup;
key.erase(erasePos, m_keyTemplate->m_groupSeparator.length());
}
// decode license key
switch ( m_keyTemplate->m_keyEncoding )
{
case ENCODING_BASE32X:
{
BASE32 base32;
int padLen;
int len = base32.encode_pad_length(((int)key.length() * 5 + 7) >> 3, &padLen);
if (len > (int)key.length())
key.append(len - key.length(), 'A');
if (padLen)
key.append(padLen,'=');
auto keyBuf = base32.decode(key.c_str(), (int)key.length(), &len );
if (keyBuf.empty())
throw new LicensingException(STATUS_INVALID_LICENSE_KEY);
// reverse last byte
keyBuf[ len - 1 ] = (unsigned char)(((keyBuf[ len - 1 ] * 0x0802LU & 0x22110LU) | (keyBuf[ len - 1 ] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
m_keyData.Attach(keyBuf, m_keyTemplate->m_keyEncoding * m_keyTemplate->m_charsPerGroup * m_keyTemplate->m_numGroups);
}
break;
case ENCODING_BASE64X:
{
BASE64 base64;
int padLen;
int len = base64.encode_pad_length(((int)key.length() * 6 + 7) >> 3, &padLen);
if (len > (int)key.length())
key.append(len - key.length(), 'A');
if (padLen)
key.append(padLen,'=');
auto keyBuf = base64.decode(key.c_str(), (int)key.length(), &len );
if (keyBuf.empty())
throw new LicensingException(STATUS_INVALID_LICENSE_KEY);
// reverse last byte
keyBuf[ len - 1 ] = (unsigned char)(((keyBuf[ len - 1 ] * 0x0802LU & 0x22110LU) | (keyBuf[ len - 1 ] * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16);
m_keyData.Attach(keyBuf, m_keyTemplate->m_keyEncoding * m_keyTemplate->m_charsPerGroup * m_keyTemplate->m_numGroups);
}
break;
default:
throw new LicensingException(STATUS_INVALID_KEY_ENCODING);
}
for (const auto& field : m_keyTemplate->m_dataFields)
m_keyData.AddField(field.first.c_str(), field.second.type, field.second.size, field.second.offset);
}
bool IsKeyValid()
{
ECC::Verifier verifier;
BitStream signedData,
signature;
signedData.Create(m_keyTemplate->m_dataSize + m_keyTemplate->m_validationDataSize);
signedData.Clear();
if (m_keyTemplate->m_dataSize)
signedData.Write(m_keyData.GetBuffer(), m_keyTemplate->m_dataSize);
if (m_keyTemplate->m_validationDataSize)
signedData.Write(m_validationData.GetBuffer(), m_keyTemplate->m_validationDataSize);
signature.Create(m_keyTemplate->m_signatureSize);
m_keyData.GetBitStream().Seek(m_keyTemplate->m_dataSize);
m_keyData.GetBitStream().Read(signature.GetBuffer(), m_keyTemplate->m_signatureSize);
signature.ReleaseBuffer(m_keyTemplate->m_signatureSize);
signature.Seek(m_keyTemplate->m_signatureSize);
signature.ZeroPadToNextByte();
signature.ReleaseBuffer(m_keyTemplate->m_signatureSize);
// we use a different algorithm than ECDSA when the signature size must be smaller than twice the key size
if (m_keyTemplate->m_signatureSize < (m_keyTemplate->m_signatureKeySize << 1))
verifier.SetHashSize(m_keyTemplate->m_signatureSize - m_keyTemplate->m_signatureKeySize);
else
verifier.SetHashSize(0);
verifier.SetPublicKey(m_keyTemplate->m_verificationKey.get());
return verifier.Verify(signedData.GetBuffer(), (signedData.GetSize() + 7) >> 3, signature.GetBuffer(), (signature.GetSize() + 7) >> 3 , m_keyTemplate->m_signatureSize);
}
void QueryKeyData(const char * fieldName, void * buf, int * len)
{
m_keyData.Get(fieldName, buf, len);
}
int QueryIntKeyData(const char * fieldName)
{
return m_keyData.GetInt(fieldName);
}
void QueryDateKeyData(const char * fieldName, int * year, int * month, int * day)
{
m_keyData.GetDate(fieldName, year, month, day);
}
void QueryValidationData(const char * fieldName, void * buf, int * len)
{
return m_validationData.Get(fieldName, buf, len);
}
public:
const LicenseTemplateImpl* m_keyTemplate;
BitStruct m_keyData;
BitStruct m_validationData;
};

View File

@@ -0,0 +1,6 @@
#pragma once
#define VERSION_MAJOR 3
#define VERSION_MINOR 9
#define VERSION_BUILD 52
#define BUILD_TIMESTAMP 1479947203

View File

@@ -0,0 +1,209 @@
#pragma once
#define _WIN32_DCOM
#include <iostream>
#include <comdef.h>
#include <Wbemidl.h>
#include <list>
#include <string>
#include "uniconv.h"
#pragma comment(lib, "wbemuuid.lib")
using namespace std;
class WmiHelper
{
public:
WmiHelper()
{
HRESULT hres;
wbemServices = NULL;
wbemLocator = NULL;
ownCoInitialize = false;
// Initialize COM.
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (hres == S_OK)
{
ownCoInitialize = true;
}
// Initialize
hres = CoInitializeSecurity(
NULL,
-1, // COM negotiates service
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &wbemLocator);
if (FAILED(hres))
{
if (ownCoInitialize)
CoUninitialize();
throw new exception("failed to create IWbemLocator", hres);
}
// Connect to the root\cimv2 namespace with the
// current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = wbemLocator->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // WMI namespace
NULL, // User name
NULL, // User password
0, // Locale
NULL, // Security flags
0, // Authority
0, // Context object
&wbemServices // IWbemServices proxy
);
if (FAILED(hres))
{
wbemLocator->Release();
if (ownCoInitialize)
CoUninitialize();
throw new exception("could not connect to WMI", hres);
}
// Set the IWbemServices proxy so that impersonation
// of the user (client) occurs.
hres = CoSetProxyBlanket(
wbemServices, // the proxy to set
RPC_C_AUTHN_WINNT, // authentication service
RPC_C_AUTHZ_NONE, // authorization service
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // authentication level
RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
NULL, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
wbemServices->Release();
wbemLocator->Release();
if (ownCoInitialize) CoUninitialize();
throw new exception("could not connecto to WMI", hres);
}
}
~WmiHelper()
{
if (wbemServices) wbemServices->Release();
if (wbemLocator) wbemLocator->Release();
if (ownCoInitialize) CoUninitialize();
}
void GetPropertyList(const char * wqlQuery, const char * propertyName, list<string> * propList, int maxElements = 0x7FFFFFFF)
{
HRESULT hres;
// For example, query for all the running processes
IEnumWbemClassObject* pEnumerator = NULL;
hres = wbemServices->ExecQuery(
bstr_t("WQL"),
bstr_t(wqlQuery),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
NULL,
&pEnumerator);
if (FAILED(hres))
{
throw new exception("WMI query failed");
}
else
{
IWbemClassObject *pclsObj;
ULONG uReturn = 0;
int numElements = 0;
while (1)
{
hres = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if(0 == uReturn)
{
break;
}
VARIANT vtProp;
VariantInit(&vtProp);
// Get the value of the Name property
hres = pclsObj->Get(_bstr_t(propertyName), 0, &vtProp, 0, 0);
//
if (SUCCEEDED(hres))
{
switch (vtProp.vt)
{
case VT_BSTR:
propList->push_back(w2s(vtProp.bstrVal).c_str());
numElements++;
break;
case VT_I1:
case VT_UI1:
case VT_I2:
case VT_UI2:
case VT_I4:
case VT_UI4:
{
char strVal[32];
_itoa(vtProp.intVal, strVal, 10);
propList->push_back(strVal);
numElements++;
}
break;
case VT_I8:
case VT_UI8:
{
char strVal[32];
_i64toa(vtProp.llVal, strVal, 10);
propList->push_back(strVal);
numElements++;
}
break;
default:
break;
}
VariantClear(&vtProp);
}
pclsObj->Release();
if (numElements >= maxElements)
break;
}
pEnumerator->Release();
}
}
private:
bool ownCoInitialize;
IWbemServices * wbemServices;
IWbemLocator * wbemLocator;
};