* Add PSP Homebrew for encode/decode save between PSP and PPSSPP.

This commit is contained in:
Xele02 2012-12-25 18:20:37 +01:00
parent 020e4e7f13
commit f965fb7623
15 changed files with 1589 additions and 0 deletions

44
Tools/SaveTool/Makefile Normal file
View File

@ -0,0 +1,44 @@
SUBDIRS = kernelcall
release:
@for i in $(SUBDIRS); do echo "make all in $$i..."; (cd $$i; $(MAKE) release; cp $$i.prx ..); done
make all
allclean:
make clean
@for i in $(SUBDIRS); do echo "Clearing in $$i..."; (cd $$i; $(MAKE) clean; rm -rf $$i.prx); done
TARGET = ppssppsavetool
OBJS = main.o decrypt.o encrypt.o hash.o psf.o $(KERNELCALL_OBJS)
BUILD_PRX=1
EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = PPSSPP Save Tool
PSP_FW_VERSION=350
INCDIR =
CFLAGS = -O0 -G0 -Wall -g
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
KERNELCALL_OBJS = kernelcall_0000.o \
kernelcall_0001.o \
kernelcall_0002.o \
kernelcall_0003.o \
kernelcall_0004.o \
kernelcall_0005.o \
kernelcall_0006.o \
kernelcall_0007.o
$(KERNELCALL_OBJS): kernelcall/kernelcall.S
psp-gcc $(CFLAGS) -DF_$* $< -c -o $@
LIBDIR =
LDFLAGS =
LIBS = -lpsputility -lpspgum -lpspgu -lm
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak

77
Tools/SaveTool/README Normal file
View File

@ -0,0 +1,77 @@
PSP Tool for encoding save data from PPSSPP to read on PSP and decoding
PSP save to read on PPSSPP.
Alpha version. Was only tested on Project Dive Extend.
Build
=====
Require PSP Toolchain with PSP SDK
make release
This will build ppssppsavetool.prx and kernelcall.prx.
clean : make allclean
How to use
==========
Require PSP Toolchain with PRX Link and usb link, pspsh to work. Seems
there is limitation for directories listing when running directly the
tool from the PSP.
A) PREPARING DATA
=================
1) Play the game on PPSSPP until a game save is done. This will create
the file "ENCRYPT_INFO.BIN" in the save directory. It contain the
encoding key and sdk version of the game. This file is the same for all
save of the game, so you can use it on different save folder without
the need to make them all on PPSSPP.
2) Run usbhostfs_pc. Then mount .ppsspp/PSP/SAVEDATA directory :
mount 1 <path to .ppsspp/PSP/SAVEDATA>
If you enter "drives", you should see host1: mapped to the directory.
3) Run PRX Link on the psp, and pspsh on the PC.
B) ENCODING A SAVE FROM PPSSPP TO PSP
=====================================
1) From pspsh, run ppssppsavetool.prx.
2) In the menu, select "Encrypt", "host1:/". This will list the
directories in ppsspp save directory which can be encoded.
For a directory to appear, it must contain the ENCRYPT_INFO.BIN file,
and the files of a ppsspp save.
3) After selecting the directory to encode, it will be copied into
the PSP/SAVEGAME directory and encoded. Now you can play the save on
the PSP.
C) DECODING A SAVE FROM PSP TO PPSSPP
=====================================
1) You should have a directory in the PPSSPP save directory with the
same name that the PSP save you want to convert. And in it, the
"ENCRYPT_INFO.BIN" file.
Ex : You want to decrypt the save in ms0:/PSP/SAVEDATA/XXXXYYY/
You create .ppsspp/PSP/SAVEDATA/XXXXYYY/ if not existing, and put the
"ENCRYPT_INFO.BIN" generated before in it.
2) From pspsh, run ppssppsavetool.prx.
3) In the menu, select "decrypt", "host1:/". You should see your
directory in the list.
4) After selecting it, the game decode the save and save it into the
PPSSPP save directory. You can now launch your game in PPSSPP and load
the save.

164
Tools/SaveTool/decrypt.c Normal file
View File

@ -0,0 +1,164 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* decrypt.c - Decryption routines using sceChnnlsv
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: decrypt.c 1562 2005-12-10 20:52:45Z jim $
*/
#include "decrypt.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <pspchnnlsv.h>
#include "kernelcall/kernelcall.h"
unsigned int align16(unsigned int v)
{
return ((v + 0xF) >> 4) << 4;
}
/* Read, decrypt, and write a savedata file. See main.c for example usage. */
int decrypt_file(const char *decrypted_filename,
const char *encrypted_filename,
const unsigned char *gamekey,
const int mainSdkVersion)
{
FILE *in, *out;
int len, aligned_len;
unsigned char *data, *cryptkey;
int retval;
/* Open file and get size */
if ((in = fopen(encrypted_filename, "r")) == NULL) {
retval = -1;
goto out;
}
fseek(in, 0, SEEK_END);
len = ftell(in);
fseek(in, 0, SEEK_SET);
if (len <= 0) {
retval = -2;
goto out1;
}
/* Allocate buffers */
aligned_len = align16(len);
if ((data = (unsigned char *) memalign(0x10, aligned_len)) == NULL) {
retval = -3;
goto out1;
}
if ((cryptkey = (unsigned char *) memalign(0x10, 0x10)) == NULL) {
retval = -4;
goto out2;
}
/* Fill buffers */
if (gamekey != NULL)
memcpy(cryptkey, gamekey, 0x10);
memset(data + len, 0, aligned_len - len);
if (fread(data, 1, len, in) != len) {
retval = -5;
goto out3;
}
/* Do the decryption */
if ((retval = decrypt_data( gamekey ? (mainSdkVersion >= 4 ? 5 : 3) : 1, // 5 for sdk >= 4, else 3
data, &len, &aligned_len,
gamekey ? cryptkey : NULL)) < 0) {
retval -= 100;
goto out3;
}
/* Write the data out. decrypt_data has set len correctly. */
if ((out = fopen(decrypted_filename, "w")) == NULL) {
retval = -6;
goto out3;
}
if (fwrite(data, 1, len, out) != len) {
retval = -7;
goto out4;
}
/* All done. Return file length. */
retval = len;
out4:
fclose(out);
out3:
free(cryptkey);
out2:
free(data);
out1:
fclose(in);
out:
return retval;
}
/* Do the actual hardware decryption.
mode is 3 for saves with a cryptkey, or 1 otherwise
data, dataLen, and cryptkey must be multiples of 0x10.
cryptkey is NULL if mode == 1.
*/
int decrypt_data(unsigned int mode,
unsigned char *data,
int *dataLen,
int *alignedLen,
unsigned char *cryptkey)
{
pspChnnlsvContext1 ctx1;
pspChnnlsvContext2 ctx2;
/* Need a 16-byte IV plus some data */
if (*alignedLen <= 0x10)
return -1;
*dataLen -= 0x10;
*alignedLen -= 0x10;
/* Set up buffers */
memset(&ctx1, 0, sizeof(pspChnnlsvContext1));
memset(&ctx2, 0, sizeof(pspChnnlsvContext2));
/* Perform the magic */
if (sceChnnlsv_E7833020_(&ctx1, mode) < 0)
return -2;
if (sceChnnlsv_ABFDFC8B_(&ctx2, mode, 2, data, cryptkey) < 0)
return -3;
if (sceChnnlsv_F21A1FCA_(&ctx1, data, 0x10) < 0)
return -4;
if (sceChnnlsv_F21A1FCA_(&ctx1, data + 0x10, *alignedLen) < 0)
return -5;
if (sceChnnlsv_850A7FA1_(&ctx2, data + 0x10, *alignedLen) < 0)
return -6;
/* Verify that it decrypted correctly */
if (sceChnnlsv_21BE78B4_(&ctx2) < 0)
return -7;
/* If desired, a new file hash from this PSP can be computed now:
if (sceChnnlsv_C4C494F8(ctx1, newhash, cryptkey) < 0)
return -8;
*/
/* The decrypted data starts at data + 0x10, so shift it back. */
memmove(data, data + 0x10, *dataLen);
/* All done */
return 0;
}

31
Tools/SaveTool/decrypt.h Normal file
View File

@ -0,0 +1,31 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* decrypt.h - Declarations for functions in decrypt.c
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: decrypt.h 1562 2005-12-10 20:52:45Z jim $
*/
#include <pspchnnlsv.h>
/* Detect the samegame format and decrypt it. See main.c for an example. */
int decrypt_file(const char *decrypted_filename,
const char *encrypted_filename,
const unsigned char *gamekey,
const int mainSdkVersion);
/* Do the actual hardware decryption.
mode is 3 for saves with a cryptkey, or 1 otherwise.
data, alignedLen, and cryptkey must be multiples of 0x10.
cryptkey is NULL if mode == 1.
*/
int decrypt_data(unsigned int mode,
unsigned char *data,
int *dataLen,
int *alignedLen,
unsigned char *cryptkey);

233
Tools/SaveTool/encrypt.c Normal file
View File

@ -0,0 +1,233 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* encrypt.c - Encryption routines using sceChnnlsv
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: encrypt.c 1560 2005-12-10 01:16:32Z jim $
*/
#include "encrypt.h"
#include "hash.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <pspchnnlsv.h>
#include "kernelcall/kernelcall.h"
static inline int align16(unsigned int v)
{
return ((v + 0xF) >> 4) << 4;
}
int fopen_getsize(const char *filename, FILE **fd, int *size)
{
if ((*fd = fopen(filename, "r")) == NULL)
return -1;
fseek(*fd, 0, SEEK_END);
*size = ftell(*fd);
fseek(*fd, 0, SEEK_SET);
if (*size <= 0) {
fclose(*fd);
return -2;
}
return 0;
}
/* Encrypt the given plaintext file, and update the message
authentication hashes in the param.sfo. The data_filename is
usually the final component of encrypted_filename, e.g. "DATA.BIN".
See main.c for an example of usage. */
int encrypt_file(const char *plaintext_filename,
const char *encrypted_filename,
const char *data_filename,
const char *paramsfo_filename,
const char *paramsfo_filename_out,
const unsigned char *gamekey,
const int mainSdkVersion)
{
FILE *in = NULL, *out = NULL, *sfo = NULL;
unsigned char *data = NULL, *cryptkey = NULL, *hash = NULL;
unsigned char paramsfo[0x1330];
int len, aligned_len, tmp;
int retval;
/* Open plaintext and param.sfo files and get size */
if (fopen_getsize(plaintext_filename, &in, &len) < 0) {
retval = -1;
goto out;
}
if (fopen_getsize(paramsfo_filename, &sfo, &tmp) < 0) {
retval = -2;
goto out;
}
/* Verify size of param.sfo; all known saves use this size */
if (tmp != 0x1330) {
retval = -3;
goto out;
}
/* Allocate buffers. data has 0x10 bytes extra for the IV. */
aligned_len = align16(len);
if ((data =
(unsigned char *) memalign(0x10, aligned_len + 0x10)) == NULL) {
retval = -4;
goto out;
}
if ((cryptkey = (unsigned char *) memalign(0x10, 0x10)) == NULL) {
retval = -5;
goto out;
}
if ((hash = (unsigned char *) memalign(0x10, 0x10)) == NULL) {
retval = -6;
goto out;
}
/* Fill buffers. */
memset(data + len, 0, aligned_len - len);
if (fread(data, 1, len, in) != len) {
retval = -7;
goto out;
}
if (fread(paramsfo, 1, 0x1330, sfo) != 0x1330) {
retval = -8;
goto out;
}
if (gamekey != NULL)
memcpy(cryptkey, gamekey, 0x10);
/* Do the encryption */
if ((retval = encrypt_data( gamekey ? (mainSdkVersion >= 4 ? 5 : 3) : 1, // 5 for sdk >= 4, 3 otherwise
data,
&len, &aligned_len,
hash,
gamekey ? cryptkey : NULL)) < 0) {
retval -= 1000;
goto out;
}
/* Update the param.sfo hashes */
if ((retval = update_hashes(paramsfo, 0x1330,
data_filename, hash,
gamekey ? 3 : 1)) < 0) {
retval -= 2000;
goto out;
}
/* Write the data to the file. encrypt_data has already set len. */
if ((out = fopen(encrypted_filename, "w")) == NULL) {
retval = -9;
goto out;
}
if (fwrite(data, 1, len, out) != len) {
retval = -10;
goto out;
}
/* Reopen param.sfo, and write the updated copy out. */
fclose(sfo);
if ((sfo = fopen(paramsfo_filename_out, "w")) == NULL) {
retval = -11;
goto out;
}
if (fwrite(paramsfo, 1, 0x1330, sfo) != 0x1330) {
retval = -12;
goto out;
}
/* All done. Return file length. */
retval = len;
out:
if(out) fclose(out);
if(hash) free(hash);
if(cryptkey) free(cryptkey);
if(data) free(data);
if(sfo) fclose(sfo);
if(in) fclose(in);
return retval;
}
/* Do the actual hardware encryption.
mode is 3 for saves with a cryptkey, or 1 otherwise
data, dataLen, and cryptkey must be multiples of 0x10.
cryptkey is NULL if mode == 1.
*/
int encrypt_data(unsigned int mode,
unsigned char *data,
int *dataLen,
int *alignedLen,
unsigned char *hash,
unsigned char *cryptkey)
{
pspChnnlsvContext1 ctx1;
pspChnnlsvContext2 ctx2;
/* Make room for the IV in front of the data. */
memmove(data + 0x10, data, *alignedLen);
/* Set up buffers */
memset(&ctx1, 0, sizeof(pspChnnlsvContext1));
memset(&ctx2, 0, sizeof(pspChnnlsvContext2));
memset(hash, 0, 0x10);
memset(data, 0, 0x10);
/* Build the 0x10-byte IV and setup encryption */
if (sceChnnlsv_ABFDFC8B_(&ctx2, mode, 1, data, cryptkey) < 0)
return -1;
if (sceChnnlsv_E7833020_(&ctx1, mode) < 0)
return -2;
if (sceChnnlsv_F21A1FCA_(&ctx1, data, 0x10) < 0)
return -3;
if (sceChnnlsv_850A7FA1_(&ctx2, data + 0x10, *alignedLen) < 0)
return -4;
/* Clear any extra bytes left from the previous steps */
memset(data + 0x10 + *dataLen, 0, *alignedLen - *dataLen);
/* Encrypt the data */
if (sceChnnlsv_F21A1FCA_(&ctx1, data + 0x10, *alignedLen) < 0)
return -5;
/* Verify encryption */
if (sceChnnlsv_21BE78B4_(&ctx2) < 0)
return -6;
/* Build the file hash from this PSP */
if (sceChnnlsv_C4C494F8_(&ctx1, hash, cryptkey) < 0)
return -7;
/* Adjust sizes to account for IV */
*alignedLen += 0x10;
*dataLen += 0x10;
/* All done */
return 0;
}

38
Tools/SaveTool/encrypt.h Normal file
View File

@ -0,0 +1,38 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* encrypt.h - Declarations for functions in encrypt.c
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: encrypt.h 1559 2005-12-10 01:10:11Z jim $
*/
#include <pspchnnlsv.h>
/* Encrypt the given plaintext file, and update the message
authentication hashes in the param.sfo. The data_filename is
usually the final component of encrypted_filename, e.g. "DATA.BIN".
See main.c for an example of usage. */
int encrypt_file(const char *plaintext_filename,
const char *encrypted_filename,
const char *data_filename,
const char *paramsfo_filename,
const char *paramsfo_filename_out,
const unsigned char *gamekey,
const int mainSdkVersion);
/* Do the actual hardware encryption.
mode is 3 for saves with a cryptkey, or 1 otherwise.
data, alignedLen, cryptkey, and hash must be multiples of 0x10.
cryptkey is NULL if mode == 1.
*/
int encrypt_data(unsigned int mode,
unsigned char *data,
int *dataLen,
int *alignedLen,
unsigned char *hash,
unsigned char *cryptkey);

129
Tools/SaveTool/hash.c Normal file
View File

@ -0,0 +1,129 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* hash.c - Hashing routines using sceChnnlsv
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: hash.c 1560 2005-12-10 01:16:32Z jim $
*/
#include "hash.h"
#include "psf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <pspchnnlsv.h>
#include "kernelcall/kernelcall.h"
static inline int align16(unsigned int v)
{
return ((v + 0xF) >> 4) << 4;
}
/* Update the hashes in the param.sfo data, using
the given file hash, and by computing the param.sfo hashes.
filehash must be a multiple of 16 bytes, and is reused to
store other hashes. The filename is e.g. "DATA.BIN". */
int update_hashes(unsigned char *data,
int len,
const char *filename,
unsigned char *filehash,
int encryptmode)
{
int alignedLen = align16(len);
unsigned char *datafile, *savedata_params;
int listLen, paramsLen;
int ret;
/* Locate SAVEDATA_PARAM section in the param.sfo. */
if ((ret = find_psf_section("SAVEDATA_PARAMS", data, 0x1330,
&savedata_params, &paramsLen)) < 0) {
return ret - 100;
}
/* Locate the pointer for this DATA.BIN equivalent */
if ((ret = find_psf_section("SAVEDATA_FILE_LIST", data, 0x1330,
&datafile, &listLen)) < 0) {
return ret - 200;
}
if ((ret = find_psf_datafile(filename, datafile,
listLen, &datafile)) < 0) {
return ret - 300;
}
/* Check minimum sizes based on where we want to write */
if ((listLen < 0x20) || (paramsLen < 0x80)) {
return -1;
}
/* Clear params and insert file hash */
memset(savedata_params, 0, paramsLen);
memcpy(datafile + 0x0D, filehash, 0x10);
/* Compute 11D0 hash over entire file */
if ((ret = build_hash(filehash, data, len, alignedLen,
(encryptmode & 2) ? 4 : 2, NULL)) < 0) { // Not sure about "2"
return ret - 400;
}
/* Copy 11D0 hash to param.sfo and set flag indicating it's there */
memcpy(savedata_params + 0x20, filehash, 0x10);
*savedata_params |= 0x01;
/* If new encryption mode, compute and insert the 1220 hash. */
if (encryptmode & 2) {
/* Enable the hash bit first */
*savedata_params |= 0x20;
if ((ret = build_hash(filehash, data, len, alignedLen,
3, 0)) < 0) {
return ret - 500;
}
memcpy(savedata_params + 0x70, filehash, 0x10);
}
/* Compute and insert the 11C0 hash. */
if ((ret = build_hash(filehash, data, len, alignedLen, 1, 0)) < 0) {
return ret - 600;
}
memcpy(savedata_params + 0x10, filehash, 0x10);
/* All done. */
return 0;
}
/* Build a single hash using the given data and mode.
data and alignedLen must be multiples of 0x10.
cryptkey is NULL for savedata. */
int build_hash(unsigned char *output,
unsigned char *data,
unsigned int len,
unsigned int alignedLen,
int mode,
unsigned char *cryptkey)
{
pspChnnlsvContext1 ctx1;
/* Set up buffers */
memset(&ctx1, 0, sizeof(pspChnnlsvContext1));
memset(output, 0, 0x10);
memset(data + len, 0, alignedLen - len);
/* Perform the magic */
if (sceChnnlsv_E7833020_(&ctx1, mode & 0xFF) < 0)
return -1;
if (sceChnnlsv_F21A1FCA_(&ctx1, data, alignedLen) < 0)
return -2;
if (sceChnnlsv_C4C494F8_(&ctx1, output, cryptkey) < 0)
return -3;
/* All done. */
return 0;
}

34
Tools/SaveTool/hash.h Normal file
View File

@ -0,0 +1,34 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* hash.h - Declarations for functions in hash.c
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: hash.h 1559 2005-12-10 01:10:11Z jim $
*/
#include <pspchnnlsv.h>
/* Update the hashes in the param.sfo data, using
the given file hash, and by computing the param.sfo hashes.
filehash must be a multiple of 16 bytes, and is reused to
store other hashes. The filename is e.g. "DATA.BIN". */
int update_hashes(unsigned char *data,
int len,
const char *filename,
unsigned char *filehash,
int encryptmode);
/* Build a single hash using the given data and mode.
data, and alignedLen must be multiples of 0x10.
cryptkey is NULL for savedata.*/
int build_hash(unsigned char *output,
unsigned char *data,
unsigned int len,
unsigned int alignedLen,
int mode,
unsigned char *cryptkey);

Binary file not shown.

View File

@ -0,0 +1,24 @@
release: all
psp-build-exports -k exports.exp
psp-build-exports -s -k -v exports.exp
TARGET = kernelcall
OBJS = kernelcall.o
BUILD_PRX=1
PRX_EXPORTS=exports.exp
USE_KERNEL_LIBS = 1
USE_KERNEL_LIBC = 1
INCDIR =
CFLAGS = -O0 -G0 -Wall -g
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)
LIBDIR =
LDFLAGS = -mno-crt0 -nostartfiles
LIBS = -lpspchnnlsv
PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak

View File

@ -0,0 +1,84 @@
#include <pspsdk.h>
#include <pspkernel.h>
#include <pspidstorage.h>
#include <pspsysreg.h>
#include <string.h>
#include <pspchnnlsv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
PSP_MODULE_INFO("kernelcall", 0x1006, 2, 0);
u64 sceSysreg_driver_4F46EEDE();
u64 GetFuseId()
{
u64 fuseId = sceSysreg_driver_4F46EEDE();
return fuseId;
}
int sceChnnlsv_E7833020_(pspChnnlsvContext1 *ctx, int mode)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_E7833020(ctx,mode);
pspSdkSetK1(k1);
return res;
}
int sceChnnlsv_F21A1FCA_(pspChnnlsvContext1 *ctx, unsigned char *data, int len)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_F21A1FCA(ctx,data,len);
pspSdkSetK1(k1);
return res;
}
int sceChnnlsv_C4C494F8_(pspChnnlsvContext1 *ctx,
unsigned char *hash, unsigned char *cryptkey)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_C4C494F8(ctx,hash,cryptkey);
pspSdkSetK1(k1);
return res;
}
int sceChnnlsv_ABFDFC8B_(pspChnnlsvContext2 *ctx, int mode1, int mode2,
unsigned char *hashkey, unsigned char *cipherkey)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_ABFDFC8B(ctx,mode1,mode2,hashkey,cipherkey);
pspSdkSetK1(k1);
return res;
}
int sceChnnlsv_850A7FA1_(pspChnnlsvContext2 *ctx, unsigned char *data, int len)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_850A7FA1(ctx,data,len);
pspSdkSetK1(k1);
return res;
}
int sceChnnlsv_21BE78B4_(pspChnnlsvContext2 *ctx)
{
int k1 = pspSdkSetK1(0);
int res = sceChnnlsv_21BE78B4(ctx);
pspSdkSetK1(k1);
return res;
}
int module_start(SceSize args, void *argp)
{
return 0;
}
int module_stop()
{
return 0;
}

View File

@ -0,0 +1,9 @@
u64 GetFuseId();
int sceChnnlsv_E7833020_(pspChnnlsvContext1 *ctx, int mode);
int sceChnnlsv_F21A1FCA_(pspChnnlsvContext1 *ctx, unsigned char *data, int len);
int sceChnnlsv_C4C494F8_(pspChnnlsvContext1 *ctx,
unsigned char *hash, unsigned char *cryptkey);
int sceChnnlsv_ABFDFC8B_(pspChnnlsvContext2 *ctx, int mode1, int mode2,
unsigned char *hashkey, unsigned char *cipherkey);
int sceChnnlsv_850A7FA1_(pspChnnlsvContext2 *ctx, unsigned char *data, int len);
int sceChnnlsv_21BE78B4_(pspChnnlsvContext2 *ctx);

579
Tools/SaveTool/main.c Normal file
View File

@ -0,0 +1,579 @@
#include <pspsdk.h>
#include <pspkernel.h>
#include <pspdebug.h>
#include <pspmoduleinfo.h>
#include <pspctrl.h>
#include <pspchnnlsv.h>
#include <psputility.h>
#include "kernelcall/kernelcall.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "encrypt.h"
#include "decrypt.h"
#include "psf.h"
#define printf pspDebugScreenPrintf
/* Define the module info section */
PSP_MODULE_INFO("ppssppsavetool", 0, 1, 0);
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_USER);
PSP_HEAP_SIZE_KB(-64);
#define ENCRYPT_FILE_VERSION 1
int currentMenu = 0;
int selectedOption = 0;
int basePath = 0;
int workDir = 0;
char *menuList0[] = {"Encrypt","Decrypt", "Exit", NULL};
char *menuList1[] = {"ms0:/PSP/SAVEDATAPPSSPP/","host0:/","host1:/", "host2:/", "Back", NULL};
char *menuList2[] = {"Back", NULL};
int GetSDKMainVersion(int sdkVersion)
{
if(sdkVersion > 0x307FFFF)
return 6;
if(sdkVersion > 0x300FFFF)
return 5;
if(sdkVersion > 0x206FFFF)
return 4;
if(sdkVersion > 0x205FFFF)
return 3;
if(sdkVersion >= 0x2000000)
return 2;
if(sdkVersion >= 0x1000000)
return 1;
return 0;
};
int ProcessInput(int maxOption, int *selectedOption)
{
SceCtrlData pad, oldpad;
sceCtrlReadBufferPositive(&oldpad, 1);
while(1)
{
sceCtrlReadBufferPositive(&pad, 1);
if (pad.Buttons != 0)
{
if (!(oldpad.Buttons & PSP_CTRL_CROSS) && pad.Buttons & PSP_CTRL_CROSS)
{
return *selectedOption;
}
else if (!(oldpad.Buttons & PSP_CTRL_UP) && pad.Buttons & PSP_CTRL_UP && *selectedOption > 0)
{
*selectedOption = *selectedOption-1;
return -1;
}
else if (!(oldpad.Buttons & PSP_CTRL_DOWN) && pad.Buttons & PSP_CTRL_DOWN && *selectedOption < maxOption-1)
{
*selectedOption = *selectedOption + 1;
return -1;
}
}
oldpad = pad;
}
}
typedef struct
{
char name[30];
char saveFile[30];
int errorId;
} DirInfo;
typedef struct
{
int fileVersion;
u8 key[16];
int sdkVersion;
} EncryptFileInfo;
DirInfo dirList[128];
int numDirList;
DirInfo invalidDirList[128];
int numInvalidDirList;
int FileExist(char* basePath, char* dirPath, char* fileName)
{
SceIoStat fileStat;
char path[1024];
sprintf(path,"%s%s/%s",basePath, dirPath, fileName);
if(sceIoGetstat(path, &fileStat) < 0) // no file
return 0;
return 1;
}
int FileRead(char* basePath, char* dirPath, char* fileName, u8* dataout, int size)
{
char path[1024];
sprintf(path,"%s%s/%s",basePath, dirPath, fileName);
SceUID fileId = sceIoOpen(path, PSP_O_RDONLY, 0777);
if(fileId < 0)
return -1;
sceIoRead(fileId, dataout, size);
sceIoClose(fileId);
return 0;
}
void AddErrorDir(char* dirName, int error)
{
if(numInvalidDirList >= 128)
return;
DirInfo *inf = &invalidDirList[numInvalidDirList];
strcpy(inf->name,dirName);
inf->errorId = error;
numInvalidDirList++;
}
int UpdateValidDir(int isEncrypt)
{
numDirList = 0;
numInvalidDirList = 0;
const char* pspPath = "ms0:/PSP/SAVEDATA/";
char* pathSrc;
char* pathDst;
if(isEncrypt)
{
pathSrc = menuList1[basePath];
pathDst = pspPath;
}
else
{
pathSrc = pspPath;
pathDst = menuList1[basePath];
}
int dfd;
dfd = sceIoDopen(menuList1[basePath]);
if(dfd >= 0)
{
SceIoDirent data;
while(sceIoDread(dfd, &data) > 0 && numDirList < 128)
{
if(!(data.d_stat.st_attr & 0x10)) // is not a directory
{
continue;
}
if(data.d_name[0] == '.') // ignore "." and ".."
continue;
if(FileExist(menuList1[basePath], data.d_name, "ENCRYPT_INFO.BIN") < 0)
{
AddErrorDir(data.d_name,1);
continue;
}
EncryptFileInfo encryptInfo;
if(FileRead(menuList1[basePath], data.d_name, "ENCRYPT_INFO.BIN",(u8*)&encryptInfo,sizeof(encryptInfo)) < 0)
{
AddErrorDir(data.d_name,2);
continue;
}
if(encryptInfo.fileVersion != ENCRYPT_FILE_VERSION) // Not good version
{
AddErrorDir(data.d_name,3);
continue;
}
if(FileExist(pathSrc, data.d_name, "PARAM.SFO") < 0)
{
AddErrorDir(data.d_name,4);
continue;
}
u8 paramsfo[0x1330];
if(FileRead(pathSrc, data.d_name, "PARAM.SFO",(u8*)&paramsfo,0x1330) < 0)
{
AddErrorDir(data.d_name,5);
continue;
}
u8 *datafile;
int listLen;
if (find_psf_section("SAVEDATA_FILE_LIST", paramsfo, 0x1330,
&datafile, &listLen) < 0)
{
AddErrorDir(data.d_name,6);
continue;
}
if(datafile[0] == 0)
{
AddErrorDir(data.d_name,7);
continue;
}
char filename[32];
strcpy(filename, (char*)datafile);
if(FileExist(pathSrc, data.d_name, filename) < 0)
{
AddErrorDir(data.d_name,8);
continue;
}
DirInfo *inf = &dirList[numDirList];
inf->errorId = 0;
strcpy(inf->name, data.d_name);
strcpy(inf->saveFile, filename);
numDirList++;
}
sceIoDclose(dfd);
if(numDirList == 0)
{
return -1;
}
}
else
{
return -2;
}
return 0;
}
int FileCopy(char* srcPath, char* destPath, char* fileName)
{
SceIoStat fileStat;
char path[258];
sprintf(path,"%s/%s",srcPath, fileName);
if(sceIoGetstat(path, &fileStat) < 0)
return -1;
u8* data = malloc(fileStat.st_size);
SceUID fileId = sceIoOpen(path, PSP_O_RDONLY, 0777);
if(fileId < 0)
{
printf("Fail opening %s\n",path);
return -1;
}
sceIoRead(fileId, data, fileStat.st_size);
sceIoClose(fileId);
sprintf(path,"%s/%s",destPath, fileName);
fileId = sceIoOpen(path, PSP_O_WRONLY | PSP_O_CREAT, 0777);
if(fileId < 0)
{
printf("Fail opening %s\n",path);
return -1;
}
sceIoWrite(fileId, data, fileStat.st_size);
sceIoClose(fileId);
free(data);
return 0;
}
int main(int argc, char *argv[])
{
int i;
pspDebugScreenInit();
SceUID mod = pspSdkLoadStartModule ("flash0:/kd/chnnlsv.prx",PSP_MEMORY_PARTITION_KERNEL);
if (mod < 0) {
printf("Error 0x%08X loading/starting chnnlsv.prx.\n", mod);
}
mod = pspSdkLoadStartModule ("kernelcall.prx",PSP_MEMORY_PARTITION_KERNEL);
if (mod < 0) {
printf("Error 0x%08X loading/starting kernelcall.prx.\n", mod);
}
sceCtrlSetSamplingCycle(0);
sceCtrlSetSamplingMode(PSP_CTRL_MODE_ANALOG);
for(;;)
{
printf("====================================================================");
printf("PPSSPP Save Tool\n");
printf("====================================================================\n\n\n");
switch(currentMenu)
{
case 0:
{
int maxOption = 0;
for(i = 0; menuList0[i]; i++)
{
if(i == selectedOption)
printf(" > %s\n",menuList0[i]);
else
printf(" %s\n",menuList0[i]);
maxOption++;
}
int input = ProcessInput(maxOption, &selectedOption);
if(input == 0)
{
currentMenu = 1;
selectedOption = 0;
}
else if(input == 1)
{
currentMenu = 4;
selectedOption = 0;
}
else if(input == 2)
{
sceKernelExitGame();
}
}
break;
case 4:
case 1:
{
int maxOption = 0;
printf("PPSSPP Decrypted Save Directory : \n");
for(i = 0; menuList1[i]; i++)
{
if(i == selectedOption)
printf(" > %s\n",menuList1[i]);
else
printf(" %s\n",menuList1[i]);
maxOption++;
}
int input = ProcessInput(maxOption, &selectedOption);
if(input == maxOption-1)
{
if(currentMenu == 1)
selectedOption = 0;
else
selectedOption = 1;
currentMenu = 0;
}
else if(input >= 0)
{
basePath = selectedOption;
if(currentMenu == 1)
{
currentMenu = 2;
UpdateValidDir(1);
}
else
{
currentMenu = 5;
UpdateValidDir(0);
}
selectedOption = 0;
}
}
break;
case 5:
case 2:
{
int maxOption = 0;
if(currentMenu == 2)
printf("Save to encrypt : \n");
else
printf("Save to decrypt : \n");
if(numDirList == 0)
{
printf("No compatible data, see README for help on use\n");
}
for(i = 0; i < numDirList; i++)
{
if(i == selectedOption)
printf(" > %s\n",dirList[i].name);
else
printf(" %s\n",dirList[i].name);
maxOption++;
}
for(i = 0; menuList2[i]; i++)
{
if((i+numDirList) == selectedOption)
printf(" > %s\n",menuList2[i]);
else
printf(" %s\n",menuList2[i]);
maxOption++;
}
printf("\n Invalid path : \n");
for(i = 0; i < numInvalidDirList && i < (22-numDirList); i++)
{
switch(invalidDirList[i].errorId)
{
case 1:
printf(" %s : ENCRYPT_INFO.BIN not found\n",invalidDirList[i].name);
break;
case 2:
printf(" %s : ENCRYPT_INFO.BIN read error\n",invalidDirList[i].name);
break;
case 3:
printf(" %s : ENCRYPT_INFO.BIN wrong version\n",invalidDirList[i].name);
break;
case 4:
printf(" %s : PARAM.SFO not found\n",invalidDirList[i].name);
break;
case 5:
printf(" %s : PARAM.SFO read error\n",invalidDirList[i].name);
break;
case 6:
printf(" %s : SAVEDATA_FILE_LIST not found in PARAM.SFO\n",invalidDirList[i].name);
break;
case 7:
printf(" %s : no save name in SAVEDATA_FILE_LIST\n",invalidDirList[i].name);
break;
case 8:
printf(" %s : no save found\n",invalidDirList[i].name);
break;
default:
break;
}
}
int input = ProcessInput(maxOption, &selectedOption);
if(input == numDirList)
{
if(currentMenu == 2)
currentMenu = 1;
else
currentMenu = 4;
selectedOption = basePath;
}
else if(input >= 0)
{
if(currentMenu == 2)
currentMenu = 3;
else
currentMenu = 6;
workDir = input;
selectedOption = 0;
}
}
break;
case 6:
case 3:
{
EncryptFileInfo encryptInfo;
if(FileRead(menuList1[basePath], dirList[workDir].name, "ENCRYPT_INFO.BIN",(u8*)&encryptInfo,sizeof(encryptInfo)) < 0)
{
printf("Can't read encrypt file\n");
}
else
{
printf("Key : ");
for(i = 0; i < 16; i++)
printf(" %02x",(u8)encryptInfo.key[i]);
printf("\n");
printf("SDK Version : 0x%x\n",encryptInfo.sdkVersion);
char srcPath[128];
char dstPath[128];
if(currentMenu == 3)
{
sprintf(srcPath,"%s%s",menuList1[basePath], dirList[workDir].name);
sprintf(dstPath,"ms0:/PSP/SAVEDATA/%s",dirList[workDir].name);
sceIoMkdir(dstPath,0777);
}
else
{
sprintf(srcPath,"ms0:/PSP/SAVEDATA/%s",dirList[workDir].name);
sprintf(dstPath,"%s%s",menuList1[basePath], dirList[workDir].name);
}
int dfd;
dfd = sceIoDopen(srcPath);
if(dfd >= 0)
{
SceIoDirent dirinfo;
while(sceIoDread(dfd, &dirinfo) > 0)
{
if(!(dirinfo.d_stat.st_mode & 0x2000)) // is not a file
continue;
if(strcmp(dirinfo.d_name,"ENCRYPT_INFO.BIN") == 0) // don't copy encrypt info
continue;
FileCopy(srcPath, dstPath, dirinfo.d_name);
}
sceIoDclose(dfd);
}
if(currentMenu == 3)
{
char decryptedFile[258], encryptedFile[258], srcSFO[258], dstSFO[258];
sprintf(decryptedFile,"%s/%s",srcPath ,dirList[workDir].saveFile);
sprintf(srcSFO,"%s/PARAM.SFO",srcPath);
sprintf(encryptedFile,"%s/%s",dstPath ,dirList[workDir].saveFile);
sprintf(dstSFO,"%s/PARAM.SFO",dstPath);
printf("Encoding %s into %s\n",decryptedFile, encryptedFile);
int ret = encrypt_file(decryptedFile,
encryptedFile,
dirList[workDir].saveFile,
srcSFO,
dstSFO,
encryptInfo.key[0] != 0 ? encryptInfo.key : NULL,
GetSDKMainVersion(encryptInfo.sdkVersion)
);
if(ret < 0) {
printf("Error: encrypt_file() returned %d\n\n", ret);
} else {
printf("Successfully wrote %d bytes to\n", ret);
printf(" %s\n", encryptedFile);
printf("and updated hashes in\n");
printf(" %s\n\n", dstSFO);
}
}
else
{
char decryptedFile[258], encryptedFile[258];
sprintf(encryptedFile,"%s/%s",srcPath ,dirList[workDir].saveFile);
sprintf(decryptedFile,"%s/%s",dstPath ,dirList[workDir].saveFile);
printf("Decoding %s into %s\n",encryptedFile, decryptedFile);
int ret = decrypt_file(decryptedFile, encryptedFile, encryptInfo.key[0] != 0 ? encryptInfo.key : NULL, GetSDKMainVersion(encryptInfo.sdkVersion));
if(ret < 0) {
printf("Error: decrypt_file() returned %d\n\n", ret);
} else {
printf("Successfully wrote %d bytes to\n", ret);
printf(" %s\n", decryptedFile);
}
}
printf(" > Back\n");
int input = ProcessInput(1, &selectedOption);
if(input >= 0)
{
if(currentMenu == 3)
currentMenu = 2;
else
currentMenu = 5;
selectedOption = 0;
}
}
}
break;
default:
sceKernelExitGame();
break;
}
pspDebugScreenClear();
sceDisplayWaitVblankStart();
sceGuSwapBuffers();
}
return 0;
}

114
Tools/SaveTool/psf.c Normal file
View File

@ -0,0 +1,114 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* psf.c - PSF parsing routines
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: psf.c 1560 2005-12-10 01:16:32Z jim $
*/
#include "psf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <pspchnnlsv.h>
/* Find to the named section in the PSF file, and return an
absolute pointer to it and the section size. */
int find_psf_section(const char *name,
unsigned char *data,
int dataLen,
unsigned char **location,
int *size)
{
unsigned short int nameLoc;
int i, magicHead, strLoc, headLen, numSects;
int sectCurLen, sectBufLen, sectBufLoc, curPos;
if (dataLen < 0x14)
return -1;
/* Get the basics from the header */
magicHead = *(unsigned int *)&data[0x00];
strLoc = *(unsigned int *)&data[0x08];
headLen = *(unsigned int *)&data[0x0C];
numSects = *(unsigned int *)&data[0x10];
/* Do some error checking */
if (magicHead != 0x46535000)
return -2;
/* Verify strLoc is proper */
if ((strLoc > headLen) || (strLoc >= dataLen))
return -3;
/* Verify headLen is proper */
if (headLen >= dataLen)
return -4;
/* Verify numSects is proper */
if (numSects != ((strLoc - 0x14) / 0x10))
return -5;
/* Process all sections */
for (i = 0; i < numSects; i++)
{
/* Get the curPos */
curPos = 0x14 + (i * 0x10);
/* Verify curPos is proper */
if (curPos >= strLoc)
return -6;
/* Get some basic info about this section */
nameLoc = *(unsigned short *)&data[curPos];
sectCurLen = *(unsigned short *)&data[curPos + 0x04];
sectBufLen = *(unsigned short *)&data[curPos + 0x08];
sectBufLoc = *(unsigned short *)&data[curPos + 0x0C];
/* Do some error checking */
if ((nameLoc < dataLen) && (sectCurLen < dataLen)
&& (sectBufLen < dataLen) && (sectBufLoc < dataLen))
{
/* Check if this is the section we want */
if (!stricmp((char *)&data[strLoc + nameLoc], name))
{
/* Update the location and size */
*location = &data[headLen + sectBufLoc];
*size = sectBufLen;
return 0;
}
}
}
/* Section was not found if it makes it here */
return -7;
}
/* Find the named file inside the FILE_LIST, and return
an absolute pointer to it. */
int find_psf_datafile(const char *name,
unsigned char *filelist,
int size,
unsigned char **location)
{
int i;
/* Process all files */
for (i = 0; (i + 0x0d) <= size; i += 0x20)
{
/* Check if this is the filename we want */
if (!strncasecmp((char *)&filelist[i], name, 0x0d)) {
*location = &filelist[i];
return 0;
}
}
/* File was not found if it makes it here */
return -1;
}

29
Tools/SaveTool/psf.h Normal file
View File

@ -0,0 +1,29 @@
/*
* PSP Software Development Kit - http://www.pspdev.org
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* psf.h - Declarations for functions in psf.c
*
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Coypright (c) 2005 psp123
*
* $Id: psf.h 1559 2005-12-10 01:10:11Z jim $
*/
#include <pspchnnlsv.h>
/* Find the named section in the PSF file, and return an
absolute pointer to it and the section size. */
int find_psf_section(const char *name,
unsigned char *data,
int dataLen,
unsigned char **location,
int *size);
/* Find the named file inside the FILE_LIST, and return
an absolute pointer to it. */
int find_psf_datafile(const char *name,
unsigned char *filelist,
int size,
unsigned char **location);