[SparsePCK] Add support for index encryption.
This commit is contained in:
parent
1cf3180537
commit
a378f9781d
6 changed files with 64 additions and 17 deletions
|
|
@ -46,7 +46,7 @@ Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t
|
|||
return ERR_FILE_UNRECOGNIZED;
|
||||
}
|
||||
|
||||
void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted, bool p_bundle, bool p_delta) {
|
||||
void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted, bool p_bundle, bool p_delta, const String &p_salt) {
|
||||
String simplified_path = p_path.simplify_path().trim_prefix("res://");
|
||||
PathMD5 pmd5(simplified_path.md5_buffer());
|
||||
|
||||
|
|
@ -57,6 +57,7 @@ void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64
|
|||
pf.bundle = p_bundle;
|
||||
pf.delta = p_delta;
|
||||
pf.pack = p_pkg_path;
|
||||
pf.salt = p_salt;
|
||||
pf.offset = p_ofs;
|
||||
pf.size = p_size;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
|
|
@ -291,22 +292,28 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
|
|||
uint32_t ver_minor = f->get_32();
|
||||
uint32_t ver_patch = f->get_32(); // Not used for validation.
|
||||
|
||||
ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION_V3 && version != PACK_FORMAT_VERSION_V2, false, vformat("Pack version unsupported: %d.", version));
|
||||
ERR_FAIL_COND_V_MSG(version != PACK_FORMAT_VERSION_V4 && version != PACK_FORMAT_VERSION_V3 && version != PACK_FORMAT_VERSION_V2, false, vformat("Pack version unsupported: %d.", version));
|
||||
ERR_FAIL_COND_V_MSG(ver_major > GODOT_VERSION_MAJOR || (ver_major == GODOT_VERSION_MAJOR && ver_minor > GODOT_VERSION_MINOR), false, vformat("Pack created with a newer version of the engine: %d.%d.%d.", ver_major, ver_minor, ver_patch));
|
||||
|
||||
uint32_t pack_flags = f->get_32();
|
||||
bool enc_directory = (pack_flags & PACK_DIR_ENCRYPTED);
|
||||
bool rel_filebase = (pack_flags & PACK_REL_FILEBASE); // Note: Always enabled for V3.
|
||||
bool sparse_bundle = (pack_flags & PACK_SPARSE_BUNDLE);
|
||||
String salt;
|
||||
|
||||
uint64_t file_base = f->get_64();
|
||||
if ((version == PACK_FORMAT_VERSION_V3) || (version == PACK_FORMAT_VERSION_V2 && rel_filebase)) {
|
||||
if ((version == PACK_FORMAT_VERSION_V4) || (version == PACK_FORMAT_VERSION_V3) || (version == PACK_FORMAT_VERSION_V2 && rel_filebase)) {
|
||||
file_base += pck_start_pos;
|
||||
}
|
||||
|
||||
if (version == PACK_FORMAT_VERSION_V3) {
|
||||
// V3: Read directory offset and skip reserved part of the header.
|
||||
if (version == PACK_FORMAT_VERSION_V3 || version == PACK_FORMAT_VERSION_V4) {
|
||||
// V3/V4: Read directory offset and skip reserved part of the header.
|
||||
uint64_t dir_offset = f->get_64() + pck_start_pos;
|
||||
if (sparse_bundle && enc_directory && version == PACK_FORMAT_VERSION_V4) {
|
||||
// V4: Read encrypted directory salt.
|
||||
Vector<uint8_t> salt_data = f->get_buffer(32);
|
||||
salt.append_latin1(Span((const char *)salt_data.ptr(), salt_data.size()));
|
||||
}
|
||||
f->seek(dir_offset);
|
||||
} else if (version == PACK_FORMAT_VERSION_V2) {
|
||||
// V2: Directory directly after the header.
|
||||
|
|
@ -350,7 +357,7 @@ bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files,
|
|||
if (flags & PACK_FILE_REMOVAL) { // The file was removed.
|
||||
PackedData::get_singleton()->remove_path(path);
|
||||
} else {
|
||||
PackedData::get_singleton()->add_path(p_path, path, file_base + ofs, size, md5, this, p_replace_files, (flags & PACK_FILE_ENCRYPTED), sparse_bundle, (flags & PACK_FILE_DELTA));
|
||||
PackedData::get_singleton()->add_path(p_path, path, file_base + ofs, size, md5, this, p_replace_files, (flags & PACK_FILE_ENCRYPTED), sparse_bundle, (flags & PACK_FILE_DELTA), salt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -512,7 +519,11 @@ FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFil
|
|||
pf = p_file;
|
||||
if (pf.bundle) {
|
||||
String simplified_path = p_path.simplify_path();
|
||||
f = FileAccess::open(simplified_path, FileAccess::READ | FileAccess::SKIP_PACK);
|
||||
if (pf.salt.is_empty()) {
|
||||
f = FileAccess::open(simplified_path, FileAccess::READ | FileAccess::SKIP_PACK);
|
||||
} else {
|
||||
f = FileAccess::open("res://" + (simplified_path + pf.salt).sha256_text(), FileAccess::READ | FileAccess::SKIP_PACK);
|
||||
}
|
||||
ERR_FAIL_COND_MSG(f.is_null(), vformat(R"(Can't open pack-referenced file "%s" from sparse pack "%s".)", simplified_path, pf.pack));
|
||||
off = 0; // For the sparse pack offset is always zero.
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -41,9 +41,10 @@
|
|||
|
||||
#define PACK_FORMAT_VERSION_V2 2
|
||||
#define PACK_FORMAT_VERSION_V3 3
|
||||
#define PACK_FORMAT_VERSION_V4 4
|
||||
|
||||
// The current packed file format version number.
|
||||
#define PACK_FORMAT_VERSION PACK_FORMAT_VERSION_V3
|
||||
#define PACK_FORMAT_VERSION PACK_FORMAT_VERSION_V4
|
||||
|
||||
enum PackFlags {
|
||||
PACK_DIR_ENCRYPTED = 1 << 0,
|
||||
|
|
@ -74,6 +75,7 @@ public:
|
|||
bool encrypted;
|
||||
bool bundle;
|
||||
bool delta;
|
||||
String salt;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
@ -119,7 +121,7 @@ private:
|
|||
|
||||
public:
|
||||
void add_pack_source(PackSource *p_source);
|
||||
void add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false, bool p_bundle = false, bool p_delta = false); // for PackSource
|
||||
void add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false, bool p_bundle = false, bool p_delta = false, const String &p_salt = String()); // for PackSource
|
||||
void remove_path(const String &p_path);
|
||||
uint8_t *get_file_hash(const String &p_path);
|
||||
Vector<PackedFile> get_delta_patches(const String &p_path) const;
|
||||
|
|
|
|||
|
|
@ -1946,7 +1946,7 @@ Dictionary EditorExportPlatform::_save_zip_patch(const Ref<EditorExportPreset> &
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool EditorExportPlatform::_store_header(Ref<FileAccess> p_fd, bool p_enc, bool p_sparse, uint64_t &r_file_base_ofs, uint64_t &r_dir_base_ofs) {
|
||||
bool EditorExportPlatform::_store_header(Ref<FileAccess> p_fd, bool p_enc, bool p_sparse, uint64_t &r_file_base_ofs, uint64_t &r_dir_base_ofs, const String &p_salt) {
|
||||
p_fd->store_32(PACK_HEADER_MAGIC);
|
||||
p_fd->store_32(PACK_FORMAT_VERSION);
|
||||
p_fd->store_32(GODOT_VERSION_MAJOR);
|
||||
|
|
@ -1968,8 +1968,18 @@ bool EditorExportPlatform::_store_header(Ref<FileAccess> p_fd, bool p_enc, bool
|
|||
r_dir_base_ofs = p_fd->get_position();
|
||||
p_fd->store_64(0); // Directory offset.
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
//reserved
|
||||
if (p_enc && p_sparse && p_salt.length() == 32) {
|
||||
CharString cs = p_salt.latin1();
|
||||
p_fd->store_buffer((const uint8_t *)cs.ptr(), 32);
|
||||
} else {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// Reserved.
|
||||
p_fd->store_32(0);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// Reserved.
|
||||
p_fd->store_32(0);
|
||||
}
|
||||
return true;
|
||||
|
|
@ -2094,7 +2104,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
|
|||
uint64_t file_base_ofs = 0;
|
||||
uint64_t dir_base_ofs = 0;
|
||||
|
||||
_store_header(f, p_preset->get_enc_pck() && p_preset->get_enc_directory(), false, file_base_ofs, dir_base_ofs);
|
||||
_store_header(f, p_preset->get_enc_pck() && p_preset->get_enc_directory(), false, file_base_ofs, dir_base_ofs, String());
|
||||
|
||||
// Align for first file.
|
||||
int file_padding = _get_pad(PCK_PADDING, f->get_position());
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ public:
|
|||
|
||||
struct PackData {
|
||||
String path;
|
||||
String salt;
|
||||
Ref<FileAccess> f;
|
||||
Vector<SavedData> file_ofs;
|
||||
EditorProgress *ep = nullptr;
|
||||
|
|
@ -101,7 +102,7 @@ public:
|
|||
bool use_sparse_pck = false;
|
||||
};
|
||||
|
||||
static bool _store_header(Ref<FileAccess> p_fd, bool p_enc, bool p_sparse, uint64_t &r_file_base_ofs, uint64_t &r_dir_base_ofs);
|
||||
static bool _store_header(Ref<FileAccess> p_fd, bool p_enc, bool p_sparse, uint64_t &r_file_base_ofs, uint64_t &r_dir_base_ofs, const String &p_salt);
|
||||
static bool _encrypt_and_store_directory(Ref<FileAccess> p_fd, PackData &p_pack_data, const Vector<uint8_t> &p_key, uint64_t p_seed, uint64_t p_file_base);
|
||||
static Error _encrypt_and_store_data(Ref<FileAccess> p_fd, const String &p_path, const Vector<uint8_t> &p_data, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key, uint64_t p_seed, bool &r_encrypt);
|
||||
String _get_script_encryption_key(const Ref<EditorExportPreset> &p_preset) const;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include "core/io/image_loader.h"
|
||||
#include "core/io/json.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "core/math/random_pcg.h"
|
||||
#include "core/string/translation_server.h"
|
||||
#include "core/version.h"
|
||||
#include "editor/editor_log.h"
|
||||
|
|
@ -815,7 +816,12 @@ Error EditorExportPlatformAndroid::save_apk_file(const Ref<EditorExportPreset> &
|
|||
return err;
|
||||
}
|
||||
|
||||
const String dst_path = String("assets/") + simplified_path.trim_prefix("res://");
|
||||
String dst_path;
|
||||
if (ed->pd.salt.length() == 32) {
|
||||
dst_path = String("assets/") + (simplified_path + ed->pd.salt).sha256_text();
|
||||
} else {
|
||||
dst_path = String("assets/") + simplified_path.trim_prefix("res://");
|
||||
}
|
||||
print_verbose("Saving project files from " + simplified_path + " into " + dst_path);
|
||||
store_in_apk(ed, dst_path, enc_data, _should_compress_asset(simplified_path, enc_data) ? Z_DEFLATED : 0);
|
||||
|
||||
|
|
@ -3531,7 +3537,7 @@ Error EditorExportPlatformAndroid::_generate_sparse_pck_metadata(const Ref<Edito
|
|||
int64_t pck_start_pos = ftmp->get_position();
|
||||
uint64_t file_base_ofs = 0;
|
||||
uint64_t dir_base_ofs = 0;
|
||||
EditorExportPlatform::_store_header(ftmp, p_preset->get_enc_pck() && p_preset->get_enc_directory(), true, file_base_ofs, dir_base_ofs);
|
||||
EditorExportPlatform::_store_header(ftmp, p_preset->get_enc_pck() && p_preset->get_enc_directory(), true, file_base_ofs, dir_base_ofs, p_pack_data.salt);
|
||||
|
||||
// Write directory.
|
||||
uint64_t dir_offset = ftmp->get_position();
|
||||
|
|
@ -3714,6 +3720,12 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||
} else {
|
||||
user_data.pd.path = "assets.sparsepck";
|
||||
user_data.pd.use_sparse_pck = true;
|
||||
if (p_preset->get_enc_directory()) {
|
||||
RandomPCG rng = RandomPCG(p_preset->get_seed());
|
||||
for (int i = 0; i < 32; i++) {
|
||||
user_data.pd.salt += String::chr(1 + rng.rand() % 254);
|
||||
}
|
||||
}
|
||||
err = export_project_files(p_preset, p_debug, rename_and_store_file_in_gradle_project, nullptr, &user_data, copy_gradle_so);
|
||||
|
||||
Vector<uint8_t> enc_data;
|
||||
|
|
@ -4219,6 +4231,12 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
|
|||
ed.apk = unaligned_apk;
|
||||
ed.pd.path = "assets.sparsepck";
|
||||
ed.pd.use_sparse_pck = true;
|
||||
if (p_preset->get_enc_directory()) {
|
||||
RandomPCG rng = RandomPCG(p_preset->get_seed());
|
||||
for (int i = 0; i < 32; i++) {
|
||||
ed.pd.salt += String::chr(1 + rng.rand() % 254);
|
||||
}
|
||||
}
|
||||
err = export_project_files(p_preset, p_debug, save_apk_file, nullptr, &ed, save_apk_so);
|
||||
|
||||
Vector<uint8_t> enc_data;
|
||||
|
|
|
|||
|
|
@ -182,7 +182,12 @@ Error rename_and_store_file_in_gradle_project(const Ref<EditorExportPreset> &p_p
|
|||
return err;
|
||||
}
|
||||
|
||||
const String dst_path = export_data->assets_directory + String("/") + simplified_path.trim_prefix("res://");
|
||||
String dst_path;
|
||||
if (export_data->pd.salt.length() == 32) {
|
||||
dst_path = export_data->assets_directory + String("/") + (simplified_path + export_data->pd.salt).sha256_text();
|
||||
} else {
|
||||
dst_path = export_data->assets_directory + String("/") + simplified_path.trim_prefix("res://");
|
||||
}
|
||||
print_verbose("Saving project files from " + simplified_path + " into " + dst_path);
|
||||
err = store_file_at_path(dst_path, enc_data);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue