Title Updates

From Vita Development Wiki
Jump to navigation Jump to search

Title update downloads are no longer as easy on on PS3. For PSVita title updates, the following path structure is used:


  • NETWORK can be np, sp-int, prod-qa, rc, or e1-np.
  • TITLEID is the TitleId of the app. For example: PCSA00007.
  • HASH is a secret calculated hash based on the below algorithm:

int main(void) {
        char network[0x10];
        char titleid[0x10];
        // Secret HMAC key found in shell.self
        unsigned char key[0x20] = {0x9A, 0x9D, 0x07, 0xD5, 0x61, 0x9C, 0x3F, 0xFD, 0xDF, 0xF7, 0x58, 0xE3, 0xFC, 0x86, 0xC4, 0xB7,
                                   0x79, 0xFD, 0x63, 0x2D, 0x8D, 0xD4, 0x22, 0x54, 0x35, 0xC2, 0xE6, 0x2B, 0x2F, 0x4A, 0x2E, 0x6B };
        char uniqdata[0x20];
        int i, res;
        unsigned char result[0x20];

        memset(network, 0, 0x10);
        memset(uniqdata, 0, 0x20);
        memset(result, 0, 0x20);
        memset(titleid, 0, 0x10);

        printf("Enter network name (np, prod-qa, sp-int, rc, e1-np):"); scanf_s("%s", network, 0x10);
        printf("Enter titleid:"); scanf_s("%s", titleid, 0x10);
        sprintf_s(uniqdata, 0x20, "%s_%s", network, titleid);
        // Lovely obfuscation
        for(i=0; i<0x20; i++)
		key[i] ^= 0x7F;
        hmac_sha256(key, 0x20, uniqdata, strlen(uniqdata), result);
        printf("https://gs-sec.ww.%s.dl.playstation.net/pl/%s/%s/", network, network, titleid);
        for(i=0; i<0x20; i++) {
		printf("%02x", result[i]);
        printf("/%s-ver.xml\n", titleid);
        // printf("%s\n", orig);
        return 0;

The hmac_sha256 function is not normal either. The made a couple of error or tweaks so it was not standard. Below is their hmac_sha256 function.

 * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104)
 * @key: Key for HMAC operations
 * @key_len: Length of the key in bytes
 * @num_elem: Number of elements in the data vector
 * @addr: Pointers to the data areas
 * @len: Lengths of the data blocks
 * @mac: Buffer for the hash (32 bytes)
void hmac_sha256_vector( u8 *key, size_t key_len, size_t num_elem,
             u8 *addr[],  size_t *len, u8 *mac)
    unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
    unsigned char tk[32];
     u8 *_addr[6];
    size_t _len[6], i;
    if (num_elem > 5) {
         * Fixed limit on the number of fragments to avoid having to
         * allocate memory (which could fail).
        /* if key is longer than 64 bytes reset it to key = SHA256(key) */
        if (key_len > 64) {
        sha256_vector(1, &key, &key_len, tk);
        key = tk;
        key_len = 32;
    /* the HMAC_SHA256 transform looks like:
     * SHA256(K XOR opad, SHA256(K XOR ipad, text))
     * where K is an n byte key
     * ipad is the byte 0x36 repeated 64 times
     * opad is the byte 0x5c repeated 64 times
     * and text is the data being protected */
    /* start out by storing key in ipad */
    memset(k_pad, 0, sizeof(k_pad));
    memcpy(k_pad, key, key_len);
    /* XOR key with ipad values */
    for (i = 0; i < 64; i++)
        k_pad[i] ^= 0x36;

    /* perform inner SHA256 */
    _addr[0] = k_pad;
    _len[0] = 64;
    for (i = 0; i < num_elem; i++) {
        _addr[i + 1] = addr[i];
        _len[i + 1] = len[i];
    sha256_vector(1 + num_elem, _addr, _len, mac);
		// NOTE: SCE HACK - they removed the clearing of the pad in their version.
    //memset(k_pad, 0, sizeof(k_pad));
    //memcpy(k_pad, key, key_len);
    /* XOR key with opad values */
    for (i = 0; i < 64; i++)
    		// NOTE: SCE HACK - they changed the normal 0x5C value to 0x6A
        k_pad[i] ^= 0x6A;
    /* perform outer SHA256 */
    _addr[0] = k_pad;
    _len[0] = 64;
    _addr[1] = mac;
    _len[1] = SHA256_MAC_LEN;
    sha256_vector(2, _addr, _len, mac);