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:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Savedata Encryption/Decryption
#61
(10-11-2013, 01:43 AM)popsdeco Wrote: Hi hykem;

Sorry to have made you come here, but I'm glad that there are some opportunities to complete stuff.
So, I checked current SAVEDATA.java and I'm sure https://github.com/cielavenir/psp-saveda...ecrypter.c 's encryption is OK, but the hash isn't proper.
# Cleaning up the code will come later.

if inbuf is decrypted save file,
EncryptSavedata(inbuf, size, key);
fwrite(inbuf,1,size+0x10,stdout);
UpdateSavedataHashes(param,inbuf,size+0x10);
is OK?

You say "You need to add PSF file parsing", but I'm already able to search for SAVEFILE_PARAMS.
Since this is mostly for searching savedata exploit, passing param to UpdateSavedataHashes() is mandatory here. So I suppose this is enough, but... calculated hash for already-encrypted-bin isn't the same as the one in PARAM.SFO...

Hi popsdeco!
What I mean with PSF file parsing is that you also need to search for SAVEDATA_FILE_LIST. This is the part of PARAM.SFO that has the SAVEDATA file name and the file key written.
Each time the encryption finishes it returns a hash that needs to be written in the PARAM.SFO.
So, in SAVEDATA_PARAMS you have the mode flags (0x01, 0x21 or 0x41) and 3 hashes (one at 0x10, another at 0x20 and another at 0x70). Then, in SAVEDATA_FILE_LIST you have the save file name (ULUSXXXXX for example) and the encryption key right after it (offset 0x0D). This key is replaced by the SAVEDATA encryption hash and is later checked by the PSP.

In JPCSP this is happening in SceUtilitySavedataParam (https://code.google.com/p/jpcsp/source/b...Param.java ) in the function writePsf.

The process in JPCSP is:
-> Encrypt the data (EncryptSavedata());
-> Save the hash generated by the encryption (hleSdGetLastIndex(ctx1, hash, key) in EncryptSavedata());
-> Write the encrypted file (in SceUtilitySavedataParam.writeEncryptedFile());
-> Use the encrypted file for hash generation (in UpdateSavedataHashes());
-> Apply the hash generation algorithm and write 3 new hashes at 0x10, 0x20 and 0x70 of the PARAM.SFO SAVEDATA_PARAMS structure (in UpdateSavedataHashes());
-> Write the saved hash in SAVEDATA_FILE_LIST right after the SAVEDATA file name (in SceUtilitySavedataParam.writePsf()).

The hashes will always be different every time you re-encrypt the data (different saves in the same game always have different hashes), but they should be all related to the SAVEDATA binary file.
Your tool is already doing everything right, all that's left is that hash generated after the save file name in PARAM.SFO.
Reply
#62
(10-12-2013, 07:53 PM)Hykem Wrote: The hashes will always be different every time you re-encrypt the data (different saves in the same game always have different hashes), but they should be all related to the SAVEDATA binary file.
Your tool is already doing everything right, all that's left is that hash generated after the save file name in PARAM.SFO.
I have added SAVEDATA_FILE_LIST handling ( https://github.com/cielavenir/psp-saveda...e57e01828c ), but PSP still refuse the encryption.

As I said before, jpcsp r3404 generates 0bytes of PARAM.SFO, so I cannot test it at all.
Reply
#63
(10-13-2013, 06:56 AM)popsdeco Wrote:
(10-12-2013, 07:53 PM)Hykem Wrote: The hashes will always be different every time you re-encrypt the data (different saves in the same game always have different hashes), but they should be all related to the SAVEDATA binary file.
Your tool is already doing everything right, all that's left is that hash generated after the save file name in PARAM.SFO.
I have added SAVEDATA_FILE_LIST handling ( https://github.com/cielavenir/psp-saveda...e57e01828c ), but PSP still refuse the encryption.

As I said before, jpcsp r3404 generates 0bytes of PARAM.SFO, so I cannot test it at all.

That's odd, I've tried loading and saving SAVEDATA for a couple games in JPCSP and PARAM.SFO is being written correctly.
Could you please tell me which game or demo you're testing with JPCSP? That should help figuring out why the file shows up empty.
Reply
#64
OK I'll test later. But are you running JPCSP in crypto mode?

Anyway do you have any more comments for my change?
Reply
#65
I just want to add that I also have the 0 bytes PARAM.SFO problem with the game Persona 3 Portable (ULUS10512). I can load my old saves just fine, but then when I try to save to a different slot, the PARAM.SFO file is empy although all the other files in the folder seem to be created correctly. JPCSP crashes when I try to load the save with the empty PARAM.SFO file.
Reply
#66
Thank you popsdeco and Itaru for testing. Smile
JPCSP should now be able to create and update PARAM.SFO files properly and I've also fixed the issue associated with games from FW 2.00 to 3.00.
Encryption and decryption should now work for every game. Wink
The PARAM.SFO hashing process still needs more testing, but I've found more details about it and I've implemented them in r3406.
Reply
#67
https://github.com/cielavenir/psp-saveda...77bd4e5142

[Edit] Seems I have corrupted my files. My success result was false positive...

[Edit2] Although this soft isn't working yet,
} else if (ctx.mode == 0x3) { // Encryption mode 0x3: XOR with SD keys, encrypt with KIRK CMD4 and XOR with the given key.
for (int i = 0; i < 0x10; i++) {
header[0x14 + 0xC + i] = (byte) (header[0x14 + 0xC + i] ^ KeyVault.sdHashKey3[i]);
}
ScrambleSD(header, 0x10, 0xE, 0x4, 0x04);
for (int i = 0; i < 0x10; i++) {
header[0xC + i] = (byte) (0xC + header[i] ^ KeyVault.sdHashKey4[i]);
}
is the 0xC + header[i] correct? I think it should be header[0xC + i]

[Edit3] Is libkirk broken? For example it lacks cmd5 support...
Reply
#68
Another suspicous code:
if ((ctx.mode == 0x2) || (ctx.mode == 0x4) || (ctx.mode == 0x6)) {
System.arraycopy(resultBuf, 0, scrambleResultBuf, 0x14, 0x10);
ScrambleSD(scrambleResultBuf, 0x10, 0x100, 0x4, 0x05);
ScrambleSD(scrambleResultBuf, 0x10, seed, 0x4, 0x04);
System.arraycopy(scrambleResultBuf, 0, resultBuf, 0, 0x10);
}

I think System.arraycopy(scrambleResultBuf, 0, scrambleResultBuf, 0x14, 0x10); is required, right?
Reply
#69
(10-22-2013, 10:32 AM)popsdeco Wrote: https://github.com/cielavenir/psp-saveda...77bd4e5142

[Edit] Seems I have corrupted my files. My success result was false positive...

[Edit2] Although this soft isn't working yet,
} else if (ctx.mode == 0x3) { // Encryption mode 0x3: XOR with SD keys, encrypt with KIRK CMD4 and XOR with the given key.
for (int i = 0; i < 0x10; i++) {
header[0x14 + 0xC + i] = (byte) (header[0x14 + 0xC + i] ^ KeyVault.sdHashKey3[i]);
}
ScrambleSD(header, 0x10, 0xE, 0x4, 0x04);
for (int i = 0; i < 0x10; i++) {
header[0xC + i] = (byte) (0xC + header[i] ^ KeyVault.sdHashKey4[i]);
}
is the 0xC + header[i] correct? I think it should be header[0xC + i]

[Edit3] Is libkirk broken? For example it lacks cmd5 support...

Indeed, the code in encryption mode 3 should be header[0xC + i].
I believe libkirk didn't implement all the CMDs, mostly because they aren't used that often and depend on the PSP's fuseID.

(10-22-2013, 12:38 PM)popsdeco Wrote: Another suspicous code:
if ((ctx.mode == 0x2) || (ctx.mode == 0x4) || (ctx.mode == 0x6)) {
System.arraycopy(resultBuf, 0, scrambleResultBuf, 0x14, 0x10);
ScrambleSD(scrambleResultBuf, 0x10, 0x100, 0x4, 0x05);
ScrambleSD(scrambleResultBuf, 0x10, seed, 0x4, 0x04);
System.arraycopy(scrambleResultBuf, 0, resultBuf, 0, 0x10);
}

I think System.arraycopy(scrambleResultBuf, 0, scrambleResultBuf, 0x14, 0x10); is required, right?

Actually it should be like this:
Code:
if ((ctx.mode == 0x2) || (ctx.mode == 0x4) || (ctx.mode == 0x6)) {
            System.arraycopy(resultBuf, 0, scrambleResultBuf, 0x14, 0x10);
            ScrambleSD(scrambleResultBuf, 0x10, 0x100, 0x4, 0x05);
            System.arraycopy(scrambleResultBuf, 0, scrambleResultBuf, 0x14, 0x10);
            for(int i = 0; i < 0x14; i++) {
                scrambleResultBuf[i] = 0;
            }
            ScrambleSD(scrambleResultBuf, 0x10, seed, 0x4, 0x04);
            System.arraycopy(scrambleResultBuf, 0, resultBuf, 0, 0x10);
        }

But you're right, the 0x14 data on the top of the buffer was indeed missing.
Thank you for finding these mistakes popsdeco, I'm fixing this right away. Wink
Reply
#70
Another update done on r3407. I've fixed the bugs detected by popsdeco and I've also done some major changes in the PARAM.SFO data generation.
Could you please test if the generated PARAM.SFO is now compatible with the PSP? Thanks! Smile
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)