Small enhancements in old code + some fixes for AesCtrBufferedInputStream
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Dmitry Isaenko 2022-09-11 05:14:37 +03:00
parent 0cc5d41aef
commit 9b5eacdef9
14 changed files with 219 additions and 86 deletions

View file

@ -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;

View file

@ -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);
}
}

View file

@ -28,4 +28,6 @@ public interface IPFS0Provider extends ISuperProvider {
byte[] getPadding();
PFS0subFile[] getPfs0subFiles();
void printDebug();
}

View file

@ -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" +
"----------------------------------------------------------------"
);
}
}
}

View file

@ -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" +
"----------------------------------------------------------------"
);
}
}
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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" +
"-------------------------------------------------------------"
);
}

View file

@ -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));

View file

@ -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;

View file

@ -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,

View 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");
}

View file

@ -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)+")");

View file

@ -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{