/*
This file is part of jpcsp.
Jpcsp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jpcsp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.HLE.modules;
import org.apache.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.util.zip.CRC32;
import jpcsp.crypto.CryptoEngine;
import jpcsp.crypto.KeyVault;
import jpcsp.filesystems.SeekableRandomFile;
import jpcsp.HLE.CanBeNull;
import jpcsp.HLE.HLEFunction;
import jpcsp.HLE.HLEModule;
import jpcsp.HLE.HLEUnimplemented;
import jpcsp.HLE.Modules;
import jpcsp.HLE.TPointer;
import jpcsp.HLE.TPointer32;
import jpcsp.settings.Settings;
public class scePauth extends HLEModule {
public static Logger log = Modules.getLogger("scePauth");
@HLEUnimplemented
@HLEFunction(nid = 0xF7AA47F6, version = 500)
public int scePauth_F7AA47F6(TPointer inputAddr, int inputLength, @CanBeNull TPointer32 resultLengthAddr, TPointer keyAddr) {
CryptoEngine crypto = new CryptoEngine();
byte[] in = inputAddr.getArray8(inputLength);
byte[] key = keyAddr.getArray8(0x10);
byte[] xor = new byte[0x10];
for(int i = 0; i < 0x10; i++) {
xor[i] = (byte)(KeyVault.pauthXorKey[i] & 0xFF);
}
// Try to read/write PAUTH data for external decryption.
try {
// Calculate CRC32 for PAUTH data.
CRC32 crc = new CRC32();
crc.update(in, 0, inputLength);
int tag = (int) crc.getValue();
// Set PAUTH file name and PAUTH dir name.
String pauthDirName = String.format("%sPAUTH%c", Settings.getInstance().getDiscTmpDirectory(), File.separatorChar);
String pauthFileName = pauthDirName + String.format("pauth-%s.bin", Integer.toHexString(tag));
String pauthDecFileName = pauthDirName + String.format("pauth-%s.bin.decrypt", Integer.toHexString(tag));
String pauthKeyFileName = pauthDirName + String.format("pauth-%s.key", Integer.toHexString(tag));
// Check for an already decrypted file.
File dec = new File(pauthDecFileName);
if (dec.exists()) {
log.info("Reading PAUTH data file from " + pauthDecFileName);
// Read the externally decrypted file.
SeekableRandomFile pauthPRXDec = new SeekableRandomFile(pauthDecFileName, "rw");
int pauthSize = (int) pauthPRXDec.length();
byte[] pauthDec = new byte[pauthSize];
pauthPRXDec.read(pauthDec);
pauthPRXDec.close();
inputAddr.setArray(pauthDec, pauthSize);
resultLengthAddr.setValue(pauthSize);
} else {
// Create PAUTH dir under tmp.
File f = new File(pauthDirName);
f.mkdirs();
log.info("Writting PAUTH data file to " + pauthFileName);
log.info("Writting PAUTH key file to " + pauthKeyFileName);
// Write the PAUTH file and key for external decryption.
SeekableRandomFile pauthPRX = new SeekableRandomFile(pauthFileName, "rw");
SeekableRandomFile pauthKey = new SeekableRandomFile(pauthKeyFileName, "rw");
pauthPRX.write(in);
pauthKey.write(key);
pauthPRX.close();
pauthKey.close();
// Decryption is not working properly due to a missing KIRK key.
int reslength = crypto.getPRXEngine().DecryptPRX(in, inputLength, null, 0, 5, key, xor);
// Fake the result.
inputAddr.clear(reslength);
resultLengthAddr.setValue(reslength);
}
} catch (IOException ioe) {
log.error(ioe);
}
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x98B83B5D, version = 500)
public int scePauth_98B83B5D(TPointer inputAddr, int inputLength, @CanBeNull TPointer32 resultLengthAddr, TPointer keyAddr) {
CryptoEngine crypto = new CryptoEngine();
byte[] in = inputAddr.getArray8(inputLength);
byte[] key = keyAddr.getArray8(0x10);
byte[] xor = new byte[0x10];
for(int i = 0; i < 0x10; i++) {
xor[i] = (byte)(KeyVault.pauthXorKey[i] & 0xFF);
}
// Try to read/write PAUTH data for external decryption.
try {
// Calculate CRC32 for PAUTH data.
CRC32 crc = new CRC32();
crc.update(in, 0, inputLength);
int tag = (int) crc.getValue();
// Set PAUTH file name and PAUTH dir name.
String pauthDirName = String.format("%sPAUTH%c", Settings.getInstance().getDiscTmpDirectory(), File.separatorChar);
String pauthFileName = pauthDirName + String.format("pauth_%s.bin", Integer.toHexString(tag));
String pauthDecFileName = pauthDirName + String.format("pauth_%s.bin.decrypt", Integer.toHexString(tag));
String pauthKeyFileName = pauthDirName + String.format("pauth_%s.key", Integer.toHexString(tag));
// Check for an already decrypted file.
File dec = new File(pauthDecFileName);
if (dec.exists()) {
log.info("Reading PAUTH data file from " + pauthDecFileName);
// Read the externally decrypted file.
SeekableRandomFile pauthPRXDec = new SeekableRandomFile(pauthDecFileName, "rw");
int pauthSize = (int) pauthPRXDec.length();
byte[] pauthDec = new byte[pauthSize];
pauthPRXDec.read(pauthDec);
pauthPRXDec.close();
inputAddr.setArray(pauthDec, pauthSize);
resultLengthAddr.setValue(pauthSize);
} else {
// Create PAUTH dir under tmp.
File f = new File(pauthDirName);
f.mkdirs();
log.info("Writting PAUTH data file to " + pauthFileName);
log.info("Writting PAUTH key file to " + pauthKeyFileName);
// Write the PAUTH file and key for external decryption.
SeekableRandomFile pauthPRX = new SeekableRandomFile(pauthFileName, "rw");
SeekableRandomFile pauthKey = new SeekableRandomFile(pauthKeyFileName, "rw");
pauthPRX.write(in);
pauthKey.write(key);
pauthPRX.close();
pauthKey.close();
// Decryption is not working properly due to a missing KIRK key.
int reslength = crypto.getPRXEngine().DecryptPRX(in, inputLength, null, 0, 5, key, xor);
// Fake the result.
inputAddr.clear(reslength);
resultLengthAddr.setValue(reslength);
}
} catch (IOException ioe) {
log.error(ioe);
}
return 0;
}
}