software: Fix decryption/decompression of blocked PUP segments

This commit is contained in:
Alexandro Sanchez Bach 2021-10-09 14:16:59 +02:00
parent 0b91ca52c8
commit 8b68b7f0fe
5 changed files with 48 additions and 37 deletions

View file

@ -21,6 +21,8 @@ find_package(SDL2 REQUIRED)
find_package(imgui REQUIRED)
find_package(RapidJSON CONFIG REQUIRED)
find_package(Vulkan REQUIRED)
find_package(zlib REQUIRED)
find_library(BOTAN_LIBRARIES NAMES BOTAN2 botan2 BOTAN botan)
# Sources
macro(ORBITAL_FILES_APPEND)
@ -51,7 +53,7 @@ target_include_directories(orbital PUBLIC ${ORBITAL_DIR_EXTERNALS})
target_include_directories(orbital PUBLIC ${ORBITAL_DIR_SOURCES})
target_include_directories(orbital PUBLIC ${RAPIDJSON_INCLUDE_DIRS})
target_include_directories(orbital PUBLIC ${Vulkan_INCLUDE_DIRS})
target_link_libraries(orbital PRIVATE SDL2::SDL2 imgui::imgui ${Vulkan_LIBRARIES})
target_link_libraries(orbital PRIVATE SDL2::SDL2 imgui::imgui ZLIB::ZLIB ${Vulkan_LIBRARIES} ${BOTAN_LIBRARIES})
include(${ORBITAL_DIR_EXTERNALS}/core.cmake)
# Properties

View file

@ -10,8 +10,7 @@
#include "crypto.h"
// Global
Crypto crypto;
#include <stdexcept>
U64 CryptoStream::read(U64 size, void* buffer) {
return 0;
@ -35,7 +34,23 @@ void Crypto::decrypt(void* buf, size_t len, Key key) {
void Crypto::decrypt(const void* input_buf, size_t input_len,
void* output_buf, size_t output_len, Key key) {
// TODO
const char* algo;
switch (key.type) {
case Key::AES_128_EBC:
algo = "AES-128/EBC";
break;
case Key::AES_128_CBC:
algo = "AES-128/CBC/CTS";
break;
default:
throw std::invalid_argument("Unrecognized key type");
}
auto cipher = Botan::get_cipher(algo, key.key, key.iv, Botan::Cipher_Dir::DECRYPTION);
Botan::Pipe pipe(cipher);
pipe.start_msg();
pipe.write((const uint8_t*)input_buf, input_len);
pipe.end_msg();
pipe.read((uint8_t*)output_buf, output_len);
}
Buffer Crypto::decrypt(const Buffer& buffer, Key key) {

View file

@ -12,6 +12,8 @@
#include <core.h>
#include <botan/botan.h>
#include <filesystem>
#include <string>
#include <string_view>
@ -24,12 +26,16 @@ struct Key {
AES_128_CBC,
} type;
union {
struct {
U08 key[32];
U08 iv[32];
} aes;
};
Botan::SymmetricKey key;
Botan::InitializationVector iv;
Key() : type(NONE) {}
Key(Type type, const void* key_buf, size_t key_len, const void* iv_buf, size_t iv_len)
: type(type), key((const U8*)key_buf, key_len), iv((const U8*)iv_buf, iv_len) {
}
Key(Type type, std::string_view key, std::string_view iv)
: type(type), key(std::string(key)), iv(std::string(iv)) {
}
};
class CryptoStream : public Stream {

View file

@ -18,29 +18,10 @@
static Crypto g_ps4Crypto;
static uint8_t parseHex(char input) {
if (input >= '0' && input <= '9')
return input - '0';
if (input >= 'A' && input <= 'F')
return input - 'A' + 10;
if (input >= 'a' && input <= 'f')
return input - 'a' + 10;
throw std::invalid_argument("Invalid input string");
}
static void parseHexBytes(std::string_view hex, uint8_t* buf, size_t len) {
for (size_t i = 0; i < hex.size() && i < 2*len; i += 2) {
buf[i >> 1] = parseHex(hex[i]) * 16 + parseHex(hex[i + 1]);
}
}
static Key parseAesKey(Key::Type type, const rapidjson::Value& value) {
Key k = { type };
parseHexBytes(value["aes_key"].GetString(),
k.aes.key, sizeof(k.aes.key));
parseHexBytes(value["aes_iv"].GetString(),
k.aes.iv, sizeof(k.aes.iv));
return k;
auto key = value["aes_key"].GetString();
auto iv = value["aes_iv"].GetString();
return Key(type, key, iv);
}
const Crypto& ps4Crypto() {
@ -57,6 +38,13 @@ const Crypto& ps4Crypto() {
// Add individual keys
g_ps4Crypto.add("pup.hdr",
parseAesKey(Key::AES_128_CBC, document["pup"]["hdr"]));
g_ps4Crypto.add("pup.root_key",
parseAesKey(Key::AES_128_CBC, document["pup"]["root_key"]));
for (const auto& m : document["self"]["80010002"].GetObject()) {
std::string name = "self.80010002.";
g_ps4Crypto.add(name + m.name.GetString(), parseAesKey(Key::AES_128_CBC, m.value));
}
return g_ps4Crypto;
}

View file

@ -137,14 +137,14 @@ Buffer PupParser::get_blocked(U64 index) {
// TODO: throw std::runtime_error("Unimplemented");
}
if (entry.is_encrypted()) {
Key key(Key::AES_128_CBC, meta.data_key, 16, meta.data_iv, 16);
crypto.decrypt(block.data(), block.size(), key);
decrypt(block, meta);
}
segment.resize(segment.size() + cur_size);
U08* dest = segment.data() + segment.size() - cur_size;
if (entry.is_compressed()) {
U08* dest = &segment[segment.size() - cur_size];
if (entry.is_compressed() && cur_size != cur_zsize) {
unsigned long cur_usize = cur_size;
uncompress(dest, &cur_usize, block.data(), cur_zsize);
int zerr = uncompress(dest, &cur_usize, block.data(), cur_zsize);
assert(zerr == 0);
} else {
memcpy(dest, block.data(), block.size());
}