summaryrefslogtreecommitdiffstats
path: root/twrp-functions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'twrp-functions.cpp')
-rw-r--r--twrp-functions.cpp199
1 files changed, 199 insertions, 0 deletions
diff --git a/twrp-functions.cpp b/twrp-functions.cpp
index a0194b379..d9014b364 100644
--- a/twrp-functions.cpp
+++ b/twrp-functions.cpp
@@ -12,17 +12,23 @@
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/vfs.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#ifdef ANDROID_RB_POWEROFF
#include "cutils/android_reboot.h"
#endif
#include <iostream>
#include <fstream>
+#include <sstream>
#include "twrp-functions.hpp"
#include "partitions.hpp"
#include "twcommon.h"
#include "data.hpp"
#include "variables.h"
#include "bootloader.h"
+#ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS
+ #include "openaes/inc/oaes_lib.h"
+#endif
extern "C" {
#include "libcrecovery/common.h"
@@ -455,6 +461,30 @@ int TWFunc::write_file(string fn, string& line) {
return -1;
}
+vector<string> TWFunc::split_string(const string &in, char del, bool skip_empty) {
+ vector<string> res;
+
+ if (in.empty() || del == '\0')
+ return res;
+
+ string field;
+ istringstream f(in);
+ if (del == '\n') {
+ while(getline(f, field)) {
+ if (field.empty() && skip_empty)
+ continue;
+ res.push_back(field);
+ }
+ } else {
+ while(getline(f, field, del)) {
+ if (field.empty() && skip_empty)
+ continue;
+ res.push_back(field);
+ }
+ }
+ return res;
+}
+
timespec TWFunc::timespec_diff(timespec& start, timespec& end)
{
timespec temp;
@@ -678,3 +708,172 @@ bool TWFunc::Install_SuperSU(void) {
return false;
return true;
}
+
+int TWFunc::Get_File_Type(string fn) {
+ string::size_type i = 0;
+ int firstbyte = 0, secondbyte = 0;
+ char header[3];
+
+ ifstream f;
+ f.open(fn.c_str(), ios::in | ios::binary);
+ f.get(header, 3);
+ f.close();
+ firstbyte = header[i] & 0xff;
+ secondbyte = header[++i] & 0xff;
+
+ if (firstbyte == 0x1f && secondbyte == 0x8b) {
+ return 1; // Compressed
+ } else if (firstbyte == 0x4f && secondbyte == 0x41) {
+ return 2; // Encrypted
+ } else {
+ return 0; // Unknown
+ }
+
+ return 0;
+}
+
+int TWFunc::Try_Decrypting_File(string fn, string password) {
+#ifndef TW_EXCLUDE_ENCRYPTED_BACKUPS
+ OAES_CTX * ctx = NULL;
+ uint8_t _key_data[32] = "";
+ FILE *f;
+ uint8_t buffer[4096];
+ uint8_t *buffer_out = NULL;
+ uint8_t *ptr = NULL;
+ size_t read_len = 0, out_len = 0;
+ int firstbyte = 0, secondbyte = 0, key_len;
+ size_t _j = 0;
+ size_t _key_data_len = 0;
+
+ // mostly kanged from OpenAES oaes.c
+ for( _j = 0; _j < 32; _j++ )
+ _key_data[_j] = _j + 1;
+ _key_data_len = password.size();
+ if( 16 >= _key_data_len )
+ _key_data_len = 16;
+ else if( 24 >= _key_data_len )
+ _key_data_len = 24;
+ else
+ _key_data_len = 32;
+ memcpy(_key_data, password.c_str(), password.size());
+
+ ctx = oaes_alloc();
+ if (ctx == NULL) {
+ LOGERR("Failed to allocate OAES\n");
+ return -1;
+ }
+
+ oaes_key_import_data(ctx, _key_data, _key_data_len);
+
+ f = fopen(fn.c_str(), "rb");
+ if (f == NULL) {
+ LOGERR("Failed to open '%s' to try decrypt\n", fn.c_str());
+ return -1;
+ }
+ read_len = fread(buffer, sizeof(uint8_t), 4096, f);
+ if (read_len <= 0) {
+ LOGERR("Read size during try decrypt failed\n");
+ fclose(f);
+ return -1;
+ }
+ if (oaes_decrypt(ctx, buffer, read_len, NULL, &out_len) != OAES_RET_SUCCESS) {
+ LOGERR("Error: Failed to retrieve required buffer size for trying decryption.\n");
+ fclose(f);
+ return -1;
+ }
+ buffer_out = (uint8_t *) calloc(out_len, sizeof(char));
+ if (buffer_out == NULL) {
+ LOGERR("Failed to allocate output buffer for try decrypt.\n");
+ fclose(f);
+ return -1;
+ }
+ if (oaes_decrypt(ctx, buffer, read_len, buffer_out, &out_len) != OAES_RET_SUCCESS) {
+ LOGERR("Failed to decrypt file '%s'\n", fn.c_str());
+ fclose(f);
+ free(buffer_out);
+ return 0;
+ }
+ fclose(f);
+ if (out_len < 2) {
+ LOGINFO("Successfully decrypted '%s' but read length %i too small.\n", fn.c_str(), out_len);
+ free(buffer_out);
+ return 1; // Decrypted successfully
+ }
+ ptr = buffer_out;
+ firstbyte = *ptr & 0xff;
+ ptr++;
+ secondbyte = *ptr & 0xff;
+ if (firstbyte == 0x1f && secondbyte == 0x8b) {
+ LOGINFO("Successfully decrypted '%s' and file is compressed.\n", fn.c_str());
+ free(buffer_out);
+ return 3; // Compressed
+ }
+ if (out_len >= 262) {
+ ptr = buffer_out + 257;
+ if (strncmp((char*)ptr, "ustar", 5) == 0) {
+ LOGINFO("Successfully decrypted '%s' and file is tar format.\n", fn.c_str());
+ free(buffer_out);
+ return 2; // Tar
+ }
+ }
+ free(buffer_out);
+ LOGINFO("No errors decrypting '%s' but no known file format.\n", fn.c_str());
+ return 1; // Decrypted successfully
+#else
+ LOGERR("Encrypted backup support not included.\n");
+ return -1;
+#endif
+}
+
+bool TWFunc::Try_Decrypting_Backup(string Restore_Path, string Password) {
+ DIR* d;
+
+ string Filename;
+ Restore_Path += "/";
+ d = opendir(Restore_Path.c_str());
+ if (d == NULL) {
+ LOGERR("Error opening '%s'\n", Restore_Path.c_str());
+ return false;
+ }
+
+ struct dirent* de;
+ while ((de = readdir(d)) != NULL) {
+ Filename = Restore_Path;
+ Filename += de->d_name;
+ if (TWFunc::Get_File_Type(Filename) == 2) {
+ if (TWFunc::Try_Decrypting_File(Filename, Password) < 2) {
+ DataManager::SetValue("tw_restore_password", ""); // Clear the bad password
+ DataManager::SetValue("tw_restore_display", ""); // Also clear the display mask
+ closedir(d);
+ return false;
+ }
+ }
+ }
+ closedir(d);
+ return true;
+}
+
+int TWFunc::Wait_For_Child(pid_t pid, int *status, string Child_Name) {
+ pid_t rc_pid;
+
+ rc_pid = waitpid(pid, status, 0);
+ if (rc_pid > 0) {
+ if (WEXITSTATUS(*status) == 0)
+ LOGINFO("%s process ended with RC=%d\n", Child_Name.c_str(), WEXITSTATUS(*status)); // Success
+ else if (WIFSIGNALED(*status)) {
+ LOGINFO("%s process ended with signal: %d\n", Child_Name.c_str(), WTERMSIG(*status)); // Seg fault or some other non-graceful termination
+ return -1;
+ } else if (WEXITSTATUS(*status) != 0) {
+ LOGINFO("%s process ended with ERROR=%d\n", Child_Name.c_str(), WEXITSTATUS(*status)); // Graceful exit, but there was an error
+ return -1;
+ }
+ } else { // no PID returned
+ if (errno == ECHILD)
+ LOGINFO("%s no child process exist\n", Child_Name.c_str());
+ else {
+ LOGINFO("%s Unexpected error\n", Child_Name.c_str());
+ return -1;
+ }
+ }
+ return 0;
+}