From 83bd483f3db1df4b69c1612030e1a1be05b303ad Mon Sep 17 00:00:00 2001 From: Dees_Troy Date: Sat, 4 May 2013 12:39:56 +0000 Subject: Support encrypted backup files Also includes features merged from: Update twrpTar by kokotas Revised function entryExists(). Added function to get archive's uncompressed size. Added option to exclude item(s) from the archive. Revised forks() http://review.teamw.in/#/c/590/ Change-Id: I01fa2c81643161984eff2625247af75990684bd9 --- twrp-functions.cpp | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) (limited to 'twrp-functions.cpp') 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 #include #include +#include +#include #ifdef ANDROID_RB_POWEROFF #include "cutils/android_reboot.h" #endif #include #include +#include #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 TWFunc::split_string(const string &in, char del, bool skip_empty) { + vector 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; +} -- cgit v1.2.3