mirror of
https://github.com/godotengine/godot.git
synced 2024-11-27 09:16:35 +08:00
Merge pull request #98918 from bruvzg/pck_enc_iv
Allow setting custom initialization vector for FileAccessEncrypted. Add export setting to set static seed for PCK encryption initialization vectors.
This commit is contained in:
commit
1627912d11
41
core/io/file_access.compat.inc
Normal file
41
core/io/file_access.compat.inc
Normal file
@ -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> FileAccess::_open_encrypted_bind_compat_98918(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
|
||||
return open_encrypted(p_path, p_mode_flags, p_key, Vector<uint8_t>());
|
||||
}
|
||||
|
||||
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
|
@ -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> FileAccess::_open(const String &p_path, ModeFlags p_mode_flags)
|
||||
return fa;
|
||||
}
|
||||
|
||||
Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
|
||||
Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key, const Vector<uint8_t> &p_iv) {
|
||||
Ref<FileAccess> fa = _open(p_path, p_mode_flags);
|
||||
if (fa.is_null()) {
|
||||
return fa;
|
||||
@ -132,7 +133,7 @@ Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mod
|
||||
|
||||
Ref<FileAccessEncrypted> 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<FileAccess>();
|
||||
@ -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<uint8_t>()));
|
||||
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);
|
||||
|
@ -109,6 +109,12 @@ protected:
|
||||
|
||||
static FileCloseFailNotify close_fail_notify;
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
static Ref<FileAccess> _open_encrypted_bind_compat_98918(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &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<FileAccess> create_for_path(const String &p_path);
|
||||
static Ref<FileAccess> 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<FileAccess> open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
|
||||
static Ref<FileAccess> open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key, const Vector<uint8_t> &p_iv = Vector<uint8_t>());
|
||||
static Ref<FileAccess> open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
|
||||
static Ref<FileAccess> open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
|
||||
static Error get_open_error();
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic) {
|
||||
Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic, const Vector<uint8_t> &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<FileAccess> p_base, const Vector<u
|
||||
writing = true;
|
||||
file = p_base;
|
||||
key = p_key;
|
||||
if (p_iv.is_empty()) {
|
||||
iv.resize(16);
|
||||
CryptoCore::RandomGenerator rng;
|
||||
ERR_FAIL_COND_V_MSG(rng.init(), FAILED, "Failed to initialize random number generator.");
|
||||
Error err = rng.get_random_bytes(iv.ptrw(), 16);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
} else {
|
||||
ERR_FAIL_COND_V(p_iv.size() != 16, ERR_INVALID_PARAMETER);
|
||||
iv = p_iv;
|
||||
}
|
||||
|
||||
} else if (p_mode == MODE_READ) {
|
||||
writing = false;
|
||||
@ -63,10 +73,8 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
|
||||
p_base->get_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<FileAccess> p_base, const Vector<u
|
||||
CryptoCore::AESContext ctx;
|
||||
|
||||
ctx.set_encode_key(key.ptrw(), 256); // Due to the nature of CFB, same key schedule is used for both encryption and decryption!
|
||||
ctx.decrypt_cfb(ds, iv, data.ptrw(), data.ptrw());
|
||||
ctx.decrypt_cfb(ds, iv.ptrw(), data.ptrw(), data.ptrw());
|
||||
}
|
||||
|
||||
data.resize(length);
|
||||
@ -145,14 +153,9 @@ void FileAccessEncrypted::_close() {
|
||||
|
||||
file->store_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();
|
||||
|
@ -44,6 +44,7 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
Vector<uint8_t> iv;
|
||||
Vector<uint8_t> key;
|
||||
bool writing = false;
|
||||
Ref<FileAccess> file;
|
||||
@ -57,9 +58,11 @@ private:
|
||||
void _close();
|
||||
|
||||
public:
|
||||
Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
|
||||
Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true, const Vector<uint8_t> &p_iv = Vector<uint8_t>());
|
||||
Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
|
||||
|
||||
Vector<uint8_t> 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
|
||||
|
||||
|
@ -308,6 +308,7 @@
|
||||
<param index="0" name="path" type="String" />
|
||||
<param index="1" name="mode_flags" type="int" enum="FileAccess.ModeFlags" />
|
||||
<param index="2" name="key" type="PackedByteArray" />
|
||||
<param index="3" name="iv" type="PackedByteArray" default="PackedByteArray()" />
|
||||
<description>
|
||||
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.
|
||||
|
@ -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<String>()));
|
||||
|
||||
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"));
|
||||
}
|
||||
|
@ -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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
Error EditorExportPlatform::_save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &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<FileAccess> ftmp = pd->f;
|
||||
|
||||
if (sd.encrypted) {
|
||||
Vector<uint8_t> 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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
Error EditorExportPlatform::_save_pack_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
Error EditorExportPlatform::_save_zip_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &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<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const {
|
||||
@ -932,7 +949,7 @@ Vector<String> EditorExportPlatform::get_forced_export_files() {
|
||||
return files;
|
||||
}
|
||||
|
||||
Error EditorExportPlatform::_script_save_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
Error EditorExportPlatform::_script_save_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &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<EditorExportPreset> &
|
||||
Vector<String> enc_in_filters;
|
||||
Vector<String> enc_ex_filters;
|
||||
Vector<uint8_t> key;
|
||||
uint64_t seed = 0;
|
||||
|
||||
if (enc_pck) {
|
||||
seed = p_preset->get_seed();
|
||||
Vector<String> 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<EditorExportPreset> &
|
||||
}
|
||||
}
|
||||
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<EditorExportPreset> &
|
||||
}
|
||||
|
||||
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<EditorExportPreset> &
|
||||
if (importer_type == "keep") {
|
||||
// Just keep file as-is.
|
||||
Vector<uint8_t> 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<EditorExportPreset> &
|
||||
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<EditorExportPreset> &
|
||||
if (remap == "path") {
|
||||
String remapped_path = config->get_value("remap", remap);
|
||||
Vector<uint8_t> 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<uint8_t> 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<EditorExportPreset> &
|
||||
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<EditorExportPreset> &
|
||||
}
|
||||
|
||||
Vector<uint8_t> 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<EditorExportPreset> &
|
||||
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<EditorExportPreset> &
|
||||
Vector<String> forced_export = get_forced_export_files();
|
||||
for (int i = 0; i < forced_export.size(); i++) {
|
||||
Vector<uint8_t> 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<EditorExportPreset> &
|
||||
Vector<uint8_t> 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<EditorExportPreset> &p_preset, b
|
||||
Ref<FileAccess> fhead = f;
|
||||
|
||||
if (enc_pck && enc_directory) {
|
||||
uint64_t seed = p_preset->get_seed();
|
||||
String script_key = _get_script_encryption_key(p_preset);
|
||||
Vector<uint8_t> key;
|
||||
key.resize(32);
|
||||
@ -1906,7 +1926,27 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
|
||||
err = fae->open_and_parse(f, key, FileAccessEncrypted::MODE_WRITE_AES256, false);
|
||||
Vector<uint8_t> 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;
|
||||
|
@ -53,7 +53,7 @@ protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &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<uint8_t> &p_data);
|
||||
|
||||
static Error _save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
static Error _save_pack_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
static Error _save_pack_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
|
||||
static Error _save_pack_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
static Error _save_zip_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
static Error _save_zip_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
|
||||
static Error _save_zip_patch_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
static Error _script_save_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &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<DirAccess> &da, const Vector<String> &p_filters, HashSet<String> &r_list, bool exclude);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<EditorExportPreset> 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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed) {
|
||||
APKExportData *ed = static_cast<APKExportData *>(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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
Error EditorExportPlatformAndroid::ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
static Error save_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
|
||||
|
||||
static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed);
|
||||
|
||||
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
|
||||
|
||||
|
@ -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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key) {
|
||||
Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed) {
|
||||
CustomExportData *export_data = static_cast<CustomExportData *>(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);
|
||||
|
@ -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<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key);
|
||||
Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &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<EditorExportPreset> &p_preset, const String &project_name, const String &p_gradle_build_dir);
|
||||
|
Loading…
Reference in New Issue
Block a user