This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

A cookie will be stored in your browser regardless of choice to prevent you being asked this question again. You will be able to change your cookie settings at any time using the link in the footer.

Thread Rating:
  • 2 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
DLC Decryption
#1
So, after finishing reverse engineering the PRX, SAVEDATA and PGD encryption/decryption processes, it's time to attempt something even harder, DLC content...
Many users have been asking if this will be supported in JPCSP, so I've finally started working hard on this and already found some interesting information concerning the formats used by the PSP.
Hopefully, soon JPCSP will have the ability of decrypting and loading DLC content through the CryptoEngine and also applying custom signing methods to expired DLC (with the proper rights, of course).
I'm starting this thread to document and share my findings so far on this subject, so, enjoy!

---------------------------------------------------------------------------------------

DLC formats:
Code:
EDAT/SPRX format:

[HEADER]
0x00: 00 50 53 50   -> .PSP
0x04: 45 44 41 54   -> EDAT
0x08: 02 00 00 00   -> License type (0x2000000 paid content -> uses rif key  / 0x0000100 free content -> uses fixed key)
0x0C: 90 00            -> Data offset                
0x0E: 01                -> Data type (0 - EDAT / 1 - SPRX)
0x0F: 01                -> Version
0x10 - 0x40            -> Content ID (e.g.: JP0700-ULJS00237_00-EXTRAMISSION0001)
0x40                      -> Name hash
0x50 - 0x58            -> NULL
0x58 - 0x80            -> Signature
0x80                      -> Header hash
[/HEADER]

0x90: [Encrypted PRX (SPRX)] / [PGD (EDATA)]

Code:
RIF format:

0x00: 00 00 00 01      -> Version
0x04: 00 00 00 02      -> License type
0x08 - 0x10               -> Account ID (e.g.: B4 1F 2C 0B DC 1B 43 31)
0x10 - 0x40               -> Content ID (e.g.: UP900-UCUS98721_00-PATAPONPSNDEMO08)
0x40                         -> Index hash
0x50                         -> Header hash
0x60: 00 00 01 1F      -> License start time
0x64: C5 16 7B D8     -> License expiration time
0x68 - 0x70               -> NULL
0x70 - 0x90               -> Signature

Code:
ACT.DAT format:

0x00: 00 00 00 01   -> Version
0x04: 00 00 00 01   -> Unknown
0x08 - 0x10            -> Account ID (e.g.: B4 1F 2C 0B DC 1B 43 31)
0x10 - 0x1010         -> Data hashes' table
0x1010 - 0x1030     -> Signature


npdrm.prx:
Code:
sceNpDrmVerifyAct(int actdat_addr) - Calls sceDdrdbHash and sceDdrdbSigvry to verify the ACT.DAT file signature.

sceNpDrmVerifyRif(int rif_addr) - Verifies the specified .RIF license file signature with extra checks by using sceOpenPSIDGetPSID and the Unique ID (hardware addresses 0xBC100090 and 0xBC100094).

sceNpDrmGetModuleKey(int sprx_addr, int unk) - Decrypts and generates a SPRX module key.
-> Algorithm:
     - First, the SPRX file signature is verified in a similar way as it is done with the licensing files.
     - A new header hash is generated using the first 0x80 bytes of data and checked against the Header Hash in the file by using sceDrmBBMacFinal2.
     - sceNpDrmGetFixedKey is then called to build a decrypting key for this module.

scePspNpDrm_driver_04618D16(int out_addr) - Calls sceOpenPSIDGetOpenPSID(out_addr, 0x1).

sceNpDrmGetContentKey(int file_addr, int actdat_addr, int rif_addr) - Calls sceNpDrmGetVersionKey(int file_addr, int actdat_addr, int rif_addr, 0).

sceNpDrmGetVersionKey(int file_addr, int actdat_addr, int rif_addr, int unk) -  Decrypts and generates an EDATA key. Verifies the .RIF file, makes a call to sceMgMemoryStick_driver_735526D6() (unknown), and uses custom algorithms and private keys to process the key generation.

sceNpDrmGetFixedKey(int file_addr, int data_addr, int type_addr) - Generates a fixed key for any kind of data (mostly used by free content).
Checks the Name Hash against a private key and then proceeds to use custom algorithms and private keys to process the key generation.

sceNpDrmEdataGetDataSize(int file_addr) - Gets a file descriptor for file_addr with IoFileMgrForKernel_13A4DEB0(file_addr, 0x4) and calls sceIoIoctl(fd, 0x41000010, 0, 0, 0, 0) to obtain the data size.

sceNpDrmRenameCheck(int file_addr) - Checks if a DRM file has been renamed.
-> Algorithm:
     - Open the file with sceIoOpen(file_addr, 0x1, 0).
     - Read the EDATA header with sceIoRead(fd, buffer, 0x80).
     - Generate a new name hash and compare it with the one in the file:
           - sceDrmBBMacInit(ctx_addr, 0x3).
           - sceDrmBBMacUpdate(ctx_addr, buffer + 0x10, 0x30).
           - strlen(filename).
           - sceDrmBBMacUpdate(ctx_addr, filename, filename_size).
           - sceDrmBBMacFinal2(ctx_addr, buffer + 0x40, private_hash).
       The new hash is generated with the Content ID and the filename and is
       checked against a private known hash.

sceNpDrmEdataSetupKey(int edat_addr) - Obtains an .edat key for decryption.
This function gets a file descriptor with IoFileMgrForKernel_13A4DEB0(file_addr, 0x4) and makes several sceIoIoctl calls.
It also verifies the edat file in a similar way as it is done with sprx. The main key decryption is processed with a call to sceNpDrmGetVersionKey. This key is later sent with another sceIoIoctl command.


sceIoIoctl commands:
Code:
// These commands are sent by some of the sceNpDrmXXX functions.
sceIoIoctl(fd, 0x41000010, 0, 0, 0, 0);   // Get DRM file size.
sceIoIoctl(fd, 0x41000006, 0, 0, 0, 0) ;  // Init DRM mode.
sceIoIoctl(fd, 0x41000005, in_addr, 0x8, out_addr, 0x90); // Unknown.
sceIoIoctl(fd, 0x41000002, in_addr, 0x4, 0, 0); // Unknown.
sceIoIoctl(fd, 0x41000001, in_addr, 0x10, 0, 0); // Send DRM AES-128bit key.


Keys:
Code:
RIF/ACT keys (sceNpDrmGetVersionKey):
byte[] rif_key = {0xDA, 0x7D, 0x4B, 0x5E, 0x49, 0x9A, 0x4F, 0x53, 0xB1, 0xC1, 0xA1, 0x4A, 0x74, 0x84, 0x44, 0x3B};
byte[] actdat_key = {0x5E, 0x06, 0xE0, 0x4F, 0xD9, 0x4A, 0x71, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
byte[] unk_key1 = {0x69, 0xB4, 0x53, 0xF2, 0xE4, 0x21, 0x89, 0x8E, 0x53, 0xE4, 0xA3, 0x5A, 0x5B, 0x91, 0x79, 0x51};
byte[] unk_key2 = {0xF0, 0x79, 0xD5, 0x19, 0x2D, 0x5D, 0xD3, 0x8C, 0xB5, 0x4B, 0x9E, 0xCD, 0xCD, 0xFD, 0xD3, 0xD7};

Free license key (sceNpDrmGetFixedKey):
byte[] fixed_key = {0x38, 0x20, 0xD0, 0x11, 0x07, 0xA3, 0xFF, 0x3E, 0x0A, 0x4C, 0x20, 0x85, 0x39, 0x10, 0xB5, 0x54};

EDAT/SPRX internal key (sceNpDrmGetModuleKey/sceNpDrmEdataSetupKey):
byte[] module_key = {0xBA, 0x87, 0xE4, 0xAB, 0x2C, 0x60, 0x5F, 0x59, 0xB8, 0x3B, 0xDB, 0xA6, 0x82, 0xFD, 0xAE, 0x14};

Rename hash (sceNpDrmRenameCheck):
byte[] rename_key = {0xEB, 0x71, 0x5D, 0xB8, 0xD3, 0x73, 0xCE, 0xA4, 0x6F, 0xE7, 0x1D, 0xCF, 0xFF, 0x63, 0xFA, 0xEA};


Signatures:
Code:
ACT.DAT/.RIF Signature:
byte[] act_rif_sig = {0x62, 0x27, 0xB0, 0x0A, 0x02, 0x85, 0x6F, 0xB0, 0x41, 0x08, 0x87, 0x67, 0x19, 0xE0, 0xA0, 0x18, 0x32, 0x91, 0xEE, 0xB9, 0x6E, 0x73, 0x6A, 0xBF, 0x81, 0xF7, 0x0E, 0xE9, 0x16, 0x1B, 0x0D, 0xDE, 0xB0, 0x26, 0x76, 0x1A, 0xFF, 0x7B, 0xC8, 0x5B};

EDAT/SPRX Signature:
byte[] edat_sprx_sig = {0x1F, 0x07, 0x2B, 0xCC, 0xC1, 0x62, 0xF2, 0xCF, 0xAE, 0xA0, 0xE7, 0xF4, 0xCD, 0xFD, 0x9C, 0xAE, 0xC6, 0xC4, 0x55, 0x21, 0x53, 0x01, 0xF4, 0xE3, 0x70, 0xC3, 0xED, 0xE2, 0xD4, 0xF5, 0xDB, 0xC3, 0xA7, 0xDE, 0x8C, 0xAA, 0xE8, 0xAD, 0x5B, 0x7D};

---------------------------------------------------------------------------------------

As you can see there's still plenty of work to do, but I think I'm on the right the track, hopefully... Tongue
Of course, all help is welcome. Wink
Reply
#2
good job
i wish i could help you but nothing to do i am student and i have no time for programming
but i want to ask you
why do you do all of that???
few people do good things and you are surly one of them
Reply
#3
If you guys aren't going to help her with something actually useful then could you not comment at all.
One more time!
Reply
#4
(09-02-2011, 09:32 AM)beanclr Wrote: If you guys aren't going to help her with something actually useful then could you not comment at all.

hi >>
this will hurt
THIS IS NOT OF YOUR BUSINESS
i have the right to comment on any post within the common........
if there is a problem hykem will tell me not you !!!
sorry again
Reply
#5
I work on this because I enjoy doing it. It's interesting to figure out more about a system's intrinsics and bring it out to everyone. Smile
Now, please avoid going off-topic. Wink
Reply
#6
(09-02-2011, 09:58 AM)shin x Wrote:
(09-02-2011, 09:32 AM)beanclr Wrote: If you guys aren't going to help her with something actually useful then could you not comment at all.
if there is a problem hykem will tell me not you !!!

(09-02-2011, 04:19 PM)Hykem Wrote: Now, please avoid going off-topic. Wink
Now will you shut up. You could have just P.M. her instead of posting the question. >_>
One more time!
Reply
#7
I said it and I ll say it again
THIS IS NOT OF YOUR BUSINESS
"shut up"????!!!!
show some respect!!!
I did not disrespect you or any body in my hole life
*
I get used on FACE BOOK
thus I wrought that Q as a comment Angry
(at least she said please!!
not like you!!)
[/color]
Reply
#8
.....Your grammar and misspelling hurts to much for me to want so to so any respect to you. Plus, how you seem to want to push tab every time you right a new sentence is puzzling me. Also don't post here again if your not gonna help. Just pm me so you wont waste anyone time.
On topic: What about having the dlc lock to my PSN account? I don't think there's away around that.
One more time!
Reply
#9
@beanclr : i think Jpcsp will have a fake PSN account or something to make that possible. Do you think the PSP generates the lock keys based on the PSN account?

I always thought the DLC for a game is like Download it on PSP -> PSP decrypts it using internal keys -> the game recognizes it.
I think it would be a hassle to encrypt the DLC with a different key based on the PSN account.

@shin x : You are still not helping anybody at all, if you want to flame do it somewhere else *SIGH*.
CPU: Intel C2D E8500 @4.2 GHZ GPU: MSI Radeon 6870 Twin Frozr II 1024MB (920/1050)
RAM: 2x2GB Corsair Dominator DDR2-1066 5-5-5-15
Reply
#10
@beanclr and andutrache: It's the ACT.DAT file that is generated with the internal OpenPSID and the unique ID (an hardware offset).
The ACT.DAT file is only needed to verify valid LICENSE files (with the .rif extension), but since we don't want to verify the files, we can just ignore this and assume all users have access to any DLC content. Wink
All we need next is to properly emulate the decryption routine, which takes place after the license verification step.
Of course, if we're talking about forging DRM data, this would require proper licensing forging. Even so, this may still be possible to emulate to some extent, but the functions used to generate the ACT.DAT file (scePcactAuth1BB and scePcactAut21BB from openpsid.prx, used by the np_inst.prx module) will need a fake PSN ID, which I'm still working on. Tongue
Reply


Forum Jump:


Users browsing this thread: 3 Guest(s)