From e5000fa577480284a9fb70a44d83bfaf3fe7812e Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Mon, 4 Jun 2012 09:38:15 -0300 Subject: [PATCH] encrypt password and account number * the encryption uses a unique machine key, this means that if anyone steals config.otml with a saved password, he will not be able to decrypt the password without the machine UUID key * the encrypt uses a simple XOR encryption method, encoded with base64 and adler32 summing --- modules/client_entergame/characterlist.lua | 10 +- modules/client_entergame/entergame.lua | 39 ++--- modules/core_lib/globals.lua | 3 + src/framework/CMakeLists.txt | 3 +- src/framework/luafunctions.cpp | 5 + src/framework/net/inputmessage.cpp | 4 +- src/framework/net/outputmessage.cpp | 4 +- src/framework/stdext/math.h | 8 +- src/framework/stdext/string.h | 6 +- src/framework/util/crypt.cpp | 161 +++++++++++++++++++++ src/framework/util/crypt.h | 38 +++++ src/framework/{net => util}/rsa.cpp | 0 src/framework/{net => util}/rsa.h | 0 13 files changed, 249 insertions(+), 32 deletions(-) create mode 100644 src/framework/util/crypt.cpp create mode 100644 src/framework/util/crypt.h rename src/framework/{net => util}/rsa.cpp (100%) rename src/framework/{net => util}/rsa.h (100%) diff --git a/modules/client_entergame/characterlist.lua b/modules/client_entergame/characterlist.lua index c0454d30..2887353f 100644 --- a/modules/client_entergame/characterlist.lua +++ b/modules/client_entergame/characterlist.lua @@ -40,7 +40,7 @@ local function tryLogin(charInfo, tries) CharacterList.destroyLoadBox() - g_game.loginWorld(EnterGame.account, EnterGame.password, charInfo.worldName, charInfo.worldHost, charInfo.worldPort, charInfo.characterName) + g_game.loginWorld(G.account, G.password, charInfo.worldName, charInfo.worldHost, charInfo.worldPort, charInfo.characterName) loadBox = displayCancelBox(tr('Please wait'), tr('Connecting to game server...')) connect(loadBox, { onCancel = function() @@ -81,6 +81,10 @@ function CharacterList.init() connect(g_game, { onConnectionError = onGameConnectionError }) connect(g_game, { onGameStart = CharacterList.destroyLoadBox }) connect(g_game, { onGameEnd = CharacterList.showAgain }) + + if G.characters then + CharacterList.create(G.characters, G.premDays) + end end function CharacterList.terminate() @@ -100,7 +104,9 @@ function CharacterList.terminate() end function CharacterList.create(characters, premDays) - CharacterList.show() + G.characters = characters + G.premDays = premDays + characterList:destroyChildren() local accountStatusLabel = charactersWindow:getChildById('accountStatusLabel') diff --git a/modules/client_entergame/entergame.lua b/modules/client_entergame/entergame.lua index 67953e3c..3a984fb5 100644 --- a/modules/client_entergame/entergame.lua +++ b/modules/client_entergame/entergame.lua @@ -3,8 +3,6 @@ EnterGame = { } -- private variables local loadBox local enterGame -local motdNumber -local motdMessage local motdButton local enterGameButton @@ -29,15 +27,15 @@ local function onError(protocol, message, connectionError) end local function onMotd(protocol, motd) - motdNumber = tonumber(motd:sub(0, motd:find("\n"))) - motdMessage = motd:sub(motd:find("\n") + 1, #motd) + G.motdNumber = tonumber(motd:sub(0, motd:find("\n"))) + G.motdMessage = motd:sub(motd:find("\n") + 1, #motd) motdButton:show() end local function onCharacterList(protocol, characters, premDays) if enterGame:getChildById('rememberPasswordBox'):isChecked() then - Settings.set('account', EnterGame.account) - Settings.set('password', EnterGame.password) + Settings.set('account', g_crypt.encrypt(G.account)) + Settings.set('password', g_crypt.encrypt(G.password)) Settings.set('autologin', enterGame:getChildById('autoLoginBox'):isChecked()) else clearAccountFields() @@ -47,11 +45,12 @@ local function onCharacterList(protocol, characters, premDays) loadBox = nil CharacterList.create(characters, premDays) + CharacterList.show() local lastMotdNumber = Settings.getNumber("motd") - if motdNumber and motdNumber ~= lastMotdNumber then + if G.motdNumber and G.motdNumber ~= lastMotdNumber then Settings.set("motd", motdNumber) - local motdBox = displayInfoBox(tr('Message of the day'), motdMessage) + local motdBox = displayInfoBox(tr('Message of the day'), G.motdMessage) connect(motdBox, { onOk = CharacterList.show }) CharacterList.hide() end @@ -65,8 +64,12 @@ function EnterGame.init() motdButton:hide() Keyboard.bindKeyDown('Ctrl+G', EnterGame.openWindow) - local account = Settings.get('account') - local password = Settings.get('password') + if G.motdNumber then + motdButton:show() + end + + local account = g_crypt.decrypt(Settings.get('account')) + local password = g_crypt.decrypt(Settings.get('password')) local host = Settings.get('host') local port = Settings.get('port') local autologin = Settings.getBoolean('autologin') @@ -119,14 +122,14 @@ function EnterGame.openWindow() end function EnterGame.doLogin() - EnterGame.account = enterGame:getChildById('accountNameTextEdit'):getText() - EnterGame.password = enterGame:getChildById('accountPasswordTextEdit'):getText() - EnterGame.host = enterGame:getChildById('serverHostTextEdit'):getText() - EnterGame.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText()) + G.account = enterGame:getChildById('accountNameTextEdit'):getText() + G.password = enterGame:getChildById('accountPasswordTextEdit'):getText() + G.host = enterGame:getChildById('serverHostTextEdit'):getText() + G.port = tonumber(enterGame:getChildById('serverPortTextEdit'):getText()) EnterGame.hide() - Settings.set('host', EnterGame.host) - Settings.set('port', EnterGame.port) + Settings.set('host', G.host) + Settings.set('port', G.port) local protocolLogin = ProtocolLogin.create() protocolLogin.onError = onError @@ -140,9 +143,9 @@ function EnterGame.doLogin() EnterGame.show() end }) - protocolLogin:login(EnterGame.host, EnterGame.port, EnterGame.account, EnterGame.password) + protocolLogin:login(G.host, G.port, G.account, G.password) end function EnterGame.displayMotd() - displayInfoBox(tr('Message of the day'), motdMessage) + displayInfoBox(tr('Message of the day'), G.motdMessage) end diff --git a/modules/core_lib/globals.lua b/modules/core_lib/globals.lua index 5f39e372..a5f41813 100644 --- a/modules/core_lib/globals.lua +++ b/modules/core_lib/globals.lua @@ -4,6 +4,9 @@ importStyle = g_ui.importStyle importFont = g_fonts.importFont setDefaultFont = g_fonts.setDefaultFont +-- G is used as a global table to save variables in memory between reloads +G = G or {} + function loadUI(otui, parent) local otuiFilePath = resolvepath(otui, 2) return g_ui.loadUI(otuiFilePath, parent) diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 7c3bafae..67e9e3cc 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -171,6 +171,8 @@ SET(framework_SOURCES ${framework_SOURCES} # framework util ${CMAKE_CURRENT_LIST_DIR}/util/color.cpp + ${CMAKE_CURRENT_LIST_DIR}/util/crypt.cpp + ${CMAKE_CURRENT_LIST_DIR}/util/rsa.cpp # framework core ${CMAKE_CURRENT_LIST_DIR}/core/adaptativeframecounter.cpp @@ -189,7 +191,6 @@ SET(framework_SOURCES ${framework_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/net/inputmessage.cpp ${CMAKE_CURRENT_LIST_DIR}/net/outputmessage.cpp ${CMAKE_CURRENT_LIST_DIR}/net/protocol.cpp - ${CMAKE_CURRENT_LIST_DIR}/net/rsa.cpp ${CMAKE_CURRENT_LIST_DIR}/net/server.cpp # framework platform diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index 04dfdb70..31fc715e 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -33,6 +33,7 @@ #include #include #include +#include void Application::registerLuaFunctions() { @@ -46,6 +47,10 @@ void Application::registerLuaFunctions() g_lua.bindGlobalFunction("colortostring", [](const Color& v) { return stdext::to_string(v); }); g_lua.bindGlobalFunction("sizetostring", [](const Size& v) { return stdext::to_string(v); }); + g_lua.registerStaticClass("g_crypt"); + g_lua.bindClassStaticFunction("g_crypt", "encrypt", Crypt::encrypt); + g_lua.bindClassStaticFunction("g_crypt", "decrypt", Crypt::decrypt); + // Event g_lua.registerClass(); g_lua.bindClassMemberFunction("cancel", &Event::cancel); diff --git a/src/framework/net/inputmessage.cpp b/src/framework/net/inputmessage.cpp index 771ee61a..a4f1839c 100644 --- a/src/framework/net/inputmessage.cpp +++ b/src/framework/net/inputmessage.cpp @@ -21,7 +21,7 @@ */ #include "inputmessage.h" -#include "rsa.h" +#include InputMessage::InputMessage() { @@ -105,7 +105,7 @@ void InputMessage::setHeaderSize(uint16 size) bool InputMessage::readChecksum() { uint32_t receivedCheck = getU32(); - uint32 checksum = stdext::generate_adler_checksum(m_buffer + m_readPos, getUnreadSize()); + uint32 checksum = stdext::adler32(m_buffer + m_readPos, getUnreadSize()); return receivedCheck == checksum; } diff --git a/src/framework/net/outputmessage.cpp b/src/framework/net/outputmessage.cpp index 0ef9c22e..3c2955ac 100644 --- a/src/framework/net/outputmessage.cpp +++ b/src/framework/net/outputmessage.cpp @@ -21,7 +21,7 @@ */ #include -#include "rsa.h" +#include OutputMessage::OutputMessage() { @@ -96,7 +96,7 @@ void OutputMessage::encryptRSA(int size, const std::string& key) void OutputMessage::writeChecksum() { - uint32 checksum = stdext::generate_adler_checksum(m_buffer + m_headerPos, m_messageSize); + uint32 checksum = stdext::adler32(m_buffer + m_headerPos, m_messageSize); assert(m_headerPos - 4 >= 0); m_headerPos -= 4; stdext::writeLE32(m_buffer + m_headerPos, checksum); diff --git a/src/framework/stdext/math.h b/src/framework/stdext/math.h index e2d3d136..ca94673e 100644 --- a/src/framework/stdext/math.h +++ b/src/framework/stdext/math.h @@ -28,7 +28,7 @@ namespace stdext { -inline uint32 generate_adler_checksum(uint8 *buffer, uint16 size) { +inline uint32 adler32(const uint8 *buffer, uint16 size) { register uint32 a = 1, b = 0, tlen; while(size > 0) { tlen = size > 5552 ? 5552 : size; @@ -57,9 +57,9 @@ inline uint32 to_power_of_two(uint32 v) { return r; } -inline uint16 readLE16(uchar *addr) { return (uint16)addr[1] << 8 | addr[0]; } -inline uint32 readLE32(uchar *addr) { return (uint32)readLE16(addr + 2) << 16 | readLE16(addr); } -inline uint64 readLE64(uchar *addr) { return (uint64)readLE32(addr + 4) << 32 | readLE32(addr); } +inline uint16 readLE16(const uchar *addr) { return (uint16)addr[1] << 8 | addr[0]; } +inline uint32 readLE32(const uchar *addr) { return (uint32)readLE16(addr + 2) << 16 | readLE16(addr); } +inline uint64 readLE64(const uchar *addr) { return (uint64)readLE32(addr + 4) << 32 | readLE32(addr); } inline void writeLE16(uchar *addr, uint16 value) { addr[1] = value >> 8; addr[0] = (uint8)value; } inline void writeLE32(uchar *addr, uint32 value) { writeLE16(addr + 2, value >> 16); writeLE16(addr, (uint16)value); } diff --git a/src/framework/stdext/string.h b/src/framework/stdext/string.h index a00a3505..b9a7abf7 100644 --- a/src/framework/stdext/string.h +++ b/src/framework/stdext/string.h @@ -161,7 +161,7 @@ inline std::string date_time_string() { } /// Convert decimal to hexadecimal -inline std::string dec_to_hex(unsigned int num) { +inline std::string dec_to_hex(uint64 num) { std::string str; std::ostringstream o; o << std::hex << num; @@ -170,8 +170,8 @@ inline std::string dec_to_hex(unsigned int num) { } /// Convert hexadecimal to decimal -inline unsigned int hex_to_dec(const std::string& str) { - unsigned int num; +inline uint64 hex_to_dec(const std::string& str) { + uint64 num; std::istringstream i(str); i >> std::hex >> num; return num; diff --git a/src/framework/util/crypt.cpp b/src/framework/util/crypt.cpp new file mode 100644 index 00000000..9a1ea024 --- /dev/null +++ b/src/framework/util/crypt.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "crypt.h" +#include + +#include +#include + +static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static inline bool is_base64(unsigned char c) { return (isalnum(c) || (c == '+') || (c == '/')); } + +std::string Crypt::base64Encode(const std::string& decoded_string) +{ + std::string ret; + int i = 0; + int j = 0; + uint8 char_array_3[3]; + uint8 char_array_4[4]; + int pos = 0; + int len = decoded_string.size(); + + while(len--) { + char_array_3[i++] = decoded_string[pos++]; + if(i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if(i) { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + } + + return ret; +} + +std::string Crypt::base64Decode(const std::string& encoded_string) +{ + int len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + uint8 char_array_4[4], char_array_3[3]; + std::string ret; + + while(len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if(i ==4) { + for(i = 0; i <4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for(i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + if(i) { + for(j = i; j <4; j++) + char_array_4[j] = 0; + + for(j = 0; j <4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for(j = 0; (j < i - 1); j++) + ret += char_array_3[j]; + } + + return ret; +} + +std::string Crypt::xorCrypt(const std::string& buffer, const std::string& key) +{ + std::string out; + out.resize(buffer.size()); + register size_t i, j=0; + for(i=0;i= key.size()) + j = 0; + } + return out; +} + +std::string Crypt::genUUIDKey() +{ + boost::hash uuid_hasher; + std::size_t hash = uuid_hasher(boost::uuids::uuid()); + std::string key; + key.assign((const char *)&hash, sizeof(hash)); + return key; +} + +std::string Crypt::encrypt(const std::string& decrypted_string) +{ + std::string tmp = "0000" + decrypted_string; + uint32 sum = stdext::adler32((const uint8*)decrypted_string.c_str(), decrypted_string.size()); + stdext::writeLE32((uint8*)&tmp[0], sum); + std::string encrypted = base64Encode(xorCrypt(tmp, genUUIDKey())); + return encrypted; +} + +std::string Crypt::decrypt(const std::string& encrypted_string) +{ + std::string decoded = base64Decode(encrypted_string); + std::string tmp = xorCrypt(base64Decode(encrypted_string), genUUIDKey()); + if(tmp.length() >= 4) { + uint32 readsum = stdext::readLE32((const uint8*)tmp.c_str()); + std::string decrypted_string = tmp.substr(4); + uint32 sum = stdext::adler32((const uint8*)decrypted_string.c_str(), decrypted_string.size()); + if(readsum == sum) + return decrypted_string; + } + return std::string(); +} diff --git a/src/framework/util/crypt.h b/src/framework/util/crypt.h new file mode 100644 index 00000000..1f4d7899 --- /dev/null +++ b/src/framework/util/crypt.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010-2012 OTClient + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef CRYPT_H +#define CRYPT_H + +#include "../stdext/types.h" +#include + +namespace Crypt { + std::string base64Encode(const std::string& decoded_string); + std::string base64Decode(const std::string& encoded_string); + std::string xorCrypt(const std::string& buffer, const std::string& key); + std::string genUUIDKey(); + std::string encrypt(const std::string& decrypted_string); + std::string decrypt(const std::string& encrypted_string); +} + +#endif diff --git a/src/framework/net/rsa.cpp b/src/framework/util/rsa.cpp similarity index 100% rename from src/framework/net/rsa.cpp rename to src/framework/util/rsa.cpp diff --git a/src/framework/net/rsa.h b/src/framework/util/rsa.h similarity index 100% rename from src/framework/net/rsa.h rename to src/framework/util/rsa.h