Join Us and become a Member for a Verified Badge to access private areas with the latest PS4 PKGs.
Status
Not open for further replies.
As the PS4Scene releases even more PS4 PKG 9.00 Game Dumps this month via the pOOBs4 Exploit, following the PS4 PKG / Keys Information and his PKG_PFS_Tool: PS4 PKG / PFS / Save Games Unpacker Tool developer @flatz disclosed on Twitter a PS4 Crypto CoProcessor (CCP) Kernel Bug that allows bruteforcing key slots from the Secure Asset Management Unit (SAMU) Processor (SAMU IPL), which he details in ccp_crypto_bug.c how the AES / HMAC Keys from PFS, Portability Keys, VTRM Keys and Save Keys are retrieved before the crypto flaw was fixed between 7.55 and 9.00 firmware! šŸŽ„šŸ”„:ninja:

To recap briefly, this comes following the PS4 PFS Protection Bypass Guide, Final Fantasy XV PS4 Game Save, PS4SaveSearch Tool, PS4 Sealedkey / pfsSKKey for SaveGame & Trophy Data Decryption, PS4 IPL AES + HMAC Key Recovery Project, PSFSKKey PS4 SaveGame Decryption Tool, PS4 Game Saves Repository, Installing PS4 Saves From Other PS4's Without Save Wizard, How to Resign PS4 Saves Without Save Wizard, the PS4 9.00 Webkit Exploit, the AMD Server Vulnerabilities revealed last month, the 9.00 PS4 Payloads and PS4 9.00 Kernel Exploit allowing all PlayStation 4 consoles on PS4 OFW 9.00 or below to be jailbroken. :lovewins:

And from ccp_crypto_bug.c:
Code:
int dump_raw_keys(unsigned int* key_ids, size_t key_count, unsigned int max_key_size, uint8_t** key_data, size_t* key_data_size) {
    uint8_t* kd = NULL;
    size_t kds;
    void* buf = NULL, *m_buf = NULL;
    struct sbl_map_list_entry* d_buf = NULL;
    size_t buf_size = PAGE_SIZE;
    struct ccp_req req;
    struct ccp_msg msg;
    size_t data_size = 0x10;
    uint8_t current_key[0x40];
    uint8_t real_hash[0x20], our_hash[0x20];
    unsigned int key_index, key_size;
    uint8_t* ckd;
    unsigned int i, j;
    size_t c;
    int found;
    int ret;

    //dprintf("Allocating memory for key data buffer...\n");
    kds = (max_key_size + sizeof(int)) * key_count;
    kd = (uint8_t*)alloc(kds);
    if (!kd) {
        //dprintf("Failed.\n");
        ret = ENOMEM;
        goto error;
    }
    memset(kd, 0, kds);

    memset(&req, 0, sizeof(req));
    memset(&msg, 0, sizeof(msg));

    TAILQ_INIT(&req.msgs);
    TAILQ_INSERT_TAIL(&req.msgs, &msg, next);

    //dprintf("Allocating memory for data buffer...\n");
    buf = alloc(buf_size);
    if (!buf) {
        //dprintf("Failed.\n");
        ret = ENOMEM;
        goto error;
    }
    //dprintf("Data buffer CPU address: %p\n", buf);
    memset(buf, 0, buf_size);

    //dprintf("Filling data buffer with random data...\n");
    for (i = 0; i < data_size; ++i)
        *((uint8_t*)buf + i) = (i + 1) & 0xFF;

    //dprintf("Mapping data buffer to GPU...\n");
    ret = sceSblDriverMapPages(&m_buf, buf, BYTES_TO_PAGES(buf_size), 0x61, NULL, &d_buf);
    if (ret != 0) {
        //dprintf("Failed.\n");
        goto error;
    }
    //dprintf("Data buffer GPU address: %p (d: %p)\n", m_buf, d_buf);

    for (c = 0; c < key_count; ++c) {
        key_index = key_ids[c];
        ckd = kd + (max_key_size + sizeof(int)) * c;

        //dprintf("Bruteforcing key index: 0x%04X\n", key_index);

        memset(current_key, 0, sizeof(current_key));
        memset(real_hash, 0, sizeof(real_hash));
        memset(our_hash, 0, sizeof(our_hash));

        for (key_size = 0; key_size < max_key_size; ++key_size) {
            memset(&msg.op, 0, sizeof(msg.op));
            msg.op.hmac.cmd = 0x09034000 | CCP_USE_KEY_FROM_SLOT;
            msg.op.hmac.data_size = data_size;
            msg.op.hmac.data = buf;
            msg.op.hmac.data_size_bits = data_size * 8;
            msg.op.hmac.key_index = key_index;
            msg.op.hmac.key_size = key_size + 1;

            //dprintf("Preparing crypto request...\n");
            ret = sceSblServiceCrypt(&req);
            if (ret != 0) {
                *(int*)(ckd + max_key_size) = ret;
                //dprintf("sceSblServiceCrypt(index) failed (code: 0x%"PRIX32").\n", ret);
                //dprintf("\t0x%04X: N/A\n", key_index);
                break;
            }
            memcpy(real_hash, msg.op.hmac.hash, sizeof(real_hash));

            found = 0;
            for (i = 0; i < 256; ++i) {
                current_key[key_size] = (uint8_t)i;

                memset(&msg.op, 0, sizeof(msg.op));
                msg.op.hmac.cmd = 0x09034000;
                msg.op.hmac.data_size = data_size;
                msg.op.hmac.data = buf;
                msg.op.hmac.data_size_bits = data_size * 8;
                for (j = 0; j < (key_size + 1); ++j)
                    msg.op.hmac.key[(key_size + 1) - j - 1] = current_key[j]; /* reversed order */
                msg.op.hmac.key_size = key_size + 1;

                //dprintf("Preparing crypto request...\n");
                ret = sceSblServiceCrypt(&req);
                if (ret != 0)
                    break;
                memcpy(our_hash, msg.op.hmac.hash, sizeof(our_hash));

                if (memcmp(real_hash, our_hash, sizeof(real_hash)) == 0) {
                    current_key[key_size] = (uint8_t)i;
                    found = 1;
                    break;
                }
            }
            if (ret != 0) {
                *(int*)(ckd + max_key_size) = ret;
                //dprintf("sceSblServiceCrypt(key) failed (code: 0x%"PRIX32").\n", ret);
                break;
            }
            if (found) {
                if (key_size == max_key_size - 1) {
                    *(int*)(ckd + max_key_size) = 0;
                    for (i = 0; i < max_key_size; ++i)
                        ckd[i] = current_key[max_key_size - i - 1];
                }
            } else {
                *(int*)(ckd + max_key_size) = ESRCH;
                //dprintf("\tNOT FOUND\n");
            }
        }
    }

    ret = 0;

    if (key_data) {
        *key_data = kd;
        kd = NULL;
    }
    if (key_data_size)
        *key_data_size = kds;

error:
    if (d_buf) {
        //dprintf("Unmapping data buffer from GPU...\n");
        sceSblDriverUnmapPages(d_buf);
    }

    if (buf) {
        //dprintf("Freeing memory of data buffer...\n");
        dealloc(buf);
    }

    if (kd) {
        //dprintf("Freeing memory of key data buffer...\n");
        dealloc(kd);
    }

    return ret;
}

int dump_gen_keys(unsigned int cmd, int use_hmac, unsigned int max_key_size, unsigned int* key_ids, size_t key_count, uint8_t** key_data, size_t* key_data_size) {
    uint8_t* kd = NULL;
    size_t kds;
    void* buf = NULL, *m_buf = NULL;
    struct sbl_map_list_entry* d_buf = NULL;
    size_t buf_size = PAGE_SIZE;
    struct ccp_req req;
    struct ccp_msg msg;
    size_t data_size = 0x80;
    uint8_t current_key[0x40];
    uint8_t real_hash[0x20], our_hash[0x20];
    unsigned int key_index, key_size, key_index_mod;
    unsigned int key_handle = 0;
    union sbl_key_desc key_desc;
    uint8_t* ckd;
    unsigned int i, j;
    size_t c;
    int found;
    int ret;

    //dprintf("Allocating memory for key data buffer...\n");
    kds = (max_key_size + sizeof(int)) * key_count;
    kd = (uint8_t*)alloc(kds);
    if (!kd) {
        //dprintf("Failed.\n");
        ret = ENOMEM;
        goto error;
    }
    memset(kd, 0, kds);

    memset(&req, 0, sizeof(req));
    memset(&msg, 0, sizeof(msg));

    TAILQ_INIT(&req.msgs);
    TAILQ_INSERT_TAIL(&req.msgs, &msg, next);

    //dprintf("Allocating memory for data buffer...\n");
    buf = alloc(buf_size);
    if (!buf) {
        //dprintf("Failed.\n");
        ret = ENOMEM;
        goto error;
    }
    //dprintf("Data buffer CPU address: %p\n", buf);
    memset(buf, 0, buf_size);

    //dprintf("Filling data buffer with random data...\n");
    for (i = 0; i < data_size; ++i)
        *((uint8_t*)buf + i) = (i + 1) & 0xFF;

    //dprintf("Mapping data buffer to GPU...\n");
    ret = sceSblDriverMapPages(&m_buf, buf, BYTES_TO_PAGES(buf_size), 0x61, NULL, &d_buf);
    if (ret != 0) {
        //dprintf("Failed.\n");
        goto error;
    }
    //dprintf("Data buffer GPU address: %p (d: %p)\n", m_buf, d_buf);

    key_index_mod = use_hmac ? 0x8000 : 0;

    for (c = 0; c < key_count; ++c) {
        key_index = key_ids[c];
        ckd = kd + (max_key_size + sizeof(int)) * c;

        //dprintf("Bruteforcing key index: 0x%04X\n", key_index | key_index_mod);

        memset(&key_desc, 0, sizeof(key_desc));
        key_desc.portability.cmd = cmd;
        key_desc.portability.key_id = key_index | key_index_mod;

        key_handle = 0;
        ret = sceSblKeymgrSetKey(&key_desc, &key_handle);
        if (ret != 0) {
            *(int*)(ckd + max_key_size) = ret;
            //dprintf("sceSblKeymgrSetKey() failed (code: 0x%"PRIX32").\n", ret);
            //dprintf("\t0x%04X: N/A\n", key_index | key_index_mod);
            break;
        }

        memset(current_key, 0, sizeof(current_key));
        memset(real_hash, 0, sizeof(real_hash));
        memset(our_hash, 0, sizeof(our_hash));

        for (key_size = 0; key_size < max_key_size; ++key_size) {
            memset(&msg.op, 0, sizeof(msg.op));
            msg.op.hmac.cmd = 0x09034000 | CCP_USE_KEY_HANDLE;
            msg.op.hmac.data_size = data_size;
            msg.op.hmac.data = buf;
            msg.op.hmac.data_size_bits = data_size * 8;
            msg.op.hmac.key_index = key_handle;
            msg.op.hmac.key_size = key_size + 1;

            //dprintf("Preparing crypto request...\n");
            ret = sceSblServiceCrypt(&req);
            if (ret != 0) {
                *(int*)(ckd + max_key_size) = ret;
                //dprintf("sceSblServiceCrypt(index) failed (code: 0x%"PRIX32").\n", ret);
                //dprintf("\t0x%04X: N/A\n", key_index | key_index_mod);
                break;
            }
            memcpy(real_hash, msg.op.hmac.hash, sizeof(real_hash));

            found = 0;
            for (i = 0; i < 256; ++i) {
                current_key[key_size] = (uint8_t)i;

                memset(&msg.op, 0, sizeof(msg.op));
                msg.op.hmac.cmd = 0x09034000;
                msg.op.hmac.data_size = data_size;
                msg.op.hmac.data = buf;
                msg.op.hmac.data_size_bits = data_size * 8;
                for (j = 0; j < (key_size + 1); ++j)
                    msg.op.hmac.key[(key_size + 1) - j - 1] = current_key[j]; /* reversed order */
                msg.op.hmac.key_size = key_size + 1;

                //dprintf("Preparing crypto request...\n");
                ret = sceSblServiceCrypt(&req);
                if (ret != 0)
                    break;
                memcpy(our_hash, msg.op.hmac.hash, sizeof(our_hash));

                if (memcmp(real_hash, our_hash, sizeof(real_hash)) == 0) {
                    current_key[key_size] = (uint8_t)i;
                    found = 1;
                    break;
                }
            }
            if (ret != 0) {
                *(int*)(ckd + max_key_size) = ret;
                //dprintf("sceSblServiceCrypt(key) failed (code: 0x%"PRIX32").\n", ret);
                //dprintf("\t0x%04X: N/A\n", key_index);
                break;
            }
            if (found) {
                if (key_size == max_key_size - 1) {
                    *(int*)(ckd + max_key_size) = 0;
                    for (i = 0; i < max_key_size; ++i)
                        ckd[i] = current_key[max_key_size - i - 1];
                }
            } else {
                *(int*)(ckd + max_key_size) = ESRCH;
                //dprintf("\tNOT FOUND\n");
            }
        }

        if (key_handle) {
            ret = sceSblKeymgrClearKey(key_handle);
            if (ret != 0) {
                *(int*)(ckd + max_key_size) = ret;
                //dprintf("sceSblKeymgrClearKey() failed (code: 0x%"PRIX32").\n", ret);
                //dprintf("\t0x%04X: N/A\n", key_index);
                break;
            }
        }
    }

    ret = 0;

    if (key_data) {
        *key_data = kd;
        kd = NULL;
    }
    if (key_data_size)
        *key_data_size = kds;

error:
    if (d_buf) {
        //dprintf("Unmapping data buffer from GPU...\n");
        sceSblDriverUnmapPages(d_buf);
    }

    if (buf) {
        //dprintf("Freeing memory of data buffer...\n");
        dealloc(buf);
    }

    if (kd) {
        //dprintf("Freeing memory of key data buffer...\n");
        dealloc(kd);
    }

    return ret;
}

Spoiler: Related Tweets

Decided to create a repo that specializes in decryption of retail ps4 eap hdd partitions:
Credits to @rajeshca911 (Twitter) for supplying the ps4 pro dumps in order to test this.

Note that if your ps4 is a phat 1000 or 1100 model, IVOFFSET will work as 0.
Spoiler: Additional Tweets

PS4 Crypto CoProcessor (CCP) Bug on SAMU Key Slots for Save Keys & More!.jpg
 

Comments

These are part of the reasons not to be tempted to update the firmware, as in the ps5, it is possible that "things" that sony has patched come out.
 
is this the thing kept by savewizard team? they know something cannot fixed and keep updating or they really stop with the "Compatible with System Software 8.52" waiting for the update of cheat and save for the 9.00 offline mode with auto usb check
 
Status
Not open for further replies.
Back
Top