Seregon/ShadPKG

A tool for deriving PKG packet encryption keys for ps4 written in c++

C++/47.3 KB/No license
core/file_format/pkg.h
1// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3 
4#pragma once
5 
6#include "common/shadpkg_endian.h"
7#include "core/crypto/crypto.h"
8#include "pfs.h"
9#include "trp.h"
10#include <array>
11#include <filesystem>
12#include <mutex>
13#include <string>
14#include <unordered_map>
15#include <vector>
16 
17struct PKGHeader {
18 u32_be magic; // Magic
19 u32_be pkg_type;
20 u32_be pkg_0x8; // unknown field
21 u32_be pkg_file_count;
22 u32_be pkg_table_entry_count;
23 u16_be pkg_sc_entry_count;
24 u16_be pkg_table_entry_count_2; // same as pkg_entry_count
25 u32_be pkg_table_entry_offset; // file table offset
26 u32_be pkg_sc_entry_data_size;
27 u64_be pkg_body_offset; // offset of PKG entries
28 u64_be pkg_body_size; // length of all PKG entries
29 u64_be pkg_content_offset;
30 u64_be pkg_content_size;
31 u8 pkg_content_id[0x24]; // packages' content ID as a 36-byte string
32 u8 pkg_padding[0xC]; // padding
33 u32_be pkg_drm_type; // DRM type
34 u32_be pkg_content_type; // Content type
35 u32_be pkg_content_flags; // Content flags
36 u32_be pkg_promote_size;
37 u32_be pkg_version_date;
38 u32_be pkg_version_hash;
39 u32_be pkg_0x088;
40 u32_be pkg_0x08C;
41 u32_be pkg_0x090;
42 u32_be pkg_0x094;
43 u32_be pkg_iro_tag;
44 u32_be pkg_drm_type_version;
45 
46 u8 pkg_zeroes_1[0x60];
47 
48 /* Digest table */
49 u8 digest_entries1[0x20]; // sha256 digest for main entry 1
50 u8 digest_entries2[0x20]; // sha256 digest for main entry 2
51 u8 digest_table_digest[0x20]; // sha256 digest for digest table
52 u8 digest_body_digest[0x20]; // sha256 digest for main table
53 
54 u8 pkg_zeroes_2[0x280];
55 
56 u32_be pkg_0x400;
57 
58 u32_be pfs_image_count; // count of PFS images
59 u64_be pfs_image_flags; // PFS flags
60 u64_be pfs_image_offset; // offset to start of external PFS image
61 u64_be pfs_image_size; // size of external PFS image
62 u64_be mount_image_offset;
63 u64_be mount_image_size;
64 u64_be pkg_size;
65 u32_be pfs_signed_size;
66 u32_be pfs_cache_size;
67 u8 pfs_image_digest[0x20];
68 u8 pfs_signed_digest[0x20];
69 u64_be pfs_split_size_nth_0;
70 u64_be pfs_split_size_nth_1;
71 
72 u8 pkg_zeroes_3[0xB50];
73 
74 u8 pkg_digest[0x20];
75};
76 
77enum class PKGContentFlag {
78 FIRST_PATCH = 0x100000,
79 PATCHGO = 0x200000,
80 REMASTER = 0x400000,
81 PS_CLOUD = 0x800000,
82 GD_AC = 0x2000000,
83 NON_GAME = 0x4000000,
84 UNKNOWN_0x8000000 = 0x8000000,
85 SUBSEQUENT_PATCH = 0x40000000,
86 DELTA_PATCH = 0x41000000,
87 CUMULATIVE_PATCH = 0x60000000
88};
89 
90struct PKGEntry {
91 u32_be id; // File ID, useful for files without a filename entry
92 u32_be filename_offset; // Offset into the filenames table (ID 0x200) where
93 // this file's name is located
94 u32_be flags1; // Flags including encrypted flag, etc
95 u32_be flags2; // Flags including encryption key index, etc
96 u32_be offset; // Offset into PKG to find the file
97 u32_be size; // Size of the file
98 u64_be padding; // blank padding
99};
100static_assert(sizeof(PKGEntry) == 32);
101 
102class PKG {
103public:
104 PKG();
105 ~PKG();
106 
107 bool Open(const std::filesystem::path &filepath, std::string &failreason);
108 void ExtractFiles(const int index);
109 bool Extract(const std::filesystem::path &filepath,
110 const std::filesystem::path &extract, std::string &failreason);
111 void ExtractAllFilesWithProgress();
112 
113 
114 bool Scan(const std::filesystem::path &filepath, std::string &failreason,
115 std::filesystem::path extract_root = ".");
116 
117 std::vector<u8> sfo;
118 
119 u32 GetNumberOfFiles() { return fsTable.size(); }
120 
121 u64 GetPkgSize() { return pkgSize; }
122 
123 std::string GetPkgFlags() { return pkgFlags; }
124 
125 std::string_view GetTitleID() { return std::string_view(pkgTitleID, 9); }
126 
127 PKGHeader GetPkgHeader() { return pkgheader; }
128 
129 // Getter per le chiavi derivate
130 const std::array<u8, 32> &GetDK3() const { return dk3_; }
131 const std::array<u8, 32> &GetIVKey() const { return ivKey; }
132 const std::array<u8, 256> &GetImgKey() const { return imgKey; }
133 const std::array<u8, 32> &GetEkpfsKey() const { return ekpfsKey; }
134 const std::array<u8, 16> &GetDataKey() const { return dataKey; }
135 const std::array<u8, 16> &GetTweakKey() const { return tweakKey; }
136 
137 static bool isFlagSet(u32_be variable, PKGContentFlag flag) {
138 return (variable) & static_cast<u32>(flag);
139 }
140 
141 static constexpr std::array<std::pair<PKGContentFlag, std::string_view>, 10>
142 flagNames = {{{PKGContentFlag::FIRST_PATCH, "FIRST_PATCH"},
143 {PKGContentFlag::PATCHGO, "PATCHGO"},
144 {PKGContentFlag::REMASTER, "REMASTER"},
145 {PKGContentFlag::PS_CLOUD, "PS_CLOUD"},
146 {PKGContentFlag::GD_AC, "GD_AC"},
147 {PKGContentFlag::NON_GAME, "NON_GAME"},
148 {PKGContentFlag::UNKNOWN_0x8000000, "UNKNOWN_0x8000000"},
149 {PKGContentFlag::SUBSEQUENT_PATCH, "SUBSEQUENT_PATCH"},
150 {PKGContentFlag::DELTA_PATCH, "DELTA_PATCH"},
151 {PKGContentFlag::CUMULATIVE_PATCH, "CUMULATIVE_PATCH"}}};
152 
153 std::vector<std::string> GetFileList() const;
154 
155 // Restituisce la lista di tutte le entry (file e directory) con tipo
156 std::vector<std::tuple<std::string, u32, u32>> GetAllEntries() const;
157 
158 struct EntryInfo {
159 std::string name;
160 u32 inode;
161 u32 type;
162 std::string path; // path completo ricostruito
163 u64 size; // valido per file
164 u32 blocks; // valido per file
165 u32 loc; // valido per file
166 };
167 
168 // Info dettagliate su tutte le entry (use per output CLI)
169 std::vector<EntryInfo> GetEntriesInfo() const;
170 
171 // Reads a file into memory
172 std::vector<u8> GetFileBuffer(const std::string &filename);
173 
174private:
175 // ╔═══════════════════════════════════════════════════════════════════════╗
176 // ║ Thread Safety: mutex protects crypto operations during extraction ║
177 // ╚═══════════════════════════════════════════════════════════════════════╝
178 mutable std::mutex crypto_mutex_;
179 
180 Crypto crypto;
181 TRP trp;
182 u64 pkgSize = 0;
183 char pkgTitleID[9];
184 PKGHeader pkgheader;
185 std::string pkgFlags;
186 
187 std::unordered_map<int, std::filesystem::path> extractPaths;
188 std::vector<pfs_fs_table> fsTable;
189 std::vector<Inode> iNodeBuf;
190 std::vector<u64> sectorMap;
191 u64 pfsc_offset;
192 
193 std::array<u8, 32> dk3_;
194 std::array<u8, 32> ivKey;
195 std::array<u8, 256> imgKey;
196 std::array<u8, 32> ekpfsKey;
197 std::array<u8, 16> dataKey;
198 std::array<u8, 16> tweakKey;
199 std::vector<u8> decNp;
200 
201 std::filesystem::path pkgpath;
202 std::filesystem::path current_dir;
203 std::filesystem::path extract_path;
204 
205 std::vector<PKGEntry> pkgEntries;
206};
207