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




CommitLineData
7214af3e 1// License information for this code is in license.txt
2
3#include <string.h>
4#include <ctype.h>
5#include "MpqCrypt.h"
6#include "SFTypes.h"
7
8bool bCryptTableInit = false;
9UInt32 dwCryptTable[0x500];
10UInt32 dwHashTableKey;
11UInt32 dwBlockTableKey;
12
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.
16bool 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 }
40
41 bCryptTableInit = true;
42 }
43
44 return true;
45}
46
47UInt32 HashString(const char *lpszString, UInt32 dwHashType)
48{
49 UInt32 seed1 = 0x7FED7FED;
50 UInt32 seed2 = 0xEEEEEEEE;
51 int ch;
52
53 char szNull = 0;
54 if (!lpszString)
55 lpszString = &szNull;
56
57 if (dwHashType==HASH_KEY)
58 while (strchr(lpszString,'\\')!=NULL) lpszString = strchr(lpszString,'\\')+1;
59 while (*lpszString != 0)
60 {
61 ch = toupper(*lpszString++);
62
63 seed1 = dwCryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
64 seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
65 }
66
67 return seed1;
68}
69
70// The EncryptData function is based on the DecryptData function by
71// Ladislav Zezula, but adapted by Quantam to encrypt rather than decrypt.
72bool EncryptData(UInt8 *lpbyBuffer, UInt32 dwLength, UInt32 dwKey)
73{
74 UInt32 *lpdwBuffer = (UInt32 *)lpbyBuffer;
75 UInt32 seed = 0xEEEEEEEE;
76 UInt32 ch;
77
78 if (!lpbyBuffer)
79 return false;
80
81 // Round to DWORDs
82 dwLength >>= 2;
83
84 while(dwLength-- > 0)
85
86 {
87 seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
88 ch = *lpdwBuffer ^ (dwKey + seed);
89
90 dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
91 seed = *lpdwBuffer + seed + (seed << 5) + 3;
92
93 *lpdwBuffer++ = ch;
94 }
95
96 return true;
97}
98
99bool DecryptData(UInt8 *lpbyBuffer, UInt32 dwLength, UInt32 dwKey)
100{
101 UInt32 *lpdwBuffer = (UInt32 *)lpbyBuffer;
102 UInt32 seed = 0xEEEEEEEE;
103 UInt32 ch;
104
105 if (!lpbyBuffer)
106 return false;
107
108 // Round to DWORDs
109 dwLength >>= 2;
110
111 while(dwLength-- > 0)
112 {
113 seed += dwCryptTable[0x400 + (dwKey & 0xFF)];
114 ch = *lpdwBuffer ^ (dwKey + seed);
115
116 dwKey = ((~dwKey << 0x15) + 0x11111111) | (dwKey >> 0x0B);
117 seed = ch + seed + (seed << 5) + 3;
118
119 *lpdwBuffer++ = ch;
120 }
121
122 return true;
123}
124
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
135
136UInt32 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)]
142
143
144 for(int i = 0; i < 0x100; i++) // Try all 256 possibilities
145 {
146 UInt32 seed1;
147 UInt32 seed2 = 0xEEEEEEEE;
148 UInt32 ch;
149
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);
154
155 if(ch != decrypted)
156 continue;
157
158 saveSeed1 = seed1 + 1;
159
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;
165
166 seed2 += dwCryptTable[0x400 + (seed1 & 0xFF)];
167 ch = block[1] ^ (seed1 + seed2);
168
169 if(ch <= decrypted + blocksize)
170 return saveSeed1;
171 }
172 return 0;
173}