• Welcome to Valhalla Legends Archive.
 

CDKey hashing

Started by brew, September 16, 2007, 09:19 PM

Previous topic - Next topic

brew

Help, I am not getting a valid cdkey hash! I don't really know where it screws up at....

#define ROL(nr, shift) ((nr << shift) | (nr >> (32 - shift)))

void HashCDKey(char *OutBuf, unsigned long ClientToken, unsigned long ServerToken,
unsigned long ProductVal, unsigned long PublicVal, unsigned long PrivateVal) {
DWORD dwHashBuff[6];
DWORD dwHashResult[5];
dwHashBuff[0] = ClientToken;
dwHashBuff[1] = ServerToken;
dwHashBuff[2] = ProductVal;
dwHashBuff[3] = PublicVal;
dwHashBuff[4] = 0;
dwHashBuff[5] = PrivateVal;
HashData((void *)dwHashBuff, 24, (void *)dwHashResult);
memcpy(OutBuf, dwHashResult, 20);
}


void HashData(void* lpSource, int nLength, void* lpResult) {
   BYTE bBuffer[1024];
   DWORD a, b, c, d, e, g, * lpdwBuffer;
   ZeroMemory(bBuffer, sizeof(bBuffer));
   CopyMemory(bBuffer, lpSource, nLength);
   lpdwBuffer = (LPDWORD) bBuffer;
   for (int i = 0; i < 64; i++)
      lpdwBuffer[i+16] = ROL(1, (lpdwBuffer[i] ^ lpdwBuffer[i+8] ^
                             lpdwBuffer[i+2] ^ lpdwBuffer[i+13]) % 32);
   a = 0x67452301lu;
   b = 0xefcdab89lu;
   c = 0x98badcfelu;
   d = 0x10325476lu;
   e = 0xc3d2e1f0lu;
   for (i = 0; i < (20 * 1); i++)
   {
      g = lpdwBuffer[i] + ROL(a,5) + e + ((b & c) | (~b & d)) + 0x5a827999lu;
      e = d;
      d = c;
      c = ROL(b,30);
      b = a;
      a = g;
   }
   for (; i < (20 * 2); i++)
   {
      g = (d ^ c ^ b) + e + ROL(g,5) + lpdwBuffer[i] + 0x6ed9eba1lu;
      e = d;
      d = c;
      c = ROL(b,30);
      b = a;
      a = g;
   }
   for (; i < (20 * 3); i++)
   {
      g = lpdwBuffer[i] + ROL(g,5) + e + ((c & b) | (d & c) | (d & b)) -
          0x70e44324lu;
      e = d;
      d = c;
      c = ROL(b,30);
      b = a;
      a = g;
   }
   for (; i < (20 * 4); i++)
   {
      g = (d ^ c ^ b) + e + ROL(g,5) + lpdwBuffer[i] - 0x359d3e2alu;
      e = d;
      d = c;
      c = ROL(b,30);
      b = a;
      a = g;
   }

   lpdwBuffer = (LPDWORD) lpResult;
   lpdwBuffer[0] = 0x67452301lu + g;
   lpdwBuffer[1] = 0xefcdab89lu + b;
   lpdwBuffer[2] = 0x98badcfelu + c;
   lpdwBuffer[3] = 0x10325476lu + d;
   lpdwBuffer[4] = 0xc3d2e1f0lu + e;
   return;
}


For the cdkey I am using 1275402843823, and the client/server tokens are both 1.
I get the results 17 ae 98 52 04 ef 56 with my function, and 4A 6A 64 5F 9A 25 64 3C 62 BD E9 4C 8F 27 E6 0B 3B E0 1C 91 with bncsutil.
:/

[Kp edit: broke up long line.  When will you people learn?]
<3 Zorm
Quote[01:08:05 AM] <@Zorm> haha, me get pussy? don't kid yourself quik
Scio te esse, sed quid sumne? :P

Yegg

I haven't done any of this stuff in quite some time, but I think you should use a slightly modified version of HashData that a friend and I worked on a while back.

void data_hash (unsigned long *result, const void *src, const int len) {
    unsigned long a = 0x67452301lu;
    unsigned long b = 0xefcdab89lu;
    unsigned long c = 0x98badcfelu;
    unsigned long d = 0x10325476lu;
    unsigned long e = 0xc3d2e1f0lu;
    unsigned long g;
    int i;

    unsigned char bBuffer [320] = {0};
    memcpy (bBuffer, src, len);
    unsigned long *lpdwBuffer = (unsigned long *) bBuffer;

    for (i = 0; i < 80; ++i) {
if (i < 64)
lpdwBuffer [i + 16] = ROL (1, (lpdwBuffer [i] ^ lpdwBuffer [i + 8] ^ lpdwBuffer [i + 2] ^ lpdwBuffer [i + 13]) % 32);
if (i < 20)
g = lpdwBuffer[i] + ROL (a, 5) + e + ((b & c) | (~b & d)) + 0x5a827999lu;
else if (i < 40)
g = (d ^ c ^ b) + e + ROL (g, 5) + lpdwBuffer[i] + 0x6ed9eba1lu;
else if (i < 60)
g = lpdwBuffer[i] + ROL (g, 5) + e + ((c & b) | (d & c) | (d & b)) - 0x70e44324lu;
else
g = (d ^ c ^ b) + e + ROL (g, 5) + lpdwBuffer[i] - 0x359d3e2alu;
e = d;
d = c;
c = ROL (b, 30);
b = a;
a = g;
    }

    result [0] = 0x67452301lu + g;
    result [1] = 0xefcdab89lu + b;
    result [2] = 0x98badcfelu + c;
    result [3] = 0x10325476lu + d;
    result [4] = 0xc3d2e1f0lu + e;
}


I'm not sure how much more "efficient" you want to call it, but since you seem to be into the "best method" for things, I figured you'd be interested in this.

Here's an example of how to use it to hash a password:

unsigned char *password_hash (const char *pass, unsigned long clientkey, unsigned long serverkey) {
    unsigned long result [7] = {clientkey, serverkey};
    unsigned char *hash = malloc (20);

    data_hash (result + 2, pass, strlen (pass));
    data_hash (result + 2, result, 28);

    memcpy (hash, result + 2, 20);
   
    return hash;
}

brew

#2
Wow, thank you for that function. It works just as well (if not better) then it looks. Much more cleaner alternative to calcHashBuf and HashData (I forget where I found those...) BTW, I found my hashing problem now that I was able to rule out making a mistake with the actual hashing of the data (had another look at my public/private values).

EDIT***
IIRC you made a 11-12 line starcraft cdkey decoder function a while back, could you post that?
<3 Zorm
Quote[01:08:05 AM] <@Zorm> haha, me get pussy? don't kid yourself quik
Scio te esse, sed quid sumne? :P

Hdx

int c;
int hashkey = 0x13AC9741;
int seq[] = {6, 0, 2, 9, 3, 11, 1, 7, 5, 4, 10, 8};
char[] key = new char[12];
for (short i = 11; i >= 0; i--) {
c = cdkey.charAt(seq[i]);
if (c <= '7') {
c ^= (byte) (hashkey & 7);
hashkey >>>= 3;
} else c ^= (byte)(i & 1);
key[i] = (char)c;
}
Should be simple to convert to c
~Hdx

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

Yegg

According to standard, I believe what Hdx posted is C++, but it's pretty much the same method I used.

devcode

The code you posted is C++ as well.

Quote from: Yegg on September 17, 2007, 03:21 PM
According to standard, I believe what Hdx posted is C++, but it's pretty much the same method I used.

Hdx

You guts should know better, almost everything i post is Java <3s
I was working with JBLS at the time and figured I'd go in an nab this part out for you.
~Hdx

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

Yegg

Quote from: devcode on September 17, 2007, 04:24 PM
The code you posted is C++ as well.

Explain how? I'm not a pro with C/++, but I'm not sure how my code is C++.

brew

There is no signed right shift operator in the ANSI C standard IIRC
<3 Zorm
Quote[01:08:05 AM] <@Zorm> haha, me get pussy? don't kid yourself quik
Scio te esse, sed quid sumne? :P

Yegg

Quote from: brew on September 17, 2007, 09:38 PM
There is no signed right shift operator in the ANSI C standard IIRC

I can't find anything to back that up. If there is no right shift, then why would there be a left shift?

Barabajagal

Right Signed Shift != Right Shift.

Kp

C does not need a >>> operator, because C has proper unsigned types.  Java needs both >> and >>> because it insists on using only signed types.  C can use >> to mean signed or unsigned, depending on the type of the variable being shifted.  Just look at the assembly for shifting a signed int versus shifting an unsigned int.
[19:20:23] (BotNet) <[vL]Kp> Any idiot can make a bot with CSB, and many do!

Barabajagal

In which case, Blake's code is not C. Hint: It's Java.

devcode

Well for one, you have

unsigned long *lpdwBuffer = (unsigned long *) bBuffer;

this wont compile in C since you have to declare all variables before you do any real work. In other news, warden decryption iz a beotch.

Quote from: Yegg on September 17, 2007, 08:50 PM
Quote from: devcode on September 17, 2007, 04:24 PM
The code you posted is C++ as well.

Explain how? I'm not a pro with C/++, but I'm not sure how my code is C++.

Camel

Quote from: devcode on September 17, 2007, 11:57 PMunsigned long *lpdwBuffer = (unsigned long *) bBuffer;

this wont compile in C since you have to declare all variables before you do any real work. In other news, warden decryption iz a beotch.

Strictly speaking, that isn't ANSI C. I'm not aware of any C compilers that are still maintained and still enforce that silly rule without specific instructions to do so ('strict mode').