From 9b5eacdef93028331f0c9370405426e3d9526857 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Sun, 11 Sep 2022 05:14:37 +0300 Subject: [PATCH] Small enhancements in old code + some fixes for AesCtrBufferedInputStream --- .../libKonogonka/Tools/NCA/NCAContent.java | 48 ++++++-- .../libKonogonka/Tools/NCA/NCAProvider.java | 1 - .../Tools/PFS0/IPFS0Provider.java | 2 + .../Tools/PFS0/PFS0EncryptedProvider.java | 61 ++++++++-- .../libKonogonka/Tools/PFS0/PFS0Provider.java | 113 ++++++++++++++---- .../libKonogonka/Tools/PFS0/PFS0subFile.java | 8 +- .../Tools/RomFs/FileSystemEntry.java | 20 ++-- .../Tools/RomFs/Level6Header.java | 20 ++-- .../Tools/RomFs/RomFsDecryptedProvider.java | 4 +- .../RomFs/RomFsEncryptedContentRetrieve.java | 1 + .../Tools/RomFs/RomFsEncryptedProvider.java | 5 +- .../RomFs/view/FileSystemTreeViewMaker.java | 2 +- .../ctraes/AesCtrBufferedInputStream.java | 17 +-- .../RomFsDecrypted/KeyChainHolderTest.java | 3 +- 14 files changed, 219 insertions(+), 86 deletions(-) diff --git a/src/main/java/libKonogonka/Tools/NCA/NCAContent.java b/src/main/java/libKonogonka/Tools/NCA/NCAContent.java index 1f1a762..f962da7 100644 --- a/src/main/java/libKonogonka/Tools/NCA/NCAContent.java +++ b/src/main/java/libKonogonka/Tools/NCA/NCAContent.java @@ -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; diff --git a/src/main/java/libKonogonka/Tools/NCA/NCAProvider.java b/src/main/java/libKonogonka/Tools/NCA/NCAProvider.java index 08543e3..fb41e99 100644 --- a/src/main/java/libKonogonka/Tools/NCA/NCAProvider.java +++ b/src/main/java/libKonogonka/Tools/NCA/NCAProvider.java @@ -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); } } diff --git a/src/main/java/libKonogonka/Tools/PFS0/IPFS0Provider.java b/src/main/java/libKonogonka/Tools/PFS0/IPFS0Provider.java index ebea018..3482834 100644 --- a/src/main/java/libKonogonka/Tools/PFS0/IPFS0Provider.java +++ b/src/main/java/libKonogonka/Tools/PFS0/IPFS0Provider.java @@ -28,4 +28,6 @@ public interface IPFS0Provider extends ISuperProvider { byte[] getPadding(); PFS0subFile[] getPfs0subFiles(); + + void printDebug(); } diff --git a/src/main/java/libKonogonka/Tools/PFS0/PFS0EncryptedProvider.java b/src/main/java/libKonogonka/Tools/PFS0/PFS0EncryptedProvider.java index 07098b9..6527f9e 100644 --- a/src/main/java/libKonogonka/Tools/PFS0/PFS0EncryptedProvider.java +++ b/src/main/java/libKonogonka/Tools/PFS0/PFS0EncryptedProvider.java @@ -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" + + "----------------------------------------------------------------" + ); + } + } } diff --git a/src/main/java/libKonogonka/Tools/PFS0/PFS0Provider.java b/src/main/java/libKonogonka/Tools/PFS0/PFS0Provider.java index 718ef9f..5ff806e 100644 --- a/src/main/java/libKonogonka/Tools/PFS0/PFS0Provider.java +++ b/src/main/java/libKonogonka/Tools/PFS0/PFS0Provider.java @@ -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 { 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" + + "----------------------------------------------------------------" + ); + } + } } diff --git a/src/main/java/libKonogonka/Tools/PFS0/PFS0subFile.java b/src/main/java/libKonogonka/Tools/PFS0/PFS0subFile.java index c654508..ed2dbca 100644 --- a/src/main/java/libKonogonka/Tools/PFS0/PFS0subFile.java +++ b/src/main/java/libKonogonka/Tools/PFS0/PFS0subFile.java @@ -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; diff --git a/src/main/java/libKonogonka/Tools/RomFs/FileSystemEntry.java b/src/main/java/libKonogonka/Tools/RomFs/FileSystemEntry.java index fd10995..8909666 100644 --- a/src/main/java/libKonogonka/Tools/RomFs/FileSystemEntry.java +++ b/src/main/java/libKonogonka/Tools/RomFs/FileSystemEntry.java @@ -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 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); } diff --git a/src/main/java/libKonogonka/Tools/RomFs/Level6Header.java b/src/main/java/libKonogonka/Tools/RomFs/Level6Header.java index 9f0b662..2a6d128 100644 --- a/src/main/java/libKonogonka/Tools/RomFs/Level6Header.java +++ b/src/main/java/libKonogonka/Tools/RomFs/Level6Header.java @@ -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" + "-------------------------------------------------------------" ); } diff --git a/src/main/java/libKonogonka/Tools/RomFs/RomFsDecryptedProvider.java b/src/main/java/libKonogonka/Tools/RomFs/RomFsDecryptedProvider.java index fde28eb..fecc077 100644 --- a/src/main/java/libKonogonka/Tools/RomFs/RomFsDecryptedProvider.java +++ b/src/main/java/libKonogonka/Tools/RomFs/RomFsDecryptedProvider.java @@ -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)); diff --git a/src/main/java/libKonogonka/Tools/RomFs/RomFsEncryptedContentRetrieve.java b/src/main/java/libKonogonka/Tools/RomFs/RomFsEncryptedContentRetrieve.java index 10b8bd1..9f42af1 100644 --- a/src/main/java/libKonogonka/Tools/RomFs/RomFsEncryptedContentRetrieve.java +++ b/src/main/java/libKonogonka/Tools/RomFs/RomFsEncryptedContentRetrieve.java @@ -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; diff --git a/src/main/java/libKonogonka/Tools/RomFs/RomFsEncryptedProvider.java b/src/main/java/libKonogonka/Tools/RomFs/RomFsEncryptedProvider.java index 8c18d35..7d56987 100644 --- a/src/main/java/libKonogonka/Tools/RomFs/RomFsEncryptedProvider.java +++ b/src/main/java/libKonogonka/Tools/RomFs/RomFsEncryptedProvider.java @@ -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, diff --git a/src/main/java/libKonogonka/Tools/RomFs/view/FileSystemTreeViewMaker.java b/src/main/java/libKonogonka/Tools/RomFs/view/FileSystemTreeViewMaker.java index 104837e..d70a34c 100644 --- a/src/main/java/libKonogonka/Tools/RomFs/view/FileSystemTreeViewMaker.java +++ b/src/main/java/libKonogonka/Tools/RomFs/view/FileSystemTreeViewMaker.java @@ -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"); } diff --git a/src/main/java/libKonogonka/ctraes/AesCtrBufferedInputStream.java b/src/main/java/libKonogonka/ctraes/AesCtrBufferedInputStream.java index 09f1c5c..426d8ea 100644 --- a/src/main/java/libKonogonka/ctraes/AesCtrBufferedInputStream.java +++ b/src/main/java/libKonogonka/ctraes/AesCtrBufferedInputStream.java @@ -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)+")"); diff --git a/src/test/java/libKonogonka/RomFsDecrypted/KeyChainHolderTest.java b/src/test/java/libKonogonka/RomFsDecrypted/KeyChainHolderTest.java index 7805299..99bb998 100644 --- a/src/test/java/libKonogonka/RomFsDecrypted/KeyChainHolderTest.java +++ b/src/test/java/libKonogonka/RomFsDecrypted/KeyChainHolderTest.java @@ -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{