/* This file is meant as a swift kick in the pants to upgrade the billing server * encryption scheme. Using the following code, anyone may reverse the supposedly * one-way password protection. * To the layman, it is important to note that passwords of odd length cannot be * reversed back to the input you use to enter the game, without some additional * work. Thus, it is a secure practice to change your password to anything with * an odd number of characters. Players may use equivalent passwords to enter, * and so this is not a "quick fix". * - Catid@pacbell.net */ BYTE SimpleChecksum(BYTE * Buffer, DWORD Length) { BYTE Checksum = 0; for (DWORD i = 0; i < Length; i++) Checksum ^= Buffer[i]; return Checksum; } // Billing Server password encryption void HashPassword(BYTE * Password) { size_t StrLen = strlen((char*)Password); BYTE Factor = SimpleChecksum(Password, StrLen); BYTE Char; for (DWORD L = 0; L < StrLen; L++) { Char = Password[L] ^ Factor; Factor = (Factor ^ (Char << (Char & 3))) & 255; if (Char == 0) Char = 0xED; Password[L] = Char; } } // Billing Server password decryption void InverseHash(size_t StrLen, BYTE * In, BYTE * Out, BYTE Key) { for (DWORD L = 0; L < StrLen; L++) { BYTE Char = In[L]; if (Char == 0xED) Char = 0; Out[L] = Char ^ (BYTE)Key; Key = (Key ^ (Char << (Char & 3))) & 255; } } bool InvalidPasswordCharacter(BYTE c) { if ((c < 33) || (c > 126)) return true; return false; } void DecryptHashedPassword(BYTE * Password) { size_t StrLen = strlen((char*)Password); BYTE * Buffer = new BYTE[StrLen + 1]; Buffer[StrLen] = 0; // Passwords of EVEN length are very easy to crack. if (StrLen % 2 != 0) { // Guess and check to find one of the solutions for (int i = 0; i < 256; i++) { // Generate a possible solution InverseHash(StrLen, Password, Buffer, i); // Compare resultant hash with given hash BYTE Char, Key = i; bool OK = true; for (DWORD L = 0; L < StrLen; L++) { Char = Buffer[L]; if (InvalidPasswordCharacter(Char)) { OK = false; break; } Char ^= Key; Key = (Key ^ (Char << (Char & 3))) & 255; if (Char == 0) Char = 0xED; if (Char != Password[L]) { OK = false; break; } } if (OK) break; } } else { // Generate password checksum InverseHash(StrLen, Password, Buffer, 0); // Generate actual password InverseHash(StrLen, Password, Buffer, SimpleChecksum(Buffer, StrLen)); } memcpy(Password, Buffer, StrLen); delete Buffer; }