diff --git a/rpcs3/Crypto/unedat.h b/rpcs3/Crypto/unedat.h index 6a8977ede9..e61ce2c502 100644 --- a/rpcs3/Crypto/unedat.h +++ b/rpcs3/Crypto/unedat.h @@ -18,6 +18,7 @@ struct loaded_npdrm_keys { atomic_t dec_keys[16]{}; atomic_t dec_keys_pos = 0; + u128 one_time_key{}; // For savestates atomic_t npdrm_fds{0}; void install_decryption_key(u128 key) @@ -162,4 +163,9 @@ public: id.type.insert(0, "EDATADecrypter: "sv); return id; } + + u128 get_key() const + { + return dec_key; + } }; diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index f31870f421..736aaf4591 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -439,6 +439,8 @@ lv2_file::lv2_file(utils::serial& ar) , flags(ar) , type(ar) { + [[maybe_unused]] const s32 version = GET_SERIALIZATION_VERSION(lv2_fs); + ar(lock); be_t arg = 0; @@ -451,13 +453,19 @@ lv2_file::lv2_file(utils::serial& ar) case lv2_file_type::edata: arg = 0x2, size = 8; break; } - const std::string retrieve_real = ar; + const std::string retrieve_real = ar.pop(); + + if (type == lv2_file_type::edata && version >= 2) + { + ar(g_fxo->get().one_time_key); + } open_result_t res = lv2_file::open(retrieve_real, flags & CELL_FS_O_ACCMODE, mode, size ? &arg : nullptr, size); file = std::move(res.file); real_path = std::move(res.real_path); g_fxo->get().npdrm_fds.raw() += type != lv2_file_type::regular; + g_fxo->get().one_time_key = {}; if (ar.pop()) // see lv2_file::save in_mem { @@ -489,6 +497,13 @@ void lv2_file::save(utils::serial& ar) USING_SERIALIZATION_VERSION(lv2_fs); ar(name, mode, flags, type, lock, ensure(vfs::retrieve(real_path), FN(!x.empty()))); + if (type == lv2_file_type::edata) + { + auto file_ptr = file.release(); + ar(static_cast(file_ptr.get())->get_key()); + file.reset(std::move(file_ptr)); + } + if (!mp.read_only && flags & CELL_FS_O_ACCMODE) { // Ensure accurate timestamps and content on disk @@ -919,6 +934,21 @@ lv2_file::open_raw_result_t lv2_file::open_raw(const std::string& local_path, s3 const auto& dec_keys = edatkeys.dec_keys; const u64 max_i = std::min(std::size(dec_keys), init_pos); + if (edatkeys.one_time_key) + { + auto edata_file = std::make_unique(std::move(file), edatkeys.one_time_key); + edatkeys.one_time_key = {}; + + if (!edata_file->ReadHeader()) + { + // Read failure + return {CELL_EFSSPECIFIC}; + } + + file.reset(std::move(edata_file)); + break; + } + for (u64 i = 0;; i++) { if (i == max_i) diff --git a/rpcs3/Emu/savestate_utils.cpp b/rpcs3/Emu/savestate_utils.cpp index 4aaed035db..3006ce1703 100644 --- a/rpcs3/Emu/savestate_utils.cpp +++ b/rpcs3/Emu/savestate_utils.cpp @@ -47,7 +47,7 @@ SERIALIZATION_VER(spu, 2, 1) SERIALIZATION_VER(lv2_sync, 3, 1) SERIALIZATION_VER(lv2_vm, 4, 1) SERIALIZATION_VER(lv2_net, 5, 1) -SERIALIZATION_VER(lv2_fs, 6, 1) +SERIALIZATION_VER(lv2_fs, 6, 1, 2/*NPDRM key saving*/) SERIALIZATION_VER(lv2_prx_overlay, 7, 1) SERIALIZATION_VER(lv2_memory, 8, 1) SERIALIZATION_VER(lv2_config, 9, 1)