From f1c38e9e4cff908ffe72d3a6852cf2677b325fd1 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Mon, 20 May 2019 01:54:46 +0300 Subject: [PATCH] movements to implementing encrypted sections PFS0 provider --- README.md | 7 +- .../konogonka/Tools/NCA/NCAContentPFS0.java | 108 ++++++++++++++++-- .../konogonka/Tools/PFS0/PFS0Provider.java | 4 - 3 files changed, 103 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index e3debe3..a8c0c0a 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,15 @@ Deep WIP multi-tool to work with XCI/NSP/NCA/NRO(?) files [GNU General Public License v3](https://github.com/developersu/konogonka/blob/master/LICENSE) ### Used libraries & resources +* [Bouncy Castle](https://www.bouncycastle.org/) for Java. * [Java-XTS-AES](https://github.com/horrorho/Java-XTS-AES) by horrorho with minimal changes. * [OpenJFX](https://wiki.openjdk.java.net/display/OpenJFX/Main) * Few icons taken from: [materialdesignicons.com](http://materialdesignicons.com/) ### System requirements -JRE/JDK 8u60 or higher. \ No newline at end of file +JRE/JDK 8u60 or higher. + +### Thanks + +TBD \ No newline at end of file diff --git a/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java b/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java index 72840f3..3985c2d 100644 --- a/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java +++ b/src/main/java/konogonka/Tools/NCA/NCAContentPFS0.java @@ -6,8 +6,7 @@ import konogonka.Tools.NCA.NCASectionTableBlock.NCASectionBlock; import konogonka.Tools.PFS0.PFS0Provider; import konogonka.ctraes.AesCtr; -import java.io.File; -import java.io.RandomAccessFile; +import java.io.*; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.LinkedList; @@ -86,22 +85,29 @@ public class NCAContentPFS0 { byte[] encryptedBlock; byte[] dectyptedBlock; - long mediaBlockSize = ncaHeaderTableEntry.getMediaEndOffset()-ncaHeaderTableEntry.getMediaStartOffset(); - - int j = 0; + long mediaBlockSize = ncaHeaderTableEntry.getMediaEndOffset() - ncaHeaderTableEntry.getMediaStartOffset(); + // Prepare thread to parse encrypted data + PipedOutputStream streamOut = new PipedOutputStream(); + PipedInputStream streamInp = new PipedInputStream(streamOut); + new Thread(new ParseEncrypted( + SHA256hashes, + streamInp, + ncaSectionBlock.getSuperBlockPFS0().getPfs0offset(), + ncaSectionBlock.getSuperBlockPFS0().getPfs0size(), + ncaSectionBlock.getSuperBlockPFS0().getHashTableOffset(), + ncaSectionBlock.getSuperBlockPFS0().getHashTableSize() + )).start(); + // Decrypt data for (int i = 0; i < mediaBlockSize; i++){ encryptedBlock = new byte[0x200]; if (raf.read(encryptedBlock) != -1){ dectyptedBlock = aesCtr.decrypt(encryptedBlock); - - System.out.println(new String(dectyptedBlock, (int)ncaSectionBlock.getSuperBlockPFS0().getPfs0offset(), 0x4, StandardCharsets.US_ASCII)); -/* -*/ - j++; - + // Writing decrypted data to pipe + streamOut.write(dectyptedBlock); } } + streamOut.flush(); /* System.arraycopy(dectyptedBlock, 0, decryptedHeader, i * 0x200, 0x200); @@ -163,4 +169,84 @@ public class NCAContentPFS0 { public LinkedList getSHA256hashes() { return SHA256hashes; } public PFS0Provider getPfs0() { return pfs0; } + + + private class ParseEncrypted implements Runnable{ + + LinkedList SHA256hashes; + PipedInputStream pipedInputStream; + + long hashTableOffset; + long hashTableSize; + long hashTableRecordsCount; + long pfs0offset; + long pfs0size; + + ParseEncrypted(LinkedList SHA256hashes, PipedInputStream pipedInputStream, long pfs0offset, long pfs0size, long hashTableOffset, long hashTableSize){ + this.SHA256hashes = SHA256hashes; + this.pipedInputStream = pipedInputStream; + this.hashTableOffset = hashTableOffset; + this.hashTableSize = hashTableSize; + this.hashTableRecordsCount = hashTableSize / 0x20; + this.pfs0offset = pfs0offset; + this.pfs0size = pfs0size; + } + + @Override + public void run() { + long counter = 0; // How many bytes already read + + try{ + if (hashTableOffset > 0){ + while (counter < hashTableOffset) { + pipedInputStream.read(); + counter++; + } + } + // Main loop + while (true){ + // Loop for collecting all recrods from sha256 hash table + while ((counter - hashTableOffset) < hashTableSize){ + int hashCounter = 0; + byte[] sectionHash = new byte[0x20]; + // Loop for collecting bytes for every SINGLE records, where record size == 0x20 + while (hashCounter < 0x20){ + int currentByte = pipedInputStream.read(); + if (currentByte == -1) + break; + sectionHash[hashCounter] = (byte)currentByte; + hashCounter++; + counter++; + } + // Write after collecting + SHA256hashes.add(sectionHash); + } + // Skip padding and go to PFS0 location + if (counter < pfs0offset){ + while (counter < pfs0offset){ + pipedInputStream.read(); + counter++; + } + } + //--------------------------------------------------------- + byte[] magic = new byte[0x4]; + for (int i = 0; i < 4; i++){ + int currentByte = pipedInputStream.read(); + if (currentByte == -1) + break; + magic[i] = (byte)currentByte; + } + RainbowHexDump.hexDumpUTF8(magic); + break; + } + } + catch (IOException ioe){ + System.out.println("'ParseEncrypted' thread exception"); + ioe.printStackTrace(); + } + finally { + System.out.println("Thread died."); + } + } + } } \ No newline at end of file diff --git a/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java b/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java index 2be1ac7..9699794 100644 --- a/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java +++ b/src/main/java/konogonka/Tools/PFS0/PFS0Provider.java @@ -11,7 +11,6 @@ import java.util.Arrays; import static konogonka.LoperConverter.*; public class PFS0Provider { - private long pfs0offsetPosition; private long rawFileDataStart; private String magic; @@ -23,8 +22,6 @@ public class PFS0Provider { public PFS0Provider(File fileWithPfs0) throws Exception{ this(fileWithPfs0, 0); } public PFS0Provider(File fileWithPfs0, long pfs0offsetPosition) throws Exception{ - this.pfs0offsetPosition = pfs0offsetPosition; - try { RandomAccessFile raf = new RandomAccessFile(fileWithPfs0, "r"); @@ -101,7 +98,6 @@ public class PFS0Provider { } } - public long getPfs0offsetPosition() { return pfs0offsetPosition; } public String getMagic() { return magic; } public int getFilesCount() { return filesCount; } public int getStringTableSize() { return stringTableSize; }