For security, just fail instead of falling back to using key of 0 or XOR obfuscating data

This commit is contained in:
UnknownShadow200 2021-02-06 19:14:08 +11:00
parent e31adc09e3
commit 6eee7a735f
7 changed files with 49 additions and 61 deletions

View File

@ -522,7 +522,7 @@ static void DirectConnectScreen_Load(struct DirectConnectScreen* s) {
Options_UNSAFE_Get("launcher-dc-port", &port); Options_UNSAFE_Get("launcher-dc-port", &port);
String_InitArray(mppass, mppassBuffer); String_InitArray(mppass, mppassBuffer);
Options_GetSecure("launcher-dc-mppass", &mppass, &user); Options_GetSecure("launcher-dc-mppass", &mppass);
String_InitArray(addr, addrBuffer); String_InitArray(addr, addrBuffer);
String_Format2(&addr, "%s:%s", &ip, &port); 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-username", user);
Options_Set("launcher-dc-ip", &ip); Options_Set("launcher-dc-ip", &ip);
Options_Set("launcher-dc-port", &port); Options_Set("launcher-dc-port", &port);
Options_SetSecure("launcher-dc-mppass", mppass, user); Options_SetSecure("launcher-dc-mppass", mppass);
DirectConnectScreen_SetStatus(""); DirectConnectScreen_SetStatus("");
Launcher_StartGame(user, mppass, &ip, &port, &String_Empty); 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; if (!full) return;
String_InitArray(info->mppass, info->_mppassBuffer); String_InitArray(info->mppass, info->_mppassBuffer);
Options_GetSecure(ROPT_MPPASS, &info->mppass, &info->user); Options_GetSecure(ROPT_MPPASS, &info->mppass);
info->valid = info->valid =
info->user.length && info->mppass.length && info->user.length && info->mppass.length &&
@ -740,7 +740,7 @@ static void MainScreen_DoLogin(void) {
if (GetTokenTask.Base.working) return; if (GetTokenTask.Base.working) return;
Options_Set(LOPT_USERNAME, user); Options_Set(LOPT_USERNAME, user);
Options_SetSecure(LOPT_PASSWORD, pass, user); Options_SetSecure(LOPT_PASSWORD, pass);
GetTokenTask_Run(); GetTokenTask_Run();
LLabel_SetConst(&s->lblStatus, "&eSigning in.."); LLabel_SetConst(&s->lblStatus, "&eSigning in..");
@ -806,7 +806,7 @@ static void MainScreen_Init(struct LScreen* s_) {
String_InitArray(pass, passBuffer); String_InitArray(pass, passBuffer);
Options_UNSAFE_Get(LOPT_USERNAME, &user); 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->iptUsername, &user);
LInput_SetText(&s->iptPassword, &pass); LInput_SetText(&s->iptPassword, &pass);

View File

@ -687,7 +687,7 @@ void Session_Load(void) {
StringsBuffer_SetLengthBits(&ccCookies, 11); StringsBuffer_SetLengthBits(&ccCookies, 11);
String_InitArray(session, buffer); String_InitArray(session, buffer);
Options_GetSecure(LOPT_SESSION, &session, &Game_Username); Options_GetSecure(LOPT_SESSION, &session);
if (!session.length) return; if (!session.length) return;
EntryList_Set(&ccCookies, &sessionKey, &session, '='); 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 #if defined CC_BUILD_WIN || defined CC_BUILD_LINUX || defined CC_BUILD_MACOS
cc_string session = EntryList_UNSAFE_Get(&ccCookies, &sessionKey, '='); cc_string session = EntryList_UNSAFE_Get(&ccCookies, &sessionKey, '=');
if (!session.length) return; if (!session.length) return;
Options_SetSecure(LOPT_SESSION, &session, &Game_Username); Options_SetSecure(LOPT_SESSION, &session);
#endif #endif
} }
#endif #endif

View File

@ -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_USER, user);
Options_Set(ROPT_IP, ip); Options_Set(ROPT_IP, ip);
Options_Set(ROPT_PORT, port); Options_Set(ROPT_PORT, port);
Options_SetSecure(ROPT_MPPASS, mppass, user); Options_SetSecure(ROPT_MPPASS, mppass);
} }
/* Save options BEFORE starting new game process */ /* Save options BEFORE starting new game process */
/* Otherwise can get 'file already in use' errors on startup */ /* Otherwise can get 'file already in use' errors on startup */

View File

@ -165,30 +165,34 @@ void Options_SetString(const cc_string* key, const cc_string* value) {
StringsBuffer_Add(&changedOpts, key); 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]; char data[2000], encData[1500+1];
cc_string tmp, enc; cc_string tmp, enc;
cc_result res;
if (!src->length) return;
String_InitArray(enc, encData); String_InitArray(enc, encData);
if (!src->length || !key->length) return; res = Platform_Encrypt(src->buffer, src->length, &enc);
if (Platform_Encrypt(key, src->buffer, src->length, &enc)) return; if (res) { Platform_Log2("Error %h encrypting option %c", &res, opt); return; }
if (enc.length > 1500) Logger_Abort("too large to base64");
if (enc.length > 1500) Logger_Abort("too large to base64");
tmp.buffer = data; tmp.buffer = data;
tmp.length = Convert_ToBase64(enc.buffer, enc.length, data); tmp.length = Convert_ToBase64(enc.buffer, enc.length, data);
tmp.capacity = tmp.length; tmp.capacity = tmp.length;
Options_Set(opt, &tmp); 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]; cc_uint8 data[1500];
int dataLen; int dataLen;
cc_string raw; cc_string raw;
cc_result res;
Options_UNSAFE_Get(opt, &raw); 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"); if (raw.length > 2000) Logger_Abort("too large to base64");
dataLen = Convert_FromBase64(raw.buffer, raw.length, data); 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);
} }

View File

@ -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); CC_API void Options_SetString(const cc_string* key, const cc_string* value);
/* Attempts to securely encode an option. */ /* Attempts to securely encode an option. */
/* NOTE: Not all platforms support secure saving. DO NOT RELY ON THIS BEING SECURE! */ /* NOTE: Not all platforms support secure saving. */
void Options_SetSecure(const char* opt, const cc_string* data, const cc_string* key); void Options_SetSecure(const char* opt, const cc_string* data);
/* Attempts to securely decode an option. */ /* Attempts to securely decode an option. */
/* NOTE: Not all platforms support secure saving. DO NOT RELY ON THIS BEING SECURE! */ /* NOTE: Not all platforms support secure saving. */
void Options_GetSecure(const char* opt, cc_string* data, const cc_string* key); void Options_GetSecure(const char* opt, cc_string* data);
#endif #endif

View File

@ -1763,7 +1763,7 @@ void Platform_Init(void) { Platform_InitPosix(); }
*-------------------------------------------------------Encryption--------------------------------------------------------* *-------------------------------------------------------Encryption--------------------------------------------------------*
*#########################################################################################################################*/ *#########################################################################################################################*/
#if defined CC_BUILD_WIN #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; DATA_BLOB input, output;
int i; int i;
input.cbData = len; input.pbData = (BYTE*)data; 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); LocalFree(output.pbData);
return 0; 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; DATA_BLOB input, output;
int i; int i;
input.cbData = len; input.pbData = (BYTE*)data; 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); LocalFree(output.pbData);
return 0; 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 */ /* 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) { 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 #if defined CC_BUILD_LINUX
/* Read /var/lib/dbus/machine-id for the key */ /* 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"); const cc_string idFile = String_FromConst("/var/lib/dbus/machine-id");
char tmp[MACHINEID_LEN]; char tmp[MACHINEID_LEN];
struct Stream s; struct Stream s;
cc_result res;
int i; int i;
for (i = 0; i < 4; i++) key[i] = 0; if ((res = Stream_OpenFile(&s, &idFile))) return res;
if (Stream_OpenFile(&s, &idFile)) return; 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); (void)s.Close(&s);
return res;
} }
#elif defined CC_BUILD_MACOS #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; io_registry_entry_t registry;
CFStringRef uuid = NULL; CFStringRef uuid = NULL;
const char* src; const char* src = NULL;
struct Stream s;
int i;
for (i = 0; i < 4; i++) key[i] = 0;
registry = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/"); registry = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/");
if (!registry) return; if (!registry) return ERR_NOT_SUPPORTED;
#ifdef kIOPlatformUUIDKey #ifdef kIOPlatformUUIDKey
uuid = IORegistryEntryCreateCFProperty(registry, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0); uuid = IORegistryEntryCreateCFProperty(registry, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
@ -1873,16 +1871,20 @@ static void GetMachineID(cc_uint32* key) {
#endif #endif
if (uuid) CFRelease(uuid); if (uuid) CFRelease(uuid);
IOObjectRelease(registry); IOObjectRelease(registry);
return src ? 0 : ERR_NOT_SUPPORTED;
} }
#else
static cc_result GetMachineID(cc_uint32* key) { return ERR_NOT_SUPPORTED; }
#endif #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; const cc_uint8* src = (const cc_uint8*)data;
cc_uint32 header[4], key[4]; cc_uint32 header[4], key[4];
cc_result res;
if ((res = GetMachineID(key))) return res;
header[0] = ENC1; header[1] = ENC2; header[0] = ENC1; header[1] = ENC2;
header[2] = ENC3; header[3] = len; header[2] = ENC3; header[3] = len;
GetMachineID(key);
EncipherBlock(header + 0, key, dst); EncipherBlock(header + 0, key, dst);
EncipherBlock(header + 2, 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; 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; const cc_uint8* src = (const cc_uint8*)data;
cc_uint32 header[4], key[4]; cc_uint32 header[4], key[4];
cc_result res;
int dataLen; int dataLen;
/* Total size must be >= header size */ /* Total size must be >= header size */
if (len < 16) return ERR_END_OF_STREAM; if (len < 16) return ERR_END_OF_STREAM;
if ((res = GetMachineID(key))) return res;
GetMachineID(key);
Mem_Copy(header, src, 16); Mem_Copy(header, src, 16);
DecipherBlock(header + 0, key); DecipherBlock(header + 0, key);
DecipherBlock(header + 2, 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; 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 #endif

View File

@ -53,11 +53,9 @@ cc_result Platform_SetDefaultCurrentDirectory(int argc, char **argv);
int Platform_GetCommandLineArgs(int argc, STRING_REF char** argv, cc_string* args); int Platform_GetCommandLineArgs(int argc, STRING_REF char** argv, cc_string* args);
/* Encrypts data in a platform-specific manner. (may not be supported) */ /* 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 void* data, int len, cc_string* dst);
cc_result Platform_Encrypt(const cc_string* key, const void* data, int len, cc_string* dst);
/* Decrypts data in a platform-specific manner. (may not be supported) */ /* 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 void* data, int len, cc_string* dst);
cc_result Platform_Decrypt(const cc_string* key, const void* data, int len, cc_string* dst);
/* Outputs more detailed information about errors with operating system functions. */ /* Outputs more detailed information about errors with operating system functions. */
/* NOTE: This is for general functions like file I/O. If a more specific /* NOTE: This is for general functions like file I/O. If a more specific
describe exists (e.g. Http_DescribeError), that should be preferred. */ describe exists (e.g. Http_DescribeError), that should be preferred. */