mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-20 11:35:45 +00:00
This commit is contained in:
parent
dbaf13ccb4
commit
f5108867df
20 changed files with 2359 additions and 5 deletions
15
cmake/Findcryptopp.cmake
Normal file
15
cmake/Findcryptopp.cmake
Normal file
|
@ -0,0 +1,15 @@
|
|||
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(CRYPTOPP QUIET IMPORTED_TARGET libcryptopp)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(cryptopp
|
||||
REQUIRED_VARS CRYPTOPP_LINK_LIBRARIES
|
||||
VERSION_VAR CRYPTOPP_VERSION
|
||||
)
|
||||
|
||||
if (cryptopp_FOUND AND NOT TARGET cryptopp::cryptopp)
|
||||
add_library(cryptopp::cryptopp ALIAS PkgConfig::CRYPTOPP)
|
||||
endif()
|
|
@ -1,4 +1,4 @@
|
|||
Fri
|
||||
Date: Fri Mar 28 16:15:31 2025 +0200
|
||||
src/core/crypto/crypto.cpp
|
||||
src/core/crypto/crypto.h
|
||||
src/core/crypto/keys.h
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Fri
|
||||
Date: Fri Mar 28 10:32:17 2025 -0700
|
||||
documents/Quickstart/2.png
|
||||
src/core/file_format/pkg.cpp
|
||||
src/core/loader.cpp
|
||||
|
|
|
@ -1 +1 @@
|
|||
Fri
|
||||
Date: Fri Mar 28 19:49:04 2025 +0200
|
||||
|
|
|
@ -1 +1 @@
|
|||
Sat
|
||||
Date: Sat Mar 29 11:03:40 2025 +0200
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
Mon
|
||||
Date: Mon Mar 31 19:29:24 2025 +0000
|
||||
cmake/Findcryptopp.cmake
|
||||
|
|
BIN
documents/Quickstart/2.png
Normal file
BIN
documents/Quickstart/2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 658 KiB |
215
src/core/crypto/crypto.cpp
Normal file
215
src/core/crypto/crypto.cpp
Normal file
|
@ -0,0 +1,215 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
CryptoPP::RSA::PrivateKey Crypto::key_pkg_derived_key3_keyset_init() {
|
||||
CryptoPP::InvertibleRSAFunction params;
|
||||
params.SetPrime1(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime1, 0x80));
|
||||
params.SetPrime2(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime2, 0x80));
|
||||
|
||||
params.SetPublicExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PublicExponent, 4));
|
||||
params.SetPrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PrivateExponent, 0x100));
|
||||
|
||||
params.SetModPrime1PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent1, 0x80));
|
||||
params.SetModPrime2PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent2, 0x80));
|
||||
|
||||
params.SetModulus(CryptoPP::Integer(PkgDerivedKey3Keyset::Modulus, 0x100));
|
||||
params.SetMultiplicativeInverseOfPrime2ModPrime1(
|
||||
CryptoPP::Integer(PkgDerivedKey3Keyset::Coefficient, 0x80));
|
||||
|
||||
CryptoPP::RSA::PrivateKey privateKey(params);
|
||||
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
CryptoPP::RSA::PrivateKey Crypto::FakeKeyset_keyset_init() {
|
||||
CryptoPP::InvertibleRSAFunction params;
|
||||
params.SetPrime1(CryptoPP::Integer(FakeKeyset::Prime1, 0x80));
|
||||
params.SetPrime2(CryptoPP::Integer(FakeKeyset::Prime2, 0x80));
|
||||
|
||||
params.SetPublicExponent(CryptoPP::Integer(FakeKeyset::PublicExponent, 4));
|
||||
params.SetPrivateExponent(CryptoPP::Integer(FakeKeyset::PrivateExponent, 0x100));
|
||||
|
||||
params.SetModPrime1PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent1, 0x80));
|
||||
params.SetModPrime2PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent2, 0x80));
|
||||
|
||||
params.SetModulus(CryptoPP::Integer(FakeKeyset::Modulus, 0x100));
|
||||
params.SetMultiplicativeInverseOfPrime2ModPrime1(
|
||||
CryptoPP::Integer(FakeKeyset::Coefficient, 0x80));
|
||||
|
||||
CryptoPP::RSA::PrivateKey privateKey(params);
|
||||
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
CryptoPP::RSA::PrivateKey Crypto::DebugRifKeyset_init() {
|
||||
CryptoPP::InvertibleRSAFunction params;
|
||||
params.SetPrime1(CryptoPP::Integer(DebugRifKeyset::Prime1, sizeof(DebugRifKeyset::Prime1)));
|
||||
params.SetPrime2(CryptoPP::Integer(DebugRifKeyset::Prime2, sizeof(DebugRifKeyset::Prime2)));
|
||||
|
||||
params.SetPublicExponent(
|
||||
CryptoPP::Integer(DebugRifKeyset::PublicExponent, sizeof(DebugRifKeyset::PublicExponent)));
|
||||
params.SetPrivateExponent(CryptoPP::Integer(DebugRifKeyset::PrivateExponent,
|
||||
sizeof(DebugRifKeyset::PrivateExponent)));
|
||||
|
||||
params.SetModPrime1PrivateExponent(
|
||||
CryptoPP::Integer(DebugRifKeyset::Exponent1, sizeof(DebugRifKeyset::Exponent1)));
|
||||
params.SetModPrime2PrivateExponent(
|
||||
CryptoPP::Integer(DebugRifKeyset::Exponent2, sizeof(DebugRifKeyset::Exponent2)));
|
||||
|
||||
params.SetModulus(CryptoPP::Integer(DebugRifKeyset::Modulus, sizeof(DebugRifKeyset::Modulus)));
|
||||
params.SetMultiplicativeInverseOfPrime2ModPrime1(
|
||||
CryptoPP::Integer(DebugRifKeyset::Coefficient, sizeof(DebugRifKeyset::Coefficient)));
|
||||
|
||||
CryptoPP::RSA::PrivateKey privateKey(params);
|
||||
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
void Crypto::RSA2048Decrypt(std::span<CryptoPP::byte, 32> dec_key,
|
||||
std::span<const CryptoPP::byte, 256> ciphertext,
|
||||
bool is_dk3) { // RSAES_PKCS1v15_
|
||||
// Create an RSA decryptor
|
||||
CryptoPP::RSA::PrivateKey privateKey;
|
||||
if (is_dk3) {
|
||||
privateKey = key_pkg_derived_key3_keyset_init();
|
||||
} else {
|
||||
privateKey = FakeKeyset_keyset_init();
|
||||
}
|
||||
|
||||
CryptoPP::RSAES_PKCS1v15_Decryptor rsaDecryptor(privateKey);
|
||||
|
||||
// Allocate memory for the decrypted data
|
||||
std::array<CryptoPP::byte, 256> decrypted;
|
||||
|
||||
// Perform the decryption
|
||||
CryptoPP::AutoSeededRandomPool rng;
|
||||
CryptoPP::DecodingResult result =
|
||||
rsaDecryptor.Decrypt(rng, ciphertext.data(), decrypted.size(), decrypted.data());
|
||||
std::copy(decrypted.begin(), decrypted.begin() + dec_key.size(), dec_key.begin());
|
||||
}
|
||||
|
||||
void Crypto::ivKeyHASH256(std::span<const CryptoPP::byte, 64> cipher_input,
|
||||
std::span<CryptoPP::byte, 32> ivkey_result) {
|
||||
CryptoPP::SHA256 sha256;
|
||||
std::array<CryptoPP::byte, CryptoPP::SHA256::DIGESTSIZE> hashResult;
|
||||
auto array_sink = new CryptoPP::ArraySink(hashResult.data(), CryptoPP::SHA256::DIGESTSIZE);
|
||||
auto filter = new CryptoPP::HashFilter(sha256, array_sink);
|
||||
CryptoPP::ArraySource r(cipher_input.data(), cipher_input.size(), true, filter);
|
||||
std::copy(hashResult.begin(), hashResult.begin() + ivkey_result.size(), ivkey_result.begin());
|
||||
}
|
||||
|
||||
void Crypto::aesCbcCfb128Decrypt(std::span<const CryptoPP::byte, 32> ivkey,
|
||||
std::span<const CryptoPP::byte, 256> ciphertext,
|
||||
std::span<CryptoPP::byte, 256> decrypted) {
|
||||
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
|
||||
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
|
||||
|
||||
std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
|
||||
std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
|
||||
|
||||
CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
|
||||
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
|
||||
|
||||
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
|
||||
cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
|
||||
CryptoPP::AES::BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void Crypto::aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
|
||||
std::span<CryptoPP::byte> ciphertext,
|
||||
std::span<CryptoPP::byte> decrypted) {
|
||||
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
|
||||
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
|
||||
|
||||
std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
|
||||
std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
|
||||
|
||||
CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
|
||||
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
|
||||
|
||||
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
|
||||
cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
|
||||
CryptoPP::AES::BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void Crypto::decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
|
||||
std::span<CryptoPP::byte, 16> NPcommID,
|
||||
std::span<CryptoPP::byte, 16> efsmIv, std::span<CryptoPP::byte> ciphertext,
|
||||
std::span<CryptoPP::byte> decrypted) {
|
||||
|
||||
// step 1: Encrypt NPcommID
|
||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
|
||||
|
||||
std::vector<CryptoPP::byte> trophyIv(16, 0);
|
||||
std::vector<CryptoPP::byte> trpKey(16);
|
||||
|
||||
encrypt.SetKeyWithIV(trophyKey.data(), trophyKey.size(), trophyIv.data());
|
||||
encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16);
|
||||
|
||||
// step 2: decrypt efsm.
|
||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt;
|
||||
decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data());
|
||||
|
||||
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
|
||||
decrypt.ProcessData(decrypted.data() + i, ciphertext.data() + i, CryptoPP::AES::BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void Crypto::PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
|
||||
std::span<const CryptoPP::byte, 16> seed,
|
||||
std::span<CryptoPP::byte, 16> dataKey,
|
||||
std::span<CryptoPP::byte, 16> tweakKey) {
|
||||
CryptoPP::HMAC<CryptoPP::SHA256> hmac(ekpfs.data(), ekpfs.size());
|
||||
|
||||
CryptoPP::SecByteBlock d(20); // Use Crypto++ SecByteBlock for better memory management
|
||||
|
||||
// Copy the bytes of 'index' to the 'd' array
|
||||
uint32_t index = 1;
|
||||
std::memcpy(d, &index, sizeof(uint32_t));
|
||||
|
||||
// Copy the bytes of 'seed' to the 'd' array starting from index 4
|
||||
std::memcpy(d + sizeof(uint32_t), seed.data(), seed.size());
|
||||
|
||||
// Allocate memory for 'u64' using new
|
||||
std::vector<CryptoPP::byte> data_tweak_key(hmac.DigestSize());
|
||||
|
||||
// Calculate the HMAC
|
||||
hmac.CalculateDigest(data_tweak_key.data(), d, d.size());
|
||||
std::copy(data_tweak_key.begin(), data_tweak_key.begin() + dataKey.size(), tweakKey.begin());
|
||||
std::copy(data_tweak_key.begin() + tweakKey.size(),
|
||||
data_tweak_key.begin() + tweakKey.size() + dataKey.size(), dataKey.begin());
|
||||
}
|
||||
|
||||
void Crypto::decryptPFS(std::span<const CryptoPP::byte, 16> dataKey,
|
||||
std::span<const CryptoPP::byte, 16> tweakKey, std::span<const u8> src_image,
|
||||
std::span<CryptoPP::byte> dst_image, u64 sector) {
|
||||
// Start at 0x10000 to keep the header when decrypting the whole pfs_image.
|
||||
for (int i = 0; i < src_image.size(); i += 0x1000) {
|
||||
const u64 current_sector = sector + (i / 0x1000);
|
||||
CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption encrypt(tweakKey.data(), tweakKey.size());
|
||||
CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption decrypt(dataKey.data(), dataKey.size());
|
||||
|
||||
std::array<CryptoPP::byte, 16> tweak{};
|
||||
std::array<CryptoPP::byte, 16> encryptedTweak;
|
||||
std::array<CryptoPP::byte, 16> xorBuffer;
|
||||
std::memcpy(tweak.data(), ¤t_sector, sizeof(u64));
|
||||
|
||||
// Encrypt the tweak for each sector.
|
||||
encrypt.ProcessData(encryptedTweak.data(), tweak.data(), 16);
|
||||
|
||||
for (int plaintextOffset = 0; plaintextOffset < 0x1000; plaintextOffset += 16) {
|
||||
xtsXorBlock(xorBuffer.data(), src_image.data() + i + plaintextOffset,
|
||||
encryptedTweak.data()); // x, c, t
|
||||
decrypt.ProcessData(xorBuffer.data(), xorBuffer.data(), 16); // x, x
|
||||
xtsXorBlock(dst_image.data() + i + plaintextOffset, xorBuffer.data(),
|
||||
encryptedTweak.data()); //(p) c, x , t
|
||||
xtsMult(encryptedTweak);
|
||||
}
|
||||
}
|
||||
}
|
63
src/core/crypto/crypto.h
Normal file
63
src/core/crypto/crypto.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <cryptopp/aes.h>
|
||||
#include <cryptopp/filters.h>
|
||||
#include <cryptopp/modes.h>
|
||||
#include <cryptopp/oaep.h>
|
||||
#include <cryptopp/osrng.h>
|
||||
#include <cryptopp/rsa.h>
|
||||
#include <cryptopp/sha.h>
|
||||
|
||||
#include "common/types.h"
|
||||
#include "keys.h"
|
||||
|
||||
class Crypto {
|
||||
public:
|
||||
CryptoPP::RSA::PrivateKey key_pkg_derived_key3_keyset_init();
|
||||
CryptoPP::RSA::PrivateKey FakeKeyset_keyset_init();
|
||||
CryptoPP::RSA::PrivateKey DebugRifKeyset_init();
|
||||
|
||||
void RSA2048Decrypt(std::span<CryptoPP::byte, 32> dk3,
|
||||
std::span<const CryptoPP::byte, 256> ciphertext,
|
||||
bool is_dk3); // RSAES_PKCS1v15_
|
||||
void ivKeyHASH256(std::span<const CryptoPP::byte, 64> cipher_input,
|
||||
std::span<CryptoPP::byte, 32> ivkey_result);
|
||||
void aesCbcCfb128Decrypt(std::span<const CryptoPP::byte, 32> ivkey,
|
||||
std::span<const CryptoPP::byte, 256> ciphertext,
|
||||
std::span<CryptoPP::byte, 256> decrypted);
|
||||
void aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
|
||||
std::span<CryptoPP::byte> ciphertext,
|
||||
std::span<CryptoPP::byte> decrypted);
|
||||
void decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
|
||||
std::span<CryptoPP::byte, 16> NPcommID, std::span<CryptoPP::byte, 16> efsmIv,
|
||||
std::span<CryptoPP::byte> ciphertext, std::span<CryptoPP::byte> decrypted);
|
||||
void PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
|
||||
std::span<const CryptoPP::byte, 16> seed,
|
||||
std::span<CryptoPP::byte, 16> dataKey,
|
||||
std::span<CryptoPP::byte, 16> tweakKey);
|
||||
void decryptPFS(std::span<const CryptoPP::byte, 16> dataKey,
|
||||
std::span<const CryptoPP::byte, 16> tweakKey, std::span<const u8> src_image,
|
||||
std::span<CryptoPP::byte> dst_image, u64 sector);
|
||||
|
||||
void xtsXorBlock(CryptoPP::byte* x, const CryptoPP::byte* a, const CryptoPP::byte* b) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
x[i] = a[i] ^ b[i];
|
||||
}
|
||||
}
|
||||
|
||||
void xtsMult(std::span<CryptoPP::byte, 16> encryptedTweak) {
|
||||
int feedback = 0;
|
||||
for (int k = 0; k < encryptedTweak.size(); k++) {
|
||||
const auto tmp = (encryptedTweak[k] >> 7) & 1;
|
||||
encryptedTweak[k] = ((encryptedTweak[k] << 1) + feedback) & 0xFF;
|
||||
feedback = tmp;
|
||||
}
|
||||
if (feedback != 0) {
|
||||
encryptedTweak[0] ^= 0x87;
|
||||
}
|
||||
}
|
||||
};
|
305
src/core/crypto/keys.h
Normal file
305
src/core/crypto/keys.h
Normal file
|
@ -0,0 +1,305 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include <cryptopp/rsa.h>
|
||||
|
||||
class FakeKeyset {
|
||||
public:
|
||||
// Constructor
|
||||
static constexpr CryptoPP::byte Exponent1[] = {
|
||||
0x6D, 0x48, 0xE0, 0x54, 0x40, 0x25, 0xC8, 0x41, 0x29, 0x52, 0x42, 0x27, 0xEB, 0xD2, 0xC7,
|
||||
0xAB, 0x6B, 0x9C, 0x27, 0x0A, 0xB4, 0x1F, 0x94, 0x4E, 0xFA, 0x42, 0x1D, 0xB7, 0xBC, 0xB9,
|
||||
0xAE, 0xBC, 0x04, 0x6F, 0x75, 0x8F, 0x10, 0x5F, 0x89, 0xAC, 0xAB, 0x9C, 0xD2, 0xFA, 0xE6,
|
||||
0xA4, 0x13, 0x83, 0x68, 0xD4, 0x56, 0x38, 0xFE, 0xE5, 0x2B, 0x78, 0x44, 0x9C, 0x34, 0xE6,
|
||||
0x5A, 0xA0, 0xBE, 0x05, 0x70, 0xAD, 0x15, 0xC3, 0x2D, 0x31, 0xAC, 0x97, 0x5D, 0x88, 0xFC,
|
||||
0xC1, 0x62, 0x3D, 0xE2, 0xED, 0x11, 0xDB, 0xB6, 0x9E, 0xFC, 0x5A, 0x5A, 0x03, 0xF6, 0xCF,
|
||||
0x08, 0xD4, 0x5D, 0x90, 0xC9, 0x2A, 0xB9, 0x9B, 0xCF, 0xC8, 0x1A, 0x65, 0xF3, 0x5B, 0xE8,
|
||||
0x7F, 0xCF, 0xA5, 0xA6, 0x4C, 0x5C, 0x2A, 0x12, 0x0F, 0x92, 0xA5, 0xE3, 0xF0, 0x17, 0x1E,
|
||||
0x9A, 0x97, 0x45, 0x86, 0xFD, 0xDB, 0x54, 0x25};
|
||||
// exponent2 = d mod (q - 1)
|
||||
static constexpr CryptoPP::byte Exponent2[] = {
|
||||
0x2A, 0x51, 0xCE, 0x02, 0x44, 0x28, 0x50, 0xE8, 0x30, 0x20, 0x7C, 0x9C, 0x55, 0xBF, 0x60,
|
||||
0x39, 0xBC, 0xD1, 0xF0, 0xE7, 0x68, 0xF8, 0x08, 0x5B, 0x61, 0x1F, 0xA7, 0xBF, 0xD0, 0xE8,
|
||||
0x8B, 0xB5, 0xB1, 0xD5, 0xD9, 0x16, 0xAC, 0x75, 0x0C, 0x6D, 0xF2, 0xE0, 0xB5, 0x97, 0x75,
|
||||
0xD2, 0x68, 0x16, 0x1F, 0x00, 0x7D, 0x8B, 0x17, 0xE8, 0x78, 0x48, 0x41, 0x71, 0x2B, 0x18,
|
||||
0x96, 0x80, 0x11, 0xDB, 0x68, 0x39, 0x9C, 0xD6, 0xE0, 0x72, 0x42, 0x86, 0xF0, 0x1B, 0x16,
|
||||
0x0D, 0x3E, 0x12, 0x94, 0x3D, 0x25, 0xA8, 0xA9, 0x30, 0x9E, 0x54, 0x5A, 0xD6, 0x36, 0x6C,
|
||||
0xD6, 0x8C, 0x20, 0x62, 0x8F, 0xA1, 0x6B, 0x1F, 0x7C, 0x6D, 0xB2, 0xB1, 0xC1, 0x2E, 0xAD,
|
||||
0x36, 0x02, 0x9C, 0x3A, 0xCA, 0x2F, 0x09, 0xD2, 0x45, 0x9E, 0xEB, 0xF2, 0xBC, 0x6C, 0xAA,
|
||||
0x3B, 0x3E, 0x90, 0xBC, 0x38, 0x67, 0x35, 0x4D};
|
||||
// e
|
||||
static constexpr CryptoPP::byte PublicExponent[] = {0, 1, 0, 1};
|
||||
// (InverseQ)(q) = 1 mod p
|
||||
static constexpr CryptoPP::byte Coefficient[] = {
|
||||
0x0B, 0x67, 0x1C, 0x0D, 0x6C, 0x57, 0xD3, 0xE7, 0x05, 0x65, 0x94, 0x31, 0x56, 0x55, 0xFD,
|
||||
0x28, 0x08, 0xFA, 0x05, 0x8A, 0xCC, 0x55, 0x39, 0x61, 0x97, 0x63, 0xA0, 0x16, 0x27, 0x3D,
|
||||
0xED, 0xC1, 0x16, 0x40, 0x2A, 0x12, 0xEA, 0x6F, 0xD9, 0xD8, 0x58, 0x56, 0xA8, 0x56, 0x8B,
|
||||
0x0D, 0x38, 0x5E, 0x1E, 0x80, 0x3B, 0x5F, 0x40, 0x80, 0x6F, 0x62, 0x4F, 0x28, 0xA2, 0x69,
|
||||
0xF3, 0xD3, 0xF7, 0xFD, 0xB2, 0xC3, 0x52, 0x43, 0x20, 0x92, 0x9D, 0x97, 0x8D, 0xA0, 0x15,
|
||||
0x07, 0x15, 0x6E, 0xA4, 0x0D, 0x56, 0xD3, 0x37, 0x1A, 0xC4, 0x9E, 0xDF, 0x02, 0x49, 0xB8,
|
||||
0x0A, 0x84, 0x62, 0xF5, 0xFA, 0xB9, 0x3F, 0xA4, 0x09, 0x76, 0xCC, 0xAA, 0xB9, 0x9B, 0xA6,
|
||||
0x4F, 0xC1, 0x6A, 0x64, 0xCE, 0xD8, 0x77, 0xAB, 0x4B, 0xF9, 0xA0, 0xAE, 0xDA, 0xF1, 0x67,
|
||||
0x87, 0x7C, 0x98, 0x5C, 0x7E, 0xB8, 0x73, 0xF5};
|
||||
// n = p * q
|
||||
static constexpr CryptoPP::byte Modulus[] = {
|
||||
0xC6, 0xCF, 0x71, 0xE7, 0xE5, 0x9A, 0xF0, 0xD1, 0x2A, 0x2C, 0x45, 0x8B, 0xF9, 0x2A, 0x0E,
|
||||
0xC1, 0x43, 0x05, 0x8B, 0xC3, 0x71, 0x17, 0x80, 0x1D, 0xCD, 0x49, 0x7D, 0xDE, 0x35, 0x9D,
|
||||
0x25, 0x9B, 0xA0, 0xD7, 0xA0, 0xF2, 0x7D, 0x6C, 0x08, 0x7E, 0xAA, 0x55, 0x02, 0x68, 0x2B,
|
||||
0x23, 0xC6, 0x44, 0xB8, 0x44, 0x18, 0xEB, 0x56, 0xCF, 0x16, 0xA2, 0x48, 0x03, 0xC9, 0xE7,
|
||||
0x4F, 0x87, 0xEB, 0x3D, 0x30, 0xC3, 0x15, 0x88, 0xBF, 0x20, 0xE7, 0x9D, 0xFF, 0x77, 0x0C,
|
||||
0xDE, 0x1D, 0x24, 0x1E, 0x63, 0xA9, 0x4F, 0x8A, 0xBF, 0x5B, 0xBE, 0x60, 0x19, 0x68, 0x33,
|
||||
0x3B, 0xFC, 0xED, 0x9F, 0x47, 0x4E, 0x5F, 0xF8, 0xEA, 0xCB, 0x3D, 0x00, 0xBD, 0x67, 0x01,
|
||||
0xF9, 0x2C, 0x6D, 0xC6, 0xAC, 0x13, 0x64, 0xE7, 0x67, 0x14, 0xF3, 0xDC, 0x52, 0x69, 0x6A,
|
||||
0xB9, 0x83, 0x2C, 0x42, 0x30, 0x13, 0x1B, 0xB2, 0xD8, 0xA5, 0x02, 0x0D, 0x79, 0xED, 0x96,
|
||||
0xB1, 0x0D, 0xF8, 0xCC, 0x0C, 0xDF, 0x81, 0x95, 0x4F, 0x03, 0x58, 0x09, 0x57, 0x0E, 0x80,
|
||||
0x69, 0x2E, 0xFE, 0xFF, 0x52, 0x77, 0xEA, 0x75, 0x28, 0xA8, 0xFB, 0xC9, 0xBE, 0xBF, 0x9F,
|
||||
0xBB, 0xB7, 0x79, 0x8E, 0x18, 0x05, 0xE1, 0x80, 0xBD, 0x50, 0x34, 0x94, 0x81, 0xD3, 0x53,
|
||||
0xC2, 0x69, 0xA2, 0xD2, 0x4C, 0xCF, 0x6C, 0xF4, 0x57, 0x2C, 0x10, 0x4A, 0x3F, 0xFB, 0x22,
|
||||
0xFD, 0x8B, 0x97, 0xE2, 0xC9, 0x5B, 0xA6, 0x2B, 0xCD, 0xD6, 0x1B, 0x6B, 0xDB, 0x68, 0x7F,
|
||||
0x4B, 0xC2, 0xA0, 0x50, 0x34, 0xC0, 0x05, 0xE5, 0x8D, 0xEF, 0x24, 0x67, 0xFF, 0x93, 0x40,
|
||||
0xCF, 0x2D, 0x62, 0xA2, 0xA0, 0x50, 0xB1, 0xF1, 0x3A, 0xA8, 0x3D, 0xFD, 0x80, 0xD1, 0xF9,
|
||||
0xB8, 0x05, 0x22, 0xAF, 0xC8, 0x35, 0x45, 0x90, 0x58, 0x8E, 0xE3, 0x3A, 0x7C, 0xBD, 0x3E,
|
||||
0x27};
|
||||
// p
|
||||
static constexpr CryptoPP::byte Prime1[] = {
|
||||
0xFE, 0xF6, 0xBF, 0x1D, 0x69, 0xAB, 0x16, 0x25, 0x08, 0x47, 0x55, 0x6B, 0x86, 0xE4, 0x35,
|
||||
0x88, 0x72, 0x2A, 0xB1, 0x3D, 0xF8, 0xB6, 0x44, 0xCA, 0xB3, 0xAB, 0x19, 0xD1, 0x04, 0x24,
|
||||
0x28, 0x0A, 0x74, 0x55, 0xB8, 0x15, 0x45, 0x09, 0xCC, 0x13, 0x1C, 0xF2, 0xBA, 0x37, 0xA9,
|
||||
0x03, 0x90, 0x8F, 0x02, 0x10, 0xFF, 0x25, 0x79, 0x86, 0xCC, 0x18, 0x50, 0x9A, 0x10, 0x5F,
|
||||
0x5B, 0x4C, 0x1C, 0x4E, 0xB0, 0xA7, 0xE3, 0x59, 0xB1, 0x2D, 0xA0, 0xC6, 0xB0, 0x20, 0x2C,
|
||||
0x21, 0x33, 0x12, 0xB3, 0xAF, 0x72, 0x34, 0x83, 0xCD, 0x52, 0x2F, 0xAF, 0x0F, 0x20, 0x5A,
|
||||
0x1B, 0xC0, 0xE2, 0xA3, 0x76, 0x34, 0x0F, 0xD7, 0xFC, 0xC1, 0x41, 0xC9, 0xF9, 0x79, 0x40,
|
||||
0x17, 0x42, 0x21, 0x3E, 0x9D, 0xFD, 0xC7, 0xC1, 0x50, 0xDE, 0x44, 0x5A, 0xC9, 0x31, 0x89,
|
||||
0x6A, 0x78, 0x05, 0xBE, 0x65, 0xB4, 0xE8, 0x2D};
|
||||
// q
|
||||
static constexpr CryptoPP::byte Prime2[] = {
|
||||
0xC7, 0x9E, 0x47, 0x58, 0x00, 0x7D, 0x62, 0x82, 0xB0, 0xD2, 0x22, 0x81, 0xD4, 0xA8, 0x97,
|
||||
0x1B, 0x79, 0x0C, 0x3A, 0xB0, 0xD7, 0xC9, 0x30, 0xE3, 0xC3, 0x53, 0x8E, 0x57, 0xEF, 0xF0,
|
||||
0x9B, 0x9F, 0xB3, 0x90, 0x52, 0xC6, 0x94, 0x22, 0x36, 0xAA, 0xE6, 0x4A, 0x5F, 0x72, 0x1D,
|
||||
0x70, 0xE8, 0x76, 0x58, 0xC8, 0xB2, 0x91, 0xCE, 0x9C, 0xC3, 0xE9, 0x09, 0x7F, 0x2E, 0x47,
|
||||
0x97, 0xCC, 0x90, 0x39, 0x15, 0x35, 0x31, 0xDE, 0x1F, 0x0C, 0x8C, 0x0D, 0xC1, 0xC2, 0x92,
|
||||
0xBE, 0x97, 0xBF, 0x2F, 0x91, 0xA1, 0x8C, 0x7D, 0x50, 0xA8, 0x21, 0x2F, 0xD7, 0xA2, 0x9A,
|
||||
0x7E, 0xB5, 0xA7, 0x2A, 0x90, 0x02, 0xD9, 0xF3, 0x3D, 0xD1, 0xEB, 0xB8, 0xE0, 0x5A, 0x79,
|
||||
0x9E, 0x7D, 0x8D, 0xCA, 0x18, 0x6D, 0xBD, 0x9E, 0xA1, 0x80, 0x28, 0x6B, 0x2A, 0xFE, 0x51,
|
||||
0x24, 0x9B, 0x6F, 0x4D, 0x84, 0x77, 0x80, 0x23};
|
||||
static constexpr CryptoPP::byte PrivateExponent[] = {
|
||||
0x7F, 0x76, 0xCD, 0x0E, 0xE2, 0xD4, 0xDE, 0x05, 0x1C, 0xC6, 0xD9, 0xA8, 0x0E, 0x8D, 0xFA,
|
||||
0x7B, 0xCA, 0x1E, 0xAA, 0x27, 0x1A, 0x40, 0xF8, 0xF1, 0x22, 0x87, 0x35, 0xDD, 0xDB, 0xFD,
|
||||
0xEE, 0xF8, 0xC2, 0xBC, 0xBD, 0x01, 0xFB, 0x8B, 0xE2, 0x3E, 0x63, 0xB2, 0xB1, 0x22, 0x5C,
|
||||
0x56, 0x49, 0x6E, 0x11, 0xBE, 0x07, 0x44, 0x0B, 0x9A, 0x26, 0x66, 0xD1, 0x49, 0x2C, 0x8F,
|
||||
0xD3, 0x1B, 0xCF, 0xA4, 0xA1, 0xB8, 0xD1, 0xFB, 0xA4, 0x9E, 0xD2, 0x21, 0x28, 0x83, 0x09,
|
||||
0x8A, 0xF6, 0xA0, 0x0B, 0xA3, 0xD6, 0x0F, 0x9B, 0x63, 0x68, 0xCC, 0xBC, 0x0C, 0x4E, 0x14,
|
||||
0x5B, 0x27, 0xA4, 0xA9, 0xF4, 0x2B, 0xB9, 0xB8, 0x7B, 0xC0, 0xE6, 0x51, 0xAD, 0x1D, 0x77,
|
||||
0xD4, 0x6B, 0xB9, 0xCE, 0x20, 0xD1, 0x26, 0x66, 0x7E, 0x5E, 0x9E, 0xA2, 0xE9, 0x6B, 0x90,
|
||||
0xF3, 0x73, 0xB8, 0x52, 0x8F, 0x44, 0x11, 0x03, 0x0C, 0x13, 0x97, 0x39, 0x3D, 0x13, 0x22,
|
||||
0x58, 0xD5, 0x43, 0x82, 0x49, 0xDA, 0x6E, 0x7C, 0xA1, 0xC5, 0x8C, 0xA5, 0xB0, 0x09, 0xE0,
|
||||
0xCE, 0x3D, 0xDF, 0xF4, 0x9D, 0x3C, 0x97, 0x15, 0xE2, 0x6A, 0xC7, 0x2B, 0x3C, 0x50, 0x93,
|
||||
0x23, 0xDB, 0xBA, 0x4A, 0x22, 0x66, 0x44, 0xAC, 0x78, 0xBB, 0x0E, 0x1A, 0x27, 0x43, 0xB5,
|
||||
0x71, 0x67, 0xAF, 0xF4, 0xAB, 0x48, 0x46, 0x93, 0x73, 0xD0, 0x42, 0xAB, 0x93, 0x63, 0xE5,
|
||||
0x6C, 0x9A, 0xDE, 0x50, 0x24, 0xC0, 0x23, 0x7D, 0x99, 0x79, 0x3F, 0x22, 0x07, 0xE0, 0xC1,
|
||||
0x48, 0x56, 0x1B, 0xDF, 0x83, 0x09, 0x12, 0xB4, 0x2D, 0x45, 0x6B, 0xC9, 0xC0, 0x68, 0x85,
|
||||
0x99, 0x90, 0x79, 0x96, 0x1A, 0xD7, 0xF5, 0x4D, 0x1F, 0x37, 0x83, 0x40, 0x4A, 0xEC, 0x39,
|
||||
0x37, 0xA6, 0x80, 0x92, 0x7D, 0xC5, 0x80, 0xC7, 0xD6, 0x6F, 0xFE, 0x8A, 0x79, 0x89, 0xC6,
|
||||
0xB1};
|
||||
};
|
||||
|
||||
class DebugRifKeyset {
|
||||
public:
|
||||
// std::uint8_t* PrivateExponent;
|
||||
static constexpr CryptoPP::byte Exponent1[] = {
|
||||
0xCD, 0x9A, 0x61, 0xB0, 0xB8, 0xD5, 0xB4, 0xE4, 0xE4, 0xF6, 0xAB, 0xF7, 0x27, 0xB7, 0x56,
|
||||
0x59, 0x6B, 0xB9, 0x11, 0xE7, 0xF4, 0x83, 0xAF, 0xB9, 0x73, 0x99, 0x7F, 0x49, 0xA2, 0x9C,
|
||||
0xF0, 0xB5, 0x6D, 0x37, 0x82, 0x14, 0x15, 0xF1, 0x04, 0x8A, 0xD4, 0x8E, 0xEB, 0x2E, 0x1F,
|
||||
0xE2, 0x81, 0xA9, 0x62, 0x6E, 0xB1, 0x68, 0x75, 0x62, 0xF3, 0x0F, 0xFE, 0xD4, 0x91, 0x87,
|
||||
0x98, 0x78, 0xBF, 0x26, 0xB5, 0x07, 0x58, 0xD0, 0xEE, 0x3F, 0x21, 0xE8, 0xC8, 0x0F, 0x5F,
|
||||
0xFA, 0x1C, 0x64, 0x74, 0x49, 0x52, 0xEB, 0xE7, 0xEE, 0xDE, 0xBA, 0x23, 0x26, 0x4A, 0xF6,
|
||||
0x9C, 0x1A, 0x09, 0x3F, 0xB9, 0x0B, 0x36, 0x26, 0x1A, 0xBE, 0xA9, 0x76, 0xE6, 0xF2, 0x69,
|
||||
0xDE, 0xFF, 0xAF, 0xCC, 0x0C, 0x9A, 0x66, 0x03, 0x86, 0x0A, 0x1F, 0x49, 0xA4, 0x10, 0xB6,
|
||||
0xBC, 0xC3, 0x7C, 0x88, 0xE8, 0xCE, 0x4B, 0xD9};
|
||||
// exponent2 = d mod (q - 1)
|
||||
static constexpr CryptoPP::byte Exponent2[] = {
|
||||
0xB3, 0x73, 0xA3, 0x59, 0xE6, 0x97, 0xC0, 0xAB, 0x3B, 0x68, 0xFC, 0x39, 0xAC, 0xDB, 0x44,
|
||||
0xB1, 0xB4, 0x9E, 0x35, 0x4D, 0xBE, 0xC5, 0x36, 0x69, 0x6C, 0x3D, 0xC5, 0xFC, 0xFE, 0x4B,
|
||||
0x2F, 0xDC, 0x86, 0x80, 0x46, 0x96, 0x40, 0x1A, 0x0D, 0x6E, 0xFA, 0x8C, 0xE0, 0x47, 0x91,
|
||||
0xAC, 0xAD, 0x95, 0x2B, 0x8E, 0x1F, 0xF2, 0x0A, 0x45, 0xF8, 0x29, 0x95, 0x70, 0xC6, 0x88,
|
||||
0x5F, 0x71, 0x03, 0x99, 0x79, 0xBC, 0x84, 0x71, 0xBD, 0xE8, 0x84, 0x8C, 0x0E, 0xD4, 0x7B,
|
||||
0x30, 0x74, 0x57, 0x1A, 0x95, 0xE7, 0x90, 0x19, 0x8D, 0xAD, 0x8B, 0x4C, 0x4E, 0xC3, 0xE7,
|
||||
0x6B, 0x23, 0x86, 0x01, 0xEE, 0x9B, 0xE0, 0x2F, 0x15, 0xA2, 0x2C, 0x4C, 0x39, 0xD3, 0xDF,
|
||||
0x9C, 0x39, 0x01, 0xF1, 0x8C, 0x44, 0x4A, 0x15, 0x44, 0xDC, 0x51, 0xF7, 0x22, 0xD7, 0x7F,
|
||||
0x41, 0x7F, 0x68, 0xFA, 0xEE, 0x56, 0xE8, 0x05};
|
||||
// e
|
||||
static constexpr CryptoPP::byte PublicExponent[] = {0x00, 0x01, 0x00, 0x01};
|
||||
// (InverseQ)(q) = 1 mod p
|
||||
static constexpr CryptoPP::byte Coefficient[] = {
|
||||
0xC0, 0x32, 0x43, 0xD3, 0x8C, 0x3D, 0xB4, 0xD2, 0x48, 0x8C, 0x42, 0x41, 0x24, 0x94, 0x6C,
|
||||
0x80, 0xC9, 0xC1, 0x79, 0x36, 0x7F, 0xAC, 0xC3, 0xFF, 0x6A, 0x25, 0xEB, 0x2C, 0xFB, 0xD4,
|
||||
0x2B, 0xA0, 0xEB, 0xFE, 0x25, 0xE9, 0xC6, 0x77, 0xCE, 0xFE, 0x2D, 0x23, 0xFE, 0xD0, 0xF4,
|
||||
0x0F, 0xD9, 0x7E, 0xD5, 0xA5, 0x7D, 0x1F, 0xC0, 0xE8, 0xE8, 0xEC, 0x80, 0x5B, 0xC7, 0xFD,
|
||||
0xE2, 0xBD, 0x94, 0xA6, 0x2B, 0xDD, 0x6A, 0x60, 0x45, 0x54, 0xAB, 0xCA, 0x42, 0x9C, 0x6A,
|
||||
0x6C, 0xBF, 0x3C, 0x84, 0xF9, 0xA5, 0x0E, 0x63, 0x0C, 0x51, 0x58, 0x62, 0x6D, 0x5A, 0xB7,
|
||||
0x3C, 0x3F, 0x49, 0x1A, 0xD0, 0x93, 0xB8, 0x4F, 0x1A, 0x6C, 0x5F, 0xC5, 0xE5, 0xA9, 0x75,
|
||||
0xD4, 0x86, 0x9E, 0xDF, 0x87, 0x0F, 0x27, 0xB0, 0x26, 0x78, 0x4E, 0xFB, 0xC1, 0x8A, 0x4A,
|
||||
0x24, 0x3F, 0x7F, 0x8F, 0x9A, 0x12, 0x51, 0xCB};
|
||||
// n = p * q
|
||||
static constexpr CryptoPP::byte Modulus[] = {
|
||||
0xC2, 0xD2, 0x44, 0xBC, 0xDD, 0x84, 0x3F, 0xD9, 0xC5, 0x22, 0xAF, 0xF7, 0xFC, 0x88, 0x8A,
|
||||
0x33, 0x80, 0xED, 0x8E, 0xE2, 0xCC, 0x81, 0xF7, 0xEC, 0xF8, 0x1C, 0x79, 0xBF, 0x02, 0xBB,
|
||||
0x12, 0x8E, 0x61, 0x68, 0x29, 0x1B, 0x15, 0xB6, 0x5E, 0xC6, 0xF8, 0xBF, 0x5A, 0xE0, 0x3B,
|
||||
0x6A, 0x6C, 0xD9, 0xD6, 0xF5, 0x75, 0xAB, 0xA0, 0x6F, 0x34, 0x81, 0x34, 0x9A, 0x5B, 0xAD,
|
||||
0xED, 0x31, 0xE3, 0xC6, 0xEA, 0x1A, 0xD1, 0x13, 0x22, 0xBB, 0xB3, 0xDA, 0xB3, 0xB2, 0x53,
|
||||
0xBD, 0x45, 0x79, 0x87, 0xAD, 0x0A, 0x01, 0x72, 0x18, 0x10, 0x29, 0x49, 0xF4, 0x41, 0x7F,
|
||||
0xD6, 0x47, 0x0C, 0x72, 0x92, 0x9E, 0xE9, 0xBB, 0x95, 0xA9, 0x5D, 0x79, 0xEB, 0xE4, 0x30,
|
||||
0x76, 0x90, 0x45, 0x4B, 0x9D, 0x9C, 0xCF, 0x92, 0x03, 0x60, 0x8C, 0x4B, 0x6C, 0xB3, 0x7A,
|
||||
0x3A, 0x05, 0x39, 0xA0, 0x66, 0xA9, 0x35, 0xCF, 0xB9, 0xFA, 0xAD, 0x9C, 0xAB, 0xEB, 0xE4,
|
||||
0x6A, 0x8C, 0xE9, 0x3B, 0xCC, 0x72, 0x12, 0x62, 0x63, 0xBD, 0x80, 0xC4, 0xEE, 0x37, 0x2B,
|
||||
0x32, 0x03, 0xA3, 0x09, 0xF7, 0xA0, 0x61, 0x57, 0xAD, 0x0D, 0xCF, 0x15, 0x98, 0x9E, 0x4E,
|
||||
0x49, 0xF8, 0xB5, 0xA3, 0x5C, 0x27, 0xEE, 0x45, 0x04, 0xEA, 0xE4, 0x4B, 0xBC, 0x8F, 0x87,
|
||||
0xED, 0x19, 0x1E, 0x46, 0x75, 0x63, 0xC4, 0x5B, 0xD5, 0xBC, 0x09, 0x2F, 0x02, 0x73, 0x19,
|
||||
0x3C, 0x58, 0x55, 0x49, 0x66, 0x4C, 0x11, 0xEC, 0x0F, 0x09, 0xFA, 0xA5, 0x56, 0x0A, 0x5A,
|
||||
0x63, 0x56, 0xAD, 0xA0, 0x0D, 0x86, 0x08, 0xC1, 0xE6, 0xB6, 0x13, 0x22, 0x49, 0x2F, 0x7C,
|
||||
0xDB, 0x4C, 0x56, 0x97, 0x0E, 0xC2, 0xD9, 0x2E, 0x87, 0xBC, 0x0E, 0x67, 0xC0, 0x1B, 0x58,
|
||||
0xBC, 0x64, 0x2B, 0xC2, 0x6E, 0xE2, 0x93, 0x2E, 0xB5, 0x6B, 0x70, 0xA4, 0x42, 0x9F, 0x64,
|
||||
0xC1};
|
||||
// p
|
||||
static constexpr CryptoPP::byte Prime1[] = {
|
||||
0xE5, 0x62, 0xE1, 0x7F, 0x9F, 0x86, 0x08, 0xE2, 0x61, 0xD3, 0xD0, 0x42, 0xE2, 0xC4, 0xB6,
|
||||
0xA8, 0x51, 0x09, 0x19, 0x14, 0xA4, 0x3A, 0x11, 0x4C, 0x33, 0xA5, 0x9C, 0x01, 0x5E, 0x34,
|
||||
0xB6, 0x3F, 0x02, 0x1A, 0xCA, 0x47, 0xF1, 0x4F, 0x3B, 0x35, 0x2A, 0x07, 0x20, 0xEC, 0xD8,
|
||||
0xC1, 0x15, 0xD9, 0xCA, 0x03, 0x4F, 0xB8, 0xE8, 0x09, 0x73, 0x3F, 0x85, 0xB7, 0x41, 0xD5,
|
||||
0x51, 0x3E, 0x7B, 0xE3, 0x53, 0x2B, 0x48, 0x8B, 0x8E, 0xCB, 0xBA, 0xF7, 0xE0, 0x60, 0xF5,
|
||||
0x35, 0x0E, 0x6F, 0xB0, 0xD9, 0x2A, 0x99, 0xD0, 0xFF, 0x60, 0x14, 0xED, 0x40, 0xEA, 0xF8,
|
||||
0xD7, 0x0B, 0xC3, 0x8D, 0x8C, 0xE8, 0x81, 0xB3, 0x75, 0x93, 0x15, 0xB3, 0x7D, 0xF6, 0x39,
|
||||
0x60, 0x1A, 0x00, 0xE7, 0xC3, 0x27, 0xAD, 0xA4, 0x33, 0xD5, 0x3E, 0xA4, 0x35, 0x48, 0x6F,
|
||||
0x22, 0xEF, 0x5D, 0xDD, 0x7D, 0x7B, 0x61, 0x05};
|
||||
// q
|
||||
static constexpr CryptoPP::byte Prime2[] = {
|
||||
0xD9, 0x6C, 0xC2, 0x0C, 0xF7, 0xAE, 0xD1, 0xF3, 0x3B, 0x3B, 0x49, 0x1E, 0x9F, 0x12, 0x9C,
|
||||
0xA1, 0x78, 0x1F, 0x35, 0x1D, 0x98, 0x26, 0x13, 0x71, 0xF9, 0x09, 0xFD, 0xF0, 0xAD, 0x38,
|
||||
0x55, 0xB7, 0xEE, 0x61, 0x04, 0x72, 0x51, 0x87, 0x2E, 0x05, 0x84, 0xB1, 0x1D, 0x0C, 0x0D,
|
||||
0xDB, 0xD4, 0x25, 0x3E, 0x26, 0xED, 0xEA, 0xB8, 0xF7, 0x49, 0xFE, 0xA2, 0x94, 0xE6, 0xF2,
|
||||
0x08, 0x92, 0xA7, 0x85, 0xF5, 0x30, 0xB9, 0x84, 0x22, 0xBF, 0xCA, 0xF0, 0x5F, 0xCB, 0x31,
|
||||
0x20, 0x34, 0x49, 0x16, 0x76, 0x34, 0xCC, 0x7A, 0xCB, 0x96, 0xFE, 0x78, 0x7A, 0x41, 0xFE,
|
||||
0x9A, 0xA2, 0x23, 0xF7, 0x68, 0x80, 0xD6, 0xCE, 0x4A, 0x78, 0xA5, 0xB7, 0x05, 0x77, 0x81,
|
||||
0x1F, 0xDE, 0x5E, 0xA8, 0x6E, 0x3E, 0x87, 0xEC, 0x44, 0xD2, 0x69, 0xC6, 0x54, 0x91, 0x6B,
|
||||
0x5E, 0x13, 0x8A, 0x03, 0x87, 0x05, 0x31, 0x8D};
|
||||
static constexpr CryptoPP::byte PrivateExponent[] = {
|
||||
0x01, 0x61, 0xAD, 0xD8, 0x9C, 0x06, 0x89, 0xD0, 0x60, 0xC8, 0x41, 0xF0, 0xB3, 0x83, 0x01,
|
||||
0x5D, 0xE3, 0xA2, 0x6B, 0xA2, 0xBA, 0x9A, 0x0A, 0x58, 0xCD, 0x1A, 0xA0, 0x97, 0x64, 0xEC,
|
||||
0xD0, 0x31, 0x1F, 0xCA, 0x36, 0x0E, 0x69, 0xDD, 0x40, 0xF7, 0x4E, 0xC0, 0xC6, 0xA3, 0x73,
|
||||
0xF0, 0x69, 0x84, 0xB2, 0xF4, 0x4B, 0x29, 0x14, 0x2A, 0x6D, 0xB8, 0x23, 0xD8, 0x1B, 0x61,
|
||||
0xD4, 0x9E, 0x87, 0xB3, 0xBB, 0xA9, 0xC4, 0x85, 0x4A, 0xF8, 0x03, 0x4A, 0xBF, 0xFE, 0xF9,
|
||||
0xFE, 0x8B, 0xDD, 0x54, 0x83, 0xBA, 0xE0, 0x2F, 0x3F, 0xB1, 0xEF, 0xA5, 0x05, 0x5D, 0x28,
|
||||
0x8B, 0xAB, 0xB5, 0xD0, 0x23, 0x2F, 0x8A, 0xCF, 0x48, 0x7C, 0xAA, 0xBB, 0xC8, 0x5B, 0x36,
|
||||
0x27, 0xC5, 0x16, 0xA4, 0xB6, 0x61, 0xAC, 0x0C, 0x28, 0x47, 0x79, 0x3F, 0x38, 0xAE, 0x5E,
|
||||
0x25, 0xC6, 0xAF, 0x35, 0xAE, 0xBC, 0xB0, 0xF3, 0xBC, 0xBD, 0xFD, 0xA4, 0x87, 0x0D, 0x14,
|
||||
0x3D, 0x90, 0xE4, 0xDE, 0x5D, 0x1D, 0x46, 0x81, 0xF1, 0x28, 0x6D, 0x2F, 0x2C, 0x5E, 0x97,
|
||||
0x2D, 0x89, 0x2A, 0x51, 0x72, 0x3C, 0x20, 0x02, 0x59, 0xB1, 0x98, 0x93, 0x05, 0x1E, 0x3F,
|
||||
0xA1, 0x8A, 0x69, 0x30, 0x0E, 0x70, 0x84, 0x8B, 0xAE, 0x97, 0xA1, 0x08, 0x95, 0x63, 0x4C,
|
||||
0xC7, 0xE8, 0x5D, 0x59, 0xCA, 0x78, 0x2A, 0x23, 0x87, 0xAC, 0x6F, 0x04, 0x33, 0xB1, 0x61,
|
||||
0xB9, 0xF0, 0x95, 0xDA, 0x33, 0xCC, 0xE0, 0x4C, 0x82, 0x68, 0x82, 0x14, 0x51, 0xBE, 0x49,
|
||||
0x1C, 0x58, 0xA2, 0x8B, 0x05, 0x4E, 0x98, 0x37, 0xEB, 0x94, 0x0B, 0x01, 0x22, 0xDC, 0xB3,
|
||||
0x19, 0xCA, 0x77, 0xA6, 0x6E, 0x97, 0xFF, 0x8A, 0x53, 0x5A, 0xC5, 0x24, 0xE4, 0xAF, 0x6E,
|
||||
0xA8, 0x2B, 0x53, 0xA4, 0xBE, 0x96, 0xA5, 0x7B, 0xCE, 0x22, 0x56, 0xA3, 0xF1, 0xCF, 0x14,
|
||||
0xA5};
|
||||
};
|
||||
|
||||
class PkgDerivedKey3Keyset {
|
||||
public:
|
||||
// std::uint8_t* PrivateExponent;
|
||||
static constexpr CryptoPP::byte Exponent1[] = {
|
||||
0x52, 0xCC, 0x2D, 0xA0, 0x9C, 0x9E, 0x75, 0xE7, 0x28, 0xEE, 0x3D, 0xDE, 0xE3, 0x45, 0xD1,
|
||||
0x4F, 0x94, 0x1C, 0xCC, 0xC8, 0x87, 0x29, 0x45, 0x3B, 0x8D, 0x6E, 0xAB, 0x6E, 0x2A, 0xA7,
|
||||
0xC7, 0x15, 0x43, 0xA3, 0x04, 0x8F, 0x90, 0x5F, 0xEB, 0xF3, 0x38, 0x4A, 0x77, 0xFA, 0x36,
|
||||
0xB7, 0x15, 0x76, 0xB6, 0x01, 0x1A, 0x8E, 0x25, 0x87, 0x82, 0xF1, 0x55, 0xD8, 0xC6, 0x43,
|
||||
0x2A, 0xC0, 0xE5, 0x98, 0xC9, 0x32, 0xD1, 0x94, 0x6F, 0xD9, 0x01, 0xBA, 0x06, 0x81, 0xE0,
|
||||
0x6D, 0x88, 0xF2, 0x24, 0x2A, 0x25, 0x01, 0x64, 0x5C, 0xBF, 0xF2, 0xD9, 0x99, 0x67, 0x3E,
|
||||
0xF6, 0x72, 0xEE, 0xE4, 0xE2, 0x33, 0x5C, 0xF8, 0x00, 0x40, 0xE3, 0x2A, 0x9A, 0xF4, 0x3D,
|
||||
0x22, 0x86, 0x44, 0x3C, 0xFB, 0x0A, 0xA5, 0x7C, 0x3F, 0xCC, 0xF5, 0xF1, 0x16, 0xC4, 0xAC,
|
||||
0x88, 0xB4, 0xDE, 0x62, 0x94, 0x92, 0x6A, 0x13};
|
||||
// exponent2 = d mod (q - 1)
|
||||
static constexpr CryptoPP::byte Exponent2[] = {
|
||||
0x7C, 0x9D, 0xAD, 0x39, 0xE0, 0xD5, 0x60, 0x14, 0x94, 0x48, 0x19, 0x7F, 0x88, 0x95, 0xD5,
|
||||
0x8B, 0x80, 0xAD, 0x85, 0x8A, 0x4B, 0x77, 0x37, 0x85, 0xD0, 0x77, 0xBB, 0xBF, 0x89, 0x71,
|
||||
0x4A, 0x72, 0xCB, 0x72, 0x68, 0x38, 0xEC, 0x02, 0xC6, 0x7D, 0xC6, 0x44, 0x06, 0x33, 0x51,
|
||||
0x1C, 0xC0, 0xFF, 0x95, 0x8F, 0x0D, 0x75, 0xDC, 0x25, 0xBB, 0x0B, 0x73, 0x91, 0xA9, 0x6D,
|
||||
0x42, 0xD8, 0x03, 0xB7, 0x68, 0xD4, 0x1E, 0x75, 0x62, 0xA3, 0x70, 0x35, 0x79, 0x78, 0x00,
|
||||
0xC8, 0xF5, 0xEF, 0x15, 0xB9, 0xFC, 0x4E, 0x47, 0x5A, 0xC8, 0x70, 0x70, 0x5B, 0x52, 0x98,
|
||||
0xC0, 0xC2, 0x58, 0x4A, 0x70, 0x96, 0xCC, 0xB8, 0x10, 0xE1, 0x2F, 0x78, 0x8B, 0x2B, 0xA1,
|
||||
0x7F, 0xF9, 0xAC, 0xDE, 0xF0, 0xBB, 0x2B, 0xE2, 0x66, 0xE3, 0x22, 0x92, 0x31, 0x21, 0x57,
|
||||
0x92, 0xC4, 0xB8, 0xF2, 0x3E, 0x76, 0x20, 0x37};
|
||||
// e
|
||||
static constexpr CryptoPP::byte PublicExponent[] = {0, 1, 0, 1};
|
||||
// (InverseQ)(q) = 1 mod p
|
||||
static constexpr CryptoPP::byte Coefficient[] = {
|
||||
0x45, 0x97, 0x55, 0xD4, 0x22, 0x08, 0x5E, 0xF3, 0x5C, 0xB4, 0x05, 0x7A, 0xFD, 0xAA, 0x42,
|
||||
0x42, 0xAD, 0x9A, 0x8C, 0xA0, 0x6C, 0xBB, 0x1D, 0x68, 0x54, 0x54, 0x6E, 0x3E, 0x32, 0xE3,
|
||||
0x53, 0x73, 0x76, 0xF1, 0x3E, 0x01, 0xEA, 0xD3, 0xCF, 0xEB, 0xEB, 0x23, 0x3E, 0xC0, 0xBE,
|
||||
0xCE, 0xEC, 0x2C, 0x89, 0x5F, 0xA8, 0x27, 0x3A, 0x4C, 0xB7, 0xE6, 0x74, 0xBC, 0x45, 0x4C,
|
||||
0x26, 0xC8, 0x25, 0xFF, 0x34, 0x63, 0x25, 0x37, 0xE1, 0x48, 0x10, 0xC1, 0x93, 0xA6, 0xAF,
|
||||
0xEB, 0xBA, 0xE3, 0xA2, 0xF1, 0x3D, 0xEF, 0x63, 0xD8, 0xF4, 0xFD, 0xD3, 0xEE, 0xE2, 0x5D,
|
||||
0xE9, 0x33, 0xCC, 0xAD, 0xBA, 0x75, 0x5C, 0x85, 0xAF, 0xCE, 0xA9, 0x3D, 0xD1, 0xA2, 0x17,
|
||||
0xF3, 0xF6, 0x98, 0xB3, 0x50, 0x8E, 0x5E, 0xF6, 0xEB, 0x02, 0x8E, 0xA1, 0x62, 0xA7, 0xD6,
|
||||
0x2C, 0xEC, 0x91, 0xFF, 0x15, 0x40, 0xD2, 0xE3};
|
||||
// n = p * q
|
||||
static constexpr CryptoPP::byte Modulus[] = {
|
||||
0xd2, 0x12, 0xfc, 0x33, 0x5f, 0x6d, 0xdb, 0x83, 0x16, 0x09, 0x62, 0x8b, 0x03, 0x56, 0x27,
|
||||
0x37, 0x82, 0xd4, 0x77, 0x85, 0x35, 0x29, 0x39, 0x2d, 0x52, 0x6b, 0x8c, 0x4c, 0x8c, 0xfb,
|
||||
0x06, 0xc1, 0x84, 0x5b, 0xe7, 0xd4, 0xf7, 0xbc, 0xd2, 0x4e, 0x62, 0x45, 0xcd, 0x2a, 0xbb,
|
||||
0xd7, 0x77, 0x76, 0x45, 0x36, 0x55, 0x27, 0x3f, 0xb3, 0xf5, 0xf9, 0x8e, 0xda, 0x4b, 0xef,
|
||||
0xaa, 0x59, 0xae, 0xb3, 0x9b, 0xea, 0x54, 0x98, 0xd2, 0x06, 0x32, 0x6a, 0x58, 0x31, 0x2a,
|
||||
0xe0, 0xd4, 0x4f, 0x90, 0xb5, 0x0a, 0x7d, 0xec, 0xf4, 0x3a, 0x9c, 0x52, 0x67, 0x2d, 0x99,
|
||||
0x31, 0x8e, 0x0c, 0x43, 0xe6, 0x82, 0xfe, 0x07, 0x46, 0xe1, 0x2e, 0x50, 0xd4, 0x1f, 0x2d,
|
||||
0x2f, 0x7e, 0xd9, 0x08, 0xba, 0x06, 0xb3, 0xbf, 0x2e, 0x20, 0x3f, 0x4e, 0x3f, 0xfe, 0x44,
|
||||
0xff, 0xaa, 0x50, 0x43, 0x57, 0x91, 0x69, 0x94, 0x49, 0x15, 0x82, 0x82, 0xe4, 0x0f, 0x4c,
|
||||
0x8d, 0x9d, 0x2c, 0xc9, 0x5b, 0x1d, 0x64, 0xbf, 0x88, 0x8b, 0xd4, 0xc5, 0x94, 0xe7, 0x65,
|
||||
0x47, 0x84, 0x1e, 0xe5, 0x79, 0x10, 0xfb, 0x98, 0x93, 0x47, 0xb9, 0x7d, 0x85, 0x12, 0xa6,
|
||||
0x40, 0x98, 0x2c, 0xf7, 0x92, 0xbc, 0x95, 0x19, 0x32, 0xed, 0xe8, 0x90, 0x56, 0x0d, 0x65,
|
||||
0xc1, 0xaa, 0x78, 0xc6, 0x2e, 0x54, 0xfd, 0x5f, 0x54, 0xa1, 0xf6, 0x7e, 0xe5, 0xe0, 0x5f,
|
||||
0x61, 0xc1, 0x20, 0xb4, 0xb9, 0xb4, 0x33, 0x08, 0x70, 0xe4, 0xdf, 0x89, 0x56, 0xed, 0x01,
|
||||
0x29, 0x46, 0x77, 0x5f, 0x8c, 0xb8, 0xa9, 0xf5, 0x1e, 0x2e, 0xb3, 0xb9, 0xbf, 0xe0, 0x09,
|
||||
0xb7, 0x8d, 0x28, 0xd4, 0xa6, 0xc3, 0xb8, 0x1e, 0x1f, 0x07, 0xeb, 0xb4, 0x12, 0x0b, 0x95,
|
||||
0xb8, 0x85, 0x30, 0xfd, 0xdc, 0x39, 0x13, 0xd0, 0x7c, 0xdc, 0x8f, 0xed, 0xf9, 0xc9, 0xa3,
|
||||
0xc1};
|
||||
// p
|
||||
static constexpr CryptoPP::byte Prime1[] = {
|
||||
0xF9, 0x67, 0xAD, 0x99, 0x12, 0x31, 0x0C, 0x56, 0xA2, 0x2E, 0x16, 0x1C, 0x46, 0xB3, 0x4D,
|
||||
0x5B, 0x43, 0xBE, 0x42, 0xA2, 0xF6, 0x86, 0x96, 0x80, 0x42, 0xC3, 0xC7, 0x3F, 0xC3, 0x42,
|
||||
0xF5, 0x87, 0x49, 0x33, 0x9F, 0x07, 0x5D, 0x6E, 0x2C, 0x04, 0xFD, 0xE3, 0xE1, 0xB2, 0xAE,
|
||||
0x0A, 0x0C, 0xF0, 0xC7, 0xA6, 0x1C, 0xA1, 0x63, 0x50, 0xC8, 0x09, 0x9C, 0x51, 0x24, 0x52,
|
||||
0x6C, 0x5E, 0x5E, 0xBD, 0x1E, 0x27, 0x06, 0xBB, 0xBC, 0x9E, 0x94, 0xE1, 0x35, 0xD4, 0x6D,
|
||||
0xB3, 0xCB, 0x3C, 0x68, 0xDD, 0x68, 0xB3, 0xFE, 0x6C, 0xCB, 0x8D, 0x82, 0x20, 0x76, 0x23,
|
||||
0x63, 0xB7, 0xE9, 0x68, 0x10, 0x01, 0x4E, 0xDC, 0xBA, 0x27, 0x5D, 0x01, 0xC1, 0x2D, 0x80,
|
||||
0x5E, 0x2B, 0xAF, 0x82, 0x6B, 0xD8, 0x84, 0xB6, 0x10, 0x52, 0x86, 0xA7, 0x89, 0x8E, 0xAE,
|
||||
0x9A, 0xE2, 0x89, 0xC6, 0xF7, 0xD5, 0x87, 0xFB};
|
||||
// q
|
||||
static constexpr CryptoPP::byte Prime2[] = {
|
||||
0xD7, 0xA1, 0x0F, 0x9A, 0x8B, 0xF2, 0xC9, 0x11, 0x95, 0x32, 0x9A, 0x8C, 0xF0, 0xD9, 0x40,
|
||||
0x47, 0xF5, 0x68, 0xA0, 0x0D, 0xBD, 0xC1, 0xFC, 0x43, 0x2F, 0x65, 0xF9, 0xC3, 0x61, 0x0F,
|
||||
0x25, 0x77, 0x54, 0xAD, 0xD7, 0x58, 0xAC, 0x84, 0x40, 0x60, 0x8D, 0x3F, 0xF3, 0x65, 0x89,
|
||||
0x75, 0xB5, 0xC6, 0x2C, 0x51, 0x1A, 0x2F, 0x1F, 0x22, 0xE4, 0x43, 0x11, 0x54, 0xBE, 0xC9,
|
||||
0xB4, 0xC7, 0xB5, 0x1B, 0x05, 0x0B, 0xBC, 0x56, 0x9A, 0xCD, 0x4A, 0xD9, 0x73, 0x68, 0x5E,
|
||||
0x5C, 0xFB, 0x92, 0xB7, 0x8B, 0x0D, 0xFF, 0xF5, 0x07, 0xCA, 0xB4, 0xC8, 0x9B, 0x96, 0x3C,
|
||||
0x07, 0x9E, 0x3E, 0x6B, 0x2A, 0x11, 0xF2, 0x8A, 0xB1, 0x8A, 0xD7, 0x2E, 0x1B, 0xA5, 0x53,
|
||||
0x24, 0x06, 0xED, 0x50, 0xB8, 0x90, 0x67, 0xB1, 0xE2, 0x41, 0xC6, 0x92, 0x01, 0xEE, 0x10,
|
||||
0xF0, 0x61, 0xBB, 0xFB, 0xB2, 0x7D, 0x4A, 0x73};
|
||||
static constexpr CryptoPP::byte PrivateExponent[] = {
|
||||
0x32, 0xD9, 0x03, 0x90, 0x8F, 0xBD, 0xB0, 0x8F, 0x57, 0x2B, 0x28, 0x5E, 0x0B, 0x8D, 0xB3,
|
||||
0xEA, 0x5C, 0xD1, 0x7E, 0xA8, 0x90, 0x88, 0x8C, 0xDD, 0x6A, 0x80, 0xBB, 0xB1, 0xDF, 0xC1,
|
||||
0xF7, 0x0D, 0xAA, 0x32, 0xF0, 0xB7, 0x7C, 0xCB, 0x88, 0x80, 0x0E, 0x8B, 0x64, 0xB0, 0xBE,
|
||||
0x4C, 0xD6, 0x0E, 0x9B, 0x8C, 0x1E, 0x2A, 0x64, 0xE1, 0xF3, 0x5C, 0xD7, 0x76, 0x01, 0x41,
|
||||
0x5E, 0x93, 0x5C, 0x94, 0xFE, 0xDD, 0x46, 0x62, 0xC3, 0x1B, 0x5A, 0xE2, 0xA0, 0xBC, 0x2D,
|
||||
0xEB, 0xC3, 0x98, 0x0A, 0xA7, 0xB7, 0x85, 0x69, 0x70, 0x68, 0x2B, 0x64, 0x4A, 0xB3, 0x1F,
|
||||
0xCC, 0x7D, 0xDC, 0x7C, 0x26, 0xF4, 0x77, 0xF6, 0x5C, 0xF2, 0xAE, 0x5A, 0x44, 0x2D, 0xD3,
|
||||
0xAB, 0x16, 0x62, 0x04, 0x19, 0xBA, 0xFB, 0x90, 0xFF, 0xE2, 0x30, 0x50, 0x89, 0x6E, 0xCB,
|
||||
0x56, 0xB2, 0xEB, 0xC0, 0x91, 0x16, 0x92, 0x5E, 0x30, 0x8E, 0xAE, 0xC7, 0x94, 0x5D, 0xFD,
|
||||
0x35, 0xE1, 0x20, 0xF8, 0xAD, 0x3E, 0xBC, 0x08, 0xBF, 0xC0, 0x36, 0x74, 0x9F, 0xD5, 0xBB,
|
||||
0x52, 0x08, 0xFD, 0x06, 0x66, 0xF3, 0x7A, 0xB3, 0x04, 0xF4, 0x75, 0x29, 0x5D, 0xE9, 0x5F,
|
||||
0xAA, 0x10, 0x30, 0xB2, 0x0F, 0x5A, 0x1A, 0xC1, 0x2A, 0xB3, 0xFE, 0xCB, 0x21, 0xAD, 0x80,
|
||||
0xEC, 0x8F, 0x20, 0x09, 0x1C, 0xDB, 0xC5, 0x58, 0x94, 0xC2, 0x9C, 0xC6, 0xCE, 0x82, 0x65,
|
||||
0x3E, 0x57, 0x90, 0xBC, 0xA9, 0x8B, 0x06, 0xB4, 0xF0, 0x72, 0xF6, 0x77, 0xDF, 0x98, 0x64,
|
||||
0xF1, 0xEC, 0xFE, 0x37, 0x2D, 0xBC, 0xAE, 0x8C, 0x08, 0x81, 0x1F, 0xC3, 0xC9, 0x89, 0x1A,
|
||||
0xC7, 0x42, 0x82, 0x4B, 0x2E, 0xDC, 0x8E, 0x8D, 0x73, 0xCE, 0xB1, 0xCC, 0x01, 0xD9, 0x08,
|
||||
0x70, 0x87, 0x3C, 0x44, 0x08, 0xEC, 0x49, 0x8F, 0x81, 0x5A, 0xE2, 0x40, 0xFF, 0x77, 0xFC,
|
||||
0x0D};
|
||||
};
|
473
src/core/file_format/pkg.cpp
Normal file
473
src/core/file_format/pkg.cpp
Normal file
|
@ -0,0 +1,473 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <zlib.h>
|
||||
#include "common/io_file.h"
|
||||
#include "common/logging/formatter.h"
|
||||
#include "core/file_format/pkg.h"
|
||||
#include "core/file_format/pkg_type.h"
|
||||
|
||||
static void DecompressPFSC(std::span<char> compressed_data, std::span<char> decompressed_data) {
|
||||
z_stream decompressStream;
|
||||
decompressStream.zalloc = Z_NULL;
|
||||
decompressStream.zfree = Z_NULL;
|
||||
decompressStream.opaque = Z_NULL;
|
||||
|
||||
if (inflateInit(&decompressStream) != Z_OK) {
|
||||
// std::cerr << "Error initializing zlib for deflation." << std::endl;
|
||||
}
|
||||
|
||||
decompressStream.avail_in = compressed_data.size();
|
||||
decompressStream.next_in = reinterpret_cast<unsigned char*>(compressed_data.data());
|
||||
decompressStream.avail_out = decompressed_data.size();
|
||||
decompressStream.next_out = reinterpret_cast<unsigned char*>(decompressed_data.data());
|
||||
|
||||
if (inflate(&decompressStream, Z_FINISH)) {
|
||||
}
|
||||
if (inflateEnd(&decompressStream) != Z_OK) {
|
||||
// std::cerr << "Error ending zlib inflate" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetPFSCOffset(std::span<const u8> pfs_image) {
|
||||
static constexpr u32 PfscMagic = 0x43534650;
|
||||
u32 value;
|
||||
for (u32 i = 0x20000; i < pfs_image.size(); i += 0x10000) {
|
||||
std::memcpy(&value, &pfs_image[i], sizeof(u32));
|
||||
if (value == PfscMagic)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
PKG::PKG() = default;
|
||||
|
||||
PKG::~PKG() = default;
|
||||
|
||||
bool PKG::Open(const std::filesystem::path& filepath, std::string& failreason) {
|
||||
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
|
||||
if (!file.IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
pkgSize = file.GetSize();
|
||||
|
||||
file.Read(pkgheader);
|
||||
if (pkgheader.magic != 0x7F434E54)
|
||||
return false;
|
||||
|
||||
for (const auto& flag : flagNames) {
|
||||
if (isFlagSet(pkgheader.pkg_content_flags, flag.first)) {
|
||||
if (!pkgFlags.empty())
|
||||
pkgFlags += (", ");
|
||||
pkgFlags += (flag.second);
|
||||
}
|
||||
}
|
||||
|
||||
// Find title id it is part of pkg_content_id starting at offset 0x40
|
||||
file.Seek(0x47); // skip first 7 characters of content_id
|
||||
file.Read(pkgTitleID);
|
||||
|
||||
u32 offset = pkgheader.pkg_table_entry_offset;
|
||||
u32 n_files = pkgheader.pkg_table_entry_count;
|
||||
|
||||
if (!file.Seek(offset)) {
|
||||
failreason = "Failed to seek to PKG table entry offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_files; i++) {
|
||||
PKGEntry entry{};
|
||||
file.Read(entry.id);
|
||||
file.Read(entry.filename_offset);
|
||||
file.Read(entry.flags1);
|
||||
file.Read(entry.flags2);
|
||||
file.Read(entry.offset);
|
||||
file.Read(entry.size);
|
||||
file.Seek(8, Common::FS::SeekOrigin::CurrentPosition);
|
||||
|
||||
// Try to figure out the name
|
||||
const auto name = GetEntryNameByType(entry.id);
|
||||
if (name == "param.sfo") {
|
||||
sfo.clear();
|
||||
if (!file.Seek(entry.offset)) {
|
||||
failreason = "Failed to seek to param.sfo offset";
|
||||
return false;
|
||||
}
|
||||
sfo.resize(entry.size);
|
||||
file.ReadRaw<u8>(sfo.data(), entry.size);
|
||||
}
|
||||
}
|
||||
file.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract,
|
||||
std::string& failreason) {
|
||||
extract_path = extract;
|
||||
pkgpath = filepath;
|
||||
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
|
||||
if (!file.IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
pkgSize = file.GetSize();
|
||||
file.ReadRaw<u8>(&pkgheader, sizeof(PKGHeader));
|
||||
|
||||
if (pkgheader.magic != 0x7F434E54)
|
||||
return false;
|
||||
|
||||
if (pkgheader.pkg_size > pkgSize) {
|
||||
failreason = "PKG file size is different";
|
||||
return false;
|
||||
}
|
||||
if ((pkgheader.pkg_content_size + pkgheader.pkg_content_offset) > pkgheader.pkg_size) {
|
||||
failreason = "Content size is bigger than pkg size";
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 offset = pkgheader.pkg_table_entry_offset;
|
||||
u32 n_files = pkgheader.pkg_table_entry_count;
|
||||
|
||||
std::array<u8, 64> concatenated_ivkey_dk3;
|
||||
std::array<u8, 32> seed_digest;
|
||||
std::array<std::array<u8, 32>, 7> digest1;
|
||||
std::array<std::array<u8, 256>, 7> key1;
|
||||
std::array<u8, 256> imgkeydata;
|
||||
|
||||
if (!file.Seek(offset)) {
|
||||
failreason = "Failed to seek to PKG table entry offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_files; i++) {
|
||||
PKGEntry entry{};
|
||||
file.Read(entry.id);
|
||||
file.Read(entry.filename_offset);
|
||||
file.Read(entry.flags1);
|
||||
file.Read(entry.flags2);
|
||||
file.Read(entry.offset);
|
||||
file.Read(entry.size);
|
||||
file.Seek(8, Common::FS::SeekOrigin::CurrentPosition);
|
||||
|
||||
auto currentPos = file.Tell();
|
||||
|
||||
// Try to figure out the name
|
||||
const auto name = GetEntryNameByType(entry.id);
|
||||
const auto filepath = extract_path / "sce_sys" / name;
|
||||
std::filesystem::create_directories(filepath.parent_path());
|
||||
|
||||
if (name.empty()) {
|
||||
// Just print with id
|
||||
Common::FS::IOFile out(extract_path / "sce_sys" / std::to_string(entry.id),
|
||||
Common::FS::FileAccessMode::Write);
|
||||
if (!file.Seek(entry.offset)) {
|
||||
failreason = "Failed to seek to PKG entry offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> data;
|
||||
data.resize(entry.size);
|
||||
file.ReadRaw<u8>(data.data(), entry.size);
|
||||
out.WriteRaw<u8>(data.data(), entry.size);
|
||||
out.Close();
|
||||
|
||||
file.Seek(currentPos);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.id == 0x1) { // DIGESTS, seek;
|
||||
// file.Seek(entry.offset, fsSeekSet);
|
||||
} else if (entry.id == 0x10) { // ENTRY_KEYS, seek;
|
||||
file.Seek(entry.offset);
|
||||
file.Read(seed_digest);
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
file.Read(digest1[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
file.Read(key1[i]);
|
||||
}
|
||||
|
||||
PKG::crypto.RSA2048Decrypt(dk3_, key1[3], true); // decrypt DK3
|
||||
} else if (entry.id == 0x20) { // IMAGE_KEY, seek; IV_KEY
|
||||
file.Seek(entry.offset);
|
||||
file.Read(imgkeydata);
|
||||
|
||||
// The Concatenated iv + dk3 imagekey for HASH256
|
||||
std::memcpy(concatenated_ivkey_dk3.data(), &entry, sizeof(entry));
|
||||
std::memcpy(concatenated_ivkey_dk3.data() + sizeof(entry), dk3_.data(), sizeof(dk3_));
|
||||
|
||||
PKG::crypto.ivKeyHASH256(concatenated_ivkey_dk3, ivKey); // ivkey_
|
||||
// imgkey_ to use for last step to get ekpfs
|
||||
PKG::crypto.aesCbcCfb128Decrypt(ivKey, imgkeydata, imgKey);
|
||||
// ekpfs key to get data and tweak keys.
|
||||
PKG::crypto.RSA2048Decrypt(ekpfsKey, imgKey, false);
|
||||
} else if (entry.id == 0x80) {
|
||||
// GENERAL_DIGESTS, seek;
|
||||
// file.Seek(entry.offset, fsSeekSet);
|
||||
}
|
||||
|
||||
Common::FS::IOFile out(extract_path / "sce_sys" / name, Common::FS::FileAccessMode::Write);
|
||||
if (!file.Seek(entry.offset)) {
|
||||
failreason = "Failed to seek to PKG entry offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> data;
|
||||
data.resize(entry.size);
|
||||
file.ReadRaw<u8>(data.data(), entry.size);
|
||||
out.WriteRaw<u8>(data.data(), entry.size);
|
||||
out.Close();
|
||||
|
||||
// Decrypt Np stuff and overwrite.
|
||||
if (entry.id == 0x400 || entry.id == 0x401 || entry.id == 0x402 ||
|
||||
entry.id == 0x403) { // somehow 0x401 is not decrypting
|
||||
decNp.resize(entry.size);
|
||||
if (!file.Seek(entry.offset)) {
|
||||
failreason = "Failed to seek to PKG entry offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> data;
|
||||
data.resize(entry.size);
|
||||
file.ReadRaw<u8>(data.data(), entry.size);
|
||||
|
||||
std::span<u8> cipherNp(data.data(), entry.size);
|
||||
std::array<u8, 64> concatenated_ivkey_dk3_;
|
||||
std::memcpy(concatenated_ivkey_dk3_.data(), &entry, sizeof(entry));
|
||||
std::memcpy(concatenated_ivkey_dk3_.data() + sizeof(entry), dk3_.data(), sizeof(dk3_));
|
||||
PKG::crypto.ivKeyHASH256(concatenated_ivkey_dk3_, ivKey);
|
||||
PKG::crypto.aesCbcCfb128DecryptEntry(ivKey, cipherNp, decNp);
|
||||
|
||||
Common::FS::IOFile out(extract_path / "sce_sys" / name,
|
||||
Common::FS::FileAccessMode::Write);
|
||||
out.Write(decNp);
|
||||
out.Close();
|
||||
}
|
||||
|
||||
file.Seek(currentPos);
|
||||
}
|
||||
|
||||
// Read the seed
|
||||
std::array<u8, 16> seed;
|
||||
if (!file.Seek(pkgheader.pfs_image_offset + 0x370)) {
|
||||
failreason = "Failed to seek to PFS image offset";
|
||||
return false;
|
||||
}
|
||||
file.Read(seed);
|
||||
|
||||
// Get data and tweak keys.
|
||||
PKG::crypto.PfsGenCryptoKey(ekpfsKey, seed, dataKey, tweakKey);
|
||||
const u32 length = pkgheader.pfs_cache_size * 0x2; // Seems to be ok.
|
||||
|
||||
int num_blocks = 0;
|
||||
std::vector<u8> pfsc(length);
|
||||
if (length != 0) {
|
||||
// Read encrypted pfs_image
|
||||
std::vector<u8> pfs_encrypted(length);
|
||||
file.Seek(pkgheader.pfs_image_offset);
|
||||
file.Read(pfs_encrypted);
|
||||
file.Close();
|
||||
// Decrypt the pfs_image.
|
||||
std::vector<u8> pfs_decrypted(length);
|
||||
PKG::crypto.decryptPFS(dataKey, tweakKey, pfs_encrypted, pfs_decrypted, 0);
|
||||
|
||||
// Retrieve PFSC from decrypted pfs_image.
|
||||
pfsc_offset = GetPFSCOffset(pfs_decrypted);
|
||||
std::memcpy(pfsc.data(), pfs_decrypted.data() + pfsc_offset, length - pfsc_offset);
|
||||
|
||||
PFSCHdr pfsChdr;
|
||||
std::memcpy(&pfsChdr, pfsc.data(), sizeof(pfsChdr));
|
||||
|
||||
num_blocks = (int)(pfsChdr.data_length / pfsChdr.block_sz2);
|
||||
sectorMap.resize(num_blocks + 1); // 8 bytes, need extra 1 to get the last offset.
|
||||
|
||||
for (int i = 0; i < num_blocks + 1; i++) {
|
||||
std::memcpy(§orMap[i], pfsc.data() + pfsChdr.block_offsets + i * 8, 8);
|
||||
}
|
||||
}
|
||||
|
||||
u32 ent_size = 0;
|
||||
u32 ndinode = 0;
|
||||
int ndinode_counter = 0;
|
||||
bool dinode_reached = false;
|
||||
bool uroot_reached = false;
|
||||
std::vector<char> compressedData;
|
||||
std::vector<char> decompressedData(0x10000);
|
||||
|
||||
// Get iNdoes and Dirents.
|
||||
for (int i = 0; i < num_blocks; i++) {
|
||||
const u64 sectorOffset = sectorMap[i];
|
||||
const u64 sectorSize = sectorMap[i + 1] - sectorOffset;
|
||||
|
||||
compressedData.resize(sectorSize);
|
||||
std::memcpy(compressedData.data(), pfsc.data() + sectorOffset, sectorSize);
|
||||
|
||||
if (sectorSize == 0x10000) // Uncompressed data
|
||||
std::memcpy(decompressedData.data(), compressedData.data(), 0x10000);
|
||||
else if (sectorSize < 0x10000) // Compressed data
|
||||
DecompressPFSC(compressedData, decompressedData);
|
||||
|
||||
if (i == 0) {
|
||||
std::memcpy(&ndinode, decompressedData.data() + 0x30, 4); // number of folders and files
|
||||
}
|
||||
|
||||
int occupied_blocks =
|
||||
(ndinode * 0xA8) / 0x10000; // how many blocks(0x10000) are taken by iNodes.
|
||||
if (((ndinode * 0xA8) % 0x10000) != 0)
|
||||
occupied_blocks += 1;
|
||||
|
||||
if (i >= 1 && i <= occupied_blocks) { // Get all iNodes, gives type, file size and location.
|
||||
for (int p = 0; p < 0x10000; p += 0xA8) {
|
||||
Inode node;
|
||||
std::memcpy(&node, &decompressedData[p], sizeof(node));
|
||||
if (node.Mode == 0) {
|
||||
break;
|
||||
}
|
||||
iNodeBuf.push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
// let's deal with the root/uroot entries here.
|
||||
// Sometimes it's more than 2 entries (Tomb Raider Remastered)
|
||||
const std::string_view flat_path_table(&decompressedData[0x10], 15);
|
||||
if (flat_path_table == "flat_path_table") {
|
||||
uroot_reached = true;
|
||||
}
|
||||
|
||||
if (uroot_reached) {
|
||||
for (int i = 0; i < 0x10000; i += ent_size) {
|
||||
Dirent dirent;
|
||||
std::memcpy(&dirent, &decompressedData[i], sizeof(dirent));
|
||||
ent_size = dirent.entsize;
|
||||
if (dirent.ino != 0) {
|
||||
ndinode_counter++;
|
||||
} else {
|
||||
// Set the the folder according to the current inode.
|
||||
// Can be 2 or more (rarely)
|
||||
auto parent_path = extract_path.parent_path();
|
||||
auto title_id = GetTitleID();
|
||||
|
||||
if (parent_path.filename() != title_id &&
|
||||
!fmt::UTF(extract_path.u8string()).data.ends_with("-patch")) {
|
||||
extractPaths[ndinode_counter] = parent_path / title_id;
|
||||
} else {
|
||||
// DLCs path has different structure
|
||||
extractPaths[ndinode_counter] = extract_path;
|
||||
}
|
||||
uroot_reached = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char dot = decompressedData[0x10];
|
||||
const std::string_view dotdot(&decompressedData[0x28], 2);
|
||||
if (dot == '.' && dotdot == "..") {
|
||||
dinode_reached = true;
|
||||
}
|
||||
|
||||
// Get folder and file names.
|
||||
bool end_reached = false;
|
||||
if (dinode_reached) {
|
||||
for (int j = 0; j < 0x10000; j += ent_size) { // Skip the first parent and child.
|
||||
Dirent dirent;
|
||||
std::memcpy(&dirent, &decompressedData[j], sizeof(dirent));
|
||||
|
||||
// Stop here and continue the main loop
|
||||
if (dirent.ino == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
ent_size = dirent.entsize;
|
||||
auto& table = fsTable.emplace_back();
|
||||
table.name = std::string(dirent.name, dirent.namelen);
|
||||
table.inode = dirent.ino;
|
||||
table.type = dirent.type;
|
||||
|
||||
if (table.type == PFS_CURRENT_DIR) {
|
||||
current_dir = extractPaths[table.inode];
|
||||
}
|
||||
extractPaths[table.inode] = current_dir / std::filesystem::path(table.name);
|
||||
|
||||
if (table.type == PFS_FILE || table.type == PFS_DIR) {
|
||||
if (table.type == PFS_DIR) { // Create dirs.
|
||||
std::filesystem::create_directory(extractPaths[table.inode]);
|
||||
}
|
||||
ndinode_counter++;
|
||||
if ((ndinode_counter + 1) == ndinode) // 1 for the image itself (root).
|
||||
end_reached = true;
|
||||
}
|
||||
}
|
||||
if (end_reached) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PKG::ExtractFiles(const int index) {
|
||||
int inode_number = fsTable[index].inode;
|
||||
int inode_type = fsTable[index].type;
|
||||
std::string inode_name = fsTable[index].name;
|
||||
|
||||
if (inode_type == PFS_FILE) {
|
||||
int sector_loc = iNodeBuf[inode_number].loc;
|
||||
int nblocks = iNodeBuf[inode_number].Blocks;
|
||||
int bsize = iNodeBuf[inode_number].Size;
|
||||
|
||||
Common::FS::IOFile inflated;
|
||||
inflated.Open(extractPaths[inode_number], Common::FS::FileAccessMode::Write);
|
||||
|
||||
Common::FS::IOFile pkgFile; // Open the file for each iteration to avoid conflict.
|
||||
pkgFile.Open(pkgpath, Common::FS::FileAccessMode::Read);
|
||||
|
||||
int size_decompressed = 0;
|
||||
std::vector<char> compressedData;
|
||||
std::vector<char> decompressedData(0x10000);
|
||||
|
||||
u64 pfsc_buf_size = 0x11000; // extra 0x1000
|
||||
std::vector<u8> pfsc(pfsc_buf_size);
|
||||
std::vector<u8> pfs_decrypted(pfsc_buf_size);
|
||||
|
||||
for (int j = 0; j < nblocks; j++) {
|
||||
u64 sectorOffset =
|
||||
sectorMap[sector_loc + j]; // offset into PFSC_image and not pfs_image.
|
||||
u64 sectorSize = sectorMap[sector_loc + j + 1] -
|
||||
sectorOffset; // indicates if data is compressed or not.
|
||||
u64 fileOffset = (pkgheader.pfs_image_offset + pfsc_offset + sectorOffset);
|
||||
u64 currentSector1 =
|
||||
(pfsc_offset + sectorOffset) / 0x1000; // block size is 0x1000 for xts decryption.
|
||||
|
||||
int sectorOffsetMask = (sectorOffset + pfsc_offset) & 0xFFFFF000;
|
||||
int previousData = (sectorOffset + pfsc_offset) - sectorOffsetMask;
|
||||
|
||||
pkgFile.Seek(fileOffset - previousData);
|
||||
pkgFile.Read(pfsc);
|
||||
|
||||
PKG::crypto.decryptPFS(dataKey, tweakKey, pfsc, pfs_decrypted, currentSector1);
|
||||
|
||||
compressedData.resize(sectorSize);
|
||||
std::memcpy(compressedData.data(), pfs_decrypted.data() + previousData, sectorSize);
|
||||
|
||||
if (sectorSize == 0x10000) // Uncompressed data
|
||||
std::memcpy(decompressedData.data(), compressedData.data(), 0x10000);
|
||||
else if (sectorSize < 0x10000) // Compressed data
|
||||
DecompressPFSC(compressedData, decompressedData);
|
||||
|
||||
size_decompressed += 0x10000;
|
||||
|
||||
if (j < nblocks - 1) {
|
||||
inflated.WriteRaw<u8>(decompressedData.data(), decompressedData.size());
|
||||
} else {
|
||||
// This is to remove the zeros at the end of the file.
|
||||
const u32 write_size = decompressedData.size() - (size_decompressed - bsize);
|
||||
inflated.WriteRaw<u8>(decompressedData.data(), write_size);
|
||||
}
|
||||
}
|
||||
pkgFile.Close();
|
||||
inflated.Close();
|
||||
}
|
||||
}
|
174
src/core/file_format/pkg.h
Normal file
174
src/core/file_format/pkg.h
Normal file
|
@ -0,0 +1,174 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "common/endian.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "pfs.h"
|
||||
#include "trp.h"
|
||||
|
||||
struct PKGHeader {
|
||||
u32_be magic; // Magic
|
||||
u32_be pkg_type;
|
||||
u32_be pkg_0x8; // unknown field
|
||||
u32_be pkg_file_count;
|
||||
u32_be pkg_table_entry_count;
|
||||
u16_be pkg_sc_entry_count;
|
||||
u16_be pkg_table_entry_count_2; // same as pkg_entry_count
|
||||
u32_be pkg_table_entry_offset; // file table offset
|
||||
u32_be pkg_sc_entry_data_size;
|
||||
u64_be pkg_body_offset; // offset of PKG entries
|
||||
u64_be pkg_body_size; // length of all PKG entries
|
||||
u64_be pkg_content_offset;
|
||||
u64_be pkg_content_size;
|
||||
u8 pkg_content_id[0x24]; // packages' content ID as a 36-byte string
|
||||
u8 pkg_padding[0xC]; // padding
|
||||
u32_be pkg_drm_type; // DRM type
|
||||
u32_be pkg_content_type; // Content type
|
||||
u32_be pkg_content_flags; // Content flags
|
||||
u32_be pkg_promote_size;
|
||||
u32_be pkg_version_date;
|
||||
u32_be pkg_version_hash;
|
||||
u32_be pkg_0x088;
|
||||
u32_be pkg_0x08C;
|
||||
u32_be pkg_0x090;
|
||||
u32_be pkg_0x094;
|
||||
u32_be pkg_iro_tag;
|
||||
u32_be pkg_drm_type_version;
|
||||
|
||||
u8 pkg_zeroes_1[0x60];
|
||||
|
||||
/* Digest table */
|
||||
u8 digest_entries1[0x20]; // sha256 digest for main entry 1
|
||||
u8 digest_entries2[0x20]; // sha256 digest for main entry 2
|
||||
u8 digest_table_digest[0x20]; // sha256 digest for digest table
|
||||
u8 digest_body_digest[0x20]; // sha256 digest for main table
|
||||
|
||||
u8 pkg_zeroes_2[0x280];
|
||||
|
||||
u32_be pkg_0x400;
|
||||
|
||||
u32_be pfs_image_count; // count of PFS images
|
||||
u64_be pfs_image_flags; // PFS flags
|
||||
u64_be pfs_image_offset; // offset to start of external PFS image
|
||||
u64_be pfs_image_size; // size of external PFS image
|
||||
u64_be mount_image_offset;
|
||||
u64_be mount_image_size;
|
||||
u64_be pkg_size;
|
||||
u32_be pfs_signed_size;
|
||||
u32_be pfs_cache_size;
|
||||
u8 pfs_image_digest[0x20];
|
||||
u8 pfs_signed_digest[0x20];
|
||||
u64_be pfs_split_size_nth_0;
|
||||
u64_be pfs_split_size_nth_1;
|
||||
|
||||
u8 pkg_zeroes_3[0xB50];
|
||||
|
||||
u8 pkg_digest[0x20];
|
||||
};
|
||||
|
||||
enum class PKGContentFlag {
|
||||
FIRST_PATCH = 0x100000,
|
||||
PATCHGO = 0x200000,
|
||||
REMASTER = 0x400000,
|
||||
PS_CLOUD = 0x800000,
|
||||
GD_AC = 0x2000000,
|
||||
NON_GAME = 0x4000000,
|
||||
UNKNOWN_0x8000000 = 0x8000000,
|
||||
SUBSEQUENT_PATCH = 0x40000000,
|
||||
DELTA_PATCH = 0x41000000,
|
||||
CUMULATIVE_PATCH = 0x60000000
|
||||
};
|
||||
|
||||
struct PKGEntry {
|
||||
u32_be id; // File ID, useful for files without a filename entry
|
||||
u32_be filename_offset; // Offset into the filenames table (ID 0x200) where this file's name is
|
||||
// located
|
||||
u32_be flags1; // Flags including encrypted flag, etc
|
||||
u32_be flags2; // Flags including encryption key index, etc
|
||||
u32_be offset; // Offset into PKG to find the file
|
||||
u32_be size; // Size of the file
|
||||
u64_be padding; // blank padding
|
||||
};
|
||||
static_assert(sizeof(PKGEntry) == 32);
|
||||
|
||||
class PKG {
|
||||
public:
|
||||
PKG();
|
||||
~PKG();
|
||||
|
||||
bool Open(const std::filesystem::path& filepath, std::string& failreason);
|
||||
void ExtractFiles(const int index);
|
||||
bool Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract,
|
||||
std::string& failreason);
|
||||
|
||||
std::vector<u8> sfo;
|
||||
|
||||
u32 GetNumberOfFiles() {
|
||||
return fsTable.size();
|
||||
}
|
||||
|
||||
u64 GetPkgSize() {
|
||||
return pkgSize;
|
||||
}
|
||||
|
||||
std::string GetPkgFlags() {
|
||||
return pkgFlags;
|
||||
}
|
||||
|
||||
std::string_view GetTitleID() {
|
||||
return std::string_view(pkgTitleID, 9);
|
||||
}
|
||||
|
||||
PKGHeader GetPkgHeader() {
|
||||
return pkgheader;
|
||||
}
|
||||
|
||||
static bool isFlagSet(u32_be variable, PKGContentFlag flag) {
|
||||
return (variable) & static_cast<u32>(flag);
|
||||
}
|
||||
|
||||
static constexpr std::array<std::pair<PKGContentFlag, std::string_view>, 10> flagNames = {
|
||||
{{PKGContentFlag::FIRST_PATCH, "FIRST_PATCH"},
|
||||
{PKGContentFlag::PATCHGO, "PATCHGO"},
|
||||
{PKGContentFlag::REMASTER, "REMASTER"},
|
||||
{PKGContentFlag::PS_CLOUD, "PS_CLOUD"},
|
||||
{PKGContentFlag::GD_AC, "GD_AC"},
|
||||
{PKGContentFlag::NON_GAME, "NON_GAME"},
|
||||
{PKGContentFlag::UNKNOWN_0x8000000, "UNKNOWN_0x8000000"},
|
||||
{PKGContentFlag::SUBSEQUENT_PATCH, "SUBSEQUENT_PATCH"},
|
||||
{PKGContentFlag::DELTA_PATCH, "DELTA_PATCH"},
|
||||
{PKGContentFlag::CUMULATIVE_PATCH, "CUMULATIVE_PATCH"}}};
|
||||
|
||||
private:
|
||||
Crypto crypto;
|
||||
TRP trp;
|
||||
u64 pkgSize = 0;
|
||||
char pkgTitleID[9];
|
||||
PKGHeader pkgheader;
|
||||
std::string pkgFlags;
|
||||
|
||||
std::unordered_map<int, std::filesystem::path> extractPaths;
|
||||
std::vector<pfs_fs_table> fsTable;
|
||||
std::vector<Inode> iNodeBuf;
|
||||
std::vector<u64> sectorMap;
|
||||
u64 pfsc_offset;
|
||||
|
||||
std::array<u8, 32> dk3_;
|
||||
std::array<u8, 32> ivKey;
|
||||
std::array<u8, 256> imgKey;
|
||||
std::array<u8, 32> ekpfsKey;
|
||||
std::array<u8, 16> dataKey;
|
||||
std::array<u8, 16> tweakKey;
|
||||
std::vector<u8> decNp;
|
||||
|
||||
std::filesystem::path pkgpath;
|
||||
std::filesystem::path current_dir;
|
||||
std::filesystem::path extract_path;
|
||||
};
|
638
src/core/file_format/pkg_type.cpp
Normal file
638
src/core/file_format/pkg_type.cpp
Normal file
|
@ -0,0 +1,638 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include "pkg_type.h"
|
||||
|
||||
struct PkgEntryValue {
|
||||
u32 type;
|
||||
std::string_view name;
|
||||
|
||||
operator u32() const noexcept {
|
||||
return type;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr static std::array<PkgEntryValue, 611> PkgEntries = {{
|
||||
{0x0001, "digests"},
|
||||
{0x0010, "entry_keys"},
|
||||
{0x0020, "image_key"},
|
||||
{0x0080, "general_digests"},
|
||||
{0x0100, "metas"},
|
||||
{0x0200, "entry_names"},
|
||||
{0x0400, "license.dat"},
|
||||
{0x0401, "license.info"},
|
||||
{0x0402, "nptitle.dat"},
|
||||
{0x0403, "npbind.dat"},
|
||||
{0x0404, "selfinfo.dat"},
|
||||
{0x0406, "imageinfo.dat"},
|
||||
{0x0407, "target-deltainfo.dat"},
|
||||
{0x0408, "origin-deltainfo.dat"},
|
||||
{0x0409, "psreserved.dat"},
|
||||
{0x1000, "param.sfo"},
|
||||
{0x1001, "playgo-chunk.dat"},
|
||||
{0x1002, "playgo-chunk.sha"},
|
||||
{0x1003, "playgo-manifest.xml"},
|
||||
{0x1004, "pronunciation.xml"},
|
||||
{0x1005, "pronunciation.sig"},
|
||||
{0x1006, "pic1.png"},
|
||||
{0x1007, "pubtoolinfo.dat"},
|
||||
{0x1008, "app/playgo-chunk.dat"},
|
||||
{0x1009, "app/playgo-chunk.sha"},
|
||||
{0x100A, "app/playgo-manifest.xml"},
|
||||
{0x100B, "shareparam.json"},
|
||||
{0x100C, "shareoverlayimage.png"},
|
||||
{0x100D, "save_data.png"},
|
||||
{0x100E, "shareprivacyguardimage.png"},
|
||||
{0x1200, "icon0.png"},
|
||||
{0x1201, "icon0_00.png"},
|
||||
{0x1202, "icon0_01.png"},
|
||||
{0x1203, "icon0_02.png"},
|
||||
{0x1204, "icon0_03.png"},
|
||||
{0x1205, "icon0_04.png"},
|
||||
{0x1206, "icon0_05.png"},
|
||||
{0x1207, "icon0_06.png"},
|
||||
{0x1208, "icon0_07.png"},
|
||||
{0x1209, "icon0_08.png"},
|
||||
{0x120A, "icon0_09.png"},
|
||||
{0x120B, "icon0_10.png"},
|
||||
{0x120C, "icon0_11.png"},
|
||||
{0x120D, "icon0_12.png"},
|
||||
{0x120E, "icon0_13.png"},
|
||||
{0x120F, "icon0_14.png"},
|
||||
{0x1210, "icon0_15.png"},
|
||||
{0x1211, "icon0_16.png"},
|
||||
{0x1212, "icon0_17.png"},
|
||||
{0x1213, "icon0_18.png"},
|
||||
{0x1214, "icon0_19.png"},
|
||||
{0x1215, "icon0_20.png"},
|
||||
{0x1216, "icon0_21.png"},
|
||||
{0x1217, "icon0_22.png"},
|
||||
{0x1218, "icon0_23.png"},
|
||||
{0x1219, "icon0_24.png"},
|
||||
{0x121A, "icon0_25.png"},
|
||||
{0x121B, "icon0_26.png"},
|
||||
{0x121C, "icon0_27.png"},
|
||||
{0x121D, "icon0_28.png"},
|
||||
{0x121E, "icon0_29.png"},
|
||||
{0x121F, "icon0_30.png"},
|
||||
{0x1220, "pic0.png"},
|
||||
{0x1240, "snd0.at9"},
|
||||
{0x1241, "pic1_00.png"},
|
||||
{0x1242, "pic1_01.png"},
|
||||
{0x1243, "pic1_02.png"},
|
||||
{0x1244, "pic1_03.png"},
|
||||
{0x1245, "pic1_04.png"},
|
||||
{0x1246, "pic1_05.png"},
|
||||
{0x1247, "pic1_06.png"},
|
||||
{0x1248, "pic1_07.png"},
|
||||
{0x1249, "pic1_08.png"},
|
||||
{0x124A, "pic1_09.png"},
|
||||
{0x124B, "pic1_10.png"},
|
||||
{0x124C, "pic1_11.png"},
|
||||
{0x124D, "pic1_12.png"},
|
||||
{0x124E, "pic1_13.png"},
|
||||
{0x124F, "pic1_14.png"},
|
||||
{0x1250, "pic1_15.png"},
|
||||
{0x1251, "pic1_16.png"},
|
||||
{0x1252, "pic1_17.png"},
|
||||
{0x1253, "pic1_18.png"},
|
||||
{0x1254, "pic1_19.png"},
|
||||
{0x1255, "pic1_20.png"},
|
||||
{0x1256, "pic1_21.png"},
|
||||
{0x1257, "pic1_22.png"},
|
||||
{0x1258, "pic1_23.png"},
|
||||
{0x1259, "pic1_24.png"},
|
||||
{0x125A, "pic1_25.png"},
|
||||
{0x125B, "pic1_26.png"},
|
||||
{0x125C, "pic1_27.png"},
|
||||
{0x125D, "pic1_28.png"},
|
||||
{0x125E, "pic1_29.png"},
|
||||
{0x125F, "pic1_30.png"},
|
||||
{0x1260, "changeinfo/changeinfo.xml"},
|
||||
{0x1261, "changeinfo/changeinfo_00.xml"},
|
||||
{0x1262, "changeinfo/changeinfo_01.xml"},
|
||||
{0x1263, "changeinfo/changeinfo_02.xml"},
|
||||
{0x1264, "changeinfo/changeinfo_03.xml"},
|
||||
{0x1265, "changeinfo/changeinfo_04.xml"},
|
||||
{0x1266, "changeinfo/changeinfo_05.xml"},
|
||||
{0x1267, "changeinfo/changeinfo_06.xml"},
|
||||
{0x1268, "changeinfo/changeinfo_07.xml"},
|
||||
{0x1269, "changeinfo/changeinfo_08.xml"},
|
||||
{0x126A, "changeinfo/changeinfo_09.xml"},
|
||||
{0x126B, "changeinfo/changeinfo_10.xml"},
|
||||
{0x126C, "changeinfo/changeinfo_11.xml"},
|
||||
{0x126D, "changeinfo/changeinfo_12.xml"},
|
||||
{0x126E, "changeinfo/changeinfo_13.xml"},
|
||||
{0x126F, "changeinfo/changeinfo_14.xml"},
|
||||
{0x1270, "changeinfo/changeinfo_15.xml"},
|
||||
{0x1271, "changeinfo/changeinfo_16.xml"},
|
||||
{0x1272, "changeinfo/changeinfo_17.xml"},
|
||||
{0x1273, "changeinfo/changeinfo_18.xml"},
|
||||
{0x1274, "changeinfo/changeinfo_19.xml"},
|
||||
{0x1275, "changeinfo/changeinfo_20.xml"},
|
||||
{0x1276, "changeinfo/changeinfo_21.xml"},
|
||||
{0x1277, "changeinfo/changeinfo_22.xml"},
|
||||
{0x1278, "changeinfo/changeinfo_23.xml"},
|
||||
{0x1279, "changeinfo/changeinfo_24.xml"},
|
||||
{0x127A, "changeinfo/changeinfo_25.xml"},
|
||||
{0x127B, "changeinfo/changeinfo_26.xml"},
|
||||
{0x127C, "changeinfo/changeinfo_27.xml"},
|
||||
{0x127D, "changeinfo/changeinfo_28.xml"},
|
||||
{0x127E, "changeinfo/changeinfo_29.xml"},
|
||||
{0x127F, "changeinfo/changeinfo_30.xml"},
|
||||
{0x1280, "icon0.dds"},
|
||||
{0x1281, "icon0_00.dds"},
|
||||
{0x1282, "icon0_01.dds"},
|
||||
{0x1283, "icon0_02.dds"},
|
||||
{0x1284, "icon0_03.dds"},
|
||||
{0x1285, "icon0_04.dds"},
|
||||
{0x1286, "icon0_05.dds"},
|
||||
{0x1287, "icon0_06.dds"},
|
||||
{0x1288, "icon0_07.dds"},
|
||||
{0x1289, "icon0_08.dds"},
|
||||
{0x128A, "icon0_09.dds"},
|
||||
{0x128B, "icon0_10.dds"},
|
||||
{0x128C, "icon0_11.dds"},
|
||||
{0x128D, "icon0_12.dds"},
|
||||
{0x128E, "icon0_13.dds"},
|
||||
{0x128F, "icon0_14.dds"},
|
||||
{0x1290, "icon0_15.dds"},
|
||||
{0x1291, "icon0_16.dds"},
|
||||
{0x1292, "icon0_17.dds"},
|
||||
{0x1293, "icon0_18.dds"},
|
||||
{0x1294, "icon0_19.dds"},
|
||||
{0x1295, "icon0_20.dds"},
|
||||
{0x1296, "icon0_21.dds"},
|
||||
{0x1297, "icon0_22.dds"},
|
||||
{0x1298, "icon0_23.dds"},
|
||||
{0x1299, "icon0_24.dds"},
|
||||
{0x129A, "icon0_25.dds"},
|
||||
{0x129B, "icon0_26.dds"},
|
||||
{0x129C, "icon0_27.dds"},
|
||||
{0x129D, "icon0_28.dds"},
|
||||
{0x129E, "icon0_29.dds"},
|
||||
{0x129F, "icon0_30.dds"},
|
||||
{0x12A0, "pic0.dds"},
|
||||
{0x12C0, "pic1.dds"},
|
||||
{0x12C1, "pic1_00.dds"},
|
||||
{0x12C2, "pic1_01.dds"},
|
||||
{0x12C3, "pic1_02.dds"},
|
||||
{0x12C4, "pic1_03.dds"},
|
||||
{0x12C5, "pic1_04.dds"},
|
||||
{0x12C6, "pic1_05.dds"},
|
||||
{0x12C7, "pic1_06.dds"},
|
||||
{0x12C8, "pic1_07.dds"},
|
||||
{0x12C9, "pic1_08.dds"},
|
||||
{0x12CA, "pic1_09.dds"},
|
||||
{0x12CB, "pic1_10.dds"},
|
||||
{0x12CC, "pic1_11.dds"},
|
||||
{0x12CD, "pic1_12.dds"},
|
||||
{0x12CE, "pic1_13.dds"},
|
||||
{0x12CF, "pic1_14.dds"},
|
||||
{0x12D0, "pic1_15.dds"},
|
||||
{0x12D1, "pic1_16.dds"},
|
||||
{0x12D2, "pic1_17.dds"},
|
||||
{0x12D3, "pic1_18.dds"},
|
||||
{0x12D4, "pic1_19.dds"},
|
||||
{0x12D5, "pic1_20.dds"},
|
||||
{0x12D6, "pic1_21.dds"},
|
||||
{0x12D7, "pic1_22.dds"},
|
||||
{0x12D8, "pic1_23.dds"},
|
||||
{0x12D9, "pic1_24.dds"},
|
||||
{0x12DA, "pic1_25.dds"},
|
||||
{0x12DB, "pic1_26.dds"},
|
||||
{0x12DC, "pic1_27.dds"},
|
||||
{0x12DD, "pic1_28.dds"},
|
||||
{0x12DE, "pic1_29.dds"},
|
||||
{0x12DF, "pic1_30.dds"},
|
||||
{0x1400, "trophy/trophy00.trp"},
|
||||
{0x1401, "trophy/trophy01.trp"},
|
||||
{0x1402, "trophy/trophy02.trp"},
|
||||
{0x1403, "trophy/trophy03.trp"},
|
||||
{0x1404, "trophy/trophy04.trp"},
|
||||
{0x1405, "trophy/trophy05.trp"},
|
||||
{0x1406, "trophy/trophy06.trp"},
|
||||
{0x1407, "trophy/trophy07.trp"},
|
||||
{0x1408, "trophy/trophy08.trp"},
|
||||
{0x1409, "trophy/trophy09.trp"},
|
||||
{0x140A, "trophy/trophy10.trp"},
|
||||
{0x140B, "trophy/trophy11.trp"},
|
||||
{0x140C, "trophy/trophy12.trp"},
|
||||
{0x140D, "trophy/trophy13.trp"},
|
||||
{0x140E, "trophy/trophy14.trp"},
|
||||
{0x140F, "trophy/trophy15.trp"},
|
||||
{0x1410, "trophy/trophy16.trp"},
|
||||
{0x1411, "trophy/trophy17.trp"},
|
||||
{0x1412, "trophy/trophy18.trp"},
|
||||
{0x1413, "trophy/trophy19.trp"},
|
||||
{0x1414, "trophy/trophy20.trp"},
|
||||
{0x1415, "trophy/trophy21.trp"},
|
||||
{0x1416, "trophy/trophy22.trp"},
|
||||
{0x1417, "trophy/trophy23.trp"},
|
||||
{0x1418, "trophy/trophy24.trp"},
|
||||
{0x1419, "trophy/trophy25.trp"},
|
||||
{0x141A, "trophy/trophy26.trp"},
|
||||
{0x141B, "trophy/trophy27.trp"},
|
||||
{0x141C, "trophy/trophy28.trp"},
|
||||
{0x141D, "trophy/trophy29.trp"},
|
||||
{0x141E, "trophy/trophy30.trp"},
|
||||
{0x141F, "trophy/trophy31.trp"},
|
||||
{0x1420, "trophy/trophy32.trp"},
|
||||
{0x1421, "trophy/trophy33.trp"},
|
||||
{0x1422, "trophy/trophy34.trp"},
|
||||
{0x1423, "trophy/trophy35.trp"},
|
||||
{0x1424, "trophy/trophy36.trp"},
|
||||
{0x1425, "trophy/trophy37.trp"},
|
||||
{0x1426, "trophy/trophy38.trp"},
|
||||
{0x1427, "trophy/trophy39.trp"},
|
||||
{0x1428, "trophy/trophy40.trp"},
|
||||
{0x1429, "trophy/trophy41.trp"},
|
||||
{0x142A, "trophy/trophy42.trp"},
|
||||
{0x142B, "trophy/trophy43.trp"},
|
||||
{0x142C, "trophy/trophy44.trp"},
|
||||
{0x142D, "trophy/trophy45.trp"},
|
||||
{0x142E, "trophy/trophy46.trp"},
|
||||
{0x142F, "trophy/trophy47.trp"},
|
||||
{0x1430, "trophy/trophy48.trp"},
|
||||
{0x1431, "trophy/trophy49.trp"},
|
||||
{0x1432, "trophy/trophy50.trp"},
|
||||
{0x1433, "trophy/trophy51.trp"},
|
||||
{0x1434, "trophy/trophy52.trp"},
|
||||
{0x1435, "trophy/trophy53.trp"},
|
||||
{0x1436, "trophy/trophy54.trp"},
|
||||
{0x1437, "trophy/trophy55.trp"},
|
||||
{0x1438, "trophy/trophy56.trp"},
|
||||
{0x1439, "trophy/trophy57.trp"},
|
||||
{0x143A, "trophy/trophy58.trp"},
|
||||
{0x143B, "trophy/trophy59.trp"},
|
||||
{0x143C, "trophy/trophy60.trp"},
|
||||
{0x143D, "trophy/trophy61.trp"},
|
||||
{0x143E, "trophy/trophy62.trp"},
|
||||
{0x143F, "trophy/trophy63.trp"},
|
||||
{0x1440, "trophy/trophy64.trp"},
|
||||
{0x1441, "trophy/trophy65.trp"},
|
||||
{0x1442, "trophy/trophy66.trp"},
|
||||
{0x1443, "trophy/trophy67.trp"},
|
||||
{0x1444, "trophy/trophy68.trp"},
|
||||
{0x1445, "trophy/trophy69.trp"},
|
||||
{0x1446, "trophy/trophy70.trp"},
|
||||
{0x1447, "trophy/trophy71.trp"},
|
||||
{0x1448, "trophy/trophy72.trp"},
|
||||
{0x1449, "trophy/trophy73.trp"},
|
||||
{0x144A, "trophy/trophy74.trp"},
|
||||
{0x144B, "trophy/trophy75.trp"},
|
||||
{0x144C, "trophy/trophy76.trp"},
|
||||
{0x144D, "trophy/trophy77.trp"},
|
||||
{0x144E, "trophy/trophy78.trp"},
|
||||
{0x144F, "trophy/trophy79.trp"},
|
||||
{0x1450, "trophy/trophy80.trp"},
|
||||
{0x1451, "trophy/trophy81.trp"},
|
||||
{0x1452, "trophy/trophy82.trp"},
|
||||
{0x1453, "trophy/trophy83.trp"},
|
||||
{0x1454, "trophy/trophy84.trp"},
|
||||
{0x1455, "trophy/trophy85.trp"},
|
||||
{0x1456, "trophy/trophy86.trp"},
|
||||
{0x1457, "trophy/trophy87.trp"},
|
||||
{0x1458, "trophy/trophy88.trp"},
|
||||
{0x1459, "trophy/trophy89.trp"},
|
||||
{0x145A, "trophy/trophy90.trp"},
|
||||
{0x145B, "trophy/trophy91.trp"},
|
||||
{0x145C, "trophy/trophy92.trp"},
|
||||
{0x145D, "trophy/trophy93.trp"},
|
||||
{0x145E, "trophy/trophy94.trp"},
|
||||
{0x145F, "trophy/trophy95.trp"},
|
||||
{0x1460, "trophy/trophy96.trp"},
|
||||
{0x1461, "trophy/trophy97.trp"},
|
||||
{0x1462, "trophy/trophy98.trp"},
|
||||
{0x1463, "trophy/trophy99.trp"},
|
||||
{0x1600, "keymap_rp/001.png"},
|
||||
{0x1601, "keymap_rp/002.png"},
|
||||
{0x1602, "keymap_rp/003.png"},
|
||||
{0x1603, "keymap_rp/004.png"},
|
||||
{0x1604, "keymap_rp/005.png"},
|
||||
{0x1605, "keymap_rp/006.png"},
|
||||
{0x1606, "keymap_rp/007.png"},
|
||||
{0x1607, "keymap_rp/008.png"},
|
||||
{0x1608, "keymap_rp/009.png"},
|
||||
{0x1609, "keymap_rp/010.png"},
|
||||
{0x1610, "keymap_rp/00/001.png"},
|
||||
{0x1611, "keymap_rp/00/002.png"},
|
||||
{0x1612, "keymap_rp/00/003.png"},
|
||||
{0x1613, "keymap_rp/00/004.png"},
|
||||
{0x1614, "keymap_rp/00/005.png"},
|
||||
{0x1615, "keymap_rp/00/006.png"},
|
||||
{0x1616, "keymap_rp/00/007.png"},
|
||||
{0x1617, "keymap_rp/00/008.png"},
|
||||
{0x1618, "keymap_rp/00/009.png"},
|
||||
{0x1619, "keymap_rp/00/010.png"},
|
||||
{0x1620, "keymap_rp/01/001.png"},
|
||||
{0x1621, "keymap_rp/01/002.png"},
|
||||
{0x1622, "keymap_rp/01/003.png"},
|
||||
{0x1623, "keymap_rp/01/004.png"},
|
||||
{0x1624, "keymap_rp/01/005.png"},
|
||||
{0x1625, "keymap_rp/01/006.png"},
|
||||
{0x1626, "keymap_rp/01/007.png"},
|
||||
{0x1627, "keymap_rp/01/008.png"},
|
||||
{0x1628, "keymap_rp/01/009.png"},
|
||||
{0x1629, "keymap_rp/01/010.png"},
|
||||
{0x1630, "keymap_rp/02/001.png"},
|
||||
{0x1631, "keymap_rp/02/002.png"},
|
||||
{0x1632, "keymap_rp/02/003.png"},
|
||||
{0x1633, "keymap_rp/02/004.png"},
|
||||
{0x1634, "keymap_rp/02/005.png"},
|
||||
{0x1635, "keymap_rp/02/006.png"},
|
||||
{0x1636, "keymap_rp/02/007.png"},
|
||||
{0x1637, "keymap_rp/02/008.png"},
|
||||
{0x1638, "keymap_rp/02/009.png"},
|
||||
{0x1639, "keymap_rp/02/010.png"},
|
||||
{0x1640, "keymap_rp/03/001.png"},
|
||||
{0x1641, "keymap_rp/03/002.png"},
|
||||
{0x1642, "keymap_rp/03/003.png"},
|
||||
{0x1643, "keymap_rp/03/004.png"},
|
||||
{0x1644, "keymap_rp/03/005.png"},
|
||||
{0x1645, "keymap_rp/03/006.png"},
|
||||
{0x1646, "keymap_rp/03/007.png"},
|
||||
{0x1647, "keymap_rp/03/008.png"},
|
||||
{0x1648, "keymap_rp/03/0010.png"},
|
||||
{0x1650, "keymap_rp/04/001.png"},
|
||||
{0x1651, "keymap_rp/04/002.png"},
|
||||
{0x1652, "keymap_rp/04/003.png"},
|
||||
{0x1653, "keymap_rp/04/004.png"},
|
||||
{0x1654, "keymap_rp/04/005.png"},
|
||||
{0x1655, "keymap_rp/04/006.png"},
|
||||
{0x1656, "keymap_rp/04/007.png"},
|
||||
{0x1657, "keymap_rp/04/008.png"},
|
||||
{0x1658, "keymap_rp/04/009.png"},
|
||||
{0x1659, "keymap_rp/04/010.png"},
|
||||
{0x1660, "keymap_rp/05/001.png"},
|
||||
{0x1661, "keymap_rp/05/002.png"},
|
||||
{0x1662, "keymap_rp/05/003.png"},
|
||||
{0x1663, "keymap_rp/05/004.png"},
|
||||
{0x1664, "keymap_rp/05/005.png"},
|
||||
{0x1665, "keymap_rp/05/006.png"},
|
||||
{0x1666, "keymap_rp/05/007.png"},
|
||||
{0x1667, "keymap_rp/05/008.png"},
|
||||
{0x1668, "keymap_rp/05/009.png"},
|
||||
{0x1669, "keymap_rp/05/010.png"},
|
||||
{0x1670, "keymap_rp/06/001.png"},
|
||||
{0x1671, "keymap_rp/06/002.png"},
|
||||
{0x1672, "keymap_rp/06/003.png"},
|
||||
{0x1673, "keymap_rp/06/004.png"},
|
||||
{0x1674, "keymap_rp/06/005.png"},
|
||||
{0x1675, "keymap_rp/06/006.png"},
|
||||
{0x1676, "keymap_rp/06/007.png"},
|
||||
{0x1677, "keymap_rp/06/008.png"},
|
||||
{0x1678, "keymap_rp/06/009.png"},
|
||||
{0x1679, "keymap_rp/06/010.png"},
|
||||
{0x1680, "keymap_rp/07/001.png"},
|
||||
{0x1681, "keymap_rp/07/002.png"},
|
||||
{0x1682, "keymap_rp/07/003.png"},
|
||||
{0x1683, "keymap_rp/07/004.png"},
|
||||
{0x1684, "keymap_rp/07/005.png"},
|
||||
{0x1685, "keymap_rp/07/006.png"},
|
||||
{0x1686, "keymap_rp/07/007.png"},
|
||||
{0x1687, "keymap_rp/07/008.png"},
|
||||
{0x1688, "keymap_rp/07/009.png"},
|
||||
{0x1689, "keymap_rp/07/010.png"},
|
||||
{0x1690, "keymap_rp/08/001.png"},
|
||||
{0x1691, "keymap_rp/08/002.png"},
|
||||
{0x1692, "keymap_rp/08/003.png"},
|
||||
{0x1693, "keymap_rp/08/004.png"},
|
||||
{0x1694, "keymap_rp/08/005.png"},
|
||||
{0x1695, "keymap_rp/08/006.png"},
|
||||
{0x1696, "keymap_rp/08/007.png"},
|
||||
{0x1697, "keymap_rp/08/008.png"},
|
||||
{0x1698, "keymap_rp/08/009.png"},
|
||||
{0x1699, "keymap_rp/08/010.png"},
|
||||
{0x16A0, "keymap_rp/09/001.png"},
|
||||
{0x16A1, "keymap_rp/09/002.png"},
|
||||
{0x16A2, "keymap_rp/09/003.png"},
|
||||
{0x16A3, "keymap_rp/09/004.png"},
|
||||
{0x16A4, "keymap_rp/09/005.png"},
|
||||
{0x16A5, "keymap_rp/09/006.png"},
|
||||
{0x16A6, "keymap_rp/09/007.png"},
|
||||
{0x16A7, "keymap_rp/09/008.png"},
|
||||
{0x16A8, "keymap_rp/09/009.png"},
|
||||
{0x16A9, "keymap_rp/09/010.png"},
|
||||
{0x16B0, "keymap_rp/10/001.png"},
|
||||
{0x16B1, "keymap_rp/10/002.png"},
|
||||
{0x16B2, "keymap_rp/10/003.png"},
|
||||
{0x16B3, "keymap_rp/10/004.png"},
|
||||
{0x16B4, "keymap_rp/10/005.png"},
|
||||
{0x16B5, "keymap_rp/10/006.png"},
|
||||
{0x16B6, "keymap_rp/10/007.png"},
|
||||
{0x16B7, "keymap_rp/10/008.png"},
|
||||
{0x16B8, "keymap_rp/10/009.png"},
|
||||
{0x16B9, "keymap_rp/10/010.png"},
|
||||
{0x16C0, "keymap_rp/11/001.png"},
|
||||
{0x16C1, "keymap_rp/11/002.png"},
|
||||
{0x16C2, "keymap_rp/11/003.png"},
|
||||
{0x16C3, "keymap_rp/11/004.png"},
|
||||
{0x16C4, "keymap_rp/11/005.png"},
|
||||
{0x16C5, "keymap_rp/11/006.png"},
|
||||
{0x16C6, "keymap_rp/11/007.png"},
|
||||
{0x16C7, "keymap_rp/11/008.png"},
|
||||
{0x16C8, "keymap_rp/11/009.png"},
|
||||
{0x16C9, "keymap_rp/11/010.png"},
|
||||
{0x16D0, "keymap_rp/12/001.png"},
|
||||
{0x16D1, "keymap_rp/12/002.png"},
|
||||
{0x16D2, "keymap_rp/12/003.png"},
|
||||
{0x16D3, "keymap_rp/12/004.png"},
|
||||
{0x16D4, "keymap_rp/12/005.png"},
|
||||
{0x16D5, "keymap_rp/12/006.png"},
|
||||
{0x16D6, "keymap_rp/12/007.png"},
|
||||
{0x16D7, "keymap_rp/12/008.png"},
|
||||
{0x16D8, "keymap_rp/12/009.png"},
|
||||
{0x16D9, "keymap_rp/12/010.png"},
|
||||
{0x16E0, "keymap_rp/13/001.png"},
|
||||
{0x16E1, "keymap_rp/13/002.png"},
|
||||
{0x16E2, "keymap_rp/13/003.png"},
|
||||
{0x16E3, "keymap_rp/13/004.png"},
|
||||
{0x16E4, "keymap_rp/13/005.png"},
|
||||
{0x16E5, "keymap_rp/13/006.png"},
|
||||
{0x16E6, "keymap_rp/13/007.png"},
|
||||
{0x16E7, "keymap_rp/13/008.png"},
|
||||
{0x16E8, "keymap_rp/13/009.png"},
|
||||
{0x16E9, "keymap_rp/13/010.png"},
|
||||
{0x16F0, "keymap_rp/14/001.png"},
|
||||
{0x16F1, "keymap_rp/14/002.png"},
|
||||
{0x16F2, "keymap_rp/14/003.png"},
|
||||
{0x16F3, "keymap_rp/14/004.png"},
|
||||
{0x16F4, "keymap_rp/14/005.png"},
|
||||
{0x16F5, "keymap_rp/14/006.png"},
|
||||
{0x16F6, "keymap_rp/14/007.png"},
|
||||
{0x16F7, "keymap_rp/14/008.png"},
|
||||
{0x16F8, "keymap_rp/14/009.png"},
|
||||
{0x16F9, "keymap_rp/14/010.png"},
|
||||
{0x1700, "keymap_rp/15/001.png"},
|
||||
{0x1701, "keymap_rp/15/002.png"},
|
||||
{0x1702, "keymap_rp/15/003.png"},
|
||||
{0x1703, "keymap_rp/15/004.png"},
|
||||
{0x1704, "keymap_rp/15/005.png"},
|
||||
{0x1705, "keymap_rp/15/006.png"},
|
||||
{0x1706, "keymap_rp/15/007.png"},
|
||||
{0x1707, "keymap_rp/15/008.png"},
|
||||
{0x1708, "keymap_rp/15/009.png"},
|
||||
{0x1709, "keymap_rp/15/010.png"},
|
||||
{0x1710, "keymap_rp/16/001.png"},
|
||||
{0x1711, "keymap_rp/16/002.png"},
|
||||
{0x1712, "keymap_rp/16/003.png"},
|
||||
{0x1713, "keymap_rp/16/004.png"},
|
||||
{0x1714, "keymap_rp/16/005.png"},
|
||||
{0x1715, "keymap_rp/16/006.png"},
|
||||
{0x1716, "keymap_rp/16/007.png"},
|
||||
{0x1717, "keymap_rp/16/008.png"},
|
||||
{0x1718, "keymap_rp/16/009.png"},
|
||||
{0x1719, "keymap_rp/16/010.png"},
|
||||
{0x1720, "keymap_rp/17/001.png"},
|
||||
{0x1721, "keymap_rp/17/002.png"},
|
||||
{0x1722, "keymap_rp/17/003.png"},
|
||||
{0x1723, "keymap_rp/17/004.png"},
|
||||
{0x1724, "keymap_rp/17/005.png"},
|
||||
{0x1725, "keymap_rp/17/006.png"},
|
||||
{0x1726, "keymap_rp/17/007.png"},
|
||||
{0x1727, "keymap_rp/17/008.png"},
|
||||
{0x1728, "keymap_rp/17/009.png"},
|
||||
{0x1729, "keymap_rp/17/010.png"},
|
||||
{0x1730, "keymap_rp/18/001.png"},
|
||||
{0x1731, "keymap_rp/18/002.png"},
|
||||
{0x1732, "keymap_rp/18/003.png"},
|
||||
{0x1733, "keymap_rp/18/004.png"},
|
||||
{0x1734, "keymap_rp/18/005.png"},
|
||||
{0x1735, "keymap_rp/18/006.png"},
|
||||
{0x1736, "keymap_rp/18/007.png"},
|
||||
{0x1737, "keymap_rp/18/008.png"},
|
||||
{0x1738, "keymap_rp/18/009.png"},
|
||||
{0x1739, "keymap_rp/18/010.png"},
|
||||
{0x1740, "keymap_rp/19/001.png"},
|
||||
{0x1741, "keymap_rp/19/002.png"},
|
||||
{0x1742, "keymap_rp/19/003.png"},
|
||||
{0x1743, "keymap_rp/19/004.png"},
|
||||
{0x1744, "keymap_rp/19/005.png"},
|
||||
{0x1745, "keymap_rp/19/006.png"},
|
||||
{0x1746, "keymap_rp/19/007.png"},
|
||||
{0x1747, "keymap_rp/19/008.png"},
|
||||
{0x1748, "keymap_rp/19/009.png"},
|
||||
{0x1749, "keymap_rp/19/010.png"},
|
||||
{0x1750, "keymap_rp/20/001.png"},
|
||||
{0x1751, "keymap_rp/20/002.png"},
|
||||
{0x1752, "keymap_rp/20/003.png"},
|
||||
{0x1753, "keymap_rp/20/004.png"},
|
||||
{0x1754, "keymap_rp/20/005.png"},
|
||||
{0x1755, "keymap_rp/20/006.png"},
|
||||
{0x1756, "keymap_rp/20/007.png"},
|
||||
{0x1757, "keymap_rp/20/008.png"},
|
||||
{0x1758, "keymap_rp/20/009.png"},
|
||||
{0x1759, "keymap_rp/20/010.png"},
|
||||
{0x1760, "keymap_rp/21/001.png"},
|
||||
{0x1761, "keymap_rp/21/002.png"},
|
||||
{0x1762, "keymap_rp/21/003.png"},
|
||||
{0x1763, "keymap_rp/21/004.png"},
|
||||
{0x1764, "keymap_rp/21/005.png"},
|
||||
{0x1765, "keymap_rp/21/006.png"},
|
||||
{0x1766, "keymap_rp/21/007.png"},
|
||||
{0x1767, "keymap_rp/21/008.png"},
|
||||
{0x1768, "keymap_rp/21/009.png"},
|
||||
{0x1769, "keymap_rp/21/010.png"},
|
||||
{0x1770, "keymap_rp/22/001.png"},
|
||||
{0x1771, "keymap_rp/22/002.png"},
|
||||
{0x1772, "keymap_rp/22/003.png"},
|
||||
{0x1773, "keymap_rp/22/004.png"},
|
||||
{0x1774, "keymap_rp/22/005.png"},
|
||||
{0x1775, "keymap_rp/22/006.png"},
|
||||
{0x1776, "keymap_rp/22/007.png"},
|
||||
{0x1777, "keymap_rp/22/008.png"},
|
||||
{0x1778, "keymap_rp/22/009.png"},
|
||||
{0x1779, "keymap_rp/22/010.png"},
|
||||
{0x1780, "keymap_rp/23/001.png"},
|
||||
{0x1781, "keymap_rp/23/002.png"},
|
||||
{0x1782, "keymap_rp/23/003.png"},
|
||||
{0x1783, "keymap_rp/23/004.png"},
|
||||
{0x1784, "keymap_rp/23/005.png"},
|
||||
{0x1785, "keymap_rp/23/006.png"},
|
||||
{0x1786, "keymap_rp/23/007.png"},
|
||||
{0x1787, "keymap_rp/23/008.png"},
|
||||
{0x1788, "keymap_rp/23/009.png"},
|
||||
{0x1789, "keymap_rp/23/010.png"},
|
||||
{0x1790, "keymap_rp/24/001.png"},
|
||||
{0x1791, "keymap_rp/24/002.png"},
|
||||
{0x1792, "keymap_rp/24/003.png"},
|
||||
{0x1793, "keymap_rp/24/004.png"},
|
||||
{0x1794, "keymap_rp/24/005.png"},
|
||||
{0x1795, "keymap_rp/24/006.png"},
|
||||
{0x1796, "keymap_rp/24/007.png"},
|
||||
{0x1797, "keymap_rp/24/008.png"},
|
||||
{0x1798, "keymap_rp/24/009.png"},
|
||||
{0x1799, "keymap_rp/24/010.png"},
|
||||
{0x17A0, "keymap_rp/25/001.png"},
|
||||
{0x17A1, "keymap_rp/25/002.png"},
|
||||
{0x17A2, "keymap_rp/25/003.png"},
|
||||
{0x17A3, "keymap_rp/25/004.png"},
|
||||
{0x17A4, "keymap_rp/25/005.png"},
|
||||
{0x17A5, "keymap_rp/25/006.png"},
|
||||
{0x17A6, "keymap_rp/25/007.png"},
|
||||
{0x17A7, "keymap_rp/25/008.png"},
|
||||
{0x17A8, "keymap_rp/25/009.png"},
|
||||
{0x17A9, "keymap_rp/25/010.png"},
|
||||
{0x17B0, "keymap_rp/26/001.png"},
|
||||
{0x17B1, "keymap_rp/26/002.png"},
|
||||
{0x17B2, "keymap_rp/26/003.png"},
|
||||
{0x17B3, "keymap_rp/26/004.png"},
|
||||
{0x17B4, "keymap_rp/26/005.png"},
|
||||
{0x17B5, "keymap_rp/26/006.png"},
|
||||
{0x17B6, "keymap_rp/26/007.png"},
|
||||
{0x17B7, "keymap_rp/26/008.png"},
|
||||
{0x17B8, "keymap_rp/26/009.png"},
|
||||
{0x17B9, "keymap_rp/26/010.png"},
|
||||
{0x17C0, "keymap_rp/27/001.png"},
|
||||
{0x17C1, "keymap_rp/27/002.png"},
|
||||
{0x17C2, "keymap_rp/27/003.png"},
|
||||
{0x17C3, "keymap_rp/27/004.png"},
|
||||
{0x17C4, "keymap_rp/27/005.png"},
|
||||
{0x17C5, "keymap_rp/27/006.png"},
|
||||
{0x17C6, "keymap_rp/27/007.png"},
|
||||
{0x17C7, "keymap_rp/27/008.png"},
|
||||
{0x17C8, "keymap_rp/27/009.png"},
|
||||
{0x17C9, "keymap_rp/27/010.png"},
|
||||
{0x17D0, "keymap_rp/28/001.png"},
|
||||
{0x17D1, "keymap_rp/28/002.png"},
|
||||
{0x17D2, "keymap_rp/28/003.png"},
|
||||
{0x17D3, "keymap_rp/28/004.png"},
|
||||
{0x17D4, "keymap_rp/28/005.png"},
|
||||
{0x17D5, "keymap_rp/28/006.png"},
|
||||
{0x17D6, "keymap_rp/28/007.png"},
|
||||
{0x17D7, "keymap_rp/28/008.png"},
|
||||
{0x17D8, "keymap_rp/28/009.png"},
|
||||
{0x17D9, "keymap_rp/28/010.png"},
|
||||
{0x17E0, "keymap_rp/29/001.png"},
|
||||
{0x17E1, "keymap_rp/29/002.png"},
|
||||
{0x17E2, "keymap_rp/29/003.png"},
|
||||
{0x17E3, "keymap_rp/29/004.png"},
|
||||
{0x17E4, "keymap_rp/29/005.png"},
|
||||
{0x17E5, "keymap_rp/29/006.png"},
|
||||
{0x17E6, "keymap_rp/29/007.png"},
|
||||
{0x17E7, "keymap_rp/29/008.png"},
|
||||
{0x17E8, "keymap_rp/29/009.png"},
|
||||
{0x17E9, "keymap_rp/29/010.png"},
|
||||
{0x17F0, "keymap_rp/30/001.png"},
|
||||
{0x17F1, "keymap_rp/30/002.png"},
|
||||
{0x17F2, "keymap_rp/30/003.png"},
|
||||
{0x17F3, "keymap_rp/30/004.png"},
|
||||
{0x17F4, "keymap_rp/30/005.png"},
|
||||
{0x17F5, "keymap_rp/30/006.png"},
|
||||
{0x17F6, "keymap_rp/30/007.png"},
|
||||
{0x17F7, "keymap_rp/30/008.png"},
|
||||
{0x17F8, "keymap_rp/30/009.png"},
|
||||
{0x17F9, "keymap_rp/30/010.png"},
|
||||
}};
|
||||
|
||||
std::string_view GetEntryNameByType(u32 type) {
|
||||
const auto key = PkgEntryValue{type};
|
||||
const auto it = std::ranges::lower_bound(PkgEntries, key);
|
||||
if (it != PkgEntries.end() && it->type == type) {
|
||||
return it->name;
|
||||
}
|
||||
return "";
|
||||
}
|
10
src/core/file_format/pkg_type.h
Normal file
10
src/core/file_format/pkg_type.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include "common/types.h"
|
||||
|
||||
/// Retrieves the PKG entry name from its type identifier.
|
||||
std::string_view GetEntryNameByType(u32 type);
|
28
src/core/loader.cpp
Normal file
28
src/core/loader.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/io_file.h"
|
||||
#include "common/types.h"
|
||||
#include "loader.h"
|
||||
|
||||
namespace Loader {
|
||||
|
||||
FileTypes DetectFileType(const std::filesystem::path& filepath) {
|
||||
// No file loaded
|
||||
if (filepath.empty()) {
|
||||
return FileTypes::Unknown;
|
||||
}
|
||||
Common::FS::IOFile file;
|
||||
file.Open(filepath, Common::FS::FileAccessMode::Read);
|
||||
file.Seek(0);
|
||||
u32 magic;
|
||||
file.Read(magic);
|
||||
file.Close();
|
||||
switch (magic) {
|
||||
case PkgMagic:
|
||||
return FileTypes::Pkg;
|
||||
}
|
||||
return FileTypes::Unknown;
|
||||
}
|
||||
|
||||
} // namespace Loader
|
18
src/core/loader.h
Normal file
18
src/core/loader.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Loader {
|
||||
|
||||
constexpr static u32 PkgMagic = 0x544e437f;
|
||||
|
||||
enum class FileTypes {
|
||||
Unknown,
|
||||
Pkg,
|
||||
};
|
||||
|
||||
FileTypes DetectFileType(const std::filesystem::path& filepath);
|
||||
} // namespace Loader
|
94
src/qt_gui/install_dir_select.cpp
Normal file
94
src/qt_gui/install_dir_select.cpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "install_dir_select.h"
|
||||
|
||||
InstallDirSelect::InstallDirSelect() : selected_dir() {
|
||||
auto install_dirs = Config::getGameInstallDirs();
|
||||
selected_dir = install_dirs.empty() ? "" : install_dirs.front();
|
||||
|
||||
if (!install_dirs.empty() && install_dirs.size() == 1) {
|
||||
accept();
|
||||
}
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
|
||||
layout->addWidget(SetupInstallDirList());
|
||||
layout->addStretch();
|
||||
layout->addWidget(SetupDialogActions());
|
||||
|
||||
setWindowTitle(tr("shadPS4 - Choose directory"));
|
||||
setWindowIcon(QIcon(":images/shadps4.ico"));
|
||||
}
|
||||
|
||||
InstallDirSelect::~InstallDirSelect() {}
|
||||
|
||||
QWidget* InstallDirSelect::SetupInstallDirList() {
|
||||
auto group = new QGroupBox(tr("Select which directory you want to install to."));
|
||||
auto vlayout = new QVBoxLayout();
|
||||
|
||||
auto m_path_list = new QListWidget();
|
||||
QList<QString> qt_list;
|
||||
for (const auto& str : Config::getGameInstallDirs()) {
|
||||
QString installDirPath;
|
||||
Common::FS::PathToQString(installDirPath, str);
|
||||
qt_list.append(installDirPath);
|
||||
}
|
||||
m_path_list->insertItems(0, qt_list);
|
||||
m_path_list->setSpacing(1);
|
||||
|
||||
connect(m_path_list, &QListWidget::itemClicked, this, &InstallDirSelect::setSelectedDirectory);
|
||||
connect(m_path_list, &QListWidget::itemActivated, this,
|
||||
&InstallDirSelect::setSelectedDirectory);
|
||||
|
||||
vlayout->addWidget(m_path_list);
|
||||
|
||||
auto checkbox = new QCheckBox(tr("Install All Queued to Selected Folder"));
|
||||
connect(checkbox, &QCheckBox::toggled, this, &InstallDirSelect::setUseForAllQueued);
|
||||
vlayout->addWidget(checkbox);
|
||||
|
||||
auto checkbox2 = new QCheckBox(tr("Delete PKG File on Install"));
|
||||
connect(checkbox2, &QCheckBox::toggled, this, &InstallDirSelect::setDeleteFileOnInstall);
|
||||
vlayout->addWidget(checkbox2);
|
||||
|
||||
group->setLayout(vlayout);
|
||||
return group;
|
||||
}
|
||||
|
||||
void InstallDirSelect::setSelectedDirectory(QListWidgetItem* item) {
|
||||
if (item) {
|
||||
const auto highlighted_path = Common::FS::PathFromQString(item->text());
|
||||
if (!highlighted_path.empty()) {
|
||||
selected_dir = highlighted_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InstallDirSelect::setUseForAllQueued(bool enabled) {
|
||||
use_for_all_queued = enabled;
|
||||
}
|
||||
|
||||
void InstallDirSelect::setDeleteFileOnInstall(bool enabled) {
|
||||
delete_file_on_install = enabled;
|
||||
}
|
||||
|
||||
QWidget* InstallDirSelect::SetupDialogActions() {
|
||||
auto actions = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
|
||||
connect(actions, &QDialogButtonBox::accepted, this, &InstallDirSelect::accept);
|
||||
connect(actions, &QDialogButtonBox::rejected, this, &InstallDirSelect::reject);
|
||||
|
||||
return actions;
|
||||
}
|
42
src/qt_gui/install_dir_select.h
Normal file
42
src/qt_gui/install_dir_select.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidget>
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/path_util.h"
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
class InstallDirSelect final : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
InstallDirSelect();
|
||||
~InstallDirSelect();
|
||||
|
||||
std::filesystem::path getSelectedDirectory() {
|
||||
return selected_dir;
|
||||
}
|
||||
|
||||
bool useForAllQueued() {
|
||||
return use_for_all_queued;
|
||||
}
|
||||
|
||||
bool deleteFileOnInstall() {
|
||||
return delete_file_on_install;
|
||||
}
|
||||
|
||||
private:
|
||||
QWidget* SetupInstallDirList();
|
||||
QWidget* SetupDialogActions();
|
||||
void setSelectedDirectory(QListWidgetItem* item);
|
||||
void setDeleteFileOnInstall(bool enabled);
|
||||
void setUseForAllQueued(bool enabled);
|
||||
std::filesystem::path selected_dir;
|
||||
bool delete_file_on_install = false;
|
||||
bool use_for_all_queued = false;
|
||||
};
|
217
src/qt_gui/pkg_viewer.cpp
Normal file
217
src/qt_gui/pkg_viewer.cpp
Normal file
|
@ -0,0 +1,217 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "pkg_viewer.h"
|
||||
|
||||
PKGViewer::PKGViewer(std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent,
|
||||
std::function<void(std::filesystem::path, int, int)> InstallDragDropPkg)
|
||||
: QMainWindow(), m_game_info(game_info_get) {
|
||||
this->resize(1280, 720);
|
||||
this->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dir_list_std = Config::getPkgViewer();
|
||||
dir_list.clear();
|
||||
for (const auto& str : dir_list_std) {
|
||||
dir_list.append(QString::fromStdString(str));
|
||||
}
|
||||
statusBar = new QStatusBar(treeWidget);
|
||||
this->setStatusBar(statusBar);
|
||||
treeWidget = new QTreeWidget(this);
|
||||
treeWidget->setColumnCount(9);
|
||||
QStringList headers;
|
||||
headers << tr("Name") << tr("Serial") << tr("Installed") << tr("Size") << tr("Category")
|
||||
<< tr("Type") << tr("App Ver") << tr("FW") << tr("Region") << tr("Flags") << tr("Path");
|
||||
treeWidget->setHeaderLabels(headers);
|
||||
treeWidget->header()->setDefaultAlignment(Qt::AlignCenter);
|
||||
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
treeWidget->setColumnWidth(8, 170);
|
||||
this->setCentralWidget(treeWidget);
|
||||
QMenuBar* menuBar = new QMenuBar(this);
|
||||
menuBar->setContextMenuPolicy(Qt::PreventContextMenu);
|
||||
QMenu* fileMenu = menuBar->addMenu(tr("File"));
|
||||
QAction* openFolderAct = new QAction(tr("Open Folder"), this);
|
||||
fileMenu->addAction(openFolderAct);
|
||||
this->setMenuBar(menuBar);
|
||||
CheckPKGFolders(); // Check for new PKG files in existing folders.
|
||||
ProcessPKGInfo();
|
||||
|
||||
connect(openFolderAct, &QAction::triggered, this, &PKGViewer::OpenPKGFolder);
|
||||
|
||||
connect(treeWidget, &QTreeWidget::customContextMenuRequested, this,
|
||||
[=, this](const QPoint& pos) {
|
||||
if (treeWidget->selectedItems().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
m_gui_context_menus.RequestGameMenuPKGViewer(pos, m_full_pkg_list, treeWidget,
|
||||
InstallDragDropPkg);
|
||||
});
|
||||
|
||||
connect(parent, &QWidget::destroyed, this, [this]() { this->deleteLater(); });
|
||||
}
|
||||
|
||||
PKGViewer::~PKGViewer() {}
|
||||
|
||||
void PKGViewer::OpenPKGFolder() {
|
||||
QString folderPath =
|
||||
QFileDialog::getExistingDirectory(this, tr("Open Folder"), QDir::homePath());
|
||||
if (!dir_list.contains(folderPath)) {
|
||||
dir_list.append(folderPath);
|
||||
QDir directory(folderPath);
|
||||
QFileInfoList fileInfoList = directory.entryInfoList(QDir::Files);
|
||||
for (const QFileInfo& fileInfo : fileInfoList) {
|
||||
QString file_ext = fileInfo.suffix();
|
||||
if (fileInfo.isFile() && file_ext == "pkg") {
|
||||
m_pkg_list.append(fileInfo.absoluteFilePath());
|
||||
}
|
||||
}
|
||||
std::sort(m_pkg_list.begin(), m_pkg_list.end());
|
||||
ProcessPKGInfo();
|
||||
dir_list_std.clear();
|
||||
for (auto dir : dir_list) {
|
||||
dir_list_std.push_back(dir.toStdString());
|
||||
}
|
||||
Config::setPkgViewer(dir_list_std);
|
||||
} else {
|
||||
// qDebug() << "Folder selection canceled.";
|
||||
}
|
||||
}
|
||||
|
||||
void PKGViewer::CheckPKGFolders() { // Check for new PKG file additions.
|
||||
m_pkg_list.clear();
|
||||
for (const QString& dir : dir_list) {
|
||||
QDir directory(dir);
|
||||
QFileInfoList fileInfoList = directory.entryInfoList(QDir::Files);
|
||||
for (const QFileInfo& fileInfo : fileInfoList) {
|
||||
QString file_ext = fileInfo.suffix();
|
||||
if (fileInfo.isFile() && file_ext == "pkg") {
|
||||
m_pkg_list.append(fileInfo.absoluteFilePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
std::sort(m_pkg_list.begin(), m_pkg_list.end());
|
||||
}
|
||||
|
||||
void PKGViewer::ProcessPKGInfo() {
|
||||
treeWidget->clear();
|
||||
map_strings.clear();
|
||||
map_integers.clear();
|
||||
m_pkg_app_list.clear();
|
||||
m_pkg_patch_list.clear();
|
||||
m_full_pkg_list.clear();
|
||||
for (int i = 0; i < m_pkg_list.size(); i++) {
|
||||
std::filesystem::path path = Common::FS::PathFromQString(m_pkg_list[i]);
|
||||
std::string failreason;
|
||||
if (!package.Open(path, failreason)) {
|
||||
QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason));
|
||||
return;
|
||||
}
|
||||
psf.Open(package.sfo);
|
||||
QString title_name = QString::fromStdString(
|
||||
std::string{psf.GetString("TITLE").value_or(std::string{tr("Unknown").toStdString()})});
|
||||
QString title_id = QString::fromStdString(std::string{
|
||||
psf.GetString("TITLE_ID").value_or(std::string{tr("Unknown").toStdString()})});
|
||||
QString app_type = GameListUtils::GetAppType(psf.GetInteger("APP_TYPE").value_or(0));
|
||||
QString app_version = QString::fromStdString(std::string{
|
||||
psf.GetString("APP_VER").value_or(std::string{tr("Unknown").toStdString()})});
|
||||
QString title_category = QString::fromStdString(std::string{
|
||||
psf.GetString("CATEGORY").value_or(std::string{tr("Unknown").toStdString()})});
|
||||
QString pkg_size = GameListUtils::FormatSize(package.GetPkgHeader().pkg_size);
|
||||
pkg_content_flag = package.GetPkgHeader().pkg_content_flags;
|
||||
QString flagss = "";
|
||||
for (const auto& flag : package.flagNames) {
|
||||
if (package.isFlagSet(pkg_content_flag, flag.first)) {
|
||||
if (!flagss.isEmpty())
|
||||
flagss += (", ");
|
||||
flagss += QString::fromStdString(flag.second.data());
|
||||
}
|
||||
}
|
||||
|
||||
QString fw_ = tr("Unknown");
|
||||
if (const auto fw_int_opt = psf.GetInteger("SYSTEM_VER"); fw_int_opt.has_value()) {
|
||||
const u32 fw_int = *fw_int_opt;
|
||||
if (fw_int == 0) {
|
||||
fw_ = "0.00";
|
||||
} else {
|
||||
QString fw = QString::number(fw_int, 16);
|
||||
fw_ = fw.length() > 7 ? QString::number(fw_int, 16).left(3).insert(2, '.')
|
||||
: fw.left(3).insert(1, '.');
|
||||
}
|
||||
}
|
||||
char region = package.GetPkgHeader().pkg_content_id[0];
|
||||
QString pkg_info = "";
|
||||
if (title_category == "gd" && !flagss.contains("PATCH")) {
|
||||
title_category = "App";
|
||||
pkg_info = title_name + ";;" + title_id + ";;" + pkg_size + ";;" + title_category +
|
||||
";;" + app_type + ";;" + app_version + ";;" + fw_ + ";;" +
|
||||
game_list_util.GetRegion(region) + ";;" + flagss + ";;" + m_pkg_list[i];
|
||||
m_pkg_app_list.append(pkg_info);
|
||||
} else {
|
||||
title_category = "Patch";
|
||||
pkg_info = title_name + ";;" + title_id + ";;" + pkg_size + ";;" + title_category +
|
||||
";;" + app_type + ";;" + app_version + ";;" + fw_ + ";;" +
|
||||
game_list_util.GetRegion(region) + ";;" + flagss + ";;" + m_pkg_list[i];
|
||||
m_pkg_patch_list.append(pkg_info);
|
||||
}
|
||||
}
|
||||
std::sort(m_pkg_app_list.begin(), m_pkg_app_list.end());
|
||||
for (int i = 0; i < m_pkg_app_list.size(); i++) {
|
||||
QTreeWidgetItem* treeItem = new QTreeWidgetItem(treeWidget);
|
||||
QStringList pkg_app_ = m_pkg_app_list[i].split(";;");
|
||||
m_full_pkg_list.append(m_pkg_app_list[i]);
|
||||
treeItem->setExpanded(true);
|
||||
treeItem->setText(0, pkg_app_[0]);
|
||||
treeItem->setText(1, pkg_app_[1]);
|
||||
treeItem->setText(3, pkg_app_[2]);
|
||||
treeItem->setTextAlignment(3, Qt::AlignCenter);
|
||||
treeItem->setText(4, pkg_app_[3]);
|
||||
treeItem->setTextAlignment(4, Qt::AlignCenter);
|
||||
treeItem->setText(5, pkg_app_[4]);
|
||||
treeItem->setTextAlignment(5, Qt::AlignCenter);
|
||||
treeItem->setText(6, pkg_app_[5]);
|
||||
treeItem->setTextAlignment(6, Qt::AlignCenter);
|
||||
treeItem->setText(7, pkg_app_[6]);
|
||||
treeItem->setTextAlignment(7, Qt::AlignCenter);
|
||||
treeItem->setText(8, pkg_app_[7]);
|
||||
treeItem->setTextAlignment(8, Qt::AlignCenter);
|
||||
treeItem->setText(9, pkg_app_[8]);
|
||||
treeItem->setText(10, pkg_app_[9]);
|
||||
for (const GameInfo& info : m_game_info->m_games) { // Check if game is installed.
|
||||
if (info.serial == pkg_app_[1].toStdString()) {
|
||||
treeItem->setText(2, QChar(0x2713));
|
||||
treeItem->setTextAlignment(2, Qt::AlignCenter);
|
||||
}
|
||||
}
|
||||
for (const QString& item : m_pkg_patch_list) {
|
||||
QStringList pkg_patch_ = item.split(";;");
|
||||
if (pkg_patch_[1] == pkg_app_[1]) { // check patches with serial.
|
||||
m_full_pkg_list.append(item);
|
||||
QTreeWidgetItem* childItem = new QTreeWidgetItem(treeItem);
|
||||
childItem->setText(0, pkg_patch_[0]);
|
||||
childItem->setText(1, pkg_patch_[1]);
|
||||
childItem->setText(3, pkg_patch_[2]);
|
||||
childItem->setTextAlignment(3, Qt::AlignCenter);
|
||||
childItem->setText(4, pkg_patch_[3]);
|
||||
childItem->setTextAlignment(4, Qt::AlignCenter);
|
||||
childItem->setText(5, pkg_patch_[4]);
|
||||
childItem->setTextAlignment(5, Qt::AlignCenter);
|
||||
childItem->setText(6, pkg_patch_[5]);
|
||||
childItem->setTextAlignment(6, Qt::AlignCenter);
|
||||
childItem->setText(7, pkg_patch_[6]);
|
||||
childItem->setTextAlignment(7, Qt::AlignCenter);
|
||||
childItem->setText(8, pkg_patch_[7]);
|
||||
childItem->setTextAlignment(8, Qt::AlignCenter);
|
||||
childItem->setText(9, pkg_patch_[8]);
|
||||
childItem->setText(10, pkg_patch_[9]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int column = 0; column < treeWidget->columnCount() - 2; ++column) {
|
||||
// Resize the column to fit its contents
|
||||
treeWidget->resizeColumnToContents(column);
|
||||
}
|
||||
// Update status bar.
|
||||
statusBar->clearMessage();
|
||||
int numPkgs = m_pkg_list.size();
|
||||
QString statusMessage = QString::number(numPkgs) + " " + tr("Package");
|
||||
statusBar->showMessage(statusMessage);
|
||||
}
|
62
src/qt_gui/pkg_viewer.h
Normal file
62
src/qt_gui/pkg_viewer.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMenuBar>
|
||||
#include <QStatusBar>
|
||||
|
||||
#include "common/io_file.h"
|
||||
#include "core/file_format/pkg.h"
|
||||
#include "core/file_format/pkg_type.h"
|
||||
#include "core/file_format/psf.h"
|
||||
#include "game_info.h"
|
||||
#include "game_list_utils.h"
|
||||
#include "gui_context_menus.h"
|
||||
|
||||
class PKGViewer : public QMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PKGViewer(
|
||||
std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent,
|
||||
std::function<void(std::filesystem::path, int, int)> InstallDragDropPkg = nullptr);
|
||||
~PKGViewer();
|
||||
void OpenPKGFolder();
|
||||
void CheckPKGFolders();
|
||||
void ProcessPKGInfo();
|
||||
|
||||
private:
|
||||
GuiContextMenus m_gui_context_menus;
|
||||
PKG package;
|
||||
PSF psf;
|
||||
PKGHeader pkgheader;
|
||||
PKGEntry entry;
|
||||
PSFHeader header;
|
||||
char pkgTitleID[9];
|
||||
std::vector<u8> pkg;
|
||||
u64 pkgSize = 0;
|
||||
std::unordered_map<std::string, std::string> map_strings;
|
||||
std::unordered_map<std::string, u32> map_integers;
|
||||
|
||||
u32_be pkg_content_flag;
|
||||
std::shared_ptr<GameInfoClass> m_game_info;
|
||||
GameListUtils game_list_util;
|
||||
// Status bar
|
||||
QStatusBar* statusBar;
|
||||
|
||||
std::vector<std::pair<int, QString>> appTypes = {
|
||||
{0, "FULL APP"},
|
||||
{1, "UPGRADABLE"},
|
||||
{2, "DEMO"},
|
||||
{3, "FREEMIUM"},
|
||||
};
|
||||
|
||||
QStringList m_full_pkg_list;
|
||||
QStringList m_pkg_app_list;
|
||||
QStringList m_pkg_patch_list;
|
||||
QStringList m_pkg_list;
|
||||
QStringList dir_list;
|
||||
std::vector<std::string> dir_list_std;
|
||||
QTreeWidget* treeWidget = nullptr;
|
||||
};
|
Loading…
Add table
Reference in a new issue