Merge "Add ozip decryption for Oppo/Realme device" into android-9.0
diff --git a/Android.mk b/Android.mk
index ab3bcc8..af49367 100755
--- a/Android.mk
+++ b/Android.mk
@@ -897,6 +897,11 @@
     include $(commands_TWRP_local_path)/libmincrypt/Android.mk
 endif
 
+ifneq ($(TW_OZIP_DECRYPT_KEY),)
+    TWRP_REQUIRED_MODULES += ozip_decrypt
+    include $(commands_TWRP_local_path)/ozip_decrypt/Android.mk
+endif
+
 ifeq ($(TW_INCLUDE_CRYPTO), true)
     include $(commands_TWRP_local_path)/crypto/fde/Android.mk
     include $(commands_TWRP_local_path)/crypto/scrypt/Android.mk
diff --git a/gui/Android.mk b/gui/Android.mk
index b14b3d8..2243ba8 100755
--- a/gui/Android.mk
+++ b/gui/Android.mk
@@ -64,7 +64,11 @@
 ifneq ($(TW_USE_KEY_CODE_TOUCH_SYNC),)
     LOCAL_CFLAGS += -DTW_USE_KEY_CODE_TOUCH_SYNC=$(TW_USE_KEY_CODE_TOUCH_SYNC)
 endif
-
+ifneq ($(TW_OZIP_DECRYPT_KEY),)
+    LOCAL_CFLAGS += -DTW_OZIP_DECRYPT_KEY=\"$(TW_OZIP_DECRYPT_KEY)\"
+else
+    LOCAL_CFLAGS += -DTW_OZIP_DECRYPT_KEY=0
+endif
 ifneq ($(TW_NO_SCREEN_BLANK),)
     LOCAL_CFLAGS += -DTW_NO_SCREEN_BLANK
 endif
diff --git a/gui/action.cpp b/gui/action.cpp
index b26d55b..caa626d 100644
--- a/gui/action.cpp
+++ b/gui/action.cpp
@@ -1029,6 +1029,17 @@
 	}
 }
 
+int GUIAction::ozip_decrypt(string zip_path)
+{
+	if (!TWFunc::Path_Exists("/sbin/ozip_decrypt")) {
+            return 1;
+        }
+    gui_msg("ozip_decrypt_decryption=Starting Ozip Decryption...");
+	TWFunc::Exec_Cmd("ozip_decrypt " + (string)TW_OZIP_DECRYPT_KEY + " '" + zip_path + "'");
+    gui_msg("ozip_decrypt_finish=Ozip Decryption Finished!");
+	return 0;
+}
+
 int GUIAction::flash(std::string arg)
 {
 	int i, ret_val = 0, wipe_cache = 0;
@@ -1039,6 +1050,20 @@
 		size_t slashpos = zip_path.find_last_of('/');
 		string zip_filename = (slashpos == string::npos) ? zip_path : zip_path.substr(slashpos + 1);
 		operation_start("Flashing");
+		if((zip_path.substr(zip_path.size() - 4, 4)) == "ozip")
+		{
+			if((ozip_decrypt(zip_path)) != 0)
+			{
+		LOGERR("Unable to find ozip_decrypt!");
+				break;
+			}
+			zip_filename = (zip_filename.substr(0, zip_filename.size() - 4)).append("zip");
+			zip_path = (zip_path.substr(0, zip_path.size() - 4)).append("zip");
+			if (!TWFunc::Path_Exists(zip_path)) {
+				LOGERR("Unable to find decrypted zip");
+				break;
+			}
+		}
 		DataManager::SetValue("tw_filename", zip_path);
 		DataManager::SetValue("tw_file", zip_filename);
 		DataManager::SetValue(TW_ZIP_INDEX, (i + 1));
diff --git a/gui/objects.hpp b/gui/objects.hpp
index 3f72418..24e9d24 100644
--- a/gui/objects.hpp
+++ b/gui/objects.hpp
@@ -288,6 +288,7 @@
 	ThreadType getThreadType(const Action& action);
 	void simulate_progress_bar(void);
 	int flash_zip(std::string filename, int* wipe_cache);
+	int ozip_decrypt(std::string zip_path);
 	void reinject_after_flash();
 	void operation_start(const string operation_name);
 	void operation_end(const int operation_status);
diff --git a/gui/theme/common/landscape.xml b/gui/theme/common/landscape.xml
index 7fc9980..3d8646c 100755
--- a/gui/theme/common/landscape.xml
+++ b/gui/theme/common/landscape.xml
@@ -310,7 +310,7 @@
 				<condition var1="tw_selectimage" var2="0"/>
 				<placement x="%col2_x_left%" y="%row1a_y%" w="%fileselector_install_width%" h="%fileselector_install_height%"/>
 				<text>%tw_zip_location%</text>
-				<filter extn=".zip" folders="0" files="1"/>
+				<filter extn=".zip;.ozip;.ZIP;.OZIP" folders="0" files="1"/>
 				<path name="tw_zip_location" default="/sdcard"/>
 				<data name="tw_filename"/>
 				<selection name="tw_file"/>
diff --git a/gui/theme/common/languages/en.xml b/gui/theme/common/languages/en.xml
index 47ab708..fbcf436 100755
--- a/gui/theme/common/languages/en.xml
+++ b/gui/theme/common/languages/en.xml
@@ -735,5 +735,7 @@
 		<string name="fbe_wipe_msg">WARNING: {1} wiped. FBE device should be booted into Android and not Recovery to set initial FBE policy after wipe.</string>
 		<string name="flash_ab_inactive">Flashing A/B zip to inactive slot: {1}</string>
 		<string name="flash_ab_reboot">To flash additional zips, please reboot recovery to switch to the updated slot.</string>
+		<string name="ozip_decrypt_decryption">Starting Ozip Decryption...</string>
+		<string name="ozip_decrypt_finish">Ozip Decryption Finished!</string>
 	</resources>
 </language>
diff --git a/gui/theme/common/portrait.xml b/gui/theme/common/portrait.xml
index a14fc43..4b8cd4a 100755
--- a/gui/theme/common/portrait.xml
+++ b/gui/theme/common/portrait.xml
@@ -267,7 +267,7 @@
 				<condition var1="tw_selectimage" var2="0"/>
 				<placement x="%indent%" y="%row3_y%" w="%content_width%" h="%fileselector_install_height%"/>
 				<text>%tw_zip_location%</text>
-				<filter extn=".zip" folders="1" files="1"/>
+				<filter extn=".zip;.ozip;.ZIP;.OZIP" folders="1" files="1"/>
 				<path name="tw_zip_location" default="/sdcard"/>
 				<data name="tw_filename"/>
 				<selection name="tw_file"/>
diff --git a/gui/theme/common/watch.xml b/gui/theme/common/watch.xml
index af6a643..7b474dd 100755
--- a/gui/theme/common/watch.xml
+++ b/gui/theme/common/watch.xml
@@ -398,7 +398,7 @@
 				<condition var1="tw_selectimage" var2="0"/>
 				<placement x="%indent%" y="%row2_header_y%" w="%content_width%" h="%fileselector_install_height%"/>
 				<text>%tw_zip_location%</text>
-				<filter extn=".zip" folders="1" files="1"/>
+				<filter extn=".zip;.ozip;.ZIP;.OZIP" folders="1" files="1"/>
 				<path name="tw_zip_location" default="/sdcard"/>
 				<data name="tw_filename"/>
 				<selection name="tw_file"/>
diff --git a/ozip_decrypt/Android.mk b/ozip_decrypt/Android.mk
new file mode 100644
index 0000000..161cae8
--- /dev/null
+++ b/ozip_decrypt/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := ozip_decrypt
+LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := ozip_decrypt.cpp
+LOCAL_C_INCLUDES := external/boringssl/src/include
+LOCAL_SHARED_LIBRARIES := libcrypto
+include $(BUILD_EXECUTABLE)
diff --git a/ozip_decrypt/ozip_decrypt.cpp b/ozip_decrypt/ozip_decrypt.cpp
new file mode 100644
index 0000000..97826ec
--- /dev/null
+++ b/ozip_decrypt/ozip_decrypt.cpp
@@ -0,0 +1,152 @@
+/*
+	Copyright 2020 Mauronofrio
+
+	This file is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This file is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	GNU General Public License <http://www.gnu.org/licenses/>.
+*/
+
+#include <iostream>
+#include <string.h>
+#include <openssl/evp.h>
+#include <openssl/ssl.h>
+#define _FILE_OFFSET_BITS 64
+//extern "C" __int64 __cdecl _ftelli64(FILE*);
+
+using namespace std;
+typedef std::basic_string<unsigned char> u_string;
+
+int decrypt(unsigned char* ciphertext, int ciphertext_len, unsigned char* key,
+	unsigned char* iv, unsigned char* plaintext)
+{
+	EVP_CIPHER_CTX* ctx;
+	int len;
+	int plaintext_len;
+	ctx = EVP_CIPHER_CTX_new();
+	EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key, iv);
+	EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len);
+	plaintext_len = len;
+	EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
+	plaintext_len += len;
+	EVP_CIPHER_CTX_free(ctx);
+	return plaintext_len;
+}
+
+std::string hexToASCII(string hex)
+{
+	int len = hex.length();
+	std::string newString;
+	for (int i = 0; i < len; i += 2)
+	{
+		string byte = hex.substr(i, 2);
+		char chr = (char)(int)strtol(byte.c_str(), nullptr, 16);
+		newString.push_back(chr);
+	}
+	return newString;
+}
+
+bool testkey(const char* keyf, const char* path) {
+	u_string key = (unsigned char*)(hexToASCII(keyf)).c_str();
+	int data[17];
+	FILE* fps = fopen(path, "rb");
+	fseek(fps, 4176, SEEK_SET);
+	fread(data, sizeof(char), 16, fps);
+	fclose(fps);
+	u_string udata = (unsigned char*)data;
+	EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
+	EVP_CIPHER_CTX_init(ctx);
+	EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), NULL, key.c_str(), NULL);
+	EVP_CIPHER_CTX_set_padding(ctx, false);
+	unsigned char buffer[1024], * pointer = buffer;
+	int outlen;
+	EVP_DecryptUpdate(ctx, pointer, &outlen, udata.c_str(), udata.length());
+	pointer += outlen;
+	EVP_DecryptFinal_ex(ctx, pointer, &outlen);
+	pointer += outlen;
+	EVP_CIPHER_CTX_free(ctx);
+	u_string test= u_string(buffer, pointer - buffer);
+	u_string checktest = test.substr(0, 4);
+	if (checktest == ((unsigned char*) "\x50\x4B\x03\x04") || checktest == ((unsigned char*) "\x41\x4E\x44\x52")) {
+		return true;
+	}
+	return false;
+}
+
+int main(int argc, char* argv[])
+{
+
+	if (argc != 3)
+	{
+		printf("Usage: ozipdecrypt key [*.ozip]\n");
+		return 0;
+	}
+	const char* key = argv[1];
+	const char* path = argv[2];
+	FILE* fp = fopen(path, "rb");
+	char magic[13];
+	fgets(magic, sizeof(magic), fp);
+	string temp(path);
+	temp = (temp.substr(0, temp.size() - 5)).append(".zip");
+	const char* destpath= temp.c_str();
+	if (strcmp(magic, "OPPOENCRYPT!") != 0)
+	{
+		printf("This is not an .ozip file!\n");
+		fclose(fp);
+		int rencheck = rename(path, destpath);
+		if (rencheck == 0) {
+			printf("Renamed .ozip file in .zip file\n");
+		}
+		else
+		{
+			printf("Unable to rename .ozip file in .zip file\n");
+		}
+		return 0;
+	}
+	if (testkey(key, path) == false)
+	{
+		printf("Key is not good!\n");
+		fclose(fp);
+		return 0;
+	}
+	else {
+		printf("Key is good!\n");
+	}
+	FILE* fp2 = fopen(destpath, "wb");
+	fseek(fp, 0L, SEEK_END);
+	unsigned long int sizetot = ftello(fp);
+	fseek(fp, 4176, SEEK_SET);
+	int bdata[16384];
+	unsigned long int sizeseek;
+	printf("Decrypting...\n");
+	while (true)
+	{
+		unsigned char data[17];
+		fread(data, sizeof(char), 16, fp);
+		decrypt(data, sizeof(data), (unsigned char*)(hexToASCII(key)).c_str(), NULL, data);
+		fwrite(data, sizeof(char), 16, fp2);
+		sizeseek = ftello(fp);
+		if ((sizetot - sizeseek) <= 16384) {
+			fread(bdata, sizeof(char), (sizetot - sizeseek), fp);
+			fwrite(bdata, sizeof(char), (sizetot - sizeseek), fp2);
+			break;
+		}
+		else
+		{
+			fread(bdata, sizeof(char), 16384, fp);
+			fwrite(bdata, sizeof(char), 16384, fp2);
+		}
+	}
+	printf("File succesfully decrypted, saved in %s\n", destpath);
+	fclose(fp2);
+	fclose(fp);
+	return 0;
+}
+
diff --git a/prebuilt/Android.mk b/prebuilt/Android.mk
index 2935113..a4f6f2e 100644
--- a/prebuilt/Android.mk
+++ b/prebuilt/Android.mk
@@ -59,6 +59,9 @@
 RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/tune2fs
 RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/resize2fs
 RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/simg2img
+ifneq ($(TW_OZIP_DECRYPT_KEY),)
+    RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/ozip_decrypt
+endif
 ifneq ($(TARGET_ARCH), x86_64)
     RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/linker
 endif