2022-04-29 23:38:29 +00:00
import os
import binascii
import sys
import struct
import math
import hashlib
from Crypto . Cipher import AES
from cryptography . hazmat . primitives . serialization import pkcs12
from cryptography . hazmat . primitives . asymmetric import padding
game_key = b " "
content_id = b " "
original_iv = b " "
file_size = 0
total_blocks = 0
def ReadGameKey ( filename ) : # Read from FAKE.RIF
global game_key
global content_id
riffd = open ( filename , " rb " )
riffd . seek ( 0x50 , 0 )
content_id = riffd . read ( 0x24 )
riffd . seek ( 0x120 , 0 )
game_key = riffd . read ( 0x10 )
riffd . close ( )
def ReadPublisherKey ( p12 , khapp ) : # used for PSM Developer Assistant (debug PSSE)
global game_key
print ( " [*] Reading PRIVATE KEY from " + p12 )
pkcs12_file = open ( p12 , ' rb ' ) . read ( )
passphrase = b " password "
private_key , certificate , additional_certificates = pkcs12 . load_key_and_certificates ( pkcs12_file , passphrase ) # Parse PKCS12 file
2022-05-02 01:21:30 +00:00
print ( " [*] Reading HKAPP " + khapp )
2022-04-29 23:38:29 +00:00
hkfd = open ( khapp , " rb " )
offset_by = 0
2022-05-02 01:21:30 +00:00
magic = hkfd . read ( 0x4 )
if magic == b " PAKR " : # Keyring
offset_by = 0x48
elif magic == b " tkdb " : # Protected_kconsole.dat- needs more research
offset_by = 0x10
elif magic == b " PSHK " : # Raw HKAPP
2022-04-29 23:38:29 +00:00
offset_by = 0
else :
2022-05-02 01:21:30 +00:00
print ( " [*] Invalid khapp, magic: " + magic . decode ( " UTF-8 " ) )
exit ( )
2022-04-29 23:38:29 +00:00
hkfd . seek ( 0x200 + offset_by , 0 )
enc = hkfd . read ( 0x100 )
dec = private_key . decrypt ( enc , padding . PKCS1v15 ( ) ) # RSA Decrypt
key = dec [ 0xC0 : 0xD0 ]
iv = dec [ 0xD0 : 0xE0 ]
hkfd . seek ( 0x80 + offset_by , 0 )
ebuffer = hkfd . read ( 0x240 )
cipher = AES . new ( key , AES . MODE_CBC , iv )
dec = cipher . decrypt ( ebuffer ) # AES Decrypt
# Dont know what these are for.
2022-05-02 01:21:30 +00:00
something1 = dec [ 0x00 : 0x10 ]
something2 = dec [ 0xA0 : 0xB0 ]
2022-04-29 23:38:29 +00:00
game_key = dec [ 0x60 : 0x70 ]
hkfd . close ( )
2022-05-02 01:21:30 +00:00
2022-04-29 23:38:29 +00:00
def IvRoll ( location ) :
iv_next = location
iv = bytearray ( original_iv )
new_iv = bytearray ( iv_next . to_bytes ( 0x10 , " little " ) )
for i in range ( 0 , 0x10 ) :
new_iv [ i ] ^ = iv [ i ]
return bytes ( new_iv )
def GetBlock ( fd , block_id ) :
global game_key
global file_size
global total_blocks
current_iv = IvRoll ( block_id )
block_loc = block_id * 0x8000
total_read = 0x8000
trim_to = total_read
if block_id == 0 : # Skip to filedata
block_loc = 0x680
total_read - = 0x680
trim_to = total_read
elif block_loc % 0x80000 == 0 : # Skip signature block
block_loc + = 0x400
total_read - = 0x400
trim_to = total_read
rd_amt = ( ( block_loc - 0x680 ) - ( 0x400 * math . floor ( block_loc / 0x80000 ) ) ) # Total amount of file read so far.
if block_id > = total_blocks - 1 : # Is this the last block?
total_read = file_size - rd_amt
trim_to = total_read
total_read + = ( 0x10 - ( total_read % 0x10 ) )
if block_id > total_blocks - 1 :
return b " "
if total_read < = 0 :
return b " "
fd . seek ( block_loc , 0 )
file_data = fd . read ( total_read )
cipher = AES . new ( game_key , AES . MODE_CBC , current_iv )
return cipher . decrypt ( file_data ) [ : trim_to ]
def DecryptFile ( input_filename ) :
global game_key
global content_id
global original_iv
global file_size
global total_blocks
2022-05-02 01:21:30 +00:00
psm_dev = False
2022-04-29 23:38:29 +00:00
iv = b " \x00 \x01 \x02 \x03 \x04 \x05 \x06 \x07 \x08 \x09 \x0A \x0B \x0C \x0D \x0E \x0F " # Header IV, used to find the real IV
key = b " \x4E \x29 \x8B \x40 \xF5 \x31 \xF4 \x69 \xD2 \x1F \x75 \xB1 \x33 \xC3 \x07 \xBE " # Header key for PSM Runtime and used in all retail games.
psm_dev_key = b " \x00 \x11 \x22 \x33 \x44 \x55 \x66 \x77 \x88 \x99 \xAA \xBB \xCC \xDD \xEE \xFF " # Header key for PSM Dev, used for all files encrypted with psm_encryptor.dll
2022-04-30 00:09:01 +00:00
runtime_game_key = b " \xA8 \x69 \x3C \x4D \xF0 \xAE \xED \xBC \x9A \xBF \xD8 \x21 \x36 \x92 \x91 \x2D " # key for the PlayStation Mobile Runtime (eg used in Sce.PlayStation.Core.dll)
2022-04-29 23:38:29 +00:00
total_blocks = math . floor ( os . path . getsize ( input_filename ) / 0x8000 ) + 1
fd = open ( input_filename , " rb " )
# Check magic is "PSSE" or "PSME"
header = fd . read ( 4 )
if header != b " PSSE " and header != b " PSME " :
2022-05-02 01:21:30 +00:00
print ( " [*] " + input_filename . decode ( " UTF-8 " ) + " is not a valid PSSE File " )
print ( " [*] Is it already decrypted? " )
2022-04-29 23:38:29 +00:00
exit ( )
# Check PSSE Version is 0x1 (not sure what it would be otherwise)
fd . seek ( 0x4 , 0 )
version = struct . unpack ( ' i ' , fd . read ( 4 ) ) [ 0 ]
if version != 0x01 :
2022-05-02 01:21:30 +00:00
print ( " [*] Unsupported PSSE version: " + str ( version ) )
2022-04-29 23:38:29 +00:00
exit ( )
fd . seek ( 0x8 , 0 )
file_size = struct . unpack ( ' Q ' , fd . read ( 8 ) ) [ 0 ]
fd . seek ( 0x10 , 0 )
psse_type = struct . unpack ( ' i ' , fd . read ( 4 ) ) [ 0 ]
if psse_type != 0x1 :
print ( " [*] Unknown PSSE Type: " + str ( psse_type ) )
exit ( )
fd . seek ( 0x14 , 0 )
read_content_id = fd . read ( 0x24 )
if read_content_id == b " IP9100-NPXS10074_00-0000000000000000 " : # Sce.PlayStation.Core.dll
game_key = runtime_game_key
elif read_content_id == ( b " \x00 " * 0x24 ) : # PSM developer assistant doenst include a Content ID
psm_dev = True
elif content_id != read_content_id :
2022-09-21 11:49:17 +00:00
print ( " [*] Content ID Mismatch! Expected: " + content_id . decode ( " UTF-8 " ) + " but got " + read_content_id . decode ( " UTF-8 " ) )
2022-04-29 23:38:29 +00:00
exit ( )
fd . seek ( 0x40 , 0 )
file_md5 = fd . read ( 0x10 )
# Supposadly this contains the filename.
#fd.seek(0x50, 0)
#enc1 = fd.read(0x20)
#cipher = AES.new(key, AES.MODE_CBC, iv)
#dec1 = cipher.decrypt(enc1)
# Determine file IV
fd . seek ( 0x70 , 0 )
enc = fd . read ( 0x10 )
if psm_dev :
key = psm_dev_key
cipher = AES . new ( key , AES . MODE_CBC , iv )
original_iv = cipher . decrypt ( enc )
total_file_data = b " "
for i in range ( 0 , total_blocks ) :
file_block = GetBlock ( fd , i )
total_file_data + = file_block
fd . close ( )
total_file_data = total_file_data [ : file_size ] # trim to file_size
md5 = hashlib . md5 ( )
md5 . update ( total_file_data )
got_md5 = md5 . digest ( )
if file_md5 != got_md5 : # Verify decrypted file.
print ( " [*] MD5 Mismatch, Expected: " + binascii . hexlify ( file_md5 ) . decode ( " UTF-8 " ) + " got: " + binascii . hexlify ( got_md5 ) . decode ( " UTF-8 " ) )
2022-05-02 01:21:30 +00:00
print ( " [*] The game key is most likely wrong. " )
2022-04-29 23:38:29 +00:00
exit ( ) ;
return total_file_data
2022-05-02 01:21:30 +00:00
if len ( sys . argv ) < = 1 :
print ( " PSSE Decryptor by SilicaAndPina v3 " )
print ( " (for retail games) <PSM_GAME_FOLDER> " )
print ( " (for PSM Dev Packages) <PSM_GAME_FOLDER> <PSM_PUBLISHER_KEY> <PSM_HKAPP_OR_KRNG> " )
print ( " (for anything) <PSM_GAME_FOLDER> <PSM_GAME_KEY> " )
print ( " " )
print ( " For retail games, you require the RO/License/FAKE.RIF file " )
print ( " And for PSM Dev Packages, you need there original publisher key and keyring. " )
exit ( )
file = sys . argv [ 1 ]
fpath = file . encode ( " UTF-8 " )
2022-05-31 12:30:51 +00:00
# Some dumb dirbusting shit.
2022-05-02 01:21:30 +00:00
applications_folder = b " /RO/Application/ "
license_file = os . path . normpath ( fpath + b " /RO/License/FAKE.rif " )
psse_list = os . path . normpath ( fpath + applications_folder + b " psse.list " )
if not os . path . exists ( psse_list ) :
applications_folder = b " /Application/ "
license_file = os . path . normpath ( fpath + b " /License/FAKE.rif " )
psse_list = os . path . normpath ( fpath + applications_folder + b " psse.list " )
if not os . path . exists ( psse_list ) :
applications_folder = b " / "
license_file = os . path . normpath ( fpath + b " /../License/FAKE.rif " )
psse_list = os . path . normpath ( fpath + applications_folder + b " psse.list " )
if not os . path . exists ( psse_list ) :
print ( " [*] Cannot find psse.list. " )
exit ( )
# Direct specify direct game key
if len ( sys . argv ) == 3 :
2022-09-21 11:49:17 +00:00
game_key = binascii . unhexlify ( sys . argv [ 2 ] )
f = open ( psse_list , " rb " )
f . seek ( 0x14 , os . SEEK_SET )
content_id = f . read ( 0x24 )
f . close ( )
2022-05-02 01:21:30 +00:00
# Read from publisher license
if game_key == b " " :
if len ( sys . argv ) == 4 :
2022-04-29 23:38:29 +00:00
pkcs12name = sys . argv [ 2 ]
khappname = sys . argv [ 3 ]
print ( " [*] Reading Publisher Key and App Key " )
if not os . path . exists ( pkcs12name ) :
print ( " [*] Publisher Key not found " )
exit ( )
if not os . path . exists ( khappname ) :
print ( " [*] App key file not found. " )
exit ( )
ReadPublisherKey ( pkcs12name , khappname )
2022-05-02 01:21:30 +00:00
# Read from fake.rif
if game_key == b " " :
if os . path . exists ( license_file ) :
2022-04-29 23:38:29 +00:00
ReadGameKey ( license_file )
2022-05-02 01:21:30 +00:00
# Is this a particular file rather than a games folder?
if os . path . isfile ( fpath ) :
print ( " Decrypting: " + file )
data = DecryptFile ( file )
open ( fpath , " wb " ) . write ( data )
exit ( )
2022-04-29 23:38:29 +00:00
2022-05-02 01:22:46 +00:00
# If game key is still unknown after all of this, abandon all hope!
2022-05-02 01:21:30 +00:00
if game_key == b " " :
print ( " [*] Game key is unknown, i cant decrypt this ! :( " )
exit ( )
print ( " [*] psse.list: " + psse_list . decode ( " UTF-8 " ) )
print ( " [*] Using game key: " + binascii . hexlify ( game_key ) . decode ( " UTF-8 " ) )
2022-04-29 23:38:29 +00:00
2022-05-02 01:21:30 +00:00
file_data = DecryptFile ( psse_list )
file_list = file_data . replace ( b " \r " , b " " ) . split ( b " \n " )
for psse_file in file_list :
if psse_file == b " " :
continue
file_path = os . path . normpath ( fpath + applications_folder + psse_file )
print ( " [*] Decrypting: " + file_path . decode ( " UTF-8 " ) )
if os . path . exists ( file_path ) :
decrypted_data = DecryptFile ( file_path )
open ( file_path , " wb " ) . write ( decrypted_data )
else :
print ( " [*] Error: File not Found: " + file_path . decode ( " UTF-8 " ) )
open ( psse_list , " wb " ) . write ( file_data )
print ( " [*] Decryption Complete! " )