LicenseManagerTest.cpp 11 KB

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