Current News
Archived News
Search News
Discussion Forum


Old Forum
Install Programs More Downloads...
Troubleshooting
Source Code
Format Specs.
Misc. Information
Non-SF Stuff
Links




1 // License information for this code is in license.txt
3 #include <string.h>
4 #include <ctype.h>
5 #include "MpqCrypt.h"
6 #include "SFTypes.h"
8 bool bCryptTableInit = false;
9 UInt32 dwCryptTable[0x500];
10 UInt32 dwHashTableKey;
11 UInt32 dwBlockTableKey;
13 // The InitCryptTable, HashString, DecryptData, and DetectFileKey are
14 // based on the versions in StormLib which were written by Ladislav 
15 // Zezula, but may have been modified somewhat by Quantam or ShadowFlare.
16 bool InitCryptTable()
17 {
18         UInt32 seed   = 0x00100001;
19         UInt32 index1 = 0;
20         UInt32 index2 = 0;
21         int   i;
22                 
23         if (!bCryptTableInit)
24         {
25                  for(index1 = 0; index1 < 0x100; index1++)
26                  {
27                           for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
28                           {
29                                         UInt32 temp1, temp2;
30                 
31                                         seed  = (seed * 125 + 3) % 0x2AAAAB;
32                                         temp1 = (seed & 0xFFFF) << 0x10;
33                 
34                                         seed  = (seed * 125 + 3) % 0x2AAAAB;
35                                         temp2 = (seed & 0xFFFF);
36                 
37                                         dwCryptTable[index2] = (temp1 | temp2);
38                           }
39                  }
41                 bCryptTableInit = true;
42         }
44         return true;
45 }
47 UInt32 HashString(const char *lpszString, UInt32 dwHashType)
48 {
49     UInt32  seed1 = 0x7FED7FED;
50     UInt32  seed2 = 0xEEEEEEEE;
51     int    ch;
53         char szNull = 0;
54         if (!lpszString)
55                 lpszString = &szNull;
57         if (dwHashType==HASH_KEY)
58                 while (strchr(lpszString,'\\')!=NULL) lpszString = strchr(lpszString,'\\')+1;
59     while (*lpszString != 0)
60     {
61         ch = toupper(*lpszString++);
63         seed1 = dwCryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
64         seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
65     }
67     return seed1;
68 }
70 // The EncryptData function is based on the DecryptData function by
71 // Ladislav Zezula, but adapted by Quantam to encrypt rather than decrypt.
72 bool EncryptData(UInt8 *lpbyBuffer, UInt32 dwLength, UInt32 dwKey)
73 {
74     UInt32 *lpdwBuffer = (UInt32 *)lpbyBuffer;
75     UInt32 seed = 0xEEEEEEEE;
76     UInt32 ch;
78         if (!lpbyBuffer)
79                 return false;
81     // Round to DWORDs
82     dwLength >>= 2;
84     while(dwLength-- > 0)
86     {
87         seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
88         ch = *lpdwBuffer ^ (dwKey + seed);
90         dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
91         seed = *lpdwBuffer + seed + (seed << 5) + 3;
93                 *lpdwBuffer++ = ch;
94     }
96          return true;
97 }
99 bool DecryptData(UInt8 *lpbyBuffer, UInt32 dwLength, UInt32 dwKey)
101         UInt32 *lpdwBuffer = (UInt32 *)lpbyBuffer;
102     UInt32 seed = 0xEEEEEEEE;
103     UInt32 ch;
105         if (!lpbyBuffer)
106                 return false;
108     // Round to DWORDs
109     dwLength >>= 2;
111     while(dwLength-- > 0)
112     {
113         seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
114         ch = *lpdwBuffer ^ (dwKey + seed);
116         dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
117         seed = ch + seed + (seed << 5) + 3;
119                 *lpdwBuffer++ = ch;
120     }
122          return true;
125 //-----------------------------------------------------------------------------
126 // Functions tries to get file decryption key. The trick comes from block
127 // positions which are stored at the begin of each compressed file. We know the
128 // file size, that means we know number of blocks that means we know the first
129 // DWORD value in block position. And if we know encrypted and decrypted value,
130 // we can find the decryption key !!!
131 //
132 // hf    - MPQ file handle
133 // block - DWORD array of block positions
134 // ch    - Decrypted value of the first block pos
136 UInt32 DetectFileSeed(UInt32 * block, UInt32 decrypted, UInt32 blocksize)
138     UInt32 saveSeed1;
139     UInt32 temp = *block ^ decrypted;    // temp = seed1 + seed2
140                                         // temp = seed1 + stormBuffer[0x400 + (seed1 & 0xFF)] + 0xEEEEEEEE
141     temp -= 0xEEEEEEEE;                 // temp = seed1 + stormBuffer[0x400 + (seed1 & 0xFF)]
142     
144     for(int i = 0; i < 0x100; i++)      // Try all 256 possibilities
145     {
146         UInt32 seed1;
147         UInt32 seed2 = 0xEEEEEEEE;
148         UInt32 ch;
150         // Try the first DWORD (We exactly know the value)
151         seed1  = temp - dwCryptTable[0x400 + i];
152         seed2 += dwCryptTable[0x400 + (seed1 & 0xFF)];
153         ch     = block[0] ^ (seed1 + seed2);
155         if(ch != decrypted)
156             continue;
158         saveSeed1 = seed1 + 1;
160         // If OK, continue and test the second value. We don't know exactly the value,
161         // but we know that the second one has a value less than or equal to the
162                 // size of the block position table plus the block size
163         seed1  = ((~seed1 << 0x15) + 0x11111111) | (seed1 >> 0x0B);
164         seed2  = ch + seed2 + (seed2 << 5) + 3;
166         seed2 += dwCryptTable[0x400 + (seed1 & 0xFF)];
167         ch     = block[1] ^ (seed1 + seed2);
169         if(ch <= decrypted + blocksize)
170             return saveSeed1;
171     }
172     return 0;