diff --git a/core/io/file_access.compat.inc b/core/io/file_access.compat.inc new file mode 100644 index 00000000000..ed16050126e --- /dev/null +++ b/core/io/file_access.compat.inc @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* file_access.compat.inc */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DISABLE_DEPRECATED + +Ref FileAccess::_open_encrypted_bind_compat_98918(const String &p_path, ModeFlags p_mode_flags, const Vector &p_key) { + return open_encrypted(p_path, p_mode_flags, p_key, Vector()); +} + +void FileAccess::_bind_compatibility_methods() { + ClassDB::bind_compatibility_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::_open_encrypted_bind_compat_98918); +} + +#endif // DISABLE_DEPRECATED diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index d8bf645a7de..dd826e626ba 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "file_access.h" +#include "file_access.compat.inc" #include "core/config/project_settings.h" #include "core/crypto/crypto_core.h" @@ -124,7 +125,7 @@ Ref FileAccess::_open(const String &p_path, ModeFlags p_mode_flags) return fa; } -Ref FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector &p_key) { +Ref FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector &p_key, const Vector &p_iv) { Ref fa = _open(p_path, p_mode_flags); if (fa.is_null()) { return fa; @@ -132,7 +133,7 @@ Ref FileAccess::open_encrypted(const String &p_path, ModeFlags p_mod Ref fae; fae.instantiate(); - Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ); + Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ, true, p_iv); last_file_open_error = err; if (err) { return Ref(); @@ -806,7 +807,7 @@ String FileAccess::get_sha256(const String &p_file) { void FileAccess::_bind_methods() { ClassDB::bind_static_method("FileAccess", D_METHOD("open", "path", "flags"), &FileAccess::_open); - ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::open_encrypted); + ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key", "iv"), &FileAccess::open_encrypted, DEFVAL(Vector())); ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &FileAccess::open_encrypted_pass); ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0)); ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error); diff --git a/core/io/file_access.h b/core/io/file_access.h index 7f5687fe036..88c8110a513 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -109,6 +109,12 @@ protected: static FileCloseFailNotify close_fail_notify; +#ifndef DISABLE_DEPRECATED + static Ref _open_encrypted_bind_compat_98918(const String &p_path, ModeFlags p_mode_flags, const Vector &p_key); + + static void _bind_compatibility_methods(); +#endif + private: static bool backup_save; thread_local static Error last_file_open_error; @@ -199,7 +205,7 @@ public: static Ref create_for_path(const String &p_path); static Ref open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files. - static Ref open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector &p_key); + static Ref open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector &p_key, const Vector &p_iv = Vector()); static Ref open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass); static Ref open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ); static Error get_open_error(); diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index 24be9ef2301..ba26f2e07bc 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -36,7 +36,7 @@ #include -Error FileAccessEncrypted::open_and_parse(Ref p_base, const Vector &p_key, Mode p_mode, bool p_with_magic) { +Error FileAccessEncrypted::open_and_parse(Ref p_base, const Vector &p_key, Mode p_mode, bool p_with_magic, const Vector &p_iv) { ERR_FAIL_COND_V_MSG(file.is_valid(), ERR_ALREADY_IN_USE, vformat("Can't open file while another file from path '%s' is open.", file->get_path_absolute())); ERR_FAIL_COND_V(p_key.size() != 32, ERR_INVALID_PARAMETER); @@ -49,6 +49,16 @@ Error FileAccessEncrypted::open_and_parse(Ref p_base, const Vector p_base, const Vectorget_buffer(md5d, 16); length = p_base->get_64(); - unsigned char iv[16]; - for (int i = 0; i < 16; i++) { - iv[i] = p_base->get_8(); - } + iv.resize(16); + p_base->get_buffer(iv.ptrw(), 16); base = p_base->get_position(); ERR_FAIL_COND_V(p_base->get_length() < base + length, ERR_FILE_CORRUPT); @@ -83,7 +91,7 @@ Error FileAccessEncrypted::open_and_parse(Ref p_base, const Vectorstore_buffer(hash, 16); file->store_64(data.size()); + file->store_buffer(iv.ptr(), 16); - unsigned char iv[16]; - for (int i = 0; i < 16; i++) { - iv[i] = Math::rand() % 256; - file->store_8(iv[i]); - } - - ctx.encrypt_cfb(len, iv, compressed.ptrw(), compressed.ptrw()); + ctx.encrypt_cfb(len, iv.ptrw(), compressed.ptrw(), compressed.ptrw()); file->store_buffer(compressed.ptr(), compressed.size()); data.clear(); diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index 5f8c803d602..63a8cab145b 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -44,6 +44,7 @@ public: }; private: + Vector iv; Vector key; bool writing = false; Ref file; @@ -57,9 +58,11 @@ private: void _close(); public: - Error open_and_parse(Ref p_base, const Vector &p_key, Mode p_mode, bool p_with_magic = true); + Error open_and_parse(Ref p_base, const Vector &p_key, Mode p_mode, bool p_with_magic = true, const Vector &p_iv = Vector()); Error open_and_parse_password(Ref p_base, const String &p_key, Mode p_mode); + Vector get_iv() const { return iv; } + virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file virtual bool is_open() const override; ///< true when file is open diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml index b782937a8ab..5c89b644298 100644 --- a/doc/classes/FileAccess.xml +++ b/doc/classes/FileAccess.xml @@ -308,6 +308,7 @@ + Creates a new [FileAccess] object and opens an encrypted file in write or read mode. You need to pass a binary key to encrypt/decrypt it. [b]Note:[/b] The provided key must be 32 bytes long. diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp index 6ca83c5e25c..cddc8173cbd 100644 --- a/editor/export/editor_export.cpp +++ b/editor/export/editor_export.cpp @@ -87,6 +87,8 @@ void EditorExport::_save() { config->set_value(section, "encryption_include_filters", preset->get_enc_in_filter()); config->set_value(section, "encryption_exclude_filters", preset->get_enc_ex_filter()); + config->set_value(section, "seed", preset->get_seed()); + config->set_value(section, "encrypt_pck", preset->get_enc_pck()); config->set_value(section, "encrypt_directory", preset->get_enc_directory()); config->set_value(section, "script_export_mode", preset->get_script_export_mode()); @@ -307,6 +309,9 @@ void EditorExport::load_config() { preset->set_script_export_mode(config->get_value(section, "script_export_mode", EditorExportPreset::MODE_SCRIPT_BINARY_TOKENS_COMPRESSED)); preset->set_patches(config->get_value(section, "patches", Vector())); + if (config->has_section_key(section, "seed")) { + preset->set_seed(config->get_value(section, "seed")); + } if (config->has_section_key(section, "encrypt_pck")) { preset->set_enc_pck(config->get_value(section, "encrypt_pck")); } diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 8b8fafcd327..91c9ff9807c 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -216,7 +216,7 @@ void EditorExportPlatform::_unload_patches() { PackedData::get_singleton()->clear(); } -Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key) { +Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed) { ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export."); PackData *pd = (PackData *)p_userdata; @@ -247,10 +247,27 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa Ref ftmp = pd->f; if (sd.encrypted) { + Vector iv; + if (p_seed != 0) { + uint64_t seed = p_seed; + + const uint8_t *ptr = p_data.ptr(); + int64_t len = p_data.size(); + for (int64_t i = 0; i < len; i++) { + seed = ((seed << 5) + seed) ^ ptr[i]; + } + + RandomPCG rng = RandomPCG(seed, RandomPCG::DEFAULT_INC); + iv.resize(16); + for (int i = 0; i < 16; i++) { + iv.write[i] = rng.rand() % 256; + } + } + fae.instantiate(); ERR_FAIL_COND_V(fae.is_null(), ERR_SKIP); - Error err = fae->open_and_parse(ftmp, p_key, FileAccessEncrypted::MODE_WRITE_AES256, false); + Error err = fae->open_and_parse(ftmp, p_key, FileAccessEncrypted::MODE_WRITE_AES256, false, iv); ERR_FAIL_COND_V(err != OK, ERR_SKIP); ftmp = fae; } @@ -288,15 +305,15 @@ Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_pa return OK; } -Error EditorExportPlatform::_save_pack_patch_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key) { +Error EditorExportPlatform::_save_pack_patch_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed) { if (_check_hash(PackedData::get_singleton()->get_file_hash(p_path), p_data)) { return OK; } - return _save_pack_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key); + return _save_pack_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key, p_seed); } -Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key) { +Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed) { ERR_FAIL_COND_V_MSG(p_total < 1, ERR_PARAMETER_RANGE_ERROR, "Must select at least one file to export."); String path = p_path.replace_first("res://", ""); @@ -328,12 +345,12 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat return OK; } -Error EditorExportPlatform::_save_zip_patch_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key) { +Error EditorExportPlatform::_save_zip_patch_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed) { if (_check_hash(PackedData::get_singleton()->get_file_hash(p_path), p_data)) { return OK; } - return _save_zip_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key); + return _save_zip_file(p_userdata, p_path, p_data, p_file, p_total, p_enc_in_filters, p_enc_ex_filters, p_key, p_seed); } Ref EditorExportPlatform::get_option_icon(int p_index) const { @@ -932,7 +949,7 @@ Vector EditorExportPlatform::get_forced_export_files() { return files; } -Error EditorExportPlatform::_script_save_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key) { +Error EditorExportPlatform::_script_save_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed) { Callable cb = ((ScriptCallbackData *)p_userdata)->file_cb; ERR_FAIL_COND_V(!cb.is_valid(), FAILED); @@ -1043,8 +1060,10 @@ Error EditorExportPlatform::export_project_files(const Ref & Vector enc_in_filters; Vector enc_ex_filters; Vector key; + uint64_t seed = 0; if (enc_pck) { + seed = p_preset->get_seed(); Vector enc_in_split = p_preset->get_enc_in_filter().split(","); for (int i = 0; i < enc_in_split.size(); i++) { String f = enc_in_split[i].strip_edges(); @@ -1116,7 +1135,7 @@ Error EditorExportPlatform::export_project_files(const Ref & } } for (int j = 0; j < export_plugins[i]->extra_files.size(); j++) { - err = p_save_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, 0, paths.size(), enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, 0, paths.size(), enc_in_filters, enc_ex_filters, key, seed); if (err != OK) { return err; } @@ -1234,7 +1253,7 @@ Error EditorExportPlatform::export_project_files(const Ref & } for (int j = 0; j < export_plugins[i]->extra_files.size(); j++) { - err = p_save_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, idx, total, enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, export_plugins[i]->extra_files[j].path, export_plugins[i]->extra_files[j].data, idx, total, enc_in_filters, enc_ex_filters, key, seed); if (err != OK) { return err; } @@ -1266,7 +1285,7 @@ Error EditorExportPlatform::export_project_files(const Ref & if (importer_type == "keep") { // Just keep file as-is. Vector array = FileAccess::get_file_as_bytes(path); - err = p_save_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key, seed); if (err != OK) { return err; @@ -1309,13 +1328,13 @@ Error EditorExportPlatform::export_project_files(const Ref & sarr.resize(cs.size()); memcpy(sarr.ptrw(), cs.ptr(), sarr.size()); - err = p_save_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key, seed); if (err != OK) { return err; } // Now actual remapped file: sarr = FileAccess::get_file_as_bytes(export_path); - err = p_save_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key, seed); if (err != OK) { return err; } @@ -1345,14 +1364,14 @@ Error EditorExportPlatform::export_project_files(const Ref & if (remap == "path") { String remapped_path = config->get_value("remap", remap); Vector array = FileAccess::get_file_as_bytes(remapped_path); - err = p_save_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key, seed); } else if (remap.begins_with("path.")) { String feature = remap.get_slice(".", 1); if (remap_features.has(feature)) { String remapped_path = config->get_value("remap", remap); Vector array = FileAccess::get_file_as_bytes(remapped_path); - err = p_save_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key, seed); } else { // Remove paths if feature not enabled. config->erase_section_key("remap", remap); @@ -1378,7 +1397,7 @@ Error EditorExportPlatform::export_project_files(const Ref & sarr.resize(cs.size()); memcpy(sarr.ptrw(), cs.ptr(), sarr.size()); - err = p_save_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, path + ".import", sarr, idx, total, enc_in_filters, enc_ex_filters, key, seed); if (err != OK) { return err; @@ -1399,7 +1418,7 @@ Error EditorExportPlatform::export_project_files(const Ref & } Vector array = FileAccess::get_file_as_bytes(export_path); - err = p_save_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key, seed); if (err != OK) { return err; } @@ -1463,7 +1482,7 @@ Error EditorExportPlatform::export_project_files(const Ref & new_file.write[j] = utf8[j]; } - err = p_save_func(p_udata, from + ".remap", new_file, idx, total, enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, from + ".remap", new_file, idx, total, enc_in_filters, enc_ex_filters, key, seed); if (err != OK) { return err; } @@ -1477,7 +1496,7 @@ Error EditorExportPlatform::export_project_files(const Ref & Vector forced_export = get_forced_export_files(); for (int i = 0; i < forced_export.size(); i++) { Vector array = FileAccess::get_file_as_bytes(forced_export[i]); - err = p_save_func(p_udata, forced_export[i], array, idx, total, enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, forced_export[i], array, idx, total, enc_in_filters, enc_ex_filters, key, seed); if (err != OK) { return err; } @@ -1489,7 +1508,7 @@ Error EditorExportPlatform::export_project_files(const Ref & Vector data = FileAccess::get_file_as_bytes(engine_cfb); DirAccess::remove_file_or_error(engine_cfb); - err = p_save_func(p_udata, "res://" + config_file, data, idx, total, enc_in_filters, enc_ex_filters, key); + err = p_save_func(p_udata, "res://" + config_file, data, idx, total, enc_in_filters, enc_ex_filters, key, seed); if (err != OK) { return err; } @@ -1872,6 +1891,7 @@ Error EditorExportPlatform::save_pack(const Ref &p_preset, b Ref fhead = f; if (enc_pck && enc_directory) { + uint64_t seed = p_preset->get_seed(); String script_key = _get_script_encryption_key(p_preset); Vector key; key.resize(32); @@ -1906,7 +1926,27 @@ Error EditorExportPlatform::save_pack(const Ref &p_preset, b return ERR_CANT_CREATE; } - err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_WRITE_AES256, false); + Vector iv; + if (seed != 0) { + for (int i = 0; i < pd.file_ofs.size(); i++) { + for (int64_t j = 0; j < pd.file_ofs[i].path_utf8.length(); j++) { + seed = ((seed << 5) + seed) ^ pd.file_ofs[i].path_utf8.get_data()[j]; + } + for (int64_t j = 0; j < pd.file_ofs[i].md5.size(); j++) { + seed = ((seed << 5) + seed) ^ pd.file_ofs[i].md5[j]; + } + seed = ((seed << 5) + seed) ^ pd.file_ofs[i].ofs; + seed = ((seed << 5) + seed) ^ pd.file_ofs[i].size; + } + + RandomPCG rng = RandomPCG(seed, RandomPCG::DEFAULT_INC); + iv.resize(16); + for (int i = 0; i < 16; i++) { + iv.write[i] = rng.rand() % 256; + } + } + + err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_WRITE_AES256, false, iv); if (err != OK) { add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), TTR("Can't open encrypted file to write.")); return ERR_CANT_CREATE; diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h index 919fb2915a4..c7378ffec7e 100644 --- a/editor/export/editor_export_platform.h +++ b/editor/export/editor_export_platform.h @@ -53,7 +53,7 @@ protected: static void _bind_methods(); public: - typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); + typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed); typedef Error (*EditorExportRemoveFunction)(void *p_userdata, const String &p_path); typedef Error (*EditorExportSaveSharedObject)(void *p_userdata, const SharedObject &p_so); @@ -114,14 +114,14 @@ private: static bool _check_hash(const uint8_t *p_hash, const Vector &p_data); - static Error _save_pack_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); - static Error _save_pack_patch_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); + static Error _save_pack_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed); + static Error _save_pack_patch_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed); static Error _pack_add_shared_object(void *p_userdata, const SharedObject &p_so); static Error _remove_pack_file(void *p_userdata, const String &p_path); - static Error _save_zip_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); - static Error _save_zip_patch_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); + static Error _save_zip_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed); + static Error _save_zip_patch_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed); static Error _zip_add_shared_object(void *p_userdata, const SharedObject &p_so); struct ScriptCallbackData { @@ -129,7 +129,7 @@ private: Callable so_cb; }; - static Error _script_save_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); + static Error _script_save_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed); static Error _script_add_shared_object(void *p_userdata, const SharedObject &p_so); void _edit_files_with_filter(Ref &da, const Vector &p_filters, HashSet &r_list, bool exclude); diff --git a/editor/export/editor_export_preset.cpp b/editor/export/editor_export_preset.cpp index da7059b7777..8ff5dd75514 100644 --- a/editor/export/editor_export_preset.cpp +++ b/editor/export/editor_export_preset.cpp @@ -451,6 +451,15 @@ String EditorExportPreset::get_enc_ex_filter() const { return enc_ex_filters; } +void EditorExportPreset::set_seed(uint64_t p_seed) { + seed = p_seed; + EditorExport::singleton->save_presets(); +} + +uint64_t EditorExportPreset::get_seed() const { + return seed; +} + void EditorExportPreset::set_enc_pck(bool p_enabled) { enc_pck = p_enabled; EditorExport::singleton->save_presets(); diff --git a/editor/export/editor_export_preset.h b/editor/export/editor_export_preset.h index af3a23fc50d..4834a483eb1 100644 --- a/editor/export/editor_export_preset.h +++ b/editor/export/editor_export_preset.h @@ -92,6 +92,7 @@ private: String enc_ex_filters; bool enc_pck = false; bool enc_directory = false; + uint64_t seed = 0; String script_key; int script_mode = MODE_SCRIPT_BINARY_TOKENS_COMPRESSED; @@ -165,6 +166,9 @@ public: void set_enc_ex_filter(const String &p_filter); String get_enc_ex_filter() const; + void set_seed(uint64_t p_seed); + uint64_t get_seed() const; + void set_enc_pck(bool p_enabled); bool get_enc_pck() const; diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index a3cd6523e98..8ae4b856a04 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -382,10 +382,16 @@ void ProjectExportDialog::_edit_preset(int p_index) { bool enc_pck_mode = current->get_enc_pck(); enc_pck->set_pressed(enc_pck_mode); + uint64_t seed = current->get_seed(); + if (!updating_seed) { + seed_input->set_text(itos(seed)); + } + enc_directory->set_disabled(!enc_pck_mode); enc_in_filters->set_editable(enc_pck_mode); enc_ex_filters->set_editable(enc_pck_mode); script_key->set_editable(enc_pck_mode); + seed_input->set_editable(enc_pck_mode); bool enc_directory_mode = current->get_enc_directory(); enc_directory->set_pressed(enc_directory_mode); @@ -591,6 +597,21 @@ void ProjectExportDialog::_enc_pck_changed(bool p_pressed) { _update_current_preset(); } +void ProjectExportDialog::_seed_input_changed(const String &p_text) { + if (updating) { + return; + } + + Ref current = get_current_preset(); + ERR_FAIL_COND(current.is_null()); + + current->set_seed(seed_input->get_text().to_int()); + + updating_seed = true; + _update_current_preset(); + updating_seed = false; +} + void ProjectExportDialog::_enc_directory_changed(bool p_pressed) { if (updating) { return; @@ -1623,6 +1644,10 @@ ProjectExportDialog::ProjectExportDialog() { sec_vb->add_child(script_key_error); sections->add_child(sec_scroll_container); + seed_input = memnew(LineEdit); + seed_input->connect(SceneStringName(text_changed), callable_mp(this, &ProjectExportDialog::_seed_input_changed)); + sec_vb->add_margin_child(TTR("Initialization vector seed"), seed_input); + Label *sec_info = memnew(Label); sec_info->set_text(TTR("Note: Encryption key needs to be stored in the binary,\nyou need to build the export templates from source.")); sec_vb->add_child(sec_info); diff --git a/editor/export/project_export.h b/editor/export/project_export.h index bbf0d81228f..68676bfc844 100644 --- a/editor/export/project_export.h +++ b/editor/export/project_export.h @@ -172,6 +172,7 @@ class ProjectExportDialog : public ConfirmationDialog { CheckButton *enc_directory = nullptr; LineEdit *enc_in_filters = nullptr; LineEdit *enc_ex_filters = nullptr; + LineEdit *seed_input = nullptr; OptionButton *script_mode = nullptr; @@ -192,9 +193,11 @@ class ProjectExportDialog : public ConfirmationDialog { bool updating_script_key = false; bool updating_enc_filters = false; + bool updating_seed = false; void _enc_pck_changed(bool p_pressed); void _enc_directory_changed(bool p_pressed); void _enc_filters_changed(const String &p_text); + void _seed_input_changed(const String &p_text); void _script_encryption_key_changed(const String &p_key); bool _validate_script_encryption_key(const String &p_key); diff --git a/misc/extension_api_validation/4.3-stable.expected b/misc/extension_api_validation/4.3-stable.expected index 4f5ebc7a68e..75e81b5ff40 100644 --- a/misc/extension_api_validation/4.3-stable.expected +++ b/misc/extension_api_validation/4.3-stable.expected @@ -115,3 +115,10 @@ GH-91201 Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/OS/methods/read_string_from_stdin': arguments Added optional argument. Compatibility method registered. + + +GH-98918 +-------- +Validate extension JSON: Error: Field 'classes/FileAccess/methods/open_encrypted/arguments': size changed value in new API, from 3 to 4. + +Optional argument added to allow setting initialization vector. Compatibility method registered. diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 65916931c26..df3142ecbb6 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -788,7 +788,7 @@ Error EditorExportPlatformAndroid::save_apk_so(void *p_userdata, const SharedObj return OK; } -Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key) { +Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed) { APKExportData *ed = static_cast(p_userdata); String dst_path = p_path.replace_first("res://", "assets/"); @@ -796,7 +796,7 @@ Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata, const String return OK; } -Error EditorExportPlatformAndroid::ignore_apk_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key) { +Error EditorExportPlatformAndroid::ignore_apk_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed) { return OK; } diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index 15e80f824d8..23b6f9b1939 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -142,9 +142,9 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { static Error save_apk_so(void *p_userdata, const SharedObject &p_so); - static Error save_apk_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); + static Error save_apk_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed); - static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); + static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed); static Error copy_gradle_so(void *p_userdata, const SharedObject &p_so); @@ -186,7 +186,7 @@ protected: void _notification(int p_what); public: - typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); + typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed); virtual void get_preset_features(const Ref &p_preset, List *r_features) const override; diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp index b2aed9a0dcd..3603565805e 100644 --- a/platform/android/export/gradle_export_util.cpp +++ b/platform/android/export/gradle_export_util.cpp @@ -169,7 +169,7 @@ Error store_string_at_path(const String &p_path, const String &p_data) { // It is used by the export_project_files method to save all the asset files into the gradle project. // It's functionality mirrors that of the method save_apk_file. // This method will be called ONLY when gradle build is enabled. -Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key) { +Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed) { CustomExportData *export_data = static_cast(p_userdata); String dst_path = p_path.replace_first("res://", export_data->assets_directory + "/"); print_verbose("Saving project files from " + p_path + " into " + dst_path); diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index a17fdf0e270..a528fd52115 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -93,7 +93,7 @@ Error store_string_at_path(const String &p_path, const String &p_data); // It is used by the export_project_files method to save all the asset files into the gradle project. // It's functionality mirrors that of the method save_apk_file. // This method will be called ONLY when gradle build is enabled. -Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); +Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key, uint64_t p_seed); // Creates strings.xml files inside the gradle project for different locales. Error _create_project_name_strings_files(const Ref &p_preset, const String &project_name, const String &p_gradle_build_dir);