From 5e6710c8155caebc70c15889aa94ddfed33d9845 Mon Sep 17 00:00:00 2001 From: Chee Yee Date: Fri, 24 Feb 2023 20:01:42 -0800 Subject: [PATCH] encrypt passwords --- CMakeLists.txt | 1 + source/actions.cpp | 2 +- source/base64.h | 106 +++++++++++++++++++++++++++++++++++++++++++++ source/config.cpp | 76 +++++++++++++++++++++++++++++--- source/config.h | 4 +- source/crypt.c | 87 +++++++++++++++++++++++++++++++++++++ source/crypt.h | 18 ++++++++ 7 files changed, 286 insertions(+), 8 deletions(-) create mode 100644 source/base64.h create mode 100644 source/crypt.c create mode 100644 source/crypt.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 97755ff..15c5477 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ add_executable(ezremote_client source/http/npxserve.cpp source/actions.cpp source/config.cpp + source/crypt.c source/fs.cpp source/ftpclient.cpp source/gui.cpp diff --git a/source/actions.cpp b/source/actions.cpp index 824400b..5f2ea82 100644 --- a/source/actions.cpp +++ b/source/actions.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "crypt.h" #include "common.h" #include "fs.h" #include "config.h" @@ -23,7 +24,6 @@ #include "http/npxserve.h" #include "http/iis.h" #include "zip_util.h" -#include "dbglogger.h" namespace Actions { diff --git a/source/base64.h b/source/base64.h new file mode 100644 index 0000000..000ed7a --- /dev/null +++ b/source/base64.h @@ -0,0 +1,106 @@ +#ifndef BASE64_H_ +#define BASE64_H_ + +#include + +class Base64 +{ +public: + static int Encode(const std::string &input, std::string &out) + { + static constexpr char sEncodingTable[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/'}; + + size_t in_len = input.size(); + size_t out_len = 4 * ((in_len + 2) / 3); + out.resize(out_len); + size_t i; + char *p = const_cast(out.c_str()); + + for (i = 0; i < in_len - 2; i += 3) + { + *p++ = sEncodingTable[(input[i] >> 2) & 0x3F]; + *p++ = sEncodingTable[((input[i] & 0x3) << 4) | ((int)(input[i + 1] & 0xF0) >> 4)]; + *p++ = sEncodingTable[((input[i + 1] & 0xF) << 2) | ((int)(input[i + 2] & 0xC0) >> 6)]; + *p++ = sEncodingTable[input[i + 2] & 0x3F]; + } + if (i < in_len) + { + *p++ = sEncodingTable[(input[i] >> 2) & 0x3F]; + if (i == (in_len - 1)) + { + *p++ = sEncodingTable[((input[i] & 0x3) << 4)]; + *p++ = '='; + } + else + { + *p++ = sEncodingTable[((input[i] & 0x3) << 4) | ((int)(input[i + 1] & 0xF0) >> 4)]; + *p++ = sEncodingTable[((input[i + 1] & 0xF) << 2)]; + } + *p++ = '='; + } + + return 1; + } + + static int Decode(const std::string &input, std::string &out) + { + static constexpr unsigned char kDecodingTable[] = { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64}; + + size_t in_len = input.size(); + if (in_len % 4 != 0) + return 0; + + size_t out_len = in_len / 4 * 3; + if (input[in_len - 1] == '=') + out_len--; + if (input[in_len - 2] == '=') + out_len--; + + out.resize(out_len); + + for (size_t i = 0, j = 0; i < in_len;) + { + uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast(input[i++])]; + + uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6); + + if (j < out_len) + out[j++] = (triple >> 2 * 8) & 0xFF; + if (j < out_len) + out[j++] = (triple >> 1 * 8) & 0xFF; + if (j < out_len) + out[j++] = (triple >> 0 * 8) & 0xFF; + } + + return 1; + } +}; + +#endif \ No newline at end of file diff --git a/source/config.cpp b/source/config.cpp index 524b510..b4c6309 100644 --- a/source/config.cpp +++ b/source/config.cpp @@ -7,6 +7,9 @@ #include "config.h" #include "fs.h" #include "lang.h" +#include +#include "crypt.h" +#include "base64.h" extern "C" { @@ -28,10 +31,43 @@ PackageUrlInfo install_pkg_url; char favorite_urls[MAX_FAVORITE_URLS][512]; bool auto_delete_tmp_pkg; int max_edit_file_size; +unsigned char cipher_key[32] = {'s', '5', 'v', '8', 'y', '/', 'B', '?', 'E', '(', 'H', '+', 'M', 'b', 'Q', 'e', 'T', 'h', 'W', 'm', 'Z', 'q', '4', 't', '7', 'w', '9', 'z', '$', 'C', '&', 'F'}; +unsigned char cipher_iv[16] = {'Y', 'p', '3', 's', '6', 'v', '9', 'y', '$', 'B', '&', 'E', ')', 'H', '@', 'M'}; + RemoteClient *remoteclient; namespace CONFIG { + int Encrypt(const std::string &text, std::string &encrypt_text) + { + unsigned char tmp_encrypt_text[text.length() * 2]; + int encrypt_text_len; + memset(tmp_encrypt_text, 0, sizeof(tmp_encrypt_text)); + int ret = openssl_encrypt((unsigned char *)text.c_str(), text.length(), cipher_key, cipher_iv, tmp_encrypt_text, &encrypt_text_len); + if (ret == 0) + return 0; + return Base64::Encode(std::string((const char*)tmp_encrypt_text, encrypt_text_len), encrypt_text); + } + + int Decrypt(const std::string &text, std::string &decrypt_text) + { + std::string tmp_decode_text; + int ret = Base64::Decode(text, tmp_decode_text); + if (ret == 0) + return 0; + + unsigned char tmp_decrypt_text[tmp_decode_text.length() * 2]; + int decrypt_text_len; + memset(tmp_decrypt_text, 0, sizeof(tmp_decrypt_text)); + ret = openssl_decrypt((unsigned char *)tmp_decode_text.c_str(), tmp_decode_text.length(), cipher_key, cipher_iv, tmp_decrypt_text, &decrypt_text_len); + if (ret == 0) + return 0; + + decrypt_text.clear(); + decrypt_text.append(std::string((const char*)tmp_decrypt_text, decrypt_text_len)); + + return 1; + } void SetClientType(RemoteSettings *setting) { @@ -59,6 +95,16 @@ namespace CONFIG void LoadConfig() { + // Get the key and iv for encryption. Inject the MAC address as part of the key and iv. + OrbisNetEtherAddr addr; + memset(&addr, 0x0, sizeof(OrbisNetEtherAddr)); + sceNetGetMacAddress(&addr, 0); + for (int i = 0; i < 6; i++) + { + cipher_key[i * 2] = addr.data[i]; + cipher_iv[i * 2] = addr.data[i]; + } + if (!FS::FolderExists(DATA_PATH)) { FS::MkDirs(DATA_PATH); @@ -67,7 +113,7 @@ namespace CONFIG sites = {"Site 1", "Site 2", "Site 3", "Site 4", "Site 5", "Site 6", "Site 7", "Site 8", "Site 9", "Site 10", "Site 11", "Site 12", "Site 13", "Site 14", "Site 15", "Site 16", "Site 17", "Site 18", "Site 19", "Site 20"}; - http_servers = { HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE}; + http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE}; OpenIniFile(CONFIG_INI_FILE); @@ -94,14 +140,15 @@ namespace CONFIG max_edit_file_size = ReadInt(CONFIG_GLOBAL, CONFIG_MAX_EDIT_FILE_SIZE, MAX_EDIT_FILE_SIZE); WriteInt(CONFIG_GLOBAL, CONFIG_MAX_EDIT_FILE_SIZE, max_edit_file_size); - + for (int i = 0; i < sites.size(); i++) { RemoteSettings setting; + memset(&setting, 0, sizeof(RemoteSettings)); sprintf(setting.site_name, "%s", sites[i].c_str()); sprintf(setting.server, "%s", ReadString(sites[i].c_str(), CONFIG_REMOTE_SERVER_URL, "")); - if (conversion_needed && strlen(setting.server)>0) + if (conversion_needed && strlen(setting.server) > 0) { std::string tmp = std::string(setting.server); tmp = std::regex_replace(tmp, std::regex("http://"), "webdav://"); @@ -113,8 +160,20 @@ namespace CONFIG sprintf(setting.username, "%s", ReadString(sites[i].c_str(), CONFIG_REMOTE_SERVER_USER, "")); WriteString(sites[i].c_str(), CONFIG_REMOTE_SERVER_USER, setting.username); - sprintf(setting.password, "%s", ReadString(sites[i].c_str(), CONFIG_REMOTE_SERVER_PASSWORD, "")); - WriteString(sites[i].c_str(), CONFIG_REMOTE_SERVER_PASSWORD, setting.password); + char tmp_password[64]; + sprintf(tmp_password, "%s", ReadString(sites[i].c_str(), CONFIG_REMOTE_SERVER_PASSWORD, "")); + std::string encrypted_password; + if (strlen(tmp_password) > 0) + { + std::string decrypted_password; + int ret = Decrypt(tmp_password, decrypted_password); + if (ret == 0) + sprintf(setting.password, "%s", tmp_password); + else + sprintf(setting.password, "%s", decrypted_password.c_str()); + Encrypt(setting.password, encrypted_password); + } + WriteString(sites[i].c_str(), CONFIG_REMOTE_SERVER_PASSWORD, encrypted_password.c_str()); setting.http_port = ReadInt(sites[i].c_str(), CONFIG_REMOTE_SERVER_HTTP_PORT, 80); WriteInt(sites[i].c_str(), CONFIG_REMOTE_SERVER_HTTP_PORT, setting.http_port); @@ -149,9 +208,14 @@ namespace CONFIG { OpenIniFile(CONFIG_INI_FILE); + std::string encrypted_text; + if (strlen(remote_settings->password) > 0) + Encrypt(remote_settings->password, encrypted_text); + else + encrypted_text = std::string(remote_settings->password); WriteString(last_site, CONFIG_REMOTE_SERVER_URL, remote_settings->server); WriteString(last_site, CONFIG_REMOTE_SERVER_USER, remote_settings->username); - WriteString(last_site, CONFIG_REMOTE_SERVER_PASSWORD, remote_settings->password); + WriteString(last_site, CONFIG_REMOTE_SERVER_PASSWORD, encrypted_text.c_str()); WriteInt(last_site, CONFIG_REMOTE_SERVER_HTTP_PORT, remote_settings->http_port); WriteBool(last_site, CONFIG_ENABLE_RPI, remote_settings->enable_rpi); WriteString(last_site, CONFIG_REMOTE_HTTP_SERVER_TYPE, remote_settings->http_server_type); diff --git a/source/config.h b/source/config.h index 6c9b60d..6039fcf 100644 --- a/source/config.h +++ b/source/config.h @@ -51,7 +51,7 @@ struct RemoteSettings char site_name[32]; char server[256]; char username[33]; - char password[25]; + char password[64]; int http_port; ClientType type; bool enable_rpi; @@ -81,6 +81,8 @@ extern PackageUrlInfo install_pkg_url; extern char favorite_urls[MAX_FAVORITE_URLS][512]; extern bool auto_delete_tmp_pkg; extern int max_edit_file_size; +extern unsigned char cipher_key[32]; +extern unsigned char cipher_iv[16]; namespace CONFIG { diff --git a/source/crypt.c b/source/crypt.c new file mode 100644 index 0000000..21b036f --- /dev/null +++ b/source/crypt.c @@ -0,0 +1,87 @@ +#include "crypt.h" + +int openssl_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, + unsigned char *iv, unsigned char *ciphertext, int *ciphertext_len) +{ + EVP_CIPHER_CTX *ctx; + + int len; + + /* Create and initialise the context */ + if (!(ctx = EVP_CIPHER_CTX_new())) + return 0; + + /* + * Initialise the encryption operation. IMPORTANT - ensure you use a key + * and IV size appropriate for your cipher + * In this example we are using 256 bit AES (i.e. a 256 bit key). The + * IV size for *most* modes is the same as the block size. For AES this + * is 128 bits + */ + if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) + return 0; + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) + return 0; + *ciphertext_len = len; + + /* + * Finalise the encryption. Further ciphertext bytes may be written at + * this stage. + */ + if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) + return 0; + *ciphertext_len += len; + + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + return 1; +} + +int openssl_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, + unsigned char *iv, unsigned char *plaintext, int *plaintext_len) +{ + EVP_CIPHER_CTX *ctx; + + int len; + + /* Create and initialise the context */ + if (!(ctx = EVP_CIPHER_CTX_new())) + return 0; + + /* + * Initialise the decryption operation. IMPORTANT - ensure you use a key + * and IV size appropriate for your cipher + * In this example we are using 256 bit AES (i.e. a 256 bit key). The + * IV size for *most* modes is the same as the block size. For AES this + * is 128 bits + */ + if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) + return 0; + + /* + * Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary. + */ + if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) + return 0; + *plaintext_len = len; + + /* + * Finalise the decryption. Further plaintext bytes may be written at + * this stage. + */ + if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) + return 0; + *plaintext_len += len; + + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + return 1; +} \ No newline at end of file diff --git a/source/crypt.h b/source/crypt.h new file mode 100644 index 0000000..a8875df --- /dev/null +++ b/source/crypt.h @@ -0,0 +1,18 @@ +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +int openssl_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, + unsigned char *iv, unsigned char *ciphertext, int *ciphertext_len); + +int openssl_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, + unsigned char *iv, unsigned char *plaintext, int *plaintext_len); + +#ifdef __cplusplus +} +#endif \ No newline at end of file