Small enhancements in old code + some fixes for AesCtrBufferedInputStream
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
0cc5d41aef
commit
9b5eacdef9
14 changed files with 219 additions and 86 deletions
|
@ -90,7 +90,7 @@ public class NCAContent {
|
||||||
}
|
}
|
||||||
private void proceedPFS0NotEncrypted() throws Exception{
|
private void proceedPFS0NotEncrypted() throws Exception{
|
||||||
RandomAccessFile raf = new RandomAccessFile(file, "r");
|
RandomAccessFile raf = new RandomAccessFile(file, "r");
|
||||||
long thisMediaLocation = offsetPosition + (ncaHeaderTableEntry.getMediaStartOffset() * 0x200);
|
long thisMediaLocation = offsetPosition + (ncaHeaderTableEntry.getMediaStartOffset() * 0x200);// TODO: NOTE already defined inside PFS0
|
||||||
long hashTableLocation = thisMediaLocation + ncaFsHeader.getSuperBlockPFS0().getHashTableOffset();
|
long hashTableLocation = thisMediaLocation + ncaFsHeader.getSuperBlockPFS0().getHashTableOffset();
|
||||||
long pfs0Location = thisMediaLocation + ncaFsHeader.getSuperBlockPFS0().getPfs0offset();
|
long pfs0Location = thisMediaLocation + ncaFsHeader.getSuperBlockPFS0().getPfs0offset();
|
||||||
|
|
||||||
|
@ -112,13 +112,37 @@ public class NCAContent {
|
||||||
// Get pfs0
|
// Get pfs0
|
||||||
pfs0 = new PFS0Provider(file, pfs0Location);
|
pfs0 = new PFS0Provider(file, pfs0Location);
|
||||||
}
|
}
|
||||||
private void proceedPFS0Encrypted() throws Exception{
|
private void proceedPFS0Encrypted() throws Exception{/*
|
||||||
|
RandomAccessFile raf = new RandomAccessFile(file, "r");
|
||||||
|
long thisMediaLocation = offsetPosition + (ncaHeaderTableEntry.getMediaStartOffset() * 0x200);
|
||||||
|
long hashTableLocation = thisMediaLocation + ncaFsHeader.getSuperBlockPFS0().getHashTableOffset();
|
||||||
|
long pfs0Location = thisMediaLocation + ncaFsHeader.getSuperBlockPFS0().getPfs0offset();
|
||||||
|
|
||||||
|
raf.seek(hashTableLocation);
|
||||||
|
|
||||||
|
byte[] rawData;
|
||||||
|
long sha256recordsNumber = ncaFsHeader.getSuperBlockPFS0().getHashTableSize() / 0x20;
|
||||||
|
// Collect hashes
|
||||||
|
for (int i = 0; i < sha256recordsNumber; i++){
|
||||||
|
rawData = new byte[0x20]; // 32 bytes - size of SHA256 hash
|
||||||
|
if (raf.read(rawData) != -1)
|
||||||
|
Pfs0SHA256hashes.add(rawData);
|
||||||
|
else {
|
||||||
|
raf.close();
|
||||||
|
return; // TODO: fix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
raf.close();
|
||||||
|
// Get pfs0
|
||||||
|
pfs0 = new PFS0Provider(file, pfs0Location);
|
||||||
|
/*/
|
||||||
new CryptoSection03Pfs0(file,
|
new CryptoSection03Pfs0(file,
|
||||||
offsetPosition,
|
offsetPosition,
|
||||||
decryptedKey,
|
decryptedKey,
|
||||||
ncaFsHeader,
|
ncaFsHeader,
|
||||||
ncaHeaderTableEntry.getMediaStartOffset(),
|
ncaHeaderTableEntry.getMediaStartOffset(),
|
||||||
ncaHeaderTableEntry.getMediaEndOffset());
|
ncaHeaderTableEntry.getMediaEndOffset());
|
||||||
|
//*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private void proceedRomFs() throws Exception{
|
private void proceedRomFs() throws Exception{
|
||||||
|
@ -170,20 +194,22 @@ public class NCAContent {
|
||||||
"SHA256 hash table size: " + RainbowDump.formatDecHexString(ncaFsHeader.getSuperBlockPFS0().getHashTableSize()) + "\n" +
|
"SHA256 hash table size: " + RainbowDump.formatDecHexString(ncaFsHeader.getSuperBlockPFS0().getHashTableSize()) + "\n" +
|
||||||
"SHA256 hash table offs: " + RainbowDump.formatDecHexString(ncaFsHeader.getSuperBlockPFS0().getHashTableOffset()) + "\n" +
|
"SHA256 hash table offs: " + RainbowDump.formatDecHexString(ncaFsHeader.getSuperBlockPFS0().getHashTableOffset()) + "\n" +
|
||||||
"PFS0 Offset: " + RainbowDump.formatDecHexString(ncaFsHeader.getSuperBlockPFS0().getPfs0offset()) + "\n" +
|
"PFS0 Offset: " + RainbowDump.formatDecHexString(ncaFsHeader.getSuperBlockPFS0().getPfs0offset()) + "\n" +
|
||||||
"SHA256 records: " + RainbowDump.formatDecHexString((ncaFsHeader.getSuperBlockPFS0().getHashTableSize() / 0x20)) + "\n" +
|
"SHA256 records: " + RainbowDump.formatDecHexString(ncaFsHeader.getSuperBlockPFS0().getHashTableSize() / 0x20) + "\n" +
|
||||||
"KEY (decrypted): " + Converter.byteArrToHexString(decryptedKey) + "\n" +
|
"KEY (decrypted): " + Converter.byteArrToHexString(decryptedKey) + "\n" +
|
||||||
"CTR: " + Converter.byteArrToHexString(ncaFsHeader.getSectionCTR()) + "\n");
|
"CTR: " + Converter.byteArrToHexString(ncaFsHeader.getSectionCTR()) + "\n" +
|
||||||
|
"-----------------------------------------------------------\n");
|
||||||
if (decryptedKey == null)
|
if (decryptedKey == null)
|
||||||
throw new Exception("CryptoSection03: unable to proceed. No decrypted key provided.");
|
throw new Exception("CryptoSection03: unable to proceed. No decrypted key provided.");
|
||||||
|
|
||||||
RandomAccessFile raf = new RandomAccessFile(file, "r");
|
RandomAccessFile raf = new RandomAccessFile(file, "r");
|
||||||
long abosluteOffsetPosition = offsetPosition + (mediaStartBlocksOffset * 0x200);
|
long absoluteOffsetPosition = offsetPosition + (mediaStartBlocksOffset * 0x200);
|
||||||
raf.seek(abosluteOffsetPosition);
|
raf.seek(absoluteOffsetPosition);
|
||||||
|
|
||||||
AesCtrDecryptSimple decryptor = new AesCtrDecryptSimple(decryptedKey, ncaFsHeader.getSectionCTR(), mediaStartBlocksOffset * 0x200);
|
AesCtrDecryptSimple decryptor = new AesCtrDecryptSimple(decryptedKey, ncaFsHeader.getSectionCTR(),
|
||||||
|
mediaStartBlocksOffset * 0x200);
|
||||||
|
|
||||||
byte[] encryptedBlock;
|
byte[] encryptedBlock;
|
||||||
byte[] dectyptedBlock;
|
byte[] decryptedBlock;
|
||||||
long mediaBlocksSize = mediaEndBlocksOffset - mediaStartBlocksOffset;
|
long mediaBlocksSize = mediaEndBlocksOffset - mediaStartBlocksOffset;
|
||||||
// Prepare thread to parse encrypted data
|
// Prepare thread to parse encrypted data
|
||||||
PipedOutputStream streamOut = new PipedOutputStream();
|
PipedOutputStream streamOut = new PipedOutputStream();
|
||||||
|
@ -206,11 +232,11 @@ public class NCAContent {
|
||||||
for (int i = 0; i < mediaBlocksSize; i++){
|
for (int i = 0; i < mediaBlocksSize; i++){
|
||||||
encryptedBlock = new byte[0x200];
|
encryptedBlock = new byte[0x200];
|
||||||
if (raf.read(encryptedBlock) != -1){
|
if (raf.read(encryptedBlock) != -1){
|
||||||
//dectyptedBlock = aesCtr.decrypt(encryptedBlock);
|
//decryptedBlock = aesCtr.decrypt(encryptedBlock);
|
||||||
dectyptedBlock = decryptor.decryptNext(encryptedBlock);
|
decryptedBlock = decryptor.decryptNext(encryptedBlock);
|
||||||
// Writing decrypted data to pipe
|
// Writing decrypted data to pipe
|
||||||
try {
|
try {
|
||||||
streamOut.write(dectyptedBlock);
|
streamOut.write(decryptedBlock);
|
||||||
}
|
}
|
||||||
catch (IOException e){
|
catch (IOException e){
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -310,7 +310,6 @@ public class NCAProvider {
|
||||||
}
|
}
|
||||||
catch (EmptySectionException ignored){}
|
catch (EmptySectionException ignored){}
|
||||||
catch (Exception e){
|
catch (Exception e){
|
||||||
this.ncaContent3 = null;
|
|
||||||
log.debug("Unable to get NCA Content "+number, e);
|
log.debug("Unable to get NCA Content "+number, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,4 +28,6 @@ public interface IPFS0Provider extends ISuperProvider {
|
||||||
byte[] getPadding();
|
byte[] getPadding();
|
||||||
|
|
||||||
PFS0subFile[] getPfs0subFiles();
|
PFS0subFile[] getPfs0subFiles();
|
||||||
|
|
||||||
|
void printDebug();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,16 +18,24 @@
|
||||||
*/
|
*/
|
||||||
package libKonogonka.Tools.PFS0;
|
package libKonogonka.Tools.PFS0;
|
||||||
|
|
||||||
|
import libKonogonka.Converter;
|
||||||
|
import libKonogonka.RainbowDump;
|
||||||
|
import libKonogonka.Tools.RomFs.Level6Header;
|
||||||
import libKonogonka.ctraes.AesCtrDecryptSimple;
|
import libKonogonka.ctraes.AesCtrDecryptSimple;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static libKonogonka.Converter.*;
|
import static libKonogonka.Converter.*;
|
||||||
|
|
||||||
public class PFS0EncryptedProvider implements IPFS0Provider{
|
public class PFS0EncryptedProvider implements IPFS0Provider{
|
||||||
private long rawFileDataStart; // Always -1 @ PFS0EncryptedProvider
|
private final static Logger log = LogManager.getLogger(PFS0EncryptedProvider.class);
|
||||||
|
|
||||||
|
//private long rawFileDataStart; // Always -1 @ PFS0EncryptedProvider
|
||||||
|
|
||||||
private final String magic;
|
private final String magic;
|
||||||
private final int filesCount;
|
private final int filesCount;
|
||||||
|
@ -56,14 +64,14 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
||||||
long mediaEndOffset
|
long mediaEndOffset
|
||||||
) throws Exception{
|
) throws Exception{
|
||||||
// Populate 'meta' data that is needed for getProviderSubFilePipedInpStream()
|
// Populate 'meta' data that is needed for getProviderSubFilePipedInpStream()
|
||||||
this.offsetPositionInFile = offsetPositionInFile;
|
this.offsetPositionInFile = offsetPositionInFile + mediaStartOffset*0x200;
|
||||||
this.file = fileWithEncPFS0;
|
this.file = fileWithEncPFS0;
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.sectionCTR = sectionCTR;
|
this.sectionCTR = sectionCTR;
|
||||||
this.mediaStartOffset = mediaStartOffset;
|
this.mediaStartOffset = mediaStartOffset;
|
||||||
this.mediaEndOffset = mediaEndOffset;
|
this.mediaEndOffset = mediaEndOffset;
|
||||||
// pfs0offsetPosition is a position relative to Media block. Let's add pfs0 'header's' bytes count and get raw data start position in media block
|
// pfs0offsetPosition is a position relative to Media block. Let's add pfs0 'header's' bytes count and get raw data start position in media block
|
||||||
rawFileDataStart = -1; // Set -1 for PFS0EncryptedProvider
|
//rawFileDataStart = -1; // Set -1 for PFS0EncryptedProvider
|
||||||
// Detect raw data start position using next var
|
// Detect raw data start position using next var
|
||||||
rawBlockDataStart = pfs0offsetPosition;
|
rawBlockDataStart = pfs0offsetPosition;
|
||||||
|
|
||||||
|
@ -161,7 +169,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
||||||
@Override
|
@Override
|
||||||
public byte[] getPadding() { return padding; }
|
public byte[] getPadding() { return padding; }
|
||||||
@Override
|
@Override
|
||||||
public long getRawFileDataStart() { return rawFileDataStart; }
|
public long getRawFileDataStart() { return rawBlockDataStart; }
|
||||||
@Override
|
@Override
|
||||||
public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; }
|
public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; }
|
||||||
@Override
|
@Override
|
||||||
|
@ -176,14 +184,21 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
||||||
|
|
||||||
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
||||||
workerThread = new Thread(() -> {
|
workerThread = new Thread(() -> {
|
||||||
System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Executing thread");
|
log.debug("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Executing thread:\nSub file: " +
|
||||||
|
pfs0subFiles[subFileNumber].getName() +
|
||||||
|
"\nFor block # "+((rawBlockDataStart + pfs0subFiles[subFileNumber].getOffset()) / 0x200) +
|
||||||
|
"\nAnd initial skipped bytes are: "+offsetPositionInFile +
|
||||||
|
"\nWhere Raw Block Data Start: "+rawBlockDataStart +
|
||||||
|
"\nAnd sub file offset: "+pfs0subFiles[subFileNumber].getOffset()+
|
||||||
|
"\nSkip bytes "+((rawBlockDataStart + pfs0subFiles[subFileNumber].getOffset()) - ((rawBlockDataStart + pfs0subFiles[subFileNumber].getOffset()) / 0x200) * 0x200)+
|
||||||
|
"\nKEY "+Converter.byteArrToHexString(key)+
|
||||||
|
"\nSection CTR "+Converter.byteArrToHexString(sectionCTR)+
|
||||||
|
"\n______________________________________________________________");
|
||||||
try {
|
try {
|
||||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(file.toPath()));
|
||||||
// Let's store what we're about to skip
|
|
||||||
long skipInitL = offsetPositionInFile + (mediaStartOffset * 0x200); // NOTE: NEVER cast to int.
|
|
||||||
// Check if skip was successful
|
// Check if skip was successful
|
||||||
if (bis.skip(skipInitL) != skipInitL) {
|
if (bis.skip(offsetPositionInFile) != offsetPositionInFile) {
|
||||||
System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Failed to skip range "+skipInitL);
|
System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Failed to skip range "+offsetPositionInFile);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +224,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
||||||
//----------------------------- Step 1: get starting bytes from the end of the junk block --------------------------------
|
//----------------------------- Step 1: get starting bytes from the end of the junk block --------------------------------
|
||||||
|
|
||||||
// Since our data could be located in position with some offset from the decrypted block, let's skip bytes left. Considering the case when data is not aligned to block
|
// Since our data could be located in position with some offset from the decrypted block, let's skip bytes left. Considering the case when data is not aligned to block
|
||||||
skipBytes = (int) ( (rawBlockDataStart + pfs0subFiles[subFileNumber].getOffset()) - startBlock * 0x200); // <- How much bytes shall we skip to reach requested data start of sub-file
|
skipBytes = (int) ((rawBlockDataStart + pfs0subFiles[subFileNumber].getOffset()) - startBlock * 0x200); // <- How much bytes shall we skip to reach requested data start of sub-file
|
||||||
|
|
||||||
if (skipBytes > 0) {
|
if (skipBytes > 0) {
|
||||||
encryptedBlock = new byte[0x200];
|
encryptedBlock = new byte[0x200];
|
||||||
|
@ -301,4 +316,28 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void printDebug(){
|
||||||
|
log.debug(".:: PFS0EncryptedProvider ::.\n" +
|
||||||
|
"File name: " + file.getName() + "\n" +
|
||||||
|
"Raw block data start " + RainbowDump.formatDecHexString(rawBlockDataStart) + "\n" +
|
||||||
|
"Magic " + magic + "\n" +
|
||||||
|
"Files count " + RainbowDump.formatDecHexString(filesCount) + "\n" +
|
||||||
|
"String Table Size " + RainbowDump.formatDecHexString(stringTableSize) + "\n" +
|
||||||
|
"Padding " + Converter.byteArrToHexString(padding) + "\n\n" +
|
||||||
|
|
||||||
|
"Offset position in file " + RainbowDump.formatDecHexString(offsetPositionInFile) + "\n" +
|
||||||
|
"Media Start Offset " + RainbowDump.formatDecHexString(mediaStartOffset) + "\n" +
|
||||||
|
"Media End Offset " + RainbowDump.formatDecHexString(mediaEndOffset) + "\n"
|
||||||
|
);
|
||||||
|
for (PFS0subFile subFile : pfs0subFiles){
|
||||||
|
log.debug(
|
||||||
|
"\nName: " + subFile.getName() + "\n" +
|
||||||
|
"Offset " + RainbowDump.formatDecHexString(subFile.getOffset()) + "\n" +
|
||||||
|
"Size " + RainbowDump.formatDecHexString(subFile.getSize()) + "\n" +
|
||||||
|
"Zeroes " + Converter.byteArrToHexString(subFile.getZeroes()) + "\n" +
|
||||||
|
"----------------------------------------------------------------"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,52 +18,99 @@
|
||||||
*/
|
*/
|
||||||
package libKonogonka.Tools.PFS0;
|
package libKonogonka.Tools.PFS0;
|
||||||
|
|
||||||
|
import libKonogonka.Converter;
|
||||||
|
import libKonogonka.RainbowDump;
|
||||||
|
import libKonogonka.ctraes.AesCtrBufferedInputStream;
|
||||||
|
import libKonogonka.ctraes.AesCtrDecryptSimple;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static libKonogonka.Converter.*;
|
import static libKonogonka.Converter.*;
|
||||||
|
|
||||||
public class PFS0Provider implements IPFS0Provider{
|
public class PFS0Provider implements IPFS0Provider{
|
||||||
private final long rawFileDataStart; // Where data starts, excluding header, string table etc.
|
private final static Logger log = LogManager.getLogger(PFS0Provider.class);
|
||||||
|
|
||||||
private final String magic;
|
private long rawFileDataStartOffset;
|
||||||
private final int filesCount;
|
|
||||||
private final int stringTableSize;
|
private String magic;
|
||||||
private final byte[] padding;
|
private int filesCount;
|
||||||
private final PFS0subFile[] pfs0subFiles;
|
private int stringTableSize;
|
||||||
|
private byte[] padding;
|
||||||
|
private PFS0subFile[] pfs0subFiles;
|
||||||
|
|
||||||
private final File file;
|
private final File file;
|
||||||
|
private final long offsetPosition; // Where data starts, excluding header, string table etc.
|
||||||
|
private long mediaStartOffset;
|
||||||
|
private long mediaEndOffset;
|
||||||
|
private AesCtrDecryptSimple decryptor;
|
||||||
|
|
||||||
|
private final boolean encrypted;
|
||||||
|
|
||||||
|
public PFS0Provider(File fileWithPfs0,
|
||||||
|
long offsetPosition,
|
||||||
|
long mediaStartOffset,
|
||||||
|
long mediaEndOffset,
|
||||||
|
AesCtrDecryptSimple decryptor) throws Exception{
|
||||||
|
this.file = fileWithPfs0;
|
||||||
|
this.offsetPosition = offsetPosition + mediaStartOffset*0x200;
|
||||||
|
this.encrypted = true;
|
||||||
|
|
||||||
|
this.mediaStartOffset = mediaStartOffset;
|
||||||
|
this.mediaEndOffset = mediaEndOffset;
|
||||||
|
this.decryptor = decryptor;
|
||||||
|
proceedPfs0();
|
||||||
|
}
|
||||||
|
|
||||||
public PFS0Provider(File fileWithPfs0) throws Exception{ this(fileWithPfs0, 0); }
|
public PFS0Provider(File fileWithPfs0) throws Exception{ this(fileWithPfs0, 0); }
|
||||||
|
|
||||||
public PFS0Provider(File fileWithPfs0, long pfs0offsetPosition) throws Exception{
|
public PFS0Provider(File fileWithPfs0, long offsetPosition) throws Exception{
|
||||||
file = fileWithPfs0;
|
this.file = fileWithPfs0;
|
||||||
RandomAccessFile raf = new RandomAccessFile(fileWithPfs0, "r"); // TODO: replace to bufferedInputStream
|
this.offsetPosition = offsetPosition;
|
||||||
|
this.encrypted = false;
|
||||||
|
//bufferedInputStream = new BufferedInputStream(Files.newInputStream(fileWithPfs0.toPath()));
|
||||||
|
proceedPfs0();
|
||||||
|
}
|
||||||
|
private void proceedPfs0() throws Exception{
|
||||||
|
BufferedInputStream bufferedInputStream;
|
||||||
|
|
||||||
|
if (encrypted) {
|
||||||
|
bufferedInputStream = new AesCtrBufferedInputStream(decryptor,
|
||||||
|
offsetPosition,
|
||||||
|
mediaStartOffset,
|
||||||
|
mediaEndOffset,
|
||||||
|
Files.newInputStream(file.toPath()));
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
bufferedInputStream = new BufferedInputStream(Files.newInputStream(file.toPath()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offsetPosition != bufferedInputStream.skip(offsetPosition))
|
||||||
|
throw new Exception("PFS0Provider: Unable to skip initial offset: "+offsetPosition);
|
||||||
|
|
||||||
raf.seek(pfs0offsetPosition);
|
|
||||||
byte[] fileStartingBytes = new byte[0x10];
|
byte[] fileStartingBytes = new byte[0x10];
|
||||||
// Read PFS0Provider, files count, header, padding (4 zero bytes)
|
// Read PFS0Provider, files count, header, padding (4 zero bytes)
|
||||||
if (raf.read(fileStartingBytes) != 0x10){
|
if (bufferedInputStream.read(fileStartingBytes) != 0x10){
|
||||||
raf.close();
|
|
||||||
throw new Exception("PFS0Provider: Unable to read starting bytes");
|
throw new Exception("PFS0Provider: Unable to read starting bytes");
|
||||||
}
|
}
|
||||||
|
rawFileDataStartOffset += 0x10;
|
||||||
// Check PFS0Provider
|
// Check PFS0Provider
|
||||||
magic = new String(fileStartingBytes, 0x0, 0x4, StandardCharsets.US_ASCII);
|
magic = new String(fileStartingBytes, 0x0, 0x4, StandardCharsets.US_ASCII);
|
||||||
if (! magic.equals("PFS0")){
|
if (! magic.equals("PFS0")){
|
||||||
raf.close();
|
|
||||||
throw new Exception("PFS0Provider: Bad magic");
|
throw new Exception("PFS0Provider: Bad magic");
|
||||||
}
|
}
|
||||||
// Get files count
|
// Get files count
|
||||||
filesCount = getLEint(fileStartingBytes, 0x4);
|
filesCount = getLEint(fileStartingBytes, 0x4);
|
||||||
if (filesCount <= 0 ) {
|
if (filesCount <= 0 ) {
|
||||||
raf.close();
|
|
||||||
throw new Exception("PFS0Provider: Files count is too small");
|
throw new Exception("PFS0Provider: Files count is too small");
|
||||||
}
|
}
|
||||||
// Get string table
|
// Get string table
|
||||||
stringTableSize = getLEint(fileStartingBytes, 0x8);
|
stringTableSize = getLEint(fileStartingBytes, 0x8);
|
||||||
if (stringTableSize <= 0 ){
|
if (stringTableSize <= 0 ){
|
||||||
raf.close();
|
|
||||||
throw new Exception("PFS0Provider: String table is too small");
|
throw new Exception("PFS0Provider: String table is too small");
|
||||||
}
|
}
|
||||||
padding = Arrays.copyOfRange(fileStartingBytes, 0xc, 0x10);
|
padding = Arrays.copyOfRange(fileStartingBytes, 0xc, 0x10);
|
||||||
|
@ -77,21 +124,22 @@ public class PFS0Provider implements IPFS0Provider{
|
||||||
|
|
||||||
byte[] fileEntryTable = new byte[0x18];
|
byte[] fileEntryTable = new byte[0x18];
|
||||||
for (int i=0; i<filesCount; i++){
|
for (int i=0; i<filesCount; i++){
|
||||||
if (raf.read(fileEntryTable) != 0x18)
|
if (bufferedInputStream.read(fileEntryTable) != 0x18)
|
||||||
throw new Exception("PFS0Provider: String table is too small");
|
throw new Exception("PFS0Provider: String table is too small");
|
||||||
offsetsSubFiles[i] = getLElong(fileEntryTable, 0);
|
offsetsSubFiles[i] = getLElong(fileEntryTable, 0);
|
||||||
sizesSubFiles[i] = getLElong(fileEntryTable, 0x8);
|
sizesSubFiles[i] = getLElong(fileEntryTable, 0x8);
|
||||||
strTableOffsets[i] = getLEint(fileEntryTable, 0x10);
|
strTableOffsets[i] = getLEint(fileEntryTable, 0x10);
|
||||||
zeroBytes[i] = Arrays.copyOfRange(fileEntryTable, 0x14, 0x18);
|
zeroBytes[i] = Arrays.copyOfRange(fileEntryTable, 0x14, 0x18);
|
||||||
|
rawFileDataStartOffset += 0x18;
|
||||||
}
|
}
|
||||||
//**********************************************************************************************************
|
//**********************************************************************************************************
|
||||||
// In here pointer in front of String table
|
// In here pointer in front of String table
|
||||||
String[] subFileNames = new String[filesCount];
|
String[] subFileNames = new String[filesCount];
|
||||||
byte[] stringTbl = new byte[stringTableSize];
|
byte[] stringTbl = new byte[stringTableSize];
|
||||||
if (raf.read(stringTbl) != stringTableSize){
|
if (bufferedInputStream.read(stringTbl) != stringTableSize){
|
||||||
throw new Exception("Read PFS0Provider String table failure. Can't read requested string table size ("+stringTableSize+")");
|
throw new Exception("Read PFS0Provider String table failure. Can't read requested string table size ("+stringTableSize+")");
|
||||||
}
|
}
|
||||||
|
rawFileDataStartOffset += stringTableSize;
|
||||||
for (int i=0; i < filesCount; i++){
|
for (int i=0; i < filesCount; i++){
|
||||||
int j = 0;
|
int j = 0;
|
||||||
while (stringTbl[strTableOffsets[i]+j] != (byte)0x00)
|
while (stringTbl[strTableOffsets[i]+j] != (byte)0x00)
|
||||||
|
@ -106,12 +154,11 @@ public class PFS0Provider implements IPFS0Provider{
|
||||||
zeroBytes[i]
|
zeroBytes[i]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
rawFileDataStart = raf.getFilePointer();
|
bufferedInputStream.close();
|
||||||
raf.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEncrypted() { return false; }
|
public boolean isEncrypted() { return encrypted; }
|
||||||
@Override
|
@Override
|
||||||
public String getMagic() { return magic; }
|
public String getMagic() { return magic; }
|
||||||
@Override
|
@Override
|
||||||
|
@ -121,7 +168,7 @@ public class PFS0Provider implements IPFS0Provider{
|
||||||
@Override
|
@Override
|
||||||
public byte[] getPadding() { return padding; }
|
public byte[] getPadding() { return padding; }
|
||||||
@Override
|
@Override
|
||||||
public long getRawFileDataStart() { return rawFileDataStart; }
|
public long getRawFileDataStart() { return rawFileDataStartOffset; }
|
||||||
@Override
|
@Override
|
||||||
public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; }
|
public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; }
|
||||||
@Override
|
@Override
|
||||||
|
@ -139,7 +186,7 @@ public class PFS0Provider implements IPFS0Provider{
|
||||||
workerThread = new Thread(() -> {
|
workerThread = new Thread(() -> {
|
||||||
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Executing thread");
|
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Executing thread");
|
||||||
try {
|
try {
|
||||||
long subFileRealPosition = rawFileDataStart + pfs0subFiles[subFileNumber].getOffset();
|
long subFileRealPosition = rawFileDataStartOffset + pfs0subFiles[subFileNumber].getOffset();
|
||||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||||
if (bis.skip(subFileRealPosition) != subFileRealPosition) {
|
if (bis.skip(subFileRealPosition) != subFileRealPosition) {
|
||||||
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Unable to skip requested offset");
|
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Unable to skip requested offset");
|
||||||
|
@ -186,4 +233,24 @@ public class PFS0Provider implements IPFS0Provider{
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void printDebug(){
|
||||||
|
log.debug(".:: PFS0Provider ::.\n" +
|
||||||
|
"File name: " + file.getName() + "\n\n" +
|
||||||
|
"Raw file data start: " + RainbowDump.formatDecHexString(rawFileDataStartOffset) + "\n" +
|
||||||
|
"Magic " + magic + "\n" +
|
||||||
|
"Files count " + RainbowDump.formatDecHexString(filesCount) + "\n" +
|
||||||
|
"String Table Size " + RainbowDump.formatDecHexString(stringTableSize) + "\n" +
|
||||||
|
"Padding " + Converter.byteArrToHexString(padding) + "\n"
|
||||||
|
);
|
||||||
|
for (PFS0subFile subFile : pfs0subFiles){
|
||||||
|
log.debug(
|
||||||
|
"\nName: " + subFile.getName() + "\n" +
|
||||||
|
"Offset " + RainbowDump.formatDecHexString(subFile.getOffset()) + "\n" +
|
||||||
|
"Size " + RainbowDump.formatDecHexString(subFile.getSize()) + "\n" +
|
||||||
|
"Zeroes " + Converter.byteArrToHexString(subFile.getZeroes()) + "\n" +
|
||||||
|
"----------------------------------------------------------------"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,10 @@
|
||||||
package libKonogonka.Tools.PFS0;
|
package libKonogonka.Tools.PFS0;
|
||||||
|
|
||||||
public class PFS0subFile {
|
public class PFS0subFile {
|
||||||
private String name;
|
private final String name;
|
||||||
private long offset; // REAL in file (including offset in NCA/NSP file)
|
private final long offset; // REAL in file (including offset in NCA/NSP file)
|
||||||
private long size;
|
private final long size;
|
||||||
private byte[] zeroes;
|
private final byte[] zeroes;
|
||||||
|
|
||||||
public PFS0subFile(String name, long offset, long size, byte[] zeroesInTable){
|
public PFS0subFile(String name, long offset, long size, byte[] zeroesInTable){
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
|
|
@ -41,8 +41,8 @@ public class FileSystemEntry {
|
||||||
private static byte[] dirsMetadataTable;
|
private static byte[] dirsMetadataTable;
|
||||||
private static byte[] filesMetadataTable;
|
private static byte[] filesMetadataTable;
|
||||||
|
|
||||||
private long fileOffset;
|
private long offset;
|
||||||
private long fileSize;
|
private long size;
|
||||||
|
|
||||||
public FileSystemEntry(byte[] dirsMetadataTable, byte[] filesMetadataTable) throws Exception{
|
public FileSystemEntry(byte[] dirsMetadataTable, byte[] filesMetadataTable) throws Exception{
|
||||||
FileSystemEntry.dirsMetadataTable = dirsMetadataTable;
|
FileSystemEntry.dirsMetadataTable = dirsMetadataTable;
|
||||||
|
@ -62,7 +62,7 @@ public class FileSystemEntry {
|
||||||
content.add(getDirectory(rootDirectoryMetaData.firstSubdirectoryOffset));
|
content.add(getDirectory(rootDirectoryMetaData.firstSubdirectoryOffset));
|
||||||
if (rootDirectoryMetaData.firstFileOffset != -1)
|
if (rootDirectoryMetaData.firstFileOffset != -1)
|
||||||
content.add(getFile(this, rootDirectoryMetaData.firstFileOffset));
|
content.add(getFile(this, rootDirectoryMetaData.firstFileOffset));
|
||||||
content.sort(Comparator.comparingLong(FileSystemEntry::getFileOffset));
|
content.sort(Comparator.comparingLong(FileSystemEntry::getOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
private FileSystemEntry(){
|
private FileSystemEntry(){
|
||||||
|
@ -85,7 +85,7 @@ public class FileSystemEntry {
|
||||||
if (directoryMetaData.firstFileOffset != -1)
|
if (directoryMetaData.firstFileOffset != -1)
|
||||||
fileSystemEntry.content.add(getFile(fileSystemEntry, directoryMetaData.firstFileOffset));
|
fileSystemEntry.content.add(getFile(fileSystemEntry, directoryMetaData.firstFileOffset));
|
||||||
|
|
||||||
fileSystemEntry.content.sort(Comparator.comparingLong(FileSystemEntry::getFileOffset));
|
fileSystemEntry.content.sort(Comparator.comparingLong(FileSystemEntry::getOffset));
|
||||||
|
|
||||||
return fileSystemEntry;
|
return fileSystemEntry;
|
||||||
}
|
}
|
||||||
|
@ -96,8 +96,8 @@ public class FileSystemEntry {
|
||||||
|
|
||||||
FileMetaData fileMetaData = new FileMetaData(childFileMetaPosition);
|
FileMetaData fileMetaData = new FileMetaData(childFileMetaPosition);
|
||||||
fileSystemEntry.name = fileMetaData.fileName;
|
fileSystemEntry.name = fileMetaData.fileName;
|
||||||
fileSystemEntry.fileOffset = fileMetaData.fileDataRealOffset;
|
fileSystemEntry.offset = fileMetaData.fileDataRealOffset;
|
||||||
fileSystemEntry.fileSize = fileMetaData.fileDataRealLength;
|
fileSystemEntry.size = fileMetaData.fileDataRealLength;
|
||||||
if (fileMetaData.nextSiblingFileOffset != -1)
|
if (fileMetaData.nextSiblingFileOffset != -1)
|
||||||
directoryContainer.content.add(getFile(directoryContainer, fileMetaData.nextSiblingFileOffset) );
|
directoryContainer.content.add(getFile(directoryContainer, fileMetaData.nextSiblingFileOffset) );
|
||||||
|
|
||||||
|
@ -106,8 +106,8 @@ public class FileSystemEntry {
|
||||||
|
|
||||||
public boolean isDirectory() { return directoryFlag; }
|
public boolean isDirectory() { return directoryFlag; }
|
||||||
public boolean isFile() { return ! directoryFlag; }
|
public boolean isFile() { return ! directoryFlag; }
|
||||||
public long getFileOffset() { return fileOffset; }
|
public long getOffset() { return offset; }
|
||||||
public long getFileSize() { return fileSize; }
|
public long getSize() { return size; }
|
||||||
public List<FileSystemEntry> getContent() { return content; }
|
public List<FileSystemEntry> getContent() { return content; }
|
||||||
public String getName(){ return name; }
|
public String getName(){ return name; }
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ public class FileSystemEntry {
|
||||||
firstFileOffset = Converter.getLEint(dirsMetadataTable, i);
|
firstFileOffset = Converter.getLEint(dirsMetadataTable, i);
|
||||||
i += 4;
|
i += 4;
|
||||||
nextHashTableBucketDirectoryOffset = Converter.getLEint(dirsMetadataTable, i);
|
nextHashTableBucketDirectoryOffset = Converter.getLEint(dirsMetadataTable, i);
|
||||||
//*
|
/*
|
||||||
if (nextHashTableBucketDirectoryOffset < 0) {
|
if (nextHashTableBucketDirectoryOffset < 0) {
|
||||||
System.out.println("nextHashTableBucketDirectoryOffset: "+ nextHashTableBucketDirectoryOffset);
|
System.out.println("nextHashTableBucketDirectoryOffset: "+ nextHashTableBucketDirectoryOffset);
|
||||||
}
|
}
|
||||||
|
@ -183,7 +183,7 @@ public class FileSystemEntry {
|
||||||
fileDataRealLength = Converter.getLElong(filesMetadataTable, i);
|
fileDataRealLength = Converter.getLElong(filesMetadataTable, i);
|
||||||
i += 8;
|
i += 8;
|
||||||
nextHashTableBucketFileOffset = Converter.getLEint(filesMetadataTable, i);
|
nextHashTableBucketFileOffset = Converter.getLEint(filesMetadataTable, i);
|
||||||
//*
|
/*
|
||||||
if (nextHashTableBucketFileOffset < 0) {
|
if (nextHashTableBucketFileOffset < 0) {
|
||||||
System.out.println("nextHashTableBucketFileOffset: "+ nextHashTableBucketFileOffset);
|
System.out.println("nextHashTableBucketFileOffset: "+ nextHashTableBucketFileOffset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,16 +91,16 @@ public class Level6Header {
|
||||||
|
|
||||||
public void printDebugInfo(){
|
public void printDebugInfo(){
|
||||||
log.debug("== Level 6 Header ==\n" +
|
log.debug("== Level 6 Header ==\n" +
|
||||||
"Header Length (usually 0x50) "+ RainbowDump.formatDecHexString(headerLength)+" (size of this structure within first 0x200 block of LEVEL 6 part)\n" +
|
"Header Length (usually 0x50) "+ RainbowDump.formatDecHexString(headerLength)+" (size of this structure within first 0x200 block of LEVEL 6 part)\n" +
|
||||||
"Directory Hash Table Offset "+ RainbowDump.formatDecHexString(directoryHashTableOffset)+" (against THIS block where HEADER contains)\n" +
|
"Directory Hash Table Offset "+ RainbowDump.formatDecHexString(directoryHashTableOffset)+" (against THIS block where HEADER contains)\n" +
|
||||||
"Directory Hash Table Length "+ RainbowDump.formatDecHexString(directoryHashTableLength) + "\n" +
|
"Directory Hash Table Length "+ RainbowDump.formatDecHexString(directoryHashTableLength) + "\n" +
|
||||||
"Directory Metadata Table Offset "+ RainbowDump.formatDecHexString(directoryMetadataTableOffset) + "\n" +
|
"Directory Metadata Table Offset "+ RainbowDump.formatDecHexString(directoryMetadataTableOffset) + "\n" +
|
||||||
"Directory Metadata Table Length "+ RainbowDump.formatDecHexString(directoryMetadataTableLength) + "\n" +
|
"Directory Metadata Table Length "+ RainbowDump.formatDecHexString(directoryMetadataTableLength) + "\n" +
|
||||||
"File Hash Table Offset "+ RainbowDump.formatDecHexString(fileHashTableOffset) + "\n" +
|
"File Hash Table Offset "+ RainbowDump.formatDecHexString(fileHashTableOffset) + "\n" +
|
||||||
"File Hash Table Length "+ RainbowDump.formatDecHexString(fileHashTableLength) + "\n" +
|
"File Hash Table Length "+ RainbowDump.formatDecHexString(fileHashTableLength) + "\n" +
|
||||||
"File Metadata Table Offset "+ RainbowDump.formatDecHexString(fileMetadataTableOffset) + "\n" +
|
"File Metadata Table Offset "+ RainbowDump.formatDecHexString(fileMetadataTableOffset) + "\n" +
|
||||||
"File Metadata Table Length "+ RainbowDump.formatDecHexString(fileMetadataTableLength) + "\n" +
|
"File Metadata Table Length "+ RainbowDump.formatDecHexString(fileMetadataTableLength) + "\n" +
|
||||||
"File Data Offset "+ RainbowDump.formatDecHexString(fileDataOffset) + "\n" +
|
"File Data Offset "+ RainbowDump.formatDecHexString(fileDataOffset) + "\n" +
|
||||||
"-------------------------------------------------------------"
|
"-------------------------------------------------------------"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,8 +58,8 @@ public class RomFsDecryptedProvider implements IRomFsProvider{
|
||||||
|
|
||||||
PipedOutputStream streamOut = new PipedOutputStream();
|
PipedOutputStream streamOut = new PipedOutputStream();
|
||||||
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
||||||
long internalFileRealPosition = level6Offset + level6Header.getFileDataOffset() + entry.getFileOffset();
|
long internalFileRealPosition = level6Offset + level6Header.getFileDataOffset() + entry.getOffset();
|
||||||
long internalFileSize = entry.getFileSize();
|
long internalFileSize = entry.getSize();
|
||||||
|
|
||||||
Thread contentRetrievingThread = new Thread(
|
Thread contentRetrievingThread = new Thread(
|
||||||
new RomFsDecryptedContentRetrieve(file, streamOut, internalFileRealPosition, internalFileSize));
|
new RomFsDecryptedContentRetrieve(file, streamOut, internalFileRealPosition, internalFileSize));
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class RomFsEncryptedContentRetrieve implements Runnable{
|
||||||
long level6Offset,
|
long level6Offset,
|
||||||
long headersFileDataOffset
|
long headersFileDataOffset
|
||||||
){
|
){
|
||||||
|
log.fatal("Current implementation works incorrectly");
|
||||||
this.parentFile = parentFile;
|
this.parentFile = parentFile;
|
||||||
this.absoluteOffsetPosition = absoluteOffsetPosition;
|
this.absoluteOffsetPosition = absoluteOffsetPosition;
|
||||||
this.streamOut = streamOut;
|
this.streamOut = streamOut;
|
||||||
|
|
|
@ -75,7 +75,6 @@ public class RomFsEncryptedProvider implements IRomFsProvider{
|
||||||
this.level6Offset = level6Offset;
|
this.level6Offset = level6Offset;
|
||||||
this.level6Header = construct.getHeader();
|
this.level6Header = construct.getHeader();
|
||||||
this.rootEntry = construct.getRootEntry();
|
this.rootEntry = construct.getRootEntry();
|
||||||
|
|
||||||
this.absoluteOffsetPosition = romFsOffsetPosition + (mediaStartOffset * 0x200);
|
this.absoluteOffsetPosition = romFsOffsetPosition + (mediaStartOffset * 0x200);
|
||||||
|
|
||||||
this.directoryMetadataTable = construct.getDirectoryMetadataTable();
|
this.directoryMetadataTable = construct.getDirectoryMetadataTable();
|
||||||
|
@ -99,8 +98,8 @@ public class RomFsEncryptedProvider implements IRomFsProvider{
|
||||||
|
|
||||||
PipedOutputStream streamOut = new PipedOutputStream();
|
PipedOutputStream streamOut = new PipedOutputStream();
|
||||||
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
||||||
long internalFileOffset = entry.getFileOffset();
|
long internalFileOffset = entry.getOffset();
|
||||||
long internalFileSize = entry.getFileSize();
|
long internalFileSize = entry.getSize();
|
||||||
|
|
||||||
Thread contentRetrievingThread = new Thread(new RomFsEncryptedContentRetrieve(
|
Thread contentRetrievingThread = new Thread(new RomFsEncryptedContentRetrieve(
|
||||||
file,
|
file,
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class FileSystemTreeViewMaker {
|
||||||
|
|
||||||
tree.append("|-");
|
tree.append("|-");
|
||||||
tree.append(entry.getName());
|
tree.append(entry.getName());
|
||||||
tree.append(String.format("%"+(spacerForSizes-entry.getName().length()-i)+"s0x%-10x 0x%-10x", "", entry.getFileOffset(), entry.getFileSize()));
|
tree.append(String.format("%"+(spacerForSizes-entry.getName().length()-i)+"s0x%-10x 0x%-10x", "", entry.getOffset(), entry.getSize()));
|
||||||
tree.append("\n");
|
tree.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,6 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
||||||
log.trace("1.2. Pointer Inside + End Position Inside (Decrypted) Encrypted Section ("+pseudoPos+"-"+(pseudoPos+b.length)+")");
|
log.trace("1.2. Pointer Inside + End Position Inside (Decrypted) Encrypted Section ("+pseudoPos+"-"+(pseudoPos+b.length)+")");
|
||||||
System.arraycopy(decryptedBytes, pointerInsideDecryptedSection, b, 0, bytesToRead);
|
System.arraycopy(decryptedBytes, pointerInsideDecryptedSection, b, 0, bytesToRead);
|
||||||
|
|
||||||
log.error("!Pointer Inside Decrypted Section "+pointerInsideDecryptedSection+" "+(pointerInsideDecryptedSection+bytesToRead));
|
|
||||||
pseudoPos += bytesToRead;
|
pseudoPos += bytesToRead;
|
||||||
pointerInsideDecryptedSection += bytesToRead;
|
pointerInsideDecryptedSection += bytesToRead;
|
||||||
return b.length;
|
return b.length;
|
||||||
|
@ -84,12 +83,12 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
||||||
return b.length;
|
return b.length;
|
||||||
}
|
}
|
||||||
log.trace("1. Pointer Inside + End Position Outside Encrypted Section ("+pseudoPos+"-"+(pseudoPos+b.length)+")");
|
log.trace("1. Pointer Inside + End Position Outside Encrypted Section ("+pseudoPos+"-"+(pseudoPos+b.length)+")");
|
||||||
int middleBlocksCount = (int) ((mediaOffsetPositionEnd - pseudoPos) / 0x200);
|
int middleBlocksCount = (int) ((mediaOffsetPositionEnd - (pseudoPos+bytesFromFirstBlock)) / 0x200);
|
||||||
int bytesFromEnd = b.length - bytesFromFirstBlock - middleBlocksCount * 0x200;
|
int bytesFromEnd = bytesToRead - bytesFromFirstBlock - middleBlocksCount * 0x200;
|
||||||
//1
|
//1
|
||||||
System.arraycopy(decryptedBytes, pointerInsideDecryptedSection, b, 0, bytesFromFirstBlock);
|
System.arraycopy(decryptedBytes, pointerInsideDecryptedSection, b, 0, bytesFromFirstBlock);
|
||||||
//2
|
//2
|
||||||
//System.out.println("\n"+bytesFromFirstBlock+"\n"+ middleBlocksCount+" - "+(middleBlocksCount*0x200)+"\n"+ bytesFromEnd+"\n");
|
System.out.println("\n"+bytesFromFirstBlock+"\n"+ middleBlocksCount+" = "+(middleBlocksCount*0x200)+" bytes\n"+ bytesFromEnd+"\n");
|
||||||
for (int i = 0; i < middleBlocksCount; i++) {
|
for (int i = 0; i < middleBlocksCount; i++) {
|
||||||
fillDecryptedCache();
|
fillDecryptedCache();
|
||||||
System.arraycopy(decryptedBytes, 0, b, bytesFromFirstBlock+i*0x200, 0x200);
|
System.arraycopy(decryptedBytes, 0, b, bytesFromFirstBlock+i*0x200, 0x200);
|
||||||
|
@ -102,7 +101,7 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
||||||
}
|
}
|
||||||
if (isEndPositionInsideEncryptedSection(bytesToRead)) {
|
if (isEndPositionInsideEncryptedSection(bytesToRead)) {
|
||||||
log.trace("2. End Position Inside Encrypted Section ("+pseudoPos+"-"+(pseudoPos+b.length)+")");
|
log.trace("2. End Position Inside Encrypted Section ("+pseudoPos+"-"+(pseudoPos+b.length)+")");
|
||||||
int bytesTillEncrypted = (int) (mediaOffsetPositionStart - pos);
|
int bytesTillEncrypted = (int) (mediaOffsetPositionStart - pseudoPos);
|
||||||
int fullEncryptedBlocks = (bytesToRead - bytesTillEncrypted) / 0x200;
|
int fullEncryptedBlocks = (bytesToRead - bytesTillEncrypted) / 0x200;
|
||||||
int incompleteEncryptedBytes = (bytesToRead - bytesTillEncrypted) % 0x200;
|
int incompleteEncryptedBytes = (bytesToRead - bytesTillEncrypted) % 0x200;
|
||||||
System.arraycopy(readChunk(bytesTillEncrypted), 0, b, 0, bytesTillEncrypted);
|
System.arraycopy(readChunk(bytesTillEncrypted), 0, b, 0, bytesTillEncrypted);
|
||||||
|
@ -150,10 +149,10 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPointerInsideEncryptedSection(){
|
private boolean isPointerInsideEncryptedSection(){
|
||||||
return (pseudoPos >= mediaOffsetPositionStart) && (pseudoPos < mediaOffsetPositionEnd);
|
return (pseudoPos-pointerInsideDecryptedSection >= mediaOffsetPositionStart) && (pseudoPos-pointerInsideDecryptedSection < mediaOffsetPositionEnd);
|
||||||
}
|
}
|
||||||
private boolean isEndPositionInsideEncryptedSection(long requestedBytesCount){
|
private boolean isEndPositionInsideEncryptedSection(long requestedBytesCount){
|
||||||
return ((pseudoPos + requestedBytesCount) >= mediaOffsetPositionStart) && ((pseudoPos + requestedBytesCount) < mediaOffsetPositionEnd);
|
return ((pseudoPos-pointerInsideDecryptedSection + requestedBytesCount) >= mediaOffsetPositionStart) && ((pseudoPos-pointerInsideDecryptedSection + requestedBytesCount) < mediaOffsetPositionEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -199,7 +198,7 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
||||||
if (isEndPositionInsideEncryptedSection(n)) { //pointer will be inside Encrypted Section, but now outside
|
if (isEndPositionInsideEncryptedSection(n)) { //pointer will be inside Encrypted Section, but now outside
|
||||||
log.trace("5. End Position Inside Encrypted Section ("+pseudoPos+"-"+(pseudoPos+n)+")");
|
log.trace("5. End Position Inside Encrypted Section ("+pseudoPos+"-"+(pseudoPos+n)+")");
|
||||||
//skip to start if the block we need
|
//skip to start if the block we need
|
||||||
long bytesToSkipTillEncryptedBlock = mediaOffsetPositionStart - pseudoPos; //TODO:FIX
|
long bytesToSkipTillEncryptedBlock = mediaOffsetPositionStart - pseudoPos;
|
||||||
long blocksToSkipCountingFromStart = (n - bytesToSkipTillEncryptedBlock) / 0x200; // always positive
|
long blocksToSkipCountingFromStart = (n - bytesToSkipTillEncryptedBlock) / 0x200; // always positive
|
||||||
long bytesToSkipTillRequiredBlock = bytesToSkipTillEncryptedBlock + blocksToSkipCountingFromStart * 0x200;
|
long bytesToSkipTillRequiredBlock = bytesToSkipTillEncryptedBlock + blocksToSkipCountingFromStart * 0x200;
|
||||||
long leftovers = n - bytesToSkipTillRequiredBlock; // most likely will be 0;
|
long leftovers = n - bytesToSkipTillRequiredBlock; // most likely will be 0;
|
||||||
|
@ -210,10 +209,12 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
||||||
bytesToSkipTillEncryptedBlock +
|
bytesToSkipTillEncryptedBlock +
|
||||||
".\nActually skipped: " + skipped +
|
".\nActually skipped: " + skipped +
|
||||||
".\nLeftovers inside encrypted section: " + leftovers);
|
".\nLeftovers inside encrypted section: " + leftovers);
|
||||||
|
log.trace("\tBlocks skipped "+blocksToSkipCountingFromStart);
|
||||||
resetAndSkip(blocksToSkipCountingFromStart);
|
resetAndSkip(blocksToSkipCountingFromStart);
|
||||||
fillDecryptedCache();
|
fillDecryptedCache();
|
||||||
pseudoPos += n;
|
pseudoPos += n;
|
||||||
pointerInsideDecryptedSection = (int) leftovers;
|
pointerInsideDecryptedSection = (int) leftovers;
|
||||||
|
log.debug(" "+pseudoPos+" "+pointerInsideDecryptedSection);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
log.trace("6. Not encrypted ("+pseudoPos+"-"+(pseudoPos+n)+")");
|
log.trace("6. Not encrypted ("+pseudoPos+"-"+(pseudoPos+n)+")");
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
package libKonogonka.RomFsDecrypted;
|
package libKonogonka.RomFsDecrypted;
|
||||||
|
|
||||||
import libKonogonka.KeyChainHolder;
|
import libKonogonka.KeyChainHolder;
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ public class KeyChainHolderTest {
|
||||||
private static final String xci_header_keyFileLocation = "./FilesForTests/xci_header_key.txt";
|
private static final String xci_header_keyFileLocation = "./FilesForTests/xci_header_key.txt";
|
||||||
private KeyChainHolder keyChainHolder;
|
private KeyChainHolder keyChainHolder;
|
||||||
|
|
||||||
@Disabled
|
//@Disabled
|
||||||
@DisplayName("Key Chain Holder Test")
|
@DisplayName("Key Chain Holder Test")
|
||||||
@Test
|
@Test
|
||||||
void keysChain() throws Exception{
|
void keysChain() throws Exception{
|
||||||
|
|
Loading…
Reference in a new issue