Seregon/PkgToolBox

Toolbox for analyzing and editing pkg application files for psp,ps3, ps4 and ps5, includes the most useful functions you might need.

Python/57.3 KB/No license
packages/PackagePS4.py
PkgToolBox / packages / PackagePS4.py
1import os
2import logging
3from Crypto.Cipher import AES
4from Crypto.Util.Padding import pad, unpad
5from Crypto.Util.number import bytes_to_long
6from Crypto.Random import get_random_bytes
7 
8# Constants
9AES_KEY_LEN_128 = 16
10 
11# AES context
12class AES_ctx:
13 def __init__(self):
14 self.key = None
15 self.iv = None
16 
17 def set_key(self, key):
18 self.key = key
19 
20 def set_iv(self, iv):
21 self.iv = iv
22 
23 def encrypt(self, data):
24 cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
25 return cipher.encrypt(pad(data, AES.block_size))
26 
27 def decrypt(self, data):
28 cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
29 return unpad(cipher.decrypt(data), AES.block_size)
30 
31# AES functions
32def AES_set_key(ctx, key, key_len):
33 ctx.key = key[:key_len]
34 ctx.iv = get_random_bytes(AES.block_size)
35 
36def AES_cbc_encrypt(ctx, data, out):
37 out[:] = ctx.encrypt(data)
38 
39def AES_cbc_decrypt(ctx, data, out):
40 out[:] = ctx.decrypt(data)
41 
42class PackagePS4:
43 def __init__(self, original_file):
44 self.original_file = original_file
45 
46 def is_encrypted(self):
47 """Check if package is encrypted"""
48 try:
49 # Controlla se il PKG è cifrato verificando il flag di crittografia
50 with open(self.original_file, 'rb') as f:
51 # Vai all'offset del flag di crittografia (0x1A nel header PS4)
52 f.seek(0x1A)
53 # Leggi il flag (2 byte)
54 encryption_flag = int.from_bytes(f.read(2), byteorder='little')
55 # Se il flag è diverso da 0, il PKG è cifrato
56 return encryption_flag != 0
57 except Exception as e:
58 logging.error(f"Error checking encryption: {str(e)}")
59 return False
60 
61 def extract_with_passcode(self, passcode, output_dir):
62 """Extract encrypted PKG with passcode"""
63 if not self.is_encrypted():
64 raise ValueError("Package is not encrypted")
65
66 try:
67 # Verifica il formato del passcode
68 if len(passcode) != 32:
69 raise ValueError("Invalid passcode length")
70
71 # Converti il passcode in chiave AES
72 key = bytes.fromhex(passcode)
73
74 # Decripta il PKG usando la chiave
75 self.decrypt_pkg(key, output_dir)
76
77 return True
78 except ValueError as e:
79 raise e
80 except Exception as e:
81 raise ValueError(f"Failed to decrypt with passcode: {str(e)}")
82 
83 def decrypt_pkg(self, key, output_dir):
84 # Implementa la decriptazione del PKG usando la chiave AES
85 pass
86 
87