/bncsutil/src/bncsutil/cdkeydecoder.cpp

http://ghostcb.googlecode.com/ · C++ · 604 lines · 444 code · 71 blank · 89 comment · 67 complexity · 0c3ac0c3b7522e08e1b1451f09ede430 MD5 · raw file

  1. /**
  2. * BNCSutil
  3. * Battle.Net Utility Library
  4. *
  5. * Copyright (C) 2004-2006 Eric Naeseth
  6. *
  7. * CD-Key Decoder Implementation
  8. * September 29, 2004
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation; either
  13. * version 2.1 of the License, or (at your option) any later version.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * A copy of the GNU Lesser General Public License is included in the BNCSutil
  21. * distribution in the file COPYING. If you did not receive this copy,
  22. * write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  23. * Boston, MA 02111-1307 USA
  24. */
  25. #include <bncsutil/mutil.h>
  26. #include <bncsutil/cdkeydecoder.h>
  27. #include <bncsutil/keytables.h> // w2/d2 and w3 tables
  28. #include <bncsutil/bsha1.h> // Broken SHA-1
  29. #include <bncsutil/sha1.h> // US Secure Hash Algorithm (for W3)
  30. #include <cctype> // for isdigit(), isalnum(), and toupper()
  31. #include <cstring> // for memcpy()
  32. #include <cstdio> // for sscanf()
  33. // #include <bncsutil/debug.h>
  34. /**
  35. * Implementation-specific CD-key hash structure.
  36. */
  37. struct CDKEYHASH {
  38. uint32_t clientToken;
  39. uint32_t serverToken;
  40. uint32_t product;
  41. uint32_t value1;
  42. union {
  43. struct {
  44. uint32_t zero;
  45. uint32_t v;
  46. unsigned char reserved[2];
  47. } s;
  48. struct {
  49. char v[10];
  50. } l;
  51. } value2;
  52. };
  53. #define W3_KEYLEN 26
  54. #define W3_BUFLEN (W3_KEYLEN << 1)
  55. /**
  56. * Creates a new CD-key decoder object.
  57. * Not really useful unless subclassed.
  58. */
  59. CDKeyDecoder::CDKeyDecoder() {
  60. initialized = 0;
  61. keyOK = 0;
  62. hashLen = 0;
  63. cdkey = (char*) 0;
  64. w3value2 = (char*) 0;
  65. keyHash = (char*) 0;
  66. }
  67. CDKeyDecoder::CDKeyDecoder(const char* cd_key) {
  68. CDKeyDecoder(cd_key, std::strlen(cd_key));
  69. }
  70. /**
  71. * Creates a new CD-key decoder object, using the specified key.
  72. * keyLength should be the length of the key, NOT INCLUDING the
  73. * null-terminator. Applications should use isKeyValid after using
  74. * this constructor to check the validity of the provided key.
  75. */
  76. CDKeyDecoder::CDKeyDecoder(const char* cdKey, size_t keyLength) {
  77. unsigned int i;
  78. initialized = 0;
  79. product = 0;
  80. value1 = 0;
  81. value2 = 0;
  82. keyOK = 0;
  83. hashLen = 0;
  84. cdkey = (char*) 0;
  85. w3value2 = (char*) 0;
  86. keyHash = (char*) 0;
  87. if (keyLength <= 0) return;
  88. // Initial sanity check
  89. if (keyLength == 13) {
  90. // StarCraft key
  91. for (i = 0; i < keyLength; i++) {
  92. if (!isdigit(cdKey[i])) return;
  93. }
  94. keyType = KEY_STARCRAFT;
  95. #if DEBUG
  96. bncsutil_debug_message_a(
  97. "Created CD key decoder with STAR key %s.", cdKey
  98. );
  99. #endif
  100. } else {
  101. // D2/W2/W3 key
  102. for (i = 0; i < keyLength; i++) {
  103. if (!isalnum(cdKey[i])) return;
  104. }
  105. switch (keyLength) {
  106. case 16:
  107. keyType = KEY_WARCRAFT2;
  108. #if DEBUG
  109. bncsutil_debug_message_a(
  110. "Created CD key decoder with W2/D2 key %s.", cdKey
  111. );
  112. #endif
  113. break;
  114. case 26:
  115. keyType = KEY_WARCRAFT3;
  116. #if DEBUG
  117. bncsutil_debug_message_a(
  118. "Created CD key decoder with WAR3 key %s.", cdKey
  119. );
  120. #endif
  121. break;
  122. default:
  123. #if DEBUG
  124. bncsutil_debug_message_a(
  125. "Created CD key decoder with unrecognized key %s.", cdKey
  126. );
  127. #endif
  128. return;
  129. }
  130. }
  131. cdkey = new char[keyLength + 1];
  132. initialized = 1;
  133. keyLen = keyLength;
  134. strcpy(cdkey, cdKey);
  135. switch (keyType) {
  136. case KEY_STARCRAFT:
  137. keyOK = processStarCraftKey();
  138. #if DEBUG
  139. bncsutil_debug_message_a("%s: ok=%d; product=%d; public=%d; "
  140. "private=%d", cdkey, keyOK, getProduct(), getVal1(), getVal2());
  141. #endif
  142. break;
  143. case KEY_WARCRAFT2:
  144. keyOK = processWarCraft2Key();
  145. #if DEBUG
  146. bncsutil_debug_message_a("%s: ok=%d; product=%d; public=%d; "
  147. "private=%d", cdkey, keyOK, getProduct(), getVal1(), getVal2());
  148. #endif
  149. break;
  150. case KEY_WARCRAFT3:
  151. keyOK = processWarCraft3Key();
  152. #if DEBUG
  153. bncsutil_debug_message_a("%s: ok=%d; product=%d; public=%d; ",
  154. cdkey, keyOK, getProduct(), getVal1());
  155. #endif
  156. break;
  157. default:
  158. return;
  159. }
  160. }
  161. CDKeyDecoder::~CDKeyDecoder() {
  162. if (initialized && cdkey != NULL)
  163. delete [] cdkey;
  164. if (hashLen > 0 && keyHash != NULL)
  165. delete [] keyHash;
  166. if (w3value2)
  167. delete [] w3value2;
  168. }
  169. int CDKeyDecoder::isKeyValid() {
  170. return (initialized && keyOK) ? 1 : 0;
  171. }
  172. int CDKeyDecoder::getVal2Length() {
  173. return (keyType == KEY_WARCRAFT3) ? 10 : 4;
  174. }
  175. uint32_t CDKeyDecoder::getProduct() {
  176. switch (keyType) {
  177. case KEY_STARCRAFT:
  178. case KEY_WARCRAFT2:
  179. return (uint32_t) LSB4(product);
  180. case KEY_WARCRAFT3:
  181. return (uint32_t) MSB4(product);
  182. default:
  183. return (uint32_t) -1;
  184. }
  185. }
  186. uint32_t CDKeyDecoder::getVal1() {
  187. switch (keyType) {
  188. case KEY_STARCRAFT:
  189. case KEY_WARCRAFT2:
  190. return (uint32_t) LSB4(value1);
  191. case KEY_WARCRAFT3:
  192. return (uint32_t) MSB4(value1);
  193. default:
  194. return (uint32_t) -1;
  195. }
  196. }
  197. uint32_t CDKeyDecoder::getVal2() {
  198. return (uint32_t) LSB4(value2);
  199. }
  200. int CDKeyDecoder::getLongVal2(char* out) {
  201. if (w3value2 != NULL && keyType == KEY_WARCRAFT3) {
  202. memcpy(out, w3value2, 10);
  203. return 10;
  204. } else {
  205. return 0;
  206. }
  207. }
  208. /**
  209. * Calculates the CD-Key hash for use in SID_AUTH_CHECK (0x51)
  210. * Returns the length of the generated hash; call getHash and pass
  211. * it a character array that is at least this size. Returns 0 on failure.
  212. *
  213. * Note that clientToken and serverToken will be added to the buffer and
  214. * hashed as-is, regardless of system endianness. It is assumed that
  215. * the program's extraction of the server token does not change its
  216. * endianness, and since the client token is generated by the client,
  217. * endianness is not a factor.
  218. */
  219. size_t CDKeyDecoder::calculateHash(uint32_t clientToken,
  220. uint32_t serverToken)
  221. {
  222. struct CDKEYHASH kh;
  223. SHA1Context sha;
  224. if (!initialized || !keyOK) return 0;
  225. hashLen = 0;
  226. kh.clientToken = clientToken;
  227. kh.serverToken = serverToken;
  228. switch (keyType) {
  229. case KEY_STARCRAFT:
  230. case KEY_WARCRAFT2:
  231. kh.product = (uint32_t) LSB4(product);
  232. kh.value1 = (uint32_t) LSB4(value1);
  233. kh.value2.s.zero = 0;
  234. kh.value2.s.v = (uint32_t) LSB4(value2);
  235. keyHash = new char[20];
  236. calcHashBuf((char*) &kh, 24, keyHash);
  237. hashLen = 20;
  238. #if DEBUG
  239. bncsutil_debug_message_a("%s: Hash calculated.", cdkey);
  240. bncsutil_debug_dump(keyHash, 20);
  241. #endif
  242. return 20;
  243. case KEY_WARCRAFT3:
  244. kh.product = (uint32_t) MSB4(product);
  245. kh.value1 = (uint32_t) MSB4(value1);
  246. memcpy(kh.value2.l.v, w3value2, 10);
  247. if (SHA1Reset(&sha))
  248. return 0;
  249. if (SHA1Input(&sha, (const unsigned char*) &kh, 26))
  250. return 0;
  251. keyHash = new char[20];
  252. if (SHA1Result(&sha, (unsigned char*) keyHash)) {
  253. SHA1Reset(&sha);
  254. return 0;
  255. }
  256. SHA1Reset(&sha);
  257. hashLen = 20;
  258. #if DEBUG
  259. bncsutil_debug_message_a("%s: Hash calculated.", cdkey);
  260. bncsutil_debug_dump(keyHash, 20);
  261. #endif
  262. return 20;
  263. default:
  264. return 0;
  265. }
  266. }
  267. /**
  268. * Places the calculated CD-key hash in outputBuffer. You must call
  269. * calculateHash before getHash. Returns the length of the hash
  270. * that was copied to outputBuffer, or 0 on failure.
  271. */
  272. size_t CDKeyDecoder::getHash(char* outputBuffer) {
  273. if (hashLen == 0 || !keyHash || !outputBuffer)
  274. return 0;
  275. memcpy(outputBuffer, keyHash, hashLen);
  276. return hashLen;
  277. }
  278. /*
  279. void CDKeyDecoder::swapChars(char* string, int a, int b) {
  280. char temp;
  281. temp = string[a];
  282. string[a] = string[b];
  283. string[b] = temp;
  284. }
  285. */
  286. int CDKeyDecoder::processStarCraftKey() {
  287. int accum, pos, i;
  288. char temp;
  289. int hashKey = 0x13AC9741;
  290. char cdkey[14];
  291. std::strcpy(cdkey, this->cdkey);
  292. // Verification
  293. accum = 3;
  294. for (i = 0; i < (int) (keyLen - 1); i++) {
  295. accum += ((tolower(cdkey[i]) - '0') ^ (accum * 2));
  296. }
  297. if ((accum % 10) != (cdkey[12] - '0')) {
  298. // bncsutil_debug_message_a("error: %s is not a valid StarCraft key", cdkey);
  299. return 0;
  300. }
  301. // Shuffling
  302. pos = 0x0B;
  303. for (i = 0xC2; i >= 7; i -= 0x11) {
  304. temp = cdkey[pos];
  305. cdkey[pos] = cdkey[i % 0x0C];
  306. cdkey[i % 0x0C] = temp;
  307. pos--;
  308. }
  309. // Final Value
  310. for (i = (int) (keyLen - 2); i >= 0; i--) {
  311. temp = toupper(cdkey[i]);
  312. cdkey[i] = temp;
  313. if (temp <= '7') {
  314. cdkey[i] ^= (char) (hashKey & 7);
  315. hashKey >>= 3;
  316. } else if (temp < 'A') {
  317. cdkey[i] ^= ((char) i & 1);
  318. }
  319. }
  320. // Final Calculations
  321. sscanf(cdkey, "%2ld%7ld%3ld", &product, &value1, &value2);
  322. return 1;
  323. }
  324. int CDKeyDecoder::processWarCraft2Key() {
  325. unsigned long r, n, n2, v, v2, checksum;
  326. int i;
  327. unsigned char c1, c2, c;
  328. char cdkey[17];
  329. std::strcpy(cdkey, this->cdkey);
  330. r = 1;
  331. checksum = 0;
  332. for (i = 0; i < 16; i += 2) {
  333. c1 = w2Map[(int) cdkey[i]];
  334. n = c1 * 3;
  335. c2 = w2Map[(int) cdkey[i + 1]];
  336. n = c2 + n * 8;
  337. if (n >= 0x100) {
  338. n -= 0x100;
  339. checksum |= r;
  340. }
  341. // !
  342. n2 = n >> 4;
  343. // !
  344. cdkey[i] = getHexValue(n2);
  345. cdkey[i + 1] = getHexValue(n);
  346. r <<= 1;
  347. }
  348. v = 3;
  349. for (i = 0; i < 16; i++) {
  350. c = cdkey[i];
  351. n = getNumValue(c);
  352. n2 = v * 2;
  353. n ^= n2;
  354. v += n;
  355. }
  356. v &= 0xFF;
  357. if (v != checksum) {
  358. return 0;
  359. }
  360. n = 0;
  361. for (int j = 15; j >= 0; j--) {
  362. c = cdkey[j];
  363. if (j > 8) {
  364. n = (j - 9);
  365. } else {
  366. n = (0xF - (8 - j));
  367. }
  368. n &= 0xF;
  369. c2 = cdkey[n];
  370. cdkey[j] = c2;
  371. cdkey[n] = c;
  372. }
  373. v2 = 0x13AC9741;
  374. for (int j = 15; j >= 0; j--) {
  375. c = toupper(cdkey[j]);
  376. cdkey[j] = c;
  377. if (c <= '7') {
  378. v = v2;
  379. c2 = ((char) (v & 0xFF)) & 7 ^ c;
  380. v >>= 3;
  381. cdkey[j] = (char) c2;
  382. v2 = v;
  383. } else if (c < 'A') {
  384. cdkey[j] = ((char) j) & 1 ^ c;
  385. }
  386. }
  387. // Final Calculations
  388. sscanf(cdkey, "%2lx%6lx%8lx", &product, &value1, &value2);
  389. return 1;
  390. }
  391. int CDKeyDecoder::processWarCraft3Key() {
  392. char table[W3_BUFLEN];
  393. int values[4];
  394. int a, b;
  395. int i;
  396. char decode;
  397. a = 0;
  398. b = 0x21;
  399. memset(table, 0, W3_BUFLEN);
  400. memset(values, 0, (sizeof(int) * 4));
  401. for (i = 0; ((unsigned int) i) < keyLen; i++) {
  402. cdkey[i] = toupper(cdkey[i]);
  403. a = (b + 0x07B5) % W3_BUFLEN;
  404. b = (a + 0x07B5) % W3_BUFLEN;
  405. decode = w3KeyMap[(int)cdkey[i]];
  406. table[a] = (decode / 5);
  407. table[b] = (decode % 5);
  408. }
  409. // Mult
  410. i = W3_BUFLEN;
  411. do {
  412. mult(4, 5, values + 3, table[i - 1]);
  413. } while (--i);
  414. decodeKeyTable(values);
  415. // 00 00 38 08 f0 64 18 6c 79 14 14 8E B9 49 1D BB
  416. // --------
  417. // val1
  418. product = values[0] >> 0xA;
  419. product = SWAP4(product);
  420. #if LITTLEENDIAN
  421. for (i = 0; i < 4; i++) {
  422. values[i] = MSB4(values[i]);
  423. }
  424. #endif
  425. value1 = LSB4(*(uint32_t*) (((char*) values) + 2)) & 0xFFFFFF00;
  426. w3value2 = new char[10];
  427. #if LITTLEENDIAN
  428. *((uint16_t*) w3value2) = MSB2(*(uint16_t*) (((char*) values) + 6));
  429. *((uint32_t*) ((char*) w3value2 + 2)) = MSB4(*(uint32_t*) (((char*) values) + 8));
  430. *((uint32_t*) ((char*) w3value2 + 6)) = MSB4(*(uint32_t*) (((char*) values) + 12));
  431. #else
  432. *((uint16_t*) w3value2) = LSB2(*(uint16_t*) (((char*) values) + 6));
  433. *((uint32_t*) ((char*) w3value2 + 2)) = LSB4(*(uint32_t*) (((char*) values) + 8));
  434. *((uint32_t*) ((char*) w3value2 + 6)) = LSB4(*(uint32_t*) (((char*) values) + 12));
  435. #endif
  436. return 1;
  437. }
  438. inline void CDKeyDecoder::mult(int r, const int x, int* a, int dcByte) {
  439. while (r--) {
  440. int64_t edxeax = ((int64_t) (*a & 0x00000000FFFFFFFFl))
  441. * ((int64_t) (x & 0x00000000FFFFFFFFl));
  442. *a-- = dcByte + (int32_t) edxeax;
  443. dcByte = (int32_t) (edxeax >> 32);
  444. }
  445. }
  446. void CDKeyDecoder::decodeKeyTable(int* keyTable) {
  447. unsigned int eax, ebx, ecx, edx, edi, esi, ebp;
  448. unsigned int varC, var4, var8;
  449. unsigned int copy[4];
  450. unsigned char* scopy;
  451. int* ckt;
  452. int ckt_temp;
  453. var8 = 29;
  454. int i = 464;
  455. // pass 1
  456. do {
  457. int j;
  458. esi = (var8 & 7) << 2;
  459. var4 = var8 >> 3;
  460. //varC = (keyTable[3 - var4] & (0xF << esi)) >> esi;
  461. varC = keyTable[3 - var4];
  462. varC &= (0xF << esi);
  463. varC = varC >> esi;
  464. if (i < 464) {
  465. for (j = 29; (unsigned int) j > var8; j--) {
  466. /*
  467. ecx = (j & 7) << 2;
  468. ebp = (keyTable[0x3 - (j >> 3)] & (0xF << ecx)) >> ecx;
  469. varC = w3TranslateMap[ebp ^ w3TranslateMap[varC + i] + i];
  470. */
  471. ecx = (j & 7) << 2;
  472. //ebp = (keyTable[0x3 - (j >> 3)] & (0xF << ecx)) >> ecx;
  473. ebp = (keyTable[0x3 - (j >> 3)]);
  474. ebp &= (0xF << ecx);
  475. ebp = ebp >> ecx;
  476. varC = w3TranslateMap[ebp ^ w3TranslateMap[varC + i] + i];
  477. }
  478. }
  479. j = --var8;
  480. while (j >= 0) {
  481. ecx = (j & 7) << 2;
  482. //ebp = (keyTable[0x3 - (j >> 3)] & (0xF << ecx)) >> ecx;
  483. ebp = (keyTable[0x3 - (j >> 3)]);
  484. ebp &= (0xF << ecx);
  485. ebp = ebp >> ecx;
  486. varC = w3TranslateMap[ebp ^ w3TranslateMap[varC + i] + i];
  487. j--;
  488. }
  489. j = 3 - var4;
  490. ebx = (w3TranslateMap[varC + i] & 0xF) << esi;
  491. keyTable[j] = (ebx | ~(0xF << esi) & ((int) keyTable[j]));
  492. } while ((i -= 16) >= 0);
  493. // pass 2
  494. eax = 0;
  495. edx = 0;
  496. ecx = 0;
  497. edi = 0;
  498. esi = 0;
  499. ebp = 0;
  500. for (i = 0; i < 4; i++) {
  501. copy[i] = LSB4(keyTable[i]);
  502. }
  503. scopy = (unsigned char*) copy;
  504. for (edi = 0; edi < 120; edi++) {
  505. unsigned int location = 12;
  506. eax = edi & 0x1F;
  507. ecx = esi & 0x1F;
  508. edx = 3 - (edi >> 5);
  509. location -= ((esi >> 5) << 2);
  510. ebp = *(int*) (scopy + location);
  511. ebp = LSB4(ebp);
  512. //ebp = (ebp & (1 << ecx)) >> ecx;
  513. ebp &= (1 << ecx);
  514. ebp = ebp >> ecx;
  515. //keyTable[edx] = ((ebp & 1) << eax) | (~(1 << eax) & keyTable[edx]);
  516. ckt = (keyTable + edx);
  517. ckt_temp = *ckt;
  518. *ckt = ebp & 1;
  519. *ckt = *ckt << eax;
  520. *ckt |= (~(1 << eax) & ckt_temp);
  521. esi += 0xB;
  522. if (esi >= 120)
  523. esi -= 120;
  524. }
  525. }
  526. inline char CDKeyDecoder::getHexValue(int v) {
  527. v &= 0xF;
  528. return (v < 10) ? (v + 0x30) : (v + 0x37);
  529. }
  530. inline int CDKeyDecoder::getNumValue(char c) {
  531. c = toupper(c);
  532. return (isdigit(c)) ? (c - 0x30) : (c - 0x37);
  533. }