diff --git a/src/LScreens.c b/src/LScreens.c index 2c41cf0f7..04a3bf325 100644 --- a/src/LScreens.c +++ b/src/LScreens.c @@ -522,7 +522,7 @@ static void DirectConnectScreen_Load(struct DirectConnectScreen* s) { Options_UNSAFE_Get("launcher-dc-port", &port); String_InitArray(mppass, mppassBuffer); - Options_GetSecure("launcher-dc-mppass", &mppass, &user); + Options_GetSecure("launcher-dc-mppass", &mppass); String_InitArray(addr, addrBuffer); String_Format2(&addr, "%s:%s", &ip, &port); @@ -568,7 +568,7 @@ static void DirectConnectScreen_StartClient(void* w, int idx) { Options_Set("launcher-dc-username", user); Options_Set("launcher-dc-ip", &ip); Options_Set("launcher-dc-port", &port); - Options_SetSecure("launcher-dc-mppass", mppass, user); + Options_SetSecure("launcher-dc-mppass", mppass); DirectConnectScreen_SetStatus(""); Launcher_StartGame(user, mppass, &ip, &port, &String_Empty); @@ -706,7 +706,7 @@ CC_NOINLINE static void MainScreen_GetResume(struct ResumeInfo* info, cc_bool fu if (!full) return; String_InitArray(info->mppass, info->_mppassBuffer); - Options_GetSecure(ROPT_MPPASS, &info->mppass, &info->user); + Options_GetSecure(ROPT_MPPASS, &info->mppass); info->valid = info->user.length && info->mppass.length && @@ -740,7 +740,7 @@ static void MainScreen_DoLogin(void) { if (GetTokenTask.Base.working) return; Options_Set(LOPT_USERNAME, user); - Options_SetSecure(LOPT_PASSWORD, pass, user); + Options_SetSecure(LOPT_PASSWORD, pass); GetTokenTask_Run(); LLabel_SetConst(&s->lblStatus, "&eSigning in.."); @@ -806,7 +806,7 @@ static void MainScreen_Init(struct LScreen* s_) { String_InitArray(pass, passBuffer); Options_UNSAFE_Get(LOPT_USERNAME, &user); - Options_GetSecure(LOPT_PASSWORD, &pass, &user); + Options_GetSecure(LOPT_PASSWORD, &pass); LInput_SetText(&s->iptUsername, &user); LInput_SetText(&s->iptPassword, &pass); diff --git a/src/LWeb.c b/src/LWeb.c index de3b1782c..c607bd0c4 100644 --- a/src/LWeb.c +++ b/src/LWeb.c @@ -687,7 +687,7 @@ void Session_Load(void) { StringsBuffer_SetLengthBits(&ccCookies, 11); String_InitArray(session, buffer); - Options_GetSecure(LOPT_SESSION, &session, &Game_Username); + Options_GetSecure(LOPT_SESSION, &session); if (!session.length) return; EntryList_Set(&ccCookies, &sessionKey, &session, '='); } @@ -696,7 +696,7 @@ void Session_Save(void) { #if defined CC_BUILD_WIN || defined CC_BUILD_LINUX || defined CC_BUILD_MACOS cc_string session = EntryList_UNSAFE_Get(&ccCookies, &sessionKey, '='); if (!session.length) return; - Options_SetSecure(LOPT_SESSION, &session, &Game_Username); + Options_SetSecure(LOPT_SESSION, &session); #endif } #endif diff --git a/src/Launcher.c b/src/Launcher.c index 28da21857..ccbe92e2e 100644 --- a/src/Launcher.c +++ b/src/Launcher.c @@ -96,7 +96,7 @@ cc_bool Launcher_StartGame(const cc_string* user, const cc_string* mppass, const Options_Set(ROPT_USER, user); Options_Set(ROPT_IP, ip); Options_Set(ROPT_PORT, port); - Options_SetSecure(ROPT_MPPASS, mppass, user); + Options_SetSecure(ROPT_MPPASS, mppass); } /* Save options BEFORE starting new game process */ /* Otherwise can get 'file already in use' errors on startup */ diff --git a/src/Options.c b/src/Options.c index 20b011e43..094398409 100644 --- a/src/Options.c +++ b/src/Options.c @@ -165,30 +165,34 @@ void Options_SetString(const cc_string* key, const cc_string* value) { StringsBuffer_Add(&changedOpts, key); } -void Options_SetSecure(const char* opt, const cc_string* src, const cc_string* key) { +void Options_SetSecure(const char* opt, const cc_string* src) { char data[2000], encData[1500+1]; cc_string tmp, enc; + cc_result res; + if (!src->length) return; String_InitArray(enc, encData); - if (!src->length || !key->length) return; - if (Platform_Encrypt(key, src->buffer, src->length, &enc)) return; - if (enc.length > 1500) Logger_Abort("too large to base64"); + res = Platform_Encrypt(src->buffer, src->length, &enc); + if (res) { Platform_Log2("Error %h encrypting option %c", &res, opt); return; } + if (enc.length > 1500) Logger_Abort("too large to base64"); tmp.buffer = data; tmp.length = Convert_ToBase64(enc.buffer, enc.length, data); tmp.capacity = tmp.length; Options_Set(opt, &tmp); } -void Options_GetSecure(const char* opt, cc_string* dst, const cc_string* key) { +void Options_GetSecure(const char* opt, cc_string* dst) { cc_uint8 data[1500]; int dataLen; cc_string raw; + cc_result res; Options_UNSAFE_Get(opt, &raw); - if (!raw.length || !key->length) return; + if (!raw.length) return; if (raw.length > 2000) Logger_Abort("too large to base64"); dataLen = Convert_FromBase64(raw.buffer, raw.length, data); - Platform_Decrypt(key, data, dataLen, dst); + res = Platform_Decrypt(data, dataLen, dst); + if (res) Platform_Log2("Error %h decrypting option %c", &res, opt); } diff --git a/src/Options.h b/src/Options.h index 0b6f19a66..1ef4d2772 100644 --- a/src/Options.h +++ b/src/Options.h @@ -124,9 +124,9 @@ CC_API void Options_Set(const char* keyRaw, const cc_string* value); CC_API void Options_SetString(const cc_string* key, const cc_string* value); /* Attempts to securely encode an option. */ -/* NOTE: Not all platforms support secure saving. DO NOT RELY ON THIS BEING SECURE! */ -void Options_SetSecure(const char* opt, const cc_string* data, const cc_string* key); +/* NOTE: Not all platforms support secure saving. */ +void Options_SetSecure(const char* opt, const cc_string* data); /* Attempts to securely decode an option. */ -/* NOTE: Not all platforms support secure saving. DO NOT RELY ON THIS BEING SECURE! */ -void Options_GetSecure(const char* opt, cc_string* data, const cc_string* key); +/* NOTE: Not all platforms support secure saving. */ +void Options_GetSecure(const char* opt, cc_string* data); #endif diff --git a/src/Platform.c b/src/Platform.c index 7e66c2f75..64114afe2 100644 --- a/src/Platform.c +++ b/src/Platform.c @@ -1763,7 +1763,7 @@ void Platform_Init(void) { Platform_InitPosix(); } *-------------------------------------------------------Encryption--------------------------------------------------------* *#########################################################################################################################*/ #if defined CC_BUILD_WIN -cc_result Platform_Encrypt(const cc_string* key, const void* data, int len, cc_string* dst) { +cc_result Platform_Encrypt(const void* data, int len, cc_string* dst) { DATA_BLOB input, output; int i; input.cbData = len; input.pbData = (BYTE*)data; @@ -1775,7 +1775,7 @@ cc_result Platform_Encrypt(const cc_string* key, const void* data, int len, cc_s LocalFree(output.pbData); return 0; } -cc_result Platform_Decrypt(const cc_string* key, const void* data, int len, cc_string* dst) { +cc_result Platform_Decrypt(const void* data, int len, cc_string* dst) { DATA_BLOB input, output; int i; input.cbData = len; input.pbData = (BYTE*)data; @@ -1787,7 +1787,7 @@ cc_result Platform_Decrypt(const cc_string* key, const void* data, int len, cc_s LocalFree(output.pbData); return 0; } -#elif defined CC_BUILD_LINUX || defined CC_BUILD_MACOS +#elif defined CC_BUILD_POSIX /* Encrypts data using XTEA block cipher, with OS specific method to get machine-specific key */ static void EncipherBlock(cc_uint32* v, const cc_uint32* key, cc_string* dst) { @@ -1839,31 +1839,29 @@ static void DecodeMachineID(char* tmp, int len, cc_uint32* key) { #if defined CC_BUILD_LINUX /* Read /var/lib/dbus/machine-id for the key */ -static void GetMachineID(cc_uint32* key) { +static cc_result GetMachineID(cc_uint32* key) { const cc_string idFile = String_FromConst("/var/lib/dbus/machine-id"); char tmp[MACHINEID_LEN]; struct Stream s; + cc_result res; int i; - for (i = 0; i < 4; i++) key[i] = 0; - if (Stream_OpenFile(&s, &idFile)) return; + if ((res = Stream_OpenFile(&s, &idFile))) return res; + res = Stream_Read(&s, tmp, MACHINEID_LEN); + if (!res) DecodeMachineID(tmp, MACHINEID_LEN, key); - if (!Stream_Read(&s, tmp, MACHINEID_LEN)) { - DecodeMachineID(tmp, MACHINEID_LEN, key); - } (void)s.Close(&s); + return res; } #elif defined CC_BUILD_MACOS -static void GetMachineID(cc_uint32* key) { +/* Read kIOPlatformUUIDKey from I/O registry for the key */ +static cc_result GetMachineID(cc_uint32* key) { io_registry_entry_t registry; CFStringRef uuid = NULL; - const char* src; - struct Stream s; - int i; + const char* src = NULL; - for (i = 0; i < 4; i++) key[i] = 0; registry = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/"); - if (!registry) return; + if (!registry) return ERR_NOT_SUPPORTED; #ifdef kIOPlatformUUIDKey uuid = IORegistryEntryCreateCFProperty(registry, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); @@ -1873,16 +1871,20 @@ static void GetMachineID(cc_uint32* key) { #endif if (uuid) CFRelease(uuid); IOObjectRelease(registry); + return src ? 0 : ERR_NOT_SUPPORTED; } +#else +static cc_result GetMachineID(cc_uint32* key) { return ERR_NOT_SUPPORTED; } #endif -cc_result Platform_Encrypt(const cc_string* key_, const void* data, int len, cc_string* dst) { +cc_result Platform_Encrypt(const void* data, int len, cc_string* dst) { const cc_uint8* src = (const cc_uint8*)data; cc_uint32 header[4], key[4]; + cc_result res; + if ((res = GetMachineID(key))) return res; + header[0] = ENC1; header[1] = ENC2; header[2] = ENC3; header[3] = len; - - GetMachineID(key); EncipherBlock(header + 0, key, dst); EncipherBlock(header + 2, key, dst); @@ -1893,14 +1895,16 @@ cc_result Platform_Encrypt(const cc_string* key_, const void* data, int len, cc_ } return 0; } -cc_result Platform_Decrypt(const cc_string* key__, const void* data, int len, cc_string* dst) { +cc_result Platform_Decrypt(const void* data, int len, cc_string* dst) { const cc_uint8* src = (const cc_uint8*)data; cc_uint32 header[4], key[4]; + cc_result res; int dataLen; + /* Total size must be >= header size */ if (len < 16) return ERR_END_OF_STREAM; + if ((res = GetMachineID(key))) return res; - GetMachineID(key); Mem_Copy(header, src, 16); DecipherBlock(header + 0, key); DecipherBlock(header + 2, key); @@ -1920,24 +1924,6 @@ cc_result Platform_Decrypt(const cc_string* key__, const void* data, int len, cc } return 0; } -#elif defined CC_BUILD_POSIX -cc_result Platform_Encrypt(const cc_string* key, const void* data, int len, cc_string* dst) { - /* TODO: Is there a similar API for macOS/Linux? */ - /* Fallback to NOT SECURE XOR. Prevents simple reading from options.txt */ - const cc_uint8* src = data; - cc_uint8 c; - int i; - - for (i = 0; i < len; i++) { - c = (cc_uint8)(src[i] ^ key->buffer[i % key->length] ^ 0x43); - String_Append(dst, c); - } - return 0; -} -cc_result Platform_Decrypt(const cc_string* key, const void* data, int len, cc_string* dst) { - /* TODO: Is there a similar API for macOS/Linux? */ - return Platform_Encrypt(key, data, len, dst); -} #endif diff --git a/src/Platform.h b/src/Platform.h index 1747f3d53..914c1a4be 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -53,11 +53,9 @@ cc_result Platform_SetDefaultCurrentDirectory(int argc, char **argv); int Platform_GetCommandLineArgs(int argc, STRING_REF char** argv, cc_string* args); /* Encrypts data in a platform-specific manner. (may not be supported) */ -/* NOTE: THIS IS NOT SECURE! Some platforms just use a simple xor obfuscation. */ -cc_result Platform_Encrypt(const cc_string* key, const void* data, int len, cc_string* dst); +cc_result Platform_Encrypt(const void* data, int len, cc_string* dst); /* Decrypts data in a platform-specific manner. (may not be supported) */ -/* NOTE: THIS IS NOT SECURE! Some platforms just use a simple xor obfuscation. */ -cc_result Platform_Decrypt(const cc_string* key, const void* data, int len, cc_string* dst); +cc_result Platform_Decrypt(const void* data, int len, cc_string* dst); /* Outputs more detailed information about errors with operating system functions. */ /* NOTE: This is for general functions like file I/O. If a more specific describe exists (e.g. Http_DescribeError), that should be preferred. */