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{
|
||||
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 pfs0Location = thisMediaLocation + ncaFsHeader.getSuperBlockPFS0().getPfs0offset();
|
||||
|
||||
|
@ -112,13 +112,37 @@ public class NCAContent {
|
|||
// Get pfs0
|
||||
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,
|
||||
offsetPosition,
|
||||
decryptedKey,
|
||||
ncaFsHeader,
|
||||
ncaHeaderTableEntry.getMediaStartOffset(),
|
||||
ncaHeaderTableEntry.getMediaEndOffset());
|
||||
//*/
|
||||
}
|
||||
|
||||
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 offs: " + RainbowDump.formatDecHexString(ncaFsHeader.getSuperBlockPFS0().getHashTableOffset()) + "\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" +
|
||||
"CTR: " + Converter.byteArrToHexString(ncaFsHeader.getSectionCTR()) + "\n");
|
||||
"CTR: " + Converter.byteArrToHexString(ncaFsHeader.getSectionCTR()) + "\n" +
|
||||
"-----------------------------------------------------------\n");
|
||||
if (decryptedKey == null)
|
||||
throw new Exception("CryptoSection03: unable to proceed. No decrypted key provided.");
|
||||
|
||||
RandomAccessFile raf = new RandomAccessFile(file, "r");
|
||||
long abosluteOffsetPosition = offsetPosition + (mediaStartBlocksOffset * 0x200);
|
||||
raf.seek(abosluteOffsetPosition);
|
||||
long absoluteOffsetPosition = offsetPosition + (mediaStartBlocksOffset * 0x200);
|
||||
raf.seek(absoluteOffsetPosition);
|
||||
|
||||
AesCtrDecryptSimple decryptor = new AesCtrDecryptSimple(decryptedKey, ncaFsHeader.getSectionCTR(), mediaStartBlocksOffset * 0x200);
|
||||
AesCtrDecryptSimple decryptor = new AesCtrDecryptSimple(decryptedKey, ncaFsHeader.getSectionCTR(),
|
||||
mediaStartBlocksOffset * 0x200);
|
||||
|
||||
byte[] encryptedBlock;
|
||||
byte[] dectyptedBlock;
|
||||
byte[] decryptedBlock;
|
||||
long mediaBlocksSize = mediaEndBlocksOffset - mediaStartBlocksOffset;
|
||||
// Prepare thread to parse encrypted data
|
||||
PipedOutputStream streamOut = new PipedOutputStream();
|
||||
|
@ -206,11 +232,11 @@ public class NCAContent {
|
|||
for (int i = 0; i < mediaBlocksSize; i++){
|
||||
encryptedBlock = new byte[0x200];
|
||||
if (raf.read(encryptedBlock) != -1){
|
||||
//dectyptedBlock = aesCtr.decrypt(encryptedBlock);
|
||||
dectyptedBlock = decryptor.decryptNext(encryptedBlock);
|
||||
//decryptedBlock = aesCtr.decrypt(encryptedBlock);
|
||||
decryptedBlock = decryptor.decryptNext(encryptedBlock);
|
||||
// Writing decrypted data to pipe
|
||||
try {
|
||||
streamOut.write(dectyptedBlock);
|
||||
streamOut.write(decryptedBlock);
|
||||
}
|
||||
catch (IOException e){
|
||||
break;
|
||||
|
|
|
@ -310,7 +310,6 @@ public class NCAProvider {
|
|||
}
|
||||
catch (EmptySectionException ignored){}
|
||||
catch (Exception e){
|
||||
this.ncaContent3 = null;
|
||||
log.debug("Unable to get NCA Content "+number, e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,4 +28,6 @@ public interface IPFS0Provider extends ISuperProvider {
|
|||
byte[] getPadding();
|
||||
|
||||
PFS0subFile[] getPfs0subFiles();
|
||||
|
||||
void printDebug();
|
||||
}
|
||||
|
|
|
@ -18,16 +18,24 @@
|
|||
*/
|
||||
package libKonogonka.Tools.PFS0;
|
||||
|
||||
import libKonogonka.Converter;
|
||||
import libKonogonka.RainbowDump;
|
||||
import libKonogonka.Tools.RomFs.Level6Header;
|
||||
import libKonogonka.ctraes.AesCtrDecryptSimple;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static libKonogonka.Converter.*;
|
||||
|
||||
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 int filesCount;
|
||||
|
@ -56,14 +64,14 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
|||
long mediaEndOffset
|
||||
) throws Exception{
|
||||
// Populate 'meta' data that is needed for getProviderSubFilePipedInpStream()
|
||||
this.offsetPositionInFile = offsetPositionInFile;
|
||||
this.offsetPositionInFile = offsetPositionInFile + mediaStartOffset*0x200;
|
||||
this.file = fileWithEncPFS0;
|
||||
this.key = key;
|
||||
this.sectionCTR = sectionCTR;
|
||||
this.mediaStartOffset = mediaStartOffset;
|
||||
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
|
||||
rawFileDataStart = -1; // Set -1 for PFS0EncryptedProvider
|
||||
//rawFileDataStart = -1; // Set -1 for PFS0EncryptedProvider
|
||||
// Detect raw data start position using next var
|
||||
rawBlockDataStart = pfs0offsetPosition;
|
||||
|
||||
|
@ -161,7 +169,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
|||
@Override
|
||||
public byte[] getPadding() { return padding; }
|
||||
@Override
|
||||
public long getRawFileDataStart() { return rawFileDataStart; }
|
||||
public long getRawFileDataStart() { return rawBlockDataStart; }
|
||||
@Override
|
||||
public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; }
|
||||
@Override
|
||||
|
@ -176,14 +184,21 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
|||
|
||||
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
||||
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 {
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||
// Let's store what we're about to skip
|
||||
long skipInitL = offsetPositionInFile + (mediaStartOffset * 0x200); // NOTE: NEVER cast to int.
|
||||
BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(file.toPath()));
|
||||
// Check if skip was successful
|
||||
if (bis.skip(skipInitL) != skipInitL) {
|
||||
System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Failed to skip range "+skipInitL);
|
||||
if (bis.skip(offsetPositionInFile) != offsetPositionInFile) {
|
||||
System.out.println("PFS0EncryptedProvider -> getPfs0subFilePipedInpStream(): Failed to skip range "+offsetPositionInFile);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -209,7 +224,7 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
|||
//----------------------------- 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
|
||||
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) {
|
||||
encryptedBlock = new byte[0x200];
|
||||
|
@ -301,4 +316,28 @@ public class PFS0EncryptedProvider implements IPFS0Provider{
|
|||
}
|
||||
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;
|
||||
|
||||
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.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static libKonogonka.Converter.*;
|
||||
|
||||
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 final int filesCount;
|
||||
private final int stringTableSize;
|
||||
private final byte[] padding;
|
||||
private final PFS0subFile[] pfs0subFiles;
|
||||
private long rawFileDataStartOffset;
|
||||
|
||||
private String magic;
|
||||
private int filesCount;
|
||||
private int stringTableSize;
|
||||
private byte[] padding;
|
||||
private PFS0subFile[] pfs0subFiles;
|
||||
|
||||
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, long pfs0offsetPosition) throws Exception{
|
||||
file = fileWithPfs0;
|
||||
RandomAccessFile raf = new RandomAccessFile(fileWithPfs0, "r"); // TODO: replace to bufferedInputStream
|
||||
public PFS0Provider(File fileWithPfs0, long offsetPosition) throws Exception{
|
||||
this.file = fileWithPfs0;
|
||||
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];
|
||||
// Read PFS0Provider, files count, header, padding (4 zero bytes)
|
||||
if (raf.read(fileStartingBytes) != 0x10){
|
||||
raf.close();
|
||||
if (bufferedInputStream.read(fileStartingBytes) != 0x10){
|
||||
throw new Exception("PFS0Provider: Unable to read starting bytes");
|
||||
}
|
||||
rawFileDataStartOffset += 0x10;
|
||||
// Check PFS0Provider
|
||||
magic = new String(fileStartingBytes, 0x0, 0x4, StandardCharsets.US_ASCII);
|
||||
if (! magic.equals("PFS0")){
|
||||
raf.close();
|
||||
throw new Exception("PFS0Provider: Bad magic");
|
||||
}
|
||||
// Get files count
|
||||
filesCount = getLEint(fileStartingBytes, 0x4);
|
||||
if (filesCount <= 0 ) {
|
||||
raf.close();
|
||||
throw new Exception("PFS0Provider: Files count is too small");
|
||||
}
|
||||
// Get string table
|
||||
stringTableSize = getLEint(fileStartingBytes, 0x8);
|
||||
if (stringTableSize <= 0 ){
|
||||
raf.close();
|
||||
throw new Exception("PFS0Provider: String table is too small");
|
||||
}
|
||||
padding = Arrays.copyOfRange(fileStartingBytes, 0xc, 0x10);
|
||||
|
@ -77,21 +124,22 @@ public class PFS0Provider implements IPFS0Provider{
|
|||
|
||||
byte[] fileEntryTable = new byte[0x18];
|
||||
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");
|
||||
offsetsSubFiles[i] = getLElong(fileEntryTable, 0);
|
||||
sizesSubFiles[i] = getLElong(fileEntryTable, 0x8);
|
||||
strTableOffsets[i] = getLEint(fileEntryTable, 0x10);
|
||||
zeroBytes[i] = Arrays.copyOfRange(fileEntryTable, 0x14, 0x18);
|
||||
rawFileDataStartOffset += 0x18;
|
||||
}
|
||||
//**********************************************************************************************************
|
||||
// In here pointer in front of String table
|
||||
String[] subFileNames = new String[filesCount];
|
||||
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+")");
|
||||
}
|
||||
|
||||
rawFileDataStartOffset += stringTableSize;
|
||||
for (int i=0; i < filesCount; i++){
|
||||
int j = 0;
|
||||
while (stringTbl[strTableOffsets[i]+j] != (byte)0x00)
|
||||
|
@ -106,12 +154,11 @@ public class PFS0Provider implements IPFS0Provider{
|
|||
zeroBytes[i]
|
||||
);
|
||||
}
|
||||
rawFileDataStart = raf.getFilePointer();
|
||||
raf.close();
|
||||
bufferedInputStream.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncrypted() { return false; }
|
||||
public boolean isEncrypted() { return encrypted; }
|
||||
@Override
|
||||
public String getMagic() { return magic; }
|
||||
@Override
|
||||
|
@ -121,7 +168,7 @@ public class PFS0Provider implements IPFS0Provider{
|
|||
@Override
|
||||
public byte[] getPadding() { return padding; }
|
||||
@Override
|
||||
public long getRawFileDataStart() { return rawFileDataStart; }
|
||||
public long getRawFileDataStart() { return rawFileDataStartOffset; }
|
||||
@Override
|
||||
public PFS0subFile[] getPfs0subFiles() { return pfs0subFiles; }
|
||||
@Override
|
||||
|
@ -139,7 +186,7 @@ public class PFS0Provider implements IPFS0Provider{
|
|||
workerThread = new Thread(() -> {
|
||||
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Executing thread");
|
||||
try {
|
||||
long subFileRealPosition = rawFileDataStart + pfs0subFiles[subFileNumber].getOffset();
|
||||
long subFileRealPosition = rawFileDataStartOffset + pfs0subFiles[subFileNumber].getOffset();
|
||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
|
||||
if (bis.skip(subFileRealPosition) != subFileRealPosition) {
|
||||
System.out.println("PFS0Provider -> getPfs0subFilePipedInpStream(): Unable to skip requested offset");
|
||||
|
@ -186,4 +233,24 @@ public class PFS0Provider implements IPFS0Provider{
|
|||
}
|
||||
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;
|
||||
|
||||
public class PFS0subFile {
|
||||
private String name;
|
||||
private long offset; // REAL in file (including offset in NCA/NSP file)
|
||||
private long size;
|
||||
private byte[] zeroes;
|
||||
private final String name;
|
||||
private final long offset; // REAL in file (including offset in NCA/NSP file)
|
||||
private final long size;
|
||||
private final byte[] zeroes;
|
||||
|
||||
public PFS0subFile(String name, long offset, long size, byte[] zeroesInTable){
|
||||
this.name = name;
|
||||
|
|
|
@ -41,8 +41,8 @@ public class FileSystemEntry {
|
|||
private static byte[] dirsMetadataTable;
|
||||
private static byte[] filesMetadataTable;
|
||||
|
||||
private long fileOffset;
|
||||
private long fileSize;
|
||||
private long offset;
|
||||
private long size;
|
||||
|
||||
public FileSystemEntry(byte[] dirsMetadataTable, byte[] filesMetadataTable) throws Exception{
|
||||
FileSystemEntry.dirsMetadataTable = dirsMetadataTable;
|
||||
|
@ -62,7 +62,7 @@ public class FileSystemEntry {
|
|||
content.add(getDirectory(rootDirectoryMetaData.firstSubdirectoryOffset));
|
||||
if (rootDirectoryMetaData.firstFileOffset != -1)
|
||||
content.add(getFile(this, rootDirectoryMetaData.firstFileOffset));
|
||||
content.sort(Comparator.comparingLong(FileSystemEntry::getFileOffset));
|
||||
content.sort(Comparator.comparingLong(FileSystemEntry::getOffset));
|
||||
}
|
||||
|
||||
private FileSystemEntry(){
|
||||
|
@ -85,7 +85,7 @@ public class FileSystemEntry {
|
|||
if (directoryMetaData.firstFileOffset != -1)
|
||||
fileSystemEntry.content.add(getFile(fileSystemEntry, directoryMetaData.firstFileOffset));
|
||||
|
||||
fileSystemEntry.content.sort(Comparator.comparingLong(FileSystemEntry::getFileOffset));
|
||||
fileSystemEntry.content.sort(Comparator.comparingLong(FileSystemEntry::getOffset));
|
||||
|
||||
return fileSystemEntry;
|
||||
}
|
||||
|
@ -96,8 +96,8 @@ public class FileSystemEntry {
|
|||
|
||||
FileMetaData fileMetaData = new FileMetaData(childFileMetaPosition);
|
||||
fileSystemEntry.name = fileMetaData.fileName;
|
||||
fileSystemEntry.fileOffset = fileMetaData.fileDataRealOffset;
|
||||
fileSystemEntry.fileSize = fileMetaData.fileDataRealLength;
|
||||
fileSystemEntry.offset = fileMetaData.fileDataRealOffset;
|
||||
fileSystemEntry.size = fileMetaData.fileDataRealLength;
|
||||
if (fileMetaData.nextSiblingFileOffset != -1)
|
||||
directoryContainer.content.add(getFile(directoryContainer, fileMetaData.nextSiblingFileOffset) );
|
||||
|
||||
|
@ -106,8 +106,8 @@ public class FileSystemEntry {
|
|||
|
||||
public boolean isDirectory() { return directoryFlag; }
|
||||
public boolean isFile() { return ! directoryFlag; }
|
||||
public long getFileOffset() { return fileOffset; }
|
||||
public long getFileSize() { return fileSize; }
|
||||
public long getOffset() { return offset; }
|
||||
public long getSize() { return size; }
|
||||
public List<FileSystemEntry> getContent() { return content; }
|
||||
public String getName(){ return name; }
|
||||
|
||||
|
@ -135,7 +135,7 @@ public class FileSystemEntry {
|
|||
firstFileOffset = Converter.getLEint(dirsMetadataTable, i);
|
||||
i += 4;
|
||||
nextHashTableBucketDirectoryOffset = Converter.getLEint(dirsMetadataTable, i);
|
||||
//*
|
||||
/*
|
||||
if (nextHashTableBucketDirectoryOffset < 0) {
|
||||
System.out.println("nextHashTableBucketDirectoryOffset: "+ nextHashTableBucketDirectoryOffset);
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ public class FileSystemEntry {
|
|||
fileDataRealLength = Converter.getLElong(filesMetadataTable, i);
|
||||
i += 8;
|
||||
nextHashTableBucketFileOffset = Converter.getLEint(filesMetadataTable, i);
|
||||
//*
|
||||
/*
|
||||
if (nextHashTableBucketFileOffset < 0) {
|
||||
System.out.println("nextHashTableBucketFileOffset: "+ nextHashTableBucketFileOffset);
|
||||
}
|
||||
|
|
|
@ -91,16 +91,16 @@ public class Level6Header {
|
|||
|
||||
public void printDebugInfo(){
|
||||
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" +
|
||||
"Directory Hash Table Offset "+ RainbowDump.formatDecHexString(directoryHashTableOffset)+" (against THIS block where HEADER contains)\n" +
|
||||
"Directory Hash Table Length "+ RainbowDump.formatDecHexString(directoryHashTableLength) + "\n" +
|
||||
"Directory Metadata Table Offset "+ RainbowDump.formatDecHexString(directoryMetadataTableOffset) + "\n" +
|
||||
"Directory Metadata Table Length "+ RainbowDump.formatDecHexString(directoryMetadataTableLength) + "\n" +
|
||||
"File Hash Table Offset "+ RainbowDump.formatDecHexString(fileHashTableOffset) + "\n" +
|
||||
"File Hash Table Length "+ RainbowDump.formatDecHexString(fileHashTableLength) + "\n" +
|
||||
"File Metadata Table Offset "+ RainbowDump.formatDecHexString(fileMetadataTableOffset) + "\n" +
|
||||
"File Metadata Table Length "+ RainbowDump.formatDecHexString(fileMetadataTableLength) + "\n" +
|
||||
"File Data Offset "+ RainbowDump.formatDecHexString(fileDataOffset) + "\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 Length "+ RainbowDump.formatDecHexString(directoryHashTableLength) + "\n" +
|
||||
"Directory Metadata Table Offset "+ RainbowDump.formatDecHexString(directoryMetadataTableOffset) + "\n" +
|
||||
"Directory Metadata Table Length "+ RainbowDump.formatDecHexString(directoryMetadataTableLength) + "\n" +
|
||||
"File Hash Table Offset "+ RainbowDump.formatDecHexString(fileHashTableOffset) + "\n" +
|
||||
"File Hash Table Length "+ RainbowDump.formatDecHexString(fileHashTableLength) + "\n" +
|
||||
"File Metadata Table Offset "+ RainbowDump.formatDecHexString(fileMetadataTableOffset) + "\n" +
|
||||
"File Metadata Table Length "+ RainbowDump.formatDecHexString(fileMetadataTableLength) + "\n" +
|
||||
"File Data Offset "+ RainbowDump.formatDecHexString(fileDataOffset) + "\n" +
|
||||
"-------------------------------------------------------------"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -58,8 +58,8 @@ public class RomFsDecryptedProvider implements IRomFsProvider{
|
|||
|
||||
PipedOutputStream streamOut = new PipedOutputStream();
|
||||
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
||||
long internalFileRealPosition = level6Offset + level6Header.getFileDataOffset() + entry.getFileOffset();
|
||||
long internalFileSize = entry.getFileSize();
|
||||
long internalFileRealPosition = level6Offset + level6Header.getFileDataOffset() + entry.getOffset();
|
||||
long internalFileSize = entry.getSize();
|
||||
|
||||
Thread contentRetrievingThread = new Thread(
|
||||
new RomFsDecryptedContentRetrieve(file, streamOut, internalFileRealPosition, internalFileSize));
|
||||
|
|
|
@ -47,6 +47,7 @@ public class RomFsEncryptedContentRetrieve implements Runnable{
|
|||
long level6Offset,
|
||||
long headersFileDataOffset
|
||||
){
|
||||
log.fatal("Current implementation works incorrectly");
|
||||
this.parentFile = parentFile;
|
||||
this.absoluteOffsetPosition = absoluteOffsetPosition;
|
||||
this.streamOut = streamOut;
|
||||
|
|
|
@ -75,7 +75,6 @@ public class RomFsEncryptedProvider implements IRomFsProvider{
|
|||
this.level6Offset = level6Offset;
|
||||
this.level6Header = construct.getHeader();
|
||||
this.rootEntry = construct.getRootEntry();
|
||||
|
||||
this.absoluteOffsetPosition = romFsOffsetPosition + (mediaStartOffset * 0x200);
|
||||
|
||||
this.directoryMetadataTable = construct.getDirectoryMetadataTable();
|
||||
|
@ -99,8 +98,8 @@ public class RomFsEncryptedProvider implements IRomFsProvider{
|
|||
|
||||
PipedOutputStream streamOut = new PipedOutputStream();
|
||||
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
||||
long internalFileOffset = entry.getFileOffset();
|
||||
long internalFileSize = entry.getFileSize();
|
||||
long internalFileOffset = entry.getOffset();
|
||||
long internalFileSize = entry.getSize();
|
||||
|
||||
Thread contentRetrievingThread = new Thread(new RomFsEncryptedContentRetrieve(
|
||||
file,
|
||||
|
|
|
@ -52,7 +52,7 @@ public class FileSystemTreeViewMaker {
|
|||
|
||||
tree.append("|-");
|
||||
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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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)+")");
|
||||
System.arraycopy(decryptedBytes, pointerInsideDecryptedSection, b, 0, bytesToRead);
|
||||
|
||||
log.error("!Pointer Inside Decrypted Section "+pointerInsideDecryptedSection+" "+(pointerInsideDecryptedSection+bytesToRead));
|
||||
pseudoPos += bytesToRead;
|
||||
pointerInsideDecryptedSection += bytesToRead;
|
||||
return b.length;
|
||||
|
@ -84,12 +83,12 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
|||
return b.length;
|
||||
}
|
||||
log.trace("1. Pointer Inside + End Position Outside Encrypted Section ("+pseudoPos+"-"+(pseudoPos+b.length)+")");
|
||||
int middleBlocksCount = (int) ((mediaOffsetPositionEnd - pseudoPos) / 0x200);
|
||||
int bytesFromEnd = b.length - bytesFromFirstBlock - middleBlocksCount * 0x200;
|
||||
int middleBlocksCount = (int) ((mediaOffsetPositionEnd - (pseudoPos+bytesFromFirstBlock)) / 0x200);
|
||||
int bytesFromEnd = bytesToRead - bytesFromFirstBlock - middleBlocksCount * 0x200;
|
||||
//1
|
||||
System.arraycopy(decryptedBytes, pointerInsideDecryptedSection, b, 0, bytesFromFirstBlock);
|
||||
//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++) {
|
||||
fillDecryptedCache();
|
||||
System.arraycopy(decryptedBytes, 0, b, bytesFromFirstBlock+i*0x200, 0x200);
|
||||
|
@ -102,7 +101,7 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
|||
}
|
||||
if (isEndPositionInsideEncryptedSection(bytesToRead)) {
|
||||
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 incompleteEncryptedBytes = (bytesToRead - bytesTillEncrypted) % 0x200;
|
||||
System.arraycopy(readChunk(bytesTillEncrypted), 0, b, 0, bytesTillEncrypted);
|
||||
|
@ -150,10 +149,10 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
|||
}
|
||||
|
||||
private boolean isPointerInsideEncryptedSection(){
|
||||
return (pseudoPos >= mediaOffsetPositionStart) && (pseudoPos < mediaOffsetPositionEnd);
|
||||
return (pseudoPos-pointerInsideDecryptedSection >= mediaOffsetPositionStart) && (pseudoPos-pointerInsideDecryptedSection < mediaOffsetPositionEnd);
|
||||
}
|
||||
private boolean isEndPositionInsideEncryptedSection(long requestedBytesCount){
|
||||
return ((pseudoPos + requestedBytesCount) >= mediaOffsetPositionStart) && ((pseudoPos + requestedBytesCount) < mediaOffsetPositionEnd);
|
||||
return ((pseudoPos-pointerInsideDecryptedSection + requestedBytesCount) >= mediaOffsetPositionStart) && ((pseudoPos-pointerInsideDecryptedSection + requestedBytesCount) < mediaOffsetPositionEnd);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -199,7 +198,7 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
|||
if (isEndPositionInsideEncryptedSection(n)) { //pointer will be inside Encrypted Section, but now outside
|
||||
log.trace("5. End Position Inside Encrypted Section ("+pseudoPos+"-"+(pseudoPos+n)+")");
|
||||
//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 bytesToSkipTillRequiredBlock = bytesToSkipTillEncryptedBlock + blocksToSkipCountingFromStart * 0x200;
|
||||
long leftovers = n - bytesToSkipTillRequiredBlock; // most likely will be 0;
|
||||
|
@ -210,10 +209,12 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
|||
bytesToSkipTillEncryptedBlock +
|
||||
".\nActually skipped: " + skipped +
|
||||
".\nLeftovers inside encrypted section: " + leftovers);
|
||||
log.trace("\tBlocks skipped "+blocksToSkipCountingFromStart);
|
||||
resetAndSkip(blocksToSkipCountingFromStart);
|
||||
fillDecryptedCache();
|
||||
pseudoPos += n;
|
||||
pointerInsideDecryptedSection = (int) leftovers;
|
||||
log.debug(" "+pseudoPos+" "+pointerInsideDecryptedSection);
|
||||
return n;
|
||||
}
|
||||
log.trace("6. Not encrypted ("+pseudoPos+"-"+(pseudoPos+n)+")");
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
package libKonogonka.RomFsDecrypted;
|
||||
|
||||
import libKonogonka.KeyChainHolder;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
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 KeyChainHolder keyChainHolder;
|
||||
|
||||
@Disabled
|
||||
//@Disabled
|
||||
@DisplayName("Key Chain Holder Test")
|
||||
@Test
|
||||
void keysChain() throws Exception{
|
||||
|
|
Loading…
Reference in a new issue