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);
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);

View File

@ -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

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_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 */

View File

@ -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);
}

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);
/* 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

View File

@ -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

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);
/* 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. */