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 Small banner for links to this site: |
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;
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;
31 seed = (seed * 125 + 3) % 0x2AAAAB;
32 temp1 = (seed & 0xFFFF) << 0x10;
34 seed = (seed * 125 + 3) % 0x2AAAAB;
35 temp2 = (seed & 0xFFFF);
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)
100 {
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;
123 }
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)
137 {
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)]
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;
173 }
|