diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/Apps/plClient/winmain.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/Apps/plClient/winmain.cpp index 608dde6c..06f9a76d 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/Apps/plClient/winmain.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/Apps/plClient/winmain.cpp @@ -200,13 +200,25 @@ struct LoginDialogParam { wchar accountName[kMaxAccountNameLength]; }; +// List of hash styles we are going to test against the server +// ... this method of trying multiple hashes against the server has risks of being more compromised than just testing one hash. +// ... So, if you know your unique client is only going to connect to your server then it would be wise to limit the testing to one hash. +// ... Which can be done simply by setting FIRST_PASSWORD_HASH and LAST_PASSWORD_HASH to the hash that you use. +enum +{ + kPasswordHashSHA0, + kPasswordHashSHA1 +}; +static const int FIRST_PASSWORD_HASH = kPasswordHashSHA1; +static const int LAST_PASSWORD_HASH = kPasswordHashSHA0; + bool AuthenticateNetClientComm(ENetError* result, HWND parentWnd); bool IsExpired(); bool GetDisksProperty(HANDLE hDevice, PSTORAGE_DEVICE_DESCRIPTOR pDevDesc); void GetOldCryptKey(UInt32* cryptKey, unsigned size); void GetCryptKey(UInt32* cryptKey, unsigned size); static void SaveUserPass (char *username, char *password, ShaDigest *pNamePassHash, bool remember_password, - bool fromGT); + int whichHash); static void LoadUserPass (const wchar *accountName, char *username, ShaDigest *pNamePassHash, bool *pRemember, bool fromGT, int *pFocus); static void AuthFailedStrings (ENetError authError, bool fromGT, @@ -322,11 +334,22 @@ static bool TGRunLoginDialog (const wchar *accountName, bool fromGT) if (Remember[0] == 'y') bRemember = true; - SaveUserPass (Username, Password, &NamePassHash, bRemember, fromGT); - - // Do login & see if it failed + // cycle through the hash types until we find one that matches or errors out ENetError auth; - bool cancelled = AuthenticateNetClientComm(&auth, NULL); + bool cancelled; + for (int whichHash=FIRST_PASSWORD_HASH; whichHash >= LAST_PASSWORD_HASH; whichHash-- ) + { + SaveUserPass (Username, Password, &NamePassHash, bRemember, whichHash); + + // Do login & see if it failed + cancelled = AuthenticateNetClientComm(&auth, NULL); + // if the password was successful then go to the end processing + if (IS_NET_SUCCESS(auth) && !cancelled) + break; + // if it was cancelled or any error other than wrong password then go to end processing + if (cancelled || auth != kNetErrAuthenticationFailed) + break; + } if (IS_NET_SUCCESS (auth) && !cancelled) break; @@ -933,18 +956,6 @@ void DebugMsgF(const char* format, ...) #endif } -static bool IsMachineLittleEndian() { - int i = 1; - char *p = (char *) &i; - if (p[0] == 1) // Lowest address contains the least significant byte - return true; - else - return false; -} - -inline static dword ToBigEndian (dword value) { - return ((value) << 24) | ((value & 0x0000ff00) << 8) | ((value & 0x00ff0000) >> 8) | ((value) >> 24); -} static void AuthFailedStrings (ENetError authError, bool fromGT, const char **ppStr1, const char **ppStr2, @@ -1081,7 +1092,7 @@ BOOL CALLBACK UruTOSDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM l } static void SaveUserPass (char *username, char *password, ShaDigest *pNamePassHash, bool remember_password, - bool fromGT) + int whichHash) { UInt32 cryptKey[4]; ZeroMemory(cryptKey, sizeof(cryptKey)); @@ -1097,7 +1108,31 @@ static void SaveUserPass (char *username, char *password, ShaDigest *pNamePassHa if (StrCmp(password, FAKE_PASS_STRING) != 0) { StrToUnicode(wpassword, password, arrsize(wpassword)); - CryptHashPassword(wusername, wpassword, pNamePassHash); + + switch( whichHash ) + { + case kPasswordHashSHA1: + CryptDigest( + kCryptSha1, + pNamePassHash, + StrLen(password) * sizeof(password[0]), + password + ); + + // switch the endianness of the hash to big endian + // NOTE: this is legacy from GameTap days to match GameTap's endianness + pNamePassHash->data[0] = hsUNSWAP32(pNamePassHash->data[0]); + pNamePassHash->data[1] = hsUNSWAP32(pNamePassHash->data[1]); + pNamePassHash->data[2] = hsUNSWAP32(pNamePassHash->data[2]); + pNamePassHash->data[3] = hsUNSWAP32(pNamePassHash->data[3]); + pNamePassHash->data[4] = hsUNSWAP32(pNamePassHash->data[4]); + break; + + case kPasswordHashSHA0: + default: + CryptHashPassword(wusername, wpassword, pNamePassHash); + break; + } } NetCommSetAccountUsernamePassword(wusername, *pNamePassHash); @@ -1106,28 +1141,26 @@ static void SaveUserPass (char *username, char *password, ShaDigest *pNamePassHa else NetCommSetAuthTokenAndOS(nil, L"win"); - if (!fromGT) { - wchar fileAndPath[MAX_PATH]; - PathGetInitDirectory(fileAndPath, arrsize(fileAndPath)); - PathAddFilename(fileAndPath, fileAndPath, L"login.dat", arrsize(fileAndPath)); + wchar fileAndPath[MAX_PATH]; + PathGetInitDirectory(fileAndPath, arrsize(fileAndPath)); + PathAddFilename(fileAndPath, fileAndPath, L"login.dat", arrsize(fileAndPath)); #ifndef PLASMA_EXTERNAL_RELEASE - // internal builds can use the local init directory - wchar localFileAndPath[MAX_PATH]; - StrCopy(localFileAndPath, L"init\\login.dat", arrsize(localFileAndPath)); - if (PathDoesFileExist(localFileAndPath)) - StrCopy(fileAndPath, localFileAndPath, arrsize(localFileAndPath)); + // internal builds can use the local init directory + wchar localFileAndPath[MAX_PATH]; + StrCopy(localFileAndPath, L"init\\login.dat", arrsize(localFileAndPath)); + if (PathDoesFileExist(localFileAndPath)) + StrCopy(fileAndPath, localFileAndPath, arrsize(localFileAndPath)); #endif - hsStream* stream = plEncryptedStream::OpenEncryptedFileWrite(fileAndPath, cryptKey); - if (stream) - { - stream->Write(sizeof(cryptKey), cryptKey); - stream->WriteSafeString(username); - stream->Writebool(remember_password); - if (remember_password) - stream->Write(sizeof(pNamePassHash->data), pNamePassHash->data); - stream->Close(); - delete stream; - } + hsStream* stream = plEncryptedStream::OpenEncryptedFileWrite(fileAndPath, cryptKey); + if (stream) + { + stream->Write(sizeof(cryptKey), cryptKey); + stream->WriteSafeString(username); + stream->Writebool(remember_password); + if (remember_password) + stream->Write(sizeof(pNamePassHash->data), pNamePassHash->data); + stream->Close(); + delete stream; } } @@ -1418,11 +1451,22 @@ BOOL CALLBACK UruLoginDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM GetDlgItemText(hwndDlg, IDC_URULOGIN_PASSWORD, password, kMaxPasswordLength); remember_password = (IsDlgButtonChecked(hwndDlg, IDC_URULOGIN_REMEMBERPASS) == BST_CHECKED); - SaveUserPass (username, password, &namePassHash, remember_password, loginParam->fromGT); - + // cycle through the hash types until we find one that matches or errors out LoginDialogParam loginParam; - MemSet(&loginParam, 0, sizeof(loginParam)); - bool cancelled = AuthenticateNetClientComm(&loginParam.authError, hwndDlg); + bool cancelled; + for (int whichHash=FIRST_PASSWORD_HASH; whichHash >= LAST_PASSWORD_HASH; whichHash-- ) + { + SaveUserPass (username, password, &namePassHash, remember_password, whichHash); + + MemSet(&loginParam, 0, sizeof(loginParam)); + cancelled = AuthenticateNetClientComm(&loginParam.authError, hwndDlg); + // if the password was successful then go to the end processing + if (IS_NET_SUCCESS(loginParam.authError) && !cancelled) + break; + // if it was cancelled or any error other than wrong password then go to end processing + if (cancelled || loginParam.authError != kNetErrAuthenticationFailed) + break; + } if (IS_NET_SUCCESS(loginParam.authError) && !cancelled) EndDialog(hwndDlg, ok);