SBORPS Random Fact 04

August 16th, 2008 silverspring

SCE media reports have always stated that the PSP has AES capabilities. These are apparently referring to the fact that the UMD format discs are AES encrypted. This means that SPOCK (the crypto engine responsible for UMD decryption) has AES decryption capabilities. KIRK on the other hand (the main crypto engine responsible for prx/eboot decryption) also has a block cipher but is unknown which algorithm it uses, though it is almost certainly AES as well. Currently what is known about the cipher is that it is:

  • a block cipher operating in CBC mode
  • an all zero 128-bit initialization vector
  • 128-bit block and key sizes
  • cmd4/7 uses a static key that is identical in all PSP’s
  • cmd5/8 uses a key based off the fuseID making all operations unique per PSP
  • cmd6/9 uses a user-defined 128-bit key
  • cmd1/2/3 uses the block cipher but also signature algorithms
  • the remaining KIRK cmd’s do not use the block cipher (sig, hash, & prng algo’s)

Interfacing with KIRK for general-purpose encryption is cumbersome and using a software-based lib is both slow and memory-consuming. Fortunately, there is another method: using the MagicGate hardware. The API provides both standard DES and AES algorithms.

  • 0x2DAD213D sceMgrDESEncrypt
  • 0xF5DFD97B sceMgrDESDecrypt
  • 0x8A916574 sceMgrAESEncrypt
  • 0x3054F8F1 sceMgrAESDecrypt

The prototypes are as follows:

C:
  1. /*
  2. dst:  output buffer
  3. src:  input buffer
  4. size: input size
  5. key:  encryption/decryption key (64-bit for DES, 128-bit for AES)
  6. iv:   initialization vector for CBC mode (pass NULL for ECB mode) (64-bit for DES, 128-bit for AES)
  7. */
  8. int sceMgrDESEncrypt(u8 *dst, u8 *src, int size, u8 *key, u8 *iv);
  9. int sceMgrDESDecrypt(u8 *dst, u8 *src, int size, u8 *key, u8 *iv);
  10. int sceMgrAESEncrypt(u8 *dst, u8 *src, int size, u8 *key, u8 *iv);
  11. int sceMgrAESDecrypt(u8 *dst, u8 *src, int size, u8 *key, u8 *iv);

sceHVAuth_Library

June 20th, 2008 silverspring

Some new nids:

  • 0x5e335df6 sceHVAuthOpen
  • 0x816a5f92 sceHVAuthAuth
  • 0x9db7de7c sceHVAuthClose

The sceHVAuth lib seems to be used for proxy config settings for the Html Viewer.

C:
  1. /*
  2. Creates an 80 char alphanumeric password
  3. (randomly generated via a time-seeded Mersenne Twister)
  4. */
  5. int sceHVAuthOpen(char *pass);
  6.  
  7. /*
  8. Verifies the password.
  9. hmac is 20-Byte SHA1 HMAC in ascii format
  10. */
  11. int sceHVAuthAuth(char *pass, const char *hmac);
  12.  
  13. /*
  14. Clears the password
  15. */
  16. int sceHVAuthClose(char *pass);

NAND set_encryption_seed NID (last remaining sceNand nid)

April 11th, 2008 silverspring

Sometimes it’s the most obvious names that are the hardest to guess (as was also the case with sceSysconBatteryReadNVM):

0x0BEE8F36 sceNandSetScramble

That finally completes the sceNand lib !!

This is used to set the encryption seed for lfat decryption (on 3.00+) and for idstorage (on slim). After correctly setting the seed, all (per-page) reads to the nand will be read decrypted (otherwise raw reads to the nand will just return rubbish).

So, how to calculate the correct seed? For slim idstorage area it is pretty straightforward:

C:
  1. u32 magic;
  2. u32 buf[4];
  3. u32 sha[5];
  4.  
  5. buf[0] = *(vu32*)(0xBC100090);
  6. buf[1] = *(vu32*)(0xBC100094);
  7. buf[2] = *(vu32*)(0xBC100090)<<1;
  8. buf[3] = 0xD41D8CD9;
  9.  
  10. sceKernelUtilsSha1Digest((u8*)buf, sizeof(buf), (u8*)sha);
  11.  
  12. magic = (sha[0] ^ sha[3]) + sha[2];
  13.  
  14. sceNandSetScramble(magic);

The 64bits stored at hardware register 0xBC100090 is unique for every psp (it is some sort of id or serial). Hence why nand dumps are also unique between psps (for 3.00 onwards).

For lfat area, things get slightly more complicated to derive the correct seed however is still based on the unique 0xBC100090 register. Maybe will come later then we’ll finally have a logical restore for slims (instead of a relatively dangerous physical restore).

UMD Firmware Version checker

April 2nd, 2008 silverspring

Here’s a quick & dirty sample to dump some info regarding your UMD Firmware.

http://silverspring.lan.st/umd_ver_check.rar

It’s a 3.xx app (source included), works on both slim & fat.

Will dump a file called umd.bin into root of MS.

In it will say something like:

SCEI UMD ROM DRIVE 1.090 Oct18 ,2004

Your UMD FW version will be at least 1.090 or above unless you have an early batch 1.00 JP model AND you have never used an official SCE updater (note: downgrading your normal psp fw version wont downgrade the umd fw version – so downgrading back to 1.00 wont work).

For another reference, here is one from pretty recent JP slim (came with 3.72):

SCEI UMD ROM DRIVE 1.240 Nov10 ,2006

Also there are a few numbers before this string appears but I couldnt figure out what they represented.

EDIT:

Ok, so the data is just in the standard ATAPI INQUIRY data format.

So:
- the drive reports to the host as a “CDROM Device” (0×5 in the Device Type field).
- that the medium is removable (RMB bit set to 1).
- is not standard in either ANSI/ECMA/ISO (all set to 0)
- Response Data Format (2)
- ATAPI Transport Version (3)
- Vendor ID is “SCEI”
- Product ID is “UMD ROM DRIVE”
- a blank Product Revision Level
- Vendor Specific info “1.240 Nov10 ,2006″

3.80 and Pandora

December 19th, 2007 silverspring

Well it looks like SCE have finally learned and have now removed the functions to read/write to the battery eeprom in 3.80 (they also took out the sceSysconBatteryAuth function too). So you can’t make a magic battery with 3.80, but nevermind, the hardware to do so is still there.

Here’s a compatible replacement:

C:
  1. int write_eeprom(u8 addr, u16 data)
  2. {
  3.     int res;
  4.     u8 param[0×60];
  5.  
  6.     if (addr>0x7F)
  7.         return(0×80000102);
  8.  
  9.     param[0x0C] = 0×73; // write battery eeprom command
  10.     param[0x0D] = 5; // tx packet length
  11.  
  12.     // tx data
  13.     param[0x0E] = addr;
  14.     param[0x0F] = data;
  15.     param[0×10] = data>>8;
  16.  
  17.     res = sceSysconCmdExec(param, 0);
  18.  
  19.     if (res<0)
  20.         return(res);
  21.  
  22.     return 0;
  23. }
  24.  
  25. int read_eeprom(u8 addr)
  26. {
  27.     int res;
  28.     u8 param[0×60];
  29.  
  30.     if (addr>0x7F)
  31.         return(0×80000102);
  32.  
  33.     param[0x0C] = 0×74; // read battery eeprom command
  34.     param[0x0D] = 3; // tx packet length
  35.  
  36.     // tx data
  37.     param[0x0E] = addr;
  38.  
  39.     res = sceSysconCmdExec(param, 0);
  40.  
  41.     if (res<0)
  42.         return(res);
  43.  
  44.     // rx data
  45.     return((param[0×21]<<8) | param[0×20]);
  46. }

EDIT:
Finally cracked the real names:

0x68ef0bef sceSysconBatteryReadNVM
0x1165c864 sceSysconBatteryWriteNVM

Idstorage Keys (0×0004-0×0008) – Generating hash

November 5th, 2007 silverspring

The idstorage area stores low level info on the PSP. Keys 4-8 are used for config data for various components (the battery, clock generator, LCD, etc.) and are in a different format to all the other keys.

Here is the code to generate the hash for these particular keys:

C:
  1. /*
  2. Idstorage Leaf Hash Gen Sample – SilverSpring 2007
  3.  
  4. The idstorage area stores low level info on the PSP.
  5. Keys 4-8 are used for config data for various components
  6. (the battery, clock generator, LCD, etc.)
  7. and are in a different format to all the other keys.
  8.  
  9. Specifically the format is as follows:
  10.  
  11. typedef struct
  12. {
  13.     u32 signature;
  14.     int type;
  15.     int datalen;
  16.     u32 hash;
  17.     u8 databuf[0x1F0];
  18.  
  19. } SceIdStorageLeaf;
  20.  
  21. Here’s the code to regenerate the hash for those keys.
  22. */
  23.  
  24. #include <stdio.h>
  25.  
  26. #define POLY (0xEDB88320)
  27.  
  28. #define LEAF_0x0004_HASH    (0x1FAB01BB)
  29. #define LEAF_DATA_SIZE  (0x1F0)
  30.  
  31. unsigned int gen_hash(unsigned int seed, unsigned char buf[], int size);
  32. void gen_table(void);
  33.  
  34.  
  35. unsigned int table[256];
  36.  
  37.  
  38. unsigned char leaf_0x0004_data[LEAF_DATA_SIZE] =
  39. {
  40.     0xD8, 0×00, 0×24, 0×00, 0×14, 0×31, 0×14, 0×00, 0×94, 0×01, 0×48, 0×00, 0xD8, 0×00, 0×00, 0×00,
  41.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  42.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  43.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  44.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  45.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  46.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  47.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  48.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  49.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  50.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  51.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  52.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  53.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  54.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  55.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  56.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  57.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  58.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  59.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  60.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  61.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  62.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  63.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  64.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  65.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  66.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  67.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  68.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  69.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  70.     0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  71. };
  72.  
  73.  
  74. int main()
  75. {
  76.     unsigned int hash;
  77.  
  78.     gen_table();
  79.     hash = gen_hash(0xFFFFFFFF, leaf_0x0004_data, LEAF_DATA_SIZE);
  80.  
  81.     if (hash != LEAF_0x0004_HASH)
  82.         printf("error: hash not match \n");
  83.  
  84.     printf("leaf_0x0004 hash: 0x%08X", hash);
  85.  
  86.     return 0;
  87. }
  88.  
  89.  
  90. unsigned int gen_hash(unsigned int seed, unsigned char buf[], int size)
  91. {
  92.     unsigned int hash = ~seed;
  93.     unsigned char index;
  94.     int i;
  95.  
  96.     for (i=0; i!=size; i++)
  97.     {
  98.         index = buf[i] ^ hash;
  99.         hash>>= 8;
  100.         hash ^= table[index];
  101.     }
  102.  
  103.     return(~hash);
  104. }
  105.  
  106. void gen_table(void)
  107. {
  108.     unsigned int i, j, x;
  109.  
  110.     for (i=0; i<256; i++)
  111.     {
  112.         x = i;
  113.  
  114.         for (j=0; j<8; j++)
  115.         {
  116.             if (x & 1)
  117.                 x = (x>>1) ^ POLY;
  118.             else
  119.                 x = (x>>1);
  120.         }
  121.  
  122.         table[i] = x;
  123.     }
  124. }

Note: this is a PC app (though you could run it on the PSP as well if you wanted).

IPL Decrypt Sample (direct HW access)

October 9th, 2007 silverspring

Since this place is pretty bare right now here’s a quick sample I wrote up demonstrating how to access the KIRK crypto engine directly to do your decryption. Doing raw hardware access means you dont need to access any of the SCE crypto API’s such as the semaphore lib (memlmd.prx).This is useful for the future since no matter how much SCE change the libs, nids, etc. The HW remains the same so it will work in all future firmwares (until new PSP motherboards are developed). Might be useful to add to PSARDUMPER since PSARDUMPER still rely on the SCE crypto libs and SCE may change the nids in the future and other stupid stuff like that.

To use just place an encrypted IPL as enc_ipl.bin in the MS root. It’ll decrypt it and save as it dec_ipl.bin.

NOTE: the same decryption routine can also decrypt prx’s, though they need to be setup first before being passed to the crypto engine (ie. the prx header needs to be descrambled with its decryption key first). I might write up a quick sample to do that later.

Anyway, enjoy and I hope you’ll find this useful…

EDIT: this is for 1.50 Kernel

Download link: IPL Decrypt Sample (direct HW access)


Admin note: The issue with the captcha not working has been fixed. Sorry for any inconvenience caused. -EvilSeph