PageRenderTime 67ms CodeModel.GetById 15ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 0ms

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