LIcenseManager.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. #include "pch.h"
  2. #include "LicenseManager.h"
  3. #include "SHA256.h"
  4. #include <iostream>
  5. #include <string>
  6. #include <fstream>
  7. #include <sstream>
  8. #include <vector>
  9. #include <map>
  10. #include <algorithm>
  11. #include <functional>
  12. #include <cctype>
  13. #include <locale>
  14. #include <ctime>
  15. using namespace std;
  16. // License 정보를 저장할 구조체
  17. struct LicenseInfo
  18. {
  19. int error;
  20. std::string errorMessage;
  21. std::string product;
  22. std::string serialId;
  23. std::string issueDay;
  24. std::string edition;
  25. std::string type;
  26. std::string accountsStr;
  27. int accounts;
  28. std::string identifiedHost;
  29. std::string signature;
  30. std::string demoDurationStr;
  31. int demoDuration;
  32. };
  33. std::string GetLocalComputerName() {
  34. char computerName[MAX_COMPUTERNAME_LENGTH + 1];
  35. DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
  36. if (GetComputerNameA(computerName, &size))
  37. {
  38. std::string computerNameStr(computerName);
  39. return computerNameStr;
  40. }
  41. return "";
  42. }
  43. inline std::string& ltrim(std::string& s) {
  44. s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
  45. return s;
  46. }
  47. // 문자열의 오른쪽 공백 제거 (in-place)
  48. inline std::string& rtrim(std::string& s) {
  49. s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
  50. return s;
  51. }
  52. // 문자열의 양쪽 공백 제거 (in-place)
  53. inline std::string& trim(std::string& s) {
  54. rtrim(s);
  55. ltrim(s);
  56. return s;
  57. }
  58. bool equalsIgnoreCase(std::string& str1, std::string& str2)
  59. {
  60. if (str1.length() != str2.length())
  61. return false;
  62. for (int i = 0; i < str1.length(); ++i) {
  63. if (tolower(str1[i]) != tolower(str2[i]))
  64. return false;
  65. }
  66. return true;
  67. }
  68. bool is_number(const std::string& s) {
  69. return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
  70. }
  71. std::string toLower(std::string& str) {
  72. for (int i = 0; i < str.length(); ++i) {
  73. str[i] = tolower(str[i]);
  74. }
  75. return str;
  76. }
  77. std::string toUpper(std::string& str) {
  78. for (int i = 0; i < str.length(); ++i) {
  79. str[i] = toupper(str[i]);
  80. }
  81. return str;
  82. }
  83. // 주어진 문자열이 유효한 날짜 형식인지 확인하는 함수
  84. bool isValidDate(const std::string& dateStr)
  85. {
  86. struct tm tm;
  87. if (sscanf(dateStr.c_str(), "%d-%d-%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday) != 3)
  88. {
  89. return false;
  90. }
  91. tm.tm_mon -= 1; // 월은 0부터 시작
  92. tm.tm_year -= 1900; // 연도는 1900을 뺀 값
  93. tm.tm_hour = 0;
  94. tm.tm_min = 0;
  95. tm.tm_sec = 0;
  96. time_t t = mktime(&tm);
  97. if (t == -1)
  98. {
  99. return false;
  100. }
  101. return true;
  102. }
  103. // 만료일이 현재일자보다 큰지 여부를 확인하는 함수
  104. bool IsExpirationDateValid(const std::string& expirationDate, int daysToAdd)
  105. {
  106. struct tm expirationTm;
  107. if (sscanf(expirationDate.c_str(), "%d-%d-%d", &expirationTm.tm_year, &expirationTm.tm_mon, &expirationTm.tm_mday) != 3)
  108. {
  109. return false;
  110. }
  111. expirationTm.tm_mon -= 1; // 월은 0부터 시작
  112. expirationTm.tm_year -= 1900; // 연도는 1900을 뺀 값
  113. expirationTm.tm_hour = 23;
  114. expirationTm.tm_min = 59;
  115. expirationTm.tm_sec = 59;
  116. expirationTm.tm_mday += daysToAdd;
  117. time_t expiredTime = mktime(&expirationTm);
  118. if (expiredTime == -1)
  119. {
  120. return false;
  121. }
  122. time_t now = time(nullptr);
  123. return expiredTime > now;
  124. }
  125. extern "C" {
  126. // SHA-256 해시를 생성하는 함수
  127. LICENSEMANAGER_API int __stdcall ValidateLicense(char* licenseFilePath, int* licenseAccount)
  128. {
  129. LicenseInfo licenseInfo;
  130. licenseInfo.error = 0;
  131. licenseInfo.errorMessage = "";
  132. licenseInfo.product = "";
  133. licenseInfo.serialId = "";
  134. licenseInfo.issueDay = "";
  135. licenseInfo.edition = "";
  136. licenseInfo.type = "";
  137. licenseInfo.accountsStr = "";
  138. licenseInfo.accounts = 0;
  139. licenseInfo.identifiedHost = "";
  140. licenseInfo.signature = "";
  141. licenseInfo.demoDurationStr = "";
  142. licenseInfo.demoDuration = 0;
  143. if (licenseFilePath == NULL || licenseAccount == NULL) {
  144. licenseInfo.error = 1;
  145. licenseInfo.errorMessage = "라이센스 요청 정보가 올바르지 않습니다.";
  146. return -1;
  147. }
  148. *licenseAccount = -1;
  149. try
  150. {
  151. std::ifstream file(licenseFilePath);
  152. if (!file.is_open())
  153. {
  154. licenseInfo.error = 1;
  155. licenseInfo.errorMessage = "라이센스 파일을 열수가 없습니다.";
  156. return -2;
  157. }
  158. std::string line;
  159. while (std::getline(file, line))
  160. {
  161. if (line.find("<product") != std::string::npos)
  162. licenseInfo.product = line.substr(line.find(">") + 1, line.find("</product>") - line.find(">") - 1);
  163. else if (line.find("<serialId>") != std::string::npos)
  164. licenseInfo.serialId = line.substr(line.find(">") + 1, line.find("</serialId>") - line.find(">") - 1);
  165. else if (line.find("<issueDay>") != std::string::npos)
  166. licenseInfo.issueDay = line.substr(line.find(">") + 1, line.find("</issueDay>") - line.find(">") - 1);
  167. else if (line.find("<edition>") != std::string::npos)
  168. licenseInfo.edition = line.substr(line.find(">") + 1, line.find("</edition>") - line.find(">") - 1);
  169. else if (line.find("<type>") != std::string::npos)
  170. licenseInfo.type = line.substr(line.find(">") + 1, line.find("</type>") - line.find(">") - 1);
  171. else if (line.find("<accounts>") != std::string::npos)
  172. licenseInfo.accountsStr = line.substr(line.find(">") + 1, line.find("</accounts>") - line.find(">") - 1);
  173. else if (line.find("<identifiedHost>") != std::string::npos)
  174. licenseInfo.identifiedHost = line.substr(line.find(">") + 1, line.find("</identifiedHost>") - line.find(">") - 1);
  175. else if (line.find("<signature>") != std::string::npos)
  176. licenseInfo.signature = line.substr(line.find(">") + 1, line.find("</signature>") - line.find(">") - 1);
  177. else if (line.find("<demoDuration>") != std::string::npos)
  178. licenseInfo.demoDurationStr = line.substr(line.find(">") + 1, line.find("</demoDuration>") - line.find(">") - 1);
  179. }
  180. licenseInfo.product = trim(licenseInfo.product);
  181. licenseInfo.serialId = trim(licenseInfo.serialId);
  182. licenseInfo.issueDay = trim(licenseInfo.issueDay);
  183. licenseInfo.edition = trim(licenseInfo.edition);
  184. licenseInfo.type = trim(licenseInfo.type);
  185. licenseInfo.accountsStr = trim(licenseInfo.accountsStr);
  186. licenseInfo.accounts = 0;
  187. licenseInfo.identifiedHost = trim(licenseInfo.identifiedHost);
  188. licenseInfo.signature = trim(licenseInfo.signature);
  189. licenseInfo.demoDurationStr = trim(licenseInfo.demoDurationStr);
  190. file.close();
  191. bool isDemo = false;
  192. if (licenseInfo.product.empty() || licenseInfo.product == "") {
  193. return 1;
  194. }
  195. if (licenseInfo.serialId.empty() || licenseInfo.serialId == "") {
  196. return 2;
  197. }
  198. if (licenseInfo.issueDay.empty() || licenseInfo.issueDay == "") {
  199. return 3;
  200. }
  201. if (!isValidDate(licenseInfo.issueDay)) {
  202. return 33;
  203. }
  204. std::string standard = "standard";
  205. std::string enterprise = "enterprise";
  206. if (licenseInfo.edition.empty() || licenseInfo.edition == "") {
  207. return 4;
  208. }
  209. if (!equalsIgnoreCase(licenseInfo.edition, standard) && !equalsIgnoreCase(licenseInfo.edition, enterprise)) {
  210. return 34;
  211. }
  212. std::string demo = "demo";
  213. std::string product = "product";
  214. if (licenseInfo.type.empty() || licenseInfo.type == "") {
  215. return 5;
  216. }
  217. if (!equalsIgnoreCase(licenseInfo.type, demo) && !equalsIgnoreCase(licenseInfo.type, product)) {
  218. return 35;
  219. }
  220. if (equalsIgnoreCase(licenseInfo.type, demo)) {
  221. isDemo = true;
  222. }
  223. if (licenseInfo.accountsStr.empty() || licenseInfo.accountsStr == "") {
  224. return 6;
  225. }
  226. if (!is_number(licenseInfo.accountsStr)) {
  227. return 36;
  228. }
  229. licenseInfo.accounts = stoi(licenseInfo.accountsStr);
  230. *licenseAccount = licenseInfo.accounts;
  231. if (licenseInfo.identifiedHost.empty() || licenseInfo.identifiedHost == "") {
  232. return 7;
  233. }
  234. if (licenseInfo.signature.empty() || licenseInfo.signature == "") {
  235. return 8;
  236. }
  237. if (isDemo) {
  238. if (licenseInfo.demoDurationStr.empty() || licenseInfo.demoDurationStr == "") {
  239. return 9;
  240. }
  241. if (!is_number(licenseInfo.demoDurationStr)) {
  242. return 39;
  243. }
  244. licenseInfo.demoDuration = stoi(licenseInfo.demoDurationStr);
  245. if (!IsExpirationDateValid(licenseInfo.issueDay, licenseInfo.demoDuration)) {
  246. return 88; // 데모 유효기간 초과
  247. }
  248. }
  249. std::string localComputerName = GetLocalComputerName();
  250. if (!equalsIgnoreCase(localComputerName, licenseInfo.identifiedHost)) {
  251. return 81; // 컴퓨터 이름이 다름
  252. }
  253. std::string encKey = "hanteinfo12#$!";
  254. std::string encProduct = toUpper(licenseInfo.product) + encKey;
  255. std::string encSerialId = toLower(licenseInfo.serialId);
  256. std::string encIssueDay = licenseInfo.issueDay;
  257. std::string encEdition = toUpper(licenseInfo.edition);
  258. std::string encType = toLower(licenseInfo.type);
  259. std::string encAccounts = std::to_string(licenseInfo.accounts + 10000);
  260. std::string encHost = toLower(licenseInfo.identifiedHost);
  261. std::string encData = encProduct + encSerialId + encIssueDay + encEdition + encType + encAccounts + encHost;
  262. SHA256 sha;
  263. sha.update(encData);
  264. std::array<uint8_t, 32> digest = sha.digest();
  265. std::string encResult = "";
  266. for (auto& data : digest) {
  267. char temp[20];
  268. memset(temp, 0x00, sizeof(temp));
  269. snprintf(temp, sizeof(temp), "%02x", data);
  270. encResult += std::string(temp);
  271. }
  272. if (!equalsIgnoreCase(licenseInfo.signature, encResult)) {
  273. return 92; //시그니처 오류
  274. }
  275. return 0;
  276. }
  277. catch (const std::exception& ex)
  278. {
  279. std::string errorMessage = ex.what();
  280. licenseInfo.error = 99;
  281. licenseInfo.errorMessage = "라이센스 정보를 확인하는 중에 오류가 발생했습니다. " + errorMessage;
  282. return -2;
  283. }
  284. }
  285. }