Sealedkey / pfsSKKey: Difference between revisions

From PS4 Developer wiki
Jump to navigation Jump to search
 
(35 intermediate revisions by 8 users not shown)
Line 1: Line 1:
This key can be found on different places and will be used for eg. SaveGame or Trophy Data decryption and encryption.
The Sealed Key is a an encrypted key used on PS Vita, PS4 and PS5 to prevent files modification and extraction. It can be found on different places in the filesystem and is used for Save Data and Trophy Data decryption and encryption.
==== Paths ====
 
See also [https://wiki.henkaku.xyz/vita/Sealedkey PS Vita Sealedkey].
 
= PS4 =
 
== Location ==
 
The sealedkey file is located in the folder of every savedata/trophies. It is not PFS encrypted.
 
{| class="wikitable"
{| class="wikitable"
|-
|-
! Kind !! Path
! Kind !! Path
|-
|-
| Trophys || /user/home/[[User ID|user Id]]/trophy/data/[[sce_trop]]/sealedkey
| Trophy || /user/home/[[User ID|User Id]]/trophy/data/[[sce_trop]]/sealedkey
|-
| Save Data (internal HDD) || /user/home/[[User ID|User Id]]/[[NP Title ID|Title ID]]/[[save data directory]]/[[sce_sys]]/
|-
|-
| SaveGames || /user/home/[[User ID|user Id]]/[[NP Title ID|title Id]]/[[save data directory]]/[[sce_sys]]/
| Save Data (USB Storage) || /PS4/SAVEDATA/[[User ID|User Id]]/[[NP Title ID|Title ID]]/<sealed_filename>.bin
|}
|}


== Structure ==
= Structure =
- size always 96 bytes
 
* Size is always 96 bytes.


{| class="wikitable"
{| class="wikitable"
|-
|-
! From !! To !! Description
! Offset !! Size !! Description !! Notes
|-
|-
| 00 || 07 || Magic ("pfsSKKey") (?playstation file system sealed key key?)
| 0 || 8 || Magic || "pfsSKKey" standing for PFS SealedKey Key
|-
|-
| 08 || 0F || Version (game=1 or version ?)
| 0x8 || 2 || [[#Keyset]] ||
|-
|-
| 10 || 1F || IV (16 bytes)
| 0xA || 6 || Padding || Zeroed
|-
|-
| 20 || 3F || Sealed Key (32 bytes)
| 0x10 || 16 || IV || AES-128-CBC IV for use with the pfsSKKey__EncKey Key
|-
|-
| 40 || 5F || SHA-256 (32 bytes)
| 0x20 || 32 || Encrypted Sealed Key ||
|-
| 0x40 || 32 || Digest || HMAC-SHA256 digest for use with the pfsSKKey__Secret Key
|}
|}


'''C'''
<source lang="c">
<source lang="c">
typedef struct {
  typedef struct {
    const char magic[8];
      const char magic[8];
    unsigned long version;
      unsigned short keyset;
    unsigned char iv[16];
      unsigned char reserved[6];
    unsigned char key[32];
      unsigned char iv[16];
    unsigned char digest[32];
      unsigned char encrypted_sealedkey[32];
} sealed_key;
      unsigned char digest[32];
  } sealed_key;
</source>
</source>


== De/En -Crypting ==
== Keyset ==
Can be decrypted by asking the OS to do it for you. You will need kernel rights to be able to ask the PS4 for it.
 
<source lang="c">
{| class="wikitable"
/* Decryption */
|-
#define USER1 10000000
! Keyset !! System Software version !! Notes
#define usb0  "/mnt/usb0/"
|-
#define usb1  "/mnt/usb1/"
| 1 || 1.01-1.73 ||
#define pfs  "decrypted_pfsSKKey.key"
|-
| 2 || 4.55 ||
typedef unsigned char byte;              /* byte defination for c/c++ */
|-
| 3 || ?4.70? ||
char usb_error = "[-] ERROR: Can't access usb0 nor usb1!\n[-] Will return now to caller.\n"
|-
char usb0path, usb1path;
| 4 || 5.05 ||
byte pfsSKKey[96];
|-
| 5 || ? ||
/* Get's the encrypted sealed key based on user id */
|-
byte get_pfsSKKey(char userID) {
| 6 || ? ||
    FILE *pfskey = fopen("/user/home/" + userID + "/trophy/data/sce_trop/sealedkey", "rb");
|-
    if (pfskey == NULL) return 0;
| 7 || ? ||
 
|-
    byte pfsSKKey[96];
| 8 || ? ||
    fread(pfsSKKey, 96, 1, pfskey);
|-
    fclose(pfskey);
| 9 || ? ||  
    return pfsSKKey;
|-
}
| 10 || ?8.00?-12.00 ||
|}
/* Dump the sealedkey. Send over tcp and save to file */
 
int dumpDecryptedSealedKey(int to) {
For example, in PS4 4.55 kernel, the function '''sceSblSsDecryptSealedKey''' checks that the keyset is less or equal 2 before calling '''sceSblSsDecryptWithPortability'''.
    if (to != 0 || to != 1) return -2;
 
== Usage ==
    byte pfsSKKey;
 
    if (sizeof((pfsSKKey = get_pfsSKKey(USER1))) != 96) {
With code execution in PS4 kernel, the sealed key can be decrypted by asking the PS4 kernel:
        knet_printf("[-] Can not load the sealed key!\n");
* with '''sceSblSsDecryptSealedKey''' (see Talk page),
        kernel.printf("[-] Can not load the sealed key!\n");
* or with '''sceSblSsDecryptWithPortability''' (reimplement '''sceSblSsDecryptSealedKey''' by reversing Kernel),
        return -1;
* or with portability master keys (see [[Vulnerabilities#%3C=_?7.55?_-_Missing_HMAC_key_length_check_in_Secure_Kernel_leading_to_Partial_SAMU_KeyRings_bruteforce]]).
    }
 
 
    /* Now decrpyt the key */
{{File Formats}}
    byte decyrpted_pfsSKKey[16];
<noinclude>[[Category:Main]]</noinclude>
    int i = kernel.sceSblSsDecryptSealedKey(pfsSKKey, decrpyted_pfsSKKey);
    knet_printf("[+] sceSblSsDecryptSealedKey returned %d\n", i);
    kernel.printf("[+] sceSblSsDecryptSealedKey returned %d\n", i); 
    /* Sending over tcp */
    if (i) {
        if (to == 0) {
            knet_printf("[+] Your decrypted sealedkey = ");
            kernel.printf("[+] Your decrypted sealedkey = "); 
            for(int x =0; x < 0x10; x++) {
                knet_printf("%02X", dec_pfsSKKey[x]);
        kernel.printf("%02X", dec_pfsSKKey[x]);
            }
            knet_printf("\n");
            kernel.printf("\n");
            return 1;
        } /* Saving to file */
        else {
            knet_printf("[+] Will try to save to file...");
            kernel.printf("[+] Will try to save to file...");
   
            usb0path = usb0 + pfs;
            usb1path = usb1 + pfs;
            FILE *dump = fopen(usb0path, "wb");
 
            if (dump == NULL) {
                dump = fopen(usb1path, "wb");
                if (dump == NULL) {
                    knet_printf("fail!\n" + usb_error);
                    kernel.printf("fail!\n" + usb_error);
                    return -3;
                }
            }
            fwrite(dec_pfsSKKey, 16, 1, dump);
            knet_printf("done!\n");
            kernel.printf("done!\n");
            fclose(dump);
            return 1;
        }
    }
    else {
        knet_printf("[+] Error!\n");
        kernel.printf("[+] Error!\n");
    }
    return -1;
}
</source>

Latest revision as of 05:04, 14 December 2024

The Sealed Key is a an encrypted key used on PS Vita, PS4 and PS5 to prevent files modification and extraction. It can be found on different places in the filesystem and is used for Save Data and Trophy Data decryption and encryption.

See also PS Vita Sealedkey.

PS4[edit | edit source]

Location[edit | edit source]

The sealedkey file is located in the folder of every savedata/trophies. It is not PFS encrypted.

Kind Path
Trophy /user/home/User Id/trophy/data/sce_trop/sealedkey
Save Data (internal HDD) /user/home/User Id/Title ID/save data directory/sce_sys/
Save Data (USB Storage) /PS4/SAVEDATA/User Id/Title ID/<sealed_filename>.bin

Structure[edit | edit source]

  • Size is always 96 bytes.
Offset Size Description Notes
0 8 Magic "pfsSKKey" standing for PFS SealedKey Key
0x8 2 #Keyset
0xA 6 Padding Zeroed
0x10 16 IV AES-128-CBC IV for use with the pfsSKKey__EncKey Key
0x20 32 Encrypted Sealed Key
0x40 32 Digest HMAC-SHA256 digest for use with the pfsSKKey__Secret Key
  typedef struct {
      const char magic[8];
      unsigned short keyset;
      unsigned char reserved[6];
      unsigned char iv[16];
      unsigned char encrypted_sealedkey[32];
      unsigned char digest[32];
  } sealed_key;

Keyset[edit | edit source]

Keyset System Software version Notes
1 1.01-1.73
2 4.55
3 ?4.70?
4 5.05
5 ?
6 ?
7 ?
8 ?
9 ?
10 ?8.00?-12.00

For example, in PS4 4.55 kernel, the function sceSblSsDecryptSealedKey checks that the keyset is less or equal 2 before calling sceSblSsDecryptWithPortability.

Usage[edit | edit source]

With code execution in PS4 kernel, the sealed key can be decrypted by asking the PS4 kernel: