Sealedkey / pfsSKKey: Difference between revisions

From PS4 Developer wiki
Jump to navigation Jump to search
mNo edit summary
No edit summary
Line 1: Line 1:
This key can be found on different places and will be used for eg. Save Data 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.


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


{| class="wikitable"
{| class="wikitable"
Line 7: Line 11:
! Kind !! Path
! Kind !! Path
|-
|-
| Trophy || /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]]/
|-
|-
| Save Data || /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 is always 96 bytes
* Size is always 96 bytes.


{| class="wikitable"
{| class="wikitable"
|-
|-
! From !! To !! Description
! Offset !! Size !! Description !! Value
|-
|-
| 00 || 07 || MAGIC ("pfsSKKey") (?playstation file system sealed key key?)
| 0 || 8 || Magic || "pfsSKKey" meaning PFS sealedkey key
|-
|-
| 08 || 09 || KeySet for getSealedKeySecret (changed beyond kernel 1.73)
| 0x8 || 2 || [[#Keyset]] ||
|-
|-
| 0A || 0F || Just 0x00 Bytes
| 0xA || 6 || Padding || Zeroed
|-
|-
| 10 || 1F || IV (16 bytes)
| 0x10 || 16 || IV ||
|-
|-
| 20 || 3F || Encrypted key (32 bytes)
| 0x20 || 32 || Encrypted Sealed Key ||
|-
|-
| 40 || 5F || SHA-256 (32 bytes)
| 0x40 || 32 || Digest || HMAC-SHA-256 ||
|}
|}


'''C'''
<source lang="c">
<source lang="c">
typedef struct sealedkey_t {
  typedef struct {
    const unsigned char MAGIC[8];
      const char magic[8];
    const unsigned char KEYSET[2]; // short
      unsigned short keyset;
    const unsigned char ALIGN0Bytes[6];
      unsigned char reserved[6];
    const unsigned char IV[16];
      unsigned char iv[16];
    const unsigned char KEY[32];
      unsigned char encrypted_sealedkey[32];
    const unsigned char SHA256[32];
      unsigned char digest[32];
} PfsSKKey;
  } sealed_key;
</source>
</source>


'''CSharp'''
== Keyset ==
<source lang="csharp">
 
protected internal struct sealedkey {
{| class="wikitable"
    internal static byte[] MAGIC = new byte[8];
|-
    internal static short KeySet;
! Keyset !! System Software version !! Notes
    internal static byte[] AlignBytes = new byte[6];
|-
    internal static byte[] IV = new byte[16];
| 1 || 1.01-1.73 ||
    internal static byte[] KEY = new byte[32];
|-
    internal static byte[] SHA256 = new byte[32];
| 2 || 4.55 ||
}
|-
</source>
| 3 || ?5.05? ||
|-
| 10 || 12.00 ||
|}
 
For example, in PS4 4.55 kernel, the function '''sceSblSsDecryptSealedKey''' checks that keyset is less or equal 2 before calling '''sceSblSsDecryptWithPortability'''.


Note: You cannot use a const byte[] definition in C#. It needs to be a static byte[].
== Usage ==


== De/En -Crypting ==
With code execution in PS4 kernel, the sealed key can be decrypted by asking the PS4 kernel.


Can be decrypted by friendly 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">
/* Decryption */
#define foreach(item, array) \
    for (int keep = 1, \
              count = 0, \
              size = sizeof(array) / sizeof*(array); \
          keep && count != size; \
          keep = !keep, count++) \
        for (item = (array) + count; keep; keep = !keep)
typedef unsigned char byte;              /* byte defination for c/c++ */
byte PFSK_IDENT[8] = "pfsSKKey";
byte VERSION[8] = "\x01\x00\x00\x00\x00\x00\x00\x00"
const char USER1 = "10000000";
const char usb0 = "/mnt/usb0/";
const char usb1 = "/mnt/usb1/";
const char pfs = "dec_pfsSK.Key";
const char home = "/user/home/";
const char tropkey = "/trophy/data/sce_trop/sealedkey";
char usb_error = "[-] ERROR: Can't access usb0 nor usb1!\n[-] Will return now to caller.\n"
char usb0path[(strlen(usb0) + strlen(pfs))];
char usb1path[strlen(usb0path)];
/* Get's the encrypted sealed key based on user id */
int get_pfsSKKey(byte *buffer, const char *userID, char path) {
    char toOpen[(strlen(home) + strlen(userID) + strlen(path))];
    sprintf(toOpen, home, userID, path)
    FILE *pfskey = fopen(toOpen, "r");
    if (!pfskey) return NULL;
 
    fread(buffer, 96, 1, pfskey);
    fclose(pfskey);
    return 1;
}
/* Dump the sealedkey. Send over tcp and save to file */
int dumpDecryptedSealedKey(int to) {
    if (to < 0 || to > 1) return -2;
    /* First load the sealedkey into a buffer */
    PfsSKKEy enc;
    if (!get_pfsSKKey(&enc, USER1, tropkey)) {
        printf("[-] Can not load the sealed key!\n");
        return -1;
    }
    /* Let's check the pfsSKKEy */
    if (enc->MAGIC == PFSK_IDENT && enc->CAT == VERSION) {
        printf("[+] Magic and version ok!\n[+] sk IV = ");
        foreach(byte *val, &enc->IV) printf("%02X", *val);
        printf("\n[+] sk KEY = ");
        foreach(byte *val, enc->KEY) printf("%02X", *val);
        printf("\n[+] sk Key-SHA256 = ");
        foreach(byte *val, sk->SHA256) printf("%02X", *val);
        printf("\n");
       
    }
    else return -4;
    /* Now decrypt it */
    byte dec[16];
    int i;
    if (!(i = kernel.sceSblSsDecryptSealedKey(&enc, &dec))) {
        printf("[-] Error!\n[-] sceSblSsDecryptSealedKey returned %d\n", i);
        return -1;
    }
    printf("[+] sceSblSsDecryptSealedKey returned %d\n", i);
    if (!to) { /* Print it out */
        printf("[+] Your decrypted sealedkey = ");
        foreach(byte *val, &dec) printf("%02X", *val);
        printf("\n");
        return 1;
    }
    else { /* Saving to file */
        printf("[+] Will try to save to file...");
   
        sprintf(usb0path, usb0, pfs);
        sprintf(usb1path, usb1, pfs);
        FILE *dump = fopen(usb0path, "w");
 
        if (!dump) {
            dump = fopen(usb1path, "w");
            if (!dump) {
                printf("fail!\n%s", usb_error);
                return -3;
            }
        }
        fwrite(&dec, 16, 1, dump);
        printf("done!\n");
        fclose(dump);
        return 1;
    }
}
</source>


{{File Formats}}
{{File Formats}}
<noinclude>[[Category:Main]]</noinclude>
<noinclude>[[Category:Main]]</noinclude>

Revision as of 03:16, 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.

PS4

Location

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

  • Size is always 96 bytes.
Offset Size Description Value
0 8 Magic "pfsSKKey" meaning PFS sealedkey key
0x8 2 #Keyset
0xA 6 Padding Zeroed
0x10 16 IV
0x20 32 Encrypted Sealed Key
0x40 32 Digest HMAC-SHA-256
  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

Keyset System Software version Notes
1 1.01-1.73
2 4.55
3 ?5.05?
10 12.00

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

Usage

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