EmuNewz Network

Full Version: PGD Decryption
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
So, after all this time without reporting or commiting anything, I'm finally back from my newest journey accross the algorithmic processes of the PSP with some exciting news. Tongue

This thread, in similarity to the SAVEDATA one, shall be used to openly discuss any findings on this particular encryption mechanism, which has been seen so far in "Kingdom Hearts: Birth by Sleep" to protect huge data files.

Ok, so, even though I sill haven't finished reversed the algorithm entirely, I can now (after almost a month Dodgy) post my first sucessful results with this. Here we go:

-----------------------------------------------------------------------------------
PGD Encryption -> DRM Encryption -> DNAS Encryption:
Apparently, this is a custom cipher based encryption format implemented by Sony in the latest firmware's.
Although it's not really much secure, it sure needs a lot of time to be fully reversed as it involves interaction from several modules.
Besides, for this particular format (PGD), Sony decided to use module loading based exports instead of direct function calls, which make it even harder to trace down.

Modules:
-> amctrl.prx - Holds the main algorithm behind the PGD encryption/decryption process. This algo is identical to the one used in SAVEDATA enc/dec, but it uses a different set of keys and seeds.

[Functions]:
sceDrmBBMacInit - identical to sceSdSetIndex.
sceDrmBBMacUpdate - identical to sceSdRemoveValue.
sceDrmBBMacFinal - identical to sceSdGetIndex.
sceDrmBBMacFinal2.
sceAmctrl_driver_9227EA79 - sema version of sceDrmBBMacUpdate.
sceDrmBBCipherInit - identical to sceSdCreateList.
sceDrmBBCipherUpdate - identical to sceSdSetMember.
sceDrmBBCipherFinal - identical to sceChnnlsv_21BE78B4.
sceAmctrl_driver_E04ADD4C - sema version of sceDrmBBCipherUpdate.

[Keys]:
Code:
KEY1 = {0x9C, 0x48, 0xB6, 0x28, 0x40, 0xE6, 0x53, 0x3F, 0x05, 0x11, 0x3A, 0x4E, 0x65, 0xE6, 0x3A, 0x64};
KEY2 = {0x70, 0xB4, 0x7B, 0xC0, 0xA1, 0x4B, 0xDA, 0xD6, 0xE0, 0x10, 0x14, 0xED, 0x72, 0x7C, 0x53, 0x4C};
KEY3 = {0xE3, 0x50, 0xED, 0x1D, 0x91, 0x0A, 0x1F, 0xD0, 0x29, 0xBB, 0x1C, 0x3E, 0xF3, 0x40, 0x77, 0xFB};
KEY4 = {0x13, 0x5F, 0xA4, 0x7C, 0xAB, 0x39, 0x5B, 0xA4, 0x76, 0xB8, 0xCC, 0xA9, 0x8F, 0x3A, 0x04, 0x45};
KEY5 = {0x67, 0x8D, 0x7F, 0xA3, 0x2A, 0x9C, 0xA0, 0xD1, 0x50, 0x8A, 0xD8, 0x38, 0x5E, 0x4B, 0x01, 0x7E};

-> iofilemgr_dnas.prx - Has no user functions and can only be started (by module_start) or stopped (by module_stop). Acts as the main gateway between iofilemgr.prx and amctrl.prx, since all it does is calling DRM functions accordingly. In order to boot this module, the kernel function IoFileMgrForKernel_B2C5D86F from iofilemgr.prx has to be called, which seems to happen when a file is opened with the flag 0x40000000.
Operates solely based on semaphores, which are responsible for calling exports located in the PRX data.

-> psheet.prx - Debug module used for developing DRM packages. This module contains all the functions resposible for building and encrypting DRM based packages from the original source, which can be used to build PGD packages or NPDRM/DLC content from PRXs.
This module also has calls to mesg_led_02g.prx, which seems to confirm
that it also handles PRX formats.

[Functions]:
sceDRMInstallInit - sets up the initial DRM params.
sceDRMInstallGetPkgInfo - determines what kind of package it is, based on hash comparison.
sceDRMInstallGetFileInfo - determines what kind of file it is, based on hash comparison.
sceDRMInstallInstall - encrypts the data and outputs the package in the specified format.
sceDRMInstallEnd - cleans up the internal param struct.
scePsheet_3BA93CFA - unknown, just waits and signals a semaphore.
sceDRMInstallAbort - stops the encryption process.

[MESG LED Tags]:
Code:
0xE92410F0 - drmkeys_6XX_1
0x692810F0 - drmkeys_6XX_2

[MESG LED Keys]:
Code:
drmkeys_6XX_1 = {0x36, 0xEF, 0x82, 0x4E, 0x74, 0xFB, 0x17, 0x5B, 0x14, 0x14, 0x05, 0xF3, 0xB3, 0x8A, 0x76, 0x18};
drmkeys_6XX_2 = {0x21, 0x52, 0x5D, 0x76, 0xF6, 0x81, 0x0F, 0x15, 0x2F, 0x4A, 0x40, 0x89, 0x63, 0xA0, 0x10, 0x55};

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

Based on this, I was finally able to decrypt the first portion of a PGD file, which is it's first relocated header at 0x30. Once decrypted, it contains another hash, 4 data fields that are checked internally (one of them always needs to be 0x400) and null padding. Big Grin
Of course, the whole file has much more relocations going around, but atleast it's a start, considering the mess this algo is... Tongue
Great job, congratulations! Wink
There are several other games (Ghost of Sparta f.e.) that have only small PGD files. I could then compare the output vs. the ones from the Connector Big Grin
(03-06-2011 07:13 AM)Darth1701 Wrote: [ -> ]There are several other games (Ghost of Sparta f.e.) that have only small PGD files. I could then compare the output vs. the ones from the Connector Big Grin

Hmm...
I wasn't aware of this! Thanks, Darth! Big Grin
(03-06-2011 07:13 AM)Darth1701 Wrote: [ -> ]There are several other games (Ghost of Sparta f.e.) that have only small PGD files. I could then compare the output vs. the ones from the Connector Big Grin
Are you interested in PGD of the GOW: Ghost of Sparta, eh.Tongue
Glad I got my PSP.Smile
I will not have to copy that file every time,for a new rev,now,right.
Great work Hykem.
Thanks to Darth's help, I was finally able to decrypt and reverse the necessary parts of the PGD header struct which, in turn, allowed to sucessfully decrypt most of the known existing PGD files. Wink

-----------------------------------------------------------------------------------
[PGD File header]:
Code:
0x00: 00 50 47 44 01 00 00 00 01 00 00 00 00 00 00 00 -> " PGD" and three bit fields that act as flags for version and encryption mode.
0x10: AES-128 bit hash key used for header decryption.
0x20: Generated hash from the 0x10 key.
0x30 - 0x50: Encrypted header of the PGD which when decrypted reveals a new hash key and four bit fields. The first is NULL, the second represents the decrypted data size, the third is the decrypting chunk size and the fourth is the data hash address.
0x60: File hash.
0x70: Hash generated from the sceIoIoctl key.
0x80: Encrypted hash generated from the sceIoIoctl key.
0x90: Data hash.
0xA0: Encrypted data hash.
-----------------------------------------------------------------------------------

By using the hash key obtained at 0x30 and decrypting the whole file again, starting at 0x90 this time, it's now possible to obtain the original plain binary file. This works great for smaller files, but for huge files, like in KHBBS case, Java needs to work with streams to avoid running out of heap.
I'll commit all this for now in order to be tested with the other games that make a less important usage of these files, but I'm still working on integrating a read/write decryption that works by chunks for the big data files.

Enjoy! Big Grin
(03-06-2011 09:17 PM)Hykem Wrote: [ -> ]Thanks to Darth's help, I was finally able to decrypt and reverse the necessary parts of the PGD header struct which, in turn, allowed to sucessfully decrypt most of the known existing PGD files. Wink

-----------------------------------------------------------------------------------
[PGD File header]:
Code:
0x00: 00 50 47 44 01 00 00 00 01 00 00 00 00 00 00 00 -> " PGD" and three bit fields that act as flags for version and encryption mode.
0x10: AES-128 bit hash key used for header decryption.
0x20: Generated hash from the 0x10 key.
0x30 - 0x50: Encrypted header of the PGD which when decrypted reveals a new hash key and four bit fields. The first is NULL, the second represents the decrypted data size, the third is the decrypting chunk size and the fourth is the data hash address.
0x60: File hash.
0x70: Hash generated from the sceIoIoctl key.
0x80: Encrypted hash generated from the sceIoIoctl key.
0x90: Data hash.
0xA0: Encrypted data hash.
-----------------------------------------------------------------------------------

By using the hash key obtained at 0x30 and decrypting the whole file again, starting at 0x90 this time, it's now possible to obtain the original plain binary file. This works great for smaller files, but for huge files, like in KHBBS case, Java needs to work with streams to avoid running out of heap.
I'll commit all this for now in order to be tested with the other games that make a less important usage of these files, but I'm still working on integrating a read/write decryption that works by chunks for the big data files.

Enjoy! Big Grin

You're great man... ;-)
Reference URL's