Seregon/ShadPKG

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

C++/47.3 KB/No license
core/file_format/rif_generator.cpp
ShadPKG / core / file_format / rif_generator.cpp
1// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3 
4#include "rif_generator.h"
5#include <fstream>
6#include <regex>
7#include <iomanip>
8#include <sstream>
9#include <cryptopp/md5.h>
10#include "common/logging/log.h"
11 
12RIFGenerator::RIFGenerator() = default;
13RIFGenerator::~RIFGenerator() = default;
14 
15bool RIFGenerator::ValidateContentID(const std::string& content_id) {
16 // Formato: REGION-CUSAXXXXX_XX-PRODUCTCODE
17 // Esempio: EP0001-CUSA12345_00-TESTGAMERETAIL01
18 // Esempio: JP2551-CUSA16074_00-RASPBERRY000000
19 std::regex pattern(R"(^[A-Z]{2}\d{4}-CUSA\d{5}_\d{2}-[A-Z0-9]{15,16}$)");
20 return std::regex_match(content_id, pattern);
21}
22 
23u32 RIFGenerator::GenerateTimestamp(const std::string& content_id) {
24 // Genera un timestamp deterministico usando MD5 del Content ID
25 CryptoPP::MD5 md5;
26 u8 hash[CryptoPP::MD5::DIGESTSIZE];
27
28 md5.Update(reinterpret_cast<const u8*>(content_id.data()), content_id.size());
29 md5.Final(hash);
30
31 // Usa i primi 4 byte dell'hash MD5 come timestamp
32 u32 timestamp = 0;
33 timestamp |= static_cast<u32>(hash[0]) << 24;
34 timestamp |= static_cast<u32>(hash[1]) << 16;
35 timestamp |= static_cast<u32>(hash[2]) << 8;
36 timestamp |= static_cast<u32>(hash[3]);
37
38 // Assicurati che sia nel range ragionevole (2013-2019)
39 // Range osservato: 0x522ec370 - 0x5d96edf0
40 const u32 min_timestamp = 0x522ec370; // ~2013
41 const u32 max_timestamp = 0x5d96edf0; // ~2019
42
43 // Normalizza il timestamp nel range
44 timestamp = min_timestamp + (timestamp % (max_timestamp - min_timestamp));
45
46 return timestamp;
47}
48 
49std::vector<u8> RIFGenerator::GenerateRIFContent(const std::string& content_id) {
50 std::vector<u8> rif_data(RIF_SIZE, 0);
51
52 // Magic number "RIF\0"
53 std::copy(RIF_MAGIC.begin(), RIF_MAGIC.end(), rif_data.begin() + MAGIC_OFFSET);
54
55 // Version
56 std::copy(RIF_VERSION.begin(), RIF_VERSION.end(), rif_data.begin() + VERSION_OFFSET);
57
58 // Unknown field
59 std::copy(RIF_UNKNOWN.begin(), RIF_UNKNOWN.end(), rif_data.begin() + UNKNOWN_OFFSET);
60
61 // Padding (già inizializzato a 0)
62
63 // Timestamp (big-endian)
64 u32 timestamp = GenerateTimestamp(content_id);
65 rif_data[TIMESTAMP_OFFSET + 0] = (timestamp >> 24) & 0xFF;
66 rif_data[TIMESTAMP_OFFSET + 1] = (timestamp >> 16) & 0xFF;
67 rif_data[TIMESTAMP_OFFSET + 2] = (timestamp >> 8) & 0xFF;
68 rif_data[TIMESTAMP_OFFSET + 3] = timestamp & 0xFF;
69
70 // Content ID
71 if (content_id.size() <= (RIF_SIZE - CONTENT_ID_OFFSET)) {
72 std::copy(content_id.begin(), content_id.end(), rif_data.begin() + CONTENT_ID_OFFSET);
73 }
74
75 return rif_data;
76}
77 
78bool RIFGenerator::GenerateRIF(const std::string& content_id, const std::filesystem::path& output_path) {
79 if (!ValidateContentID(content_id)) {
80 LOG_ERROR(Lib_Kernel, "Invalid Content ID format: {}", content_id);
81 return false;
82 }
83
84 try {
85 // Genera il contenuto del file RIF
86 auto rif_content = GenerateRIFContent(content_id);
87
88 // Crea il nome del file RIF
89 std::filesystem::path rif_filename = content_id + ".rif";
90 std::filesystem::path full_path = output_path / rif_filename;
91
92 // Crea la directory se non esiste
93 std::filesystem::create_directories(output_path);
94
95 // Scrivi il file RIF
96 std::ofstream file(full_path, std::ios::binary);
97 if (!file) {
98 LOG_ERROR(Lib_Kernel, "Failed to create RIF file: {}", full_path.string());
99 return false;
100 }
101
102 file.write(reinterpret_cast<const char*>(rif_content.data()), rif_content.size());
103 file.close();
104
105 if (file.fail()) {
106 LOG_ERROR(Lib_Kernel, "Failed to write RIF file: {}", full_path.string());
107 return false;
108 }
109
110 LOG_INFO(Lib_Kernel, "Generated RIF file: {} (size: {} bytes, timestamp: 0x{:08x})",
111 full_path.string(), rif_content.size(), GenerateTimestamp(content_id));
112
113 return true;
114 } catch (const std::exception& e) {
115 LOG_ERROR(Lib_Kernel, "Exception while generating RIF: {}", e.what());
116 return false;
117 }
118}
119 
120bool RIFGenerator::ValidateRIF(const std::filesystem::path& rif_path) {
121 try {
122 std::ifstream file(rif_path, std::ios::binary);
123 if (!file) {
124 return false;
125 }
126
127 // Verifica la dimensione del file
128 file.seekg(0, std::ios::end);
129 auto file_size = file.tellg();
130 if (file_size != RIF_SIZE) {
131 return false;
132 }
133
134 file.seekg(0, std::ios::beg);
135
136 // Verifica il magic number
137 std::array<u8, 4> magic;
138 file.read(reinterpret_cast<char*>(magic.data()), magic.size());
139 if (magic != RIF_MAGIC) {
140 return false;
141 }
142
143 // Verifica la versione
144 std::array<u8, 2> version;
145 file.read(reinterpret_cast<char*>(version.data()), version.size());
146 if (version != RIF_VERSION) {
147 return false;
148 }
149
150 return true;
151 } catch (const std::exception&) {
152 return false;
153 }
154}