PSSE

From Vita Developer wiki
Revision as of 11:41, 23 April 2024 by Li (talk | contribs) (→‎Data Structure)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

What is PSSE?

PSSE stands for PlayStation Suite Encrypted. It is an encryption layer that encrypts the PSM game's filesystem.

The encryption layer is comparable to the PS Vita Protected Filesystem (PFS) in many ways; however, it seemed that there was a bug at Sony, where besides executable files, the first directory level of a PSM app is not encrypted with PSSE, whose directory level is below the root of RO/. Similarly, the PSM SaveData is not encrypted by such layer either.

Data Structure

offset value description
0x00 0x50535345 (ASCII "PSSE" / "PSME") Magic Number / File Header
0x4 int32 Version
0x8 int64 Decrypted file size
0x10 int32 PSSE Type (always 0x1)
0x14 char[0x24] CONTENT_ID Contents of /RW/System/content_id
0x40 char[0x10] MD5 Of Original File (Plaintext)
0x50 char[0x20] Encrypted Filename
0x70 char[0x10] Encrypted IV
0x80 char[0x200] RSA Signature?
0x280 char[0x20] HMAC hash of (encrypted) first block, (Vita), key is in RIF
0x2A0 char[0x1E0] Reserved (all 0's)
0x480 char[0x20] HMAC hash of (encrypted) first block, (Android) key is in RIF
0x4A0 char[0x1E0] Reserved (all 0's)
0x680 char[until next multiple of 0x8000] encrypted block data

Decryption

AES-128-CBC decrypt 0x10 bytes from 0x70 using PSSE Header IV and PSSE Header Key the resulting decryption is the Contents IV, now take 0x10 bytes from 0x120 of the game's NoPsmDrm RIF, this is the Content Key (if its one of the DLL's in the PSM Runtime Package, then the content key is Runtime PSSE App Key)


the content data section (0x680 onwards) is made up of blocks, each 0x8000 bytes in size however the first block is only 0x7980 bytes, (0x8000 - 0x680) as if the block started at 0x00, however you start reading from 0x680 all subsequent blocks are 0x8000 bytes, so block 0 is at 0x680, block 1 at 0x8000, block 2 at 0x10000 etc, and, at every interval of 0x80000 bytes there is an 0x400 byte gap before the next block starts

(that next block is then 0x7C00 bytes long, as if the block started at 0x80000, even though it starts at 0x800400) and of course all subsequent ones are then 0x8000 past there again,

when reading each block the IV used to decrypt it changes slightly, usually just the first byte changes. to calculate the IV for any given block, take that block's number (counting sequentially from 0x800, following all above rules) as an int32, little endain, put it into a byte-array. and make that byte array be 0x10 bytes long, with the block number at the very start eg, for block 4 it would be 0x04000000000000000000000000000000 then, XOR the original IV from the PSSE Header, with that byte array,

Decrypt each block using AES-128-CBC with the content IV you calculated earlier from header + block ID and the content KEY from the rif,

to decrypt the entire file, decrypt each block in-order.

A script that implements the above algorithm can be found here: https://github.com/KuromeSan/psse-decrypt it is in the public domain, so feel free to use it for whatever you want