Example #1
0
        static DecryptMaterial parse_backup_file_module_info(XmlDocument xml_entry)
        {
            string          aString = xml_entry.FirstChild.Attributes["table"].Value;
            DecryptMaterial decm    = new DecryptMaterial(aString);

            XmlNodeList elemList = xml_entry.GetElementsByTagName("column");

            foreach (XmlNode entry in elemList)
            {
                string name = entry.Attributes["name"].Value;
                if (name == "encMsgV3")
                {
                    decm.encMsgV3 = xml_get_column_value(entry) as string;
                }
                else if (name == "checkMsgV3")
                {
                    // TBR: reverse this double sized checkMsgV3.
                }
                else if (name == "name")
                {
                    decm.name = xml_get_column_value(entry) as string;
                }
            }

            if (decm.do_check() == false)
            {
                return(null);
            }

            return(decm);
        }
Example #2
0
        static HybridDictionary parse_xml(string filepath, HybridDictionary decrypt_material_dict)
        {
            string filename = Path.GetFileName(filepath);

            Console.WriteLine("parsing xml file " + filename);

            // Create the XmlDocument.
            XmlDocument xml_dom = new XmlDocument();

            xml_dom.Load(filepath);

            string fullpath = Directory.GetParent(filepath).FullName;
            string parent   = Path.Combine(fullpath, Path.GetFileNameWithoutExtension(filepath));

            XmlNodeList elemList = xml_dom.GetElementsByTagName("File");

            foreach (XmlNode node in elemList)
            {
                string path = node.SelectSingleNode("Path").InnerText;
                string iv   = node.SelectSingleNode("Iv").InnerText;
                if (!String.IsNullOrEmpty(path) && !String.IsNullOrEmpty(iv))
                {
                    DecryptMaterial dec_material = new DecryptMaterial(Path.GetFileNameWithoutExtension(filepath));
                    // XML files use Windows style path separator, backslash.
                    dec_material.path = path;
                    dec_material.iv   = iv;
                    string dkey = Path.Combine(parent, path.TrimStart(new char[] { '\\' }));
                    decrypt_material_dict[dkey] = dec_material;
                }
            }

            return(decrypt_material_dict);
        }
Example #3
0
        internal string decrypt_package(DecryptMaterial dec_material, byte[] data)
        {
            if (this.good == false)
            {
                Console.WriteLine("well, it is hard to decrypt with a wrong key.");
            }

            if (String.IsNullOrEmpty(dec_material.encMsgV3))
            {
                Console.WriteLine("cannot decrypt with an empty encMsgV3!");
                return(null);
            }

            byte[] salt       = dec_material._encMsgV3Bytes.Take(32).ToArray();
            byte[] counter_iv = dec_material._encMsgV3Bytes.Skip(32).ToArray();

            byte[] key = PBKDF2_SHA256_GetBytes(Encoding.UTF8.GetBytes(this._bkey), salt, Decryptor.dklen, Decryptor.count);

            string       filename = @"./__temp__/" + Guid.NewGuid().ToString();
            FileStream   output   = new FileStream(filename, FileMode.CreateNew, FileAccess.Write);
            MemoryStream input    = new MemoryStream(data);

            AES_CTR_Transform(key, counter_iv, input, output);
            output.Dispose();
            output.Close();

            return(filename);
        }
Example #4
0
        internal byte[] decrypt_package(DecryptMaterial dec_material, byte[] data)
        {
            if (this.good == false)
            {
                Console.WriteLine("well, it is hard to decrypt with a wrong key.");
            }

            if (String.IsNullOrEmpty(dec_material.encMsgV3))
            {
                Console.WriteLine("cannot decrypt with an empty encMsgV3!");
                return(null);
            }

            byte[] salt       = dec_material._encMsgV3Bytes.Take(32).ToArray();
            byte[] counter_iv = dec_material._encMsgV3Bytes.Skip(32).ToArray();

            byte[] key = PBKDF2_SHA256_GetBytes(Encoding.UTF8.GetBytes(this._bkey), salt, Decryptor.dklen, Decryptor.count);

            MemoryStream output = new MemoryStream();
            MemoryStream input  = new MemoryStream(data);

            AES_CTR_Transform(key, counter_iv, input, output);

            return(output.ToArray());
        }
Example #5
0
        static HybridDictionary parse_info_xml(string filepath, ref Decryptor decryptor, HybridDictionary decrypt_material_dict)
        {
            // Create the XmlDocument.
            XmlDocument info_dom = new XmlDocument();

            info_dom.Load(filepath);

            if (info_dom.GetElementsByTagName("info.xml").Count != 1)
            {
                Console.WriteLine("First tag should be 'info.xml', not '{0}'", info_dom.FirstChild.Name);
                decryptor = null;
                return(null);
            }

            string parent = Directory.GetParent(filepath).FullName;

            XmlDocument doc;
            XmlNodeList elemList = info_dom.GetElementsByTagName("row");

            foreach (XmlNode entry in elemList)
            {
                string title = entry.Attributes["table"].Value;
                switch (title)
                {
                case "BackupFilesTypeInfo":
                    doc = new XmlDocument();
                    doc.LoadXml(entry.OuterXml);
                    parse_backup_files_type_info(ref decryptor, doc);
                    break;

                case "HeaderInfo":
                case "BackupFilePhoneInfo":
                case "BackupFileVersionInfo":
                    ignore_entry(entry);
                    break;

                case "BackupFileModuleInfo":
                case "BackupFileModuleInfo_Contact":
                case "BackupFileModuleInfo_Media":
                case "BackupFileModuleInfo_SystemData":
                    doc = new XmlDocument();
                    doc.LoadXml(entry.OuterXml);
                    DecryptMaterial dec_material = parse_backup_file_module_info(doc);
                    if (dec_material != null)
                    {
                        string dkey = Path.Combine(parent, dec_material.name);
                        decrypt_material_dict[dkey] = dec_material;
                    }
                    break;

                default:
                    Console.WriteLine("Unknown entry in 'info.xml': {0}", title);
                    break;
                }
            }

            return(decrypt_material_dict);
        }
Example #6
0
        internal void crypto_init()
        {
            if (this.good == true)
            {
                Console.WriteLine("crypto_init: already done with success!");
                return;
            }

            if (this.type_attch != 3)
            {
                Console.WriteLine("crypto_init: type_attch *should be* 3!");
                return;
            }

            if (!String.IsNullOrEmpty(this.e_perbackupkey) && !String.IsNullOrEmpty(this.pwkey_salt))
            {
                Console.WriteLine("crypto_init: using version 4");
                __decrypt_bkey_v4();
            }
            else
            {
                Console.WriteLine("crypto_init: using version 3");
                this._bkey = this._upwd;
            }

            var passwordBytes = Encoding.UTF8.GetBytes(this._bkey);

            passwordBytes     = SHA256.Create().ComputeHash(passwordBytes);
            this._bkey_sha256 = passwordBytes.Take(16).ToArray();
            Console.WriteLine("SHA256(BKEY)[{0}] = {1}", this._bkey_sha256.Length,
                              DecryptMaterial.hexlify(this._bkey_sha256));

            byte[] salt = this._checkMsgBytes.Skip(32).ToArray();
            Console.WriteLine("SALT[{0}] = {1}", salt.Length, DecryptMaterial.hexlify(salt));

            byte[] res = PBKDF2_SHA256_GetBytes(Encoding.UTF8.GetBytes(this._bkey), salt, Decryptor.dklen, Decryptor.count);
            Console.WriteLine("KEY check expected = {0}",
                              DecryptMaterial.hexlify(this._checkMsgBytes.Take(32).ToArray()));
            Console.WriteLine("RESULT = {0}", DecryptMaterial.hexlify(res));

            if (res.SequenceEqual(this._checkMsgBytes.Take(32)) == true)
            {
                Console.WriteLine("OK, backup key is correct!");
                this.good = true;
            }
            else
            {
                Console.WriteLine("KO, backup key is wrong!");
                this.good = false;
            }
        }
Example #7
0
        internal byte[] decrypt_file(DecryptMaterial dec_material, byte[] data)
        {
            if (this.good == false)
            {
                Console.WriteLine("well, it is hard to decrypt with a wrong key.");
            }

            if (String.IsNullOrEmpty(dec_material.iv))
            {
                Console.WriteLine("cannot decrypt with an empty iv!");
                return(null);
            }

            MemoryStream output = new MemoryStream();
            MemoryStream input  = new MemoryStream(data);

            AES_CTR_Transform(this._bkey_sha256, dec_material._ivBytes, input, output);

            return(output.ToArray());
        }
Example #8
0
        internal static void decrypt(string user_password, string backup_path_in, string dest_path_out)
        {
            Console.WriteLine("getting files and folders from: " + backup_path_in);
            if (!Directory.Exists(backup_path_in))
            {
                Console.WriteLine("input backup folder does not exist!");
                return;
            }

            Console.WriteLine("using output folder: " + dest_path_out);
            if (Directory.Exists(dest_path_out))
            {
                List <string> files = Directory.GetFiles(dest_path_out, "*.*", SearchOption.AllDirectories).ToList();
                if (files.Count > 0)
                {
                    Console.WriteLine("output folder contains {0} files, cannot overwrite them!", files.Count);
                    return;
                }
            }

            List <string> backup_all_files = Directory.GetFiles(backup_path_in, "*.*", SearchOption.AllDirectories).ToList();
            List <string> xml_files        = new List <string>();
            List <string> apk_files        = new List <string>();
            List <string> tar_files        = new List <string>();
            List <string> db_files         = new List <string>();
            List <string> enc_files        = new List <string>();
            List <string> unk_files        = new List <string>();
            List <string> done_list;

            foreach (string entry in backup_all_files)
            {
                string extension = Path.GetExtension(entry).ToLower();
                switch (extension)
                {
                case ".xml":
                    xml_files.Add(entry);
                    break;

                case ".apk":
                    apk_files.Add(entry);
                    break;

                case ".tar":
                    tar_files.Add(entry);
                    break;

                case ".db":
                    db_files.Add(entry);
                    break;

                case ".enc":
                    enc_files.Add(entry);
                    break;

                default:
                    unk_files.Add(entry);
                    break;
                }
            }

            HybridDictionary decrypt_material_dict = new HybridDictionary();
            Decryptor        decryptor             = new Decryptor(user_password);

            Console.WriteLine("parsing XML files...");
            foreach (string entry in xml_files)
            {
                string filename = Path.GetFileName(entry);
                Console.WriteLine("parsing xml " + filename);
                if (filename.ToLower() == "info.xml")
                {
                    decrypt_material_dict = parse_info_xml(entry, ref decryptor, decrypt_material_dict);
                }
                else
                {
                    decrypt_material_dict = parse_xml(entry, decrypt_material_dict);
                }
            }

            decryptor.crypto_init();
            if (decryptor.good == false)
            {
                Console.WriteLine("decryption key is not good...");
                return;
            }

            if (apk_files.Count > 0)
            {
                Console.WriteLine("copying APK to destination...");
                string data_apk_dir = Path.Combine(dest_path_out, @"data\app");
                Directory.CreateDirectory(data_apk_dir);

                done_list = new List <string>();
                foreach (string entry in apk_files)
                {
                    string filename = Path.GetFileName(entry);
                    Console.WriteLine("working on " + filename);
                    string dest_file = Path.Combine(data_apk_dir, filename + "-1");
                    Directory.CreateDirectory(dest_file);
                    dest_file = Path.Combine(dest_file, "base.apk");
                    File.Copy(entry, dest_file);
                    done_list.Add(entry);
                }

                foreach (string entry in done_list)
                {
                    apk_files.Remove(entry);
                }
            }

            if (tar_files.Count > 0)
            {
                Console.WriteLine("decrypting and un-TAR-ing packages to destination...");
                string data_app_dir = Path.Combine(dest_path_out, @"data\data");
                Directory.CreateDirectory(data_app_dir);

                done_list = new List <string>();
                foreach (string entry in tar_files)
                {
                    Console.WriteLine("working on " + Path.GetFileName(entry));
                    string cleartext = null;
                    string directory = Path.GetDirectoryName(entry);
                    string filename  = Path.GetFileNameWithoutExtension(entry);
                    string skey      = Path.Combine(directory, filename);
                    if (decrypt_material_dict.Contains(skey))
                    {
                        done_list.Add(entry);
                        DecryptMaterial dec_material = (DecryptMaterial)decrypt_material_dict[skey];
                        cleartext = decryptor.decrypt_package(dec_material, File.ReadAllBytes(entry));
                    }
                    else
                    {
                        Console.WriteLine("entry '{0}' has no decrypt material!", skey);
                    }

                    if (cleartext != null)
                    {
                        using (FileStream ms = new FileStream(cleartext, FileMode.Open, FileAccess.Read))
                        {
                            TAR_Extract(ms, data_app_dir);
                        }
                    }
                    else if (File.Exists(entry))
                    {
                        using (StreamReader sr = new StreamReader(entry))
                        {
                            TAR_Extract(sr.BaseStream, data_app_dir);
                        }
                    }
                }

                foreach (string entry in done_list)
                {
                    tar_files.Remove(entry);
                }
            }

            if (db_files.Count > 0)
            {
                Console.WriteLine("decrypting database DB files to destination...");
                string data_app_dir = Path.Combine(dest_path_out, "db");
                Directory.CreateDirectory(data_app_dir);

                done_list = new List <string>();
                foreach (string entry in db_files)
                {
                    Console.WriteLine("working on " + Path.GetFileName(entry));
                    string cleartext = null;
                    string directory = Path.GetDirectoryName(entry);
                    string filename  = Path.GetFileNameWithoutExtension(entry);
                    string skey      = Path.Combine(directory, filename);
                    if (decrypt_material_dict.Contains(skey))
                    {
                        done_list.Add(entry);
                        DecryptMaterial dec_material = (DecryptMaterial)decrypt_material_dict[skey];
                        cleartext = decryptor.decrypt_package(dec_material, File.ReadAllBytes(entry));
                    }
                    else
                    {
                        Console.WriteLine("entry '{0}' has no decrypt material!", skey);
                    }

                    if (cleartext != null)
                    {
                        string dest_file = Path.Combine(data_app_dir, Path.GetFileName(entry));
                        File.Copy(cleartext, dest_file);
                        //File.WriteAllBytes(dest_file, cleartext);
                    }
                }

                foreach (string entry in done_list)
                {
                    db_files.Remove(entry);
                }
            }

            if (enc_files.Count > 0)
            {
                Console.WriteLine("decrypting multimedia ENC files to destination...");

                string asterisk = @"|/-\-";

                done_list = new List <string>();
                for (int i = 1; i <= enc_files.Count; i++)
                {
                    string          entry        = enc_files[i - 1];
                    byte[]          cleartext    = null;
                    DecryptMaterial dec_material = null;
                    string          directory    = Path.GetDirectoryName(entry);
                    string          filename     = Path.GetFileNameWithoutExtension(entry);
                    string          skey         = Path.Combine(directory, filename);
                    if (decrypt_material_dict.Contains(skey))
                    {
                        done_list.Add(entry);
                        dec_material = (DecryptMaterial)decrypt_material_dict[skey];
                        string aString = String.Format("{0} of {1}: {2}",
                                                       i, enc_files.Count,
                                                       Path.GetFileName(dec_material.path));
                        aString = aString.PadRight(Console.WindowWidth - 2).Substring(0, Console.WindowWidth - 2);
                        Console.Write("\r{0}{1}", aString, asterisk[i % asterisk.Length]);
                        cleartext = decryptor.decrypt_file(dec_material, File.ReadAllBytes(entry));
                    }
                    else
                    {
                        Console.WriteLine("entry '{0}' has no decrypt material!", skey);
                    }

                    if (cleartext != null && dec_material != null)
                    {
                        string dest_file = dest_path_out;
                        string tmp_path  = dec_material.path.TrimStart(new char[] { '\\', '/' });
                        dest_file = Path.Combine(dest_file, tmp_path);
                        string dest_dir = Directory.GetParent(dest_file).FullName;
                        Directory.CreateDirectory(dest_dir);
                        File.WriteAllBytes(dest_file, cleartext);
                    }
                }
                if (enc_files.Count > 0)
                {
                    Console.Write("\r");
                }

                foreach (string entry in done_list)
                {
                    enc_files.Remove(entry);
                }
            }


            if (unk_files.Count > 0)
            {
                Console.WriteLine("copying unmanaged files to destination...");
                string data_unk_dir = Path.Combine(dest_path_out, "misc");
                Directory.CreateDirectory(data_unk_dir);

                done_list = new List <string>();
                foreach (string entry in unk_files)
                {
                    string common_path = FindCommonPath(new List <string>()
                    {
                        entry,
                        backup_path_in
                    });
                    string relative_path = entry.Replace(common_path, "");
                    relative_path = relative_path.TrimStart(new char[] { '\\', '/' });
                    string dest_file = Path.Combine(data_unk_dir, relative_path);
                    Directory.CreateDirectory(Directory.GetParent(dest_file).FullName);
                    File.Copy(entry, dest_file);
                    done_list.Add(entry);
                }

                foreach (string entry in done_list)
                {
                    unk_files.Remove(entry);
                }
            }

            foreach (string entry in apk_files)
            {
                string filename = Path.GetFileName(entry);
                Console.WriteLine("APK file not handled: " + filename);
            }

            foreach (string entry in tar_files)
            {
                string filename = Path.GetFileName(entry);
                Console.WriteLine("TAR file not handled: " + filename);
            }

            foreach (string entry in db_files)
            {
                string filename = Path.GetFileName(entry);
                Console.WriteLine("DB file not handled: " + filename);
            }

            foreach (string entry in enc_files)
            {
                string filename = Path.GetFileName(entry);
                Console.WriteLine("ENC file not handled: " + filename);
            }

            foreach (string entry in unk_files)
            {
                string filename = Path.GetFileName(entry);
                Console.WriteLine("UNK file not handled: " + filename);
            }

            Console.WriteLine("DONE!");
        }