From 5c7a9f1dc80aa307319ffbb9f4ab6ae3e3c68912 Mon Sep 17 00:00:00 2001 From: Dmitry Isaenko Date: Tue, 20 Aug 2019 07:02:40 +0300 Subject: [PATCH] Ticket reader implemented --- .../java/konogonka/Child/ChildWindow.java | 8 + .../konogonka/Controllers/ITabController.java | 2 +- .../konogonka/Controllers/MainController.java | 11 +- .../Controllers/NCA/NCAController.java | 14 +- .../NCA/NCASectionContentController.java | 5 +- .../Controllers/NSP/NSPController.java | 47 +- .../Controllers/TIK/TIKController.java | 154 ++++ .../Controllers/XCI/XCIController.java | 2 +- .../java/konogonka/Tools/NCA/NCAProvider.java | 7 +- .../java/konogonka/Tools/TIK/TIKProvider.java | 161 ++++ .../java/konogonka/Workers/AnalyzerTIK.java | 45 ++ .../konogonka/Workers/NspXciExtractor.java | 2 +- src/main/resources/FXML/TIK/TIKTab.fxml | 705 ++++++++++++++++++ src/main/resources/FXML/landingPage.fxml | 8 + src/main/resources/locale.properties | 2 +- src/main/resources/locale_fra.properties | 2 +- src/main/resources/locale_rus.properties | 2 +- src/main/resources/locale_ukr.properties | 2 +- 18 files changed, 1134 insertions(+), 45 deletions(-) create mode 100644 src/main/java/konogonka/Controllers/TIK/TIKController.java create mode 100644 src/main/java/konogonka/Tools/TIK/TIKProvider.java create mode 100644 src/main/java/konogonka/Workers/AnalyzerTIK.java create mode 100644 src/main/resources/FXML/TIK/TIKTab.fxml diff --git a/src/main/java/konogonka/Child/ChildWindow.java b/src/main/java/konogonka/Child/ChildWindow.java index afab958..ee41ffb 100644 --- a/src/main/java/konogonka/Child/ChildWindow.java +++ b/src/main/java/konogonka/Child/ChildWindow.java @@ -7,6 +7,7 @@ import javafx.scene.image.Image; import javafx.stage.Stage; import konogonka.Controllers.IRowModel; import konogonka.Controllers.NCA.NCAController; +import konogonka.Controllers.TIK.TIKController; import konogonka.Tools.ISuperProvider; import java.io.IOException; @@ -25,6 +26,9 @@ public class ChildWindow { if (model.getFileName().endsWith(".nca")){ loaderSettings = new FXMLLoader(getClass().getResource("/FXML/NCA/NCATab.fxml")); } + else if(model.getFileName().endsWith(".tik")){ + loaderSettings = new FXMLLoader(getClass().getResource("/FXML/TIK/TIKTab.fxml")); + } else if(model.getFileName().endsWith(".cert")){ // TODO: IMPLEMENT return; @@ -51,6 +55,10 @@ public class ChildWindow { NCAController ncaController = loaderSettings.getController(); ncaController.analyze(provider.getFile(), provider.getRawFileDataStart()+model.getFileOffset()); } + else if(model.getFileName().endsWith(".tik")){ + TIKController tikController = loaderSettings.getController(); + tikController.analyze(provider.getFile(), provider.getRawFileDataStart()+model.getFileOffset()); + } stageSettings.setTitle(model.getFileName()); diff --git a/src/main/java/konogonka/Controllers/ITabController.java b/src/main/java/konogonka/Controllers/ITabController.java index 0717d75..a9ea10e 100644 --- a/src/main/java/konogonka/Controllers/ITabController.java +++ b/src/main/java/konogonka/Controllers/ITabController.java @@ -7,6 +7,6 @@ import java.io.File; public interface ITabController extends Initializable { void analyze(File file); - void analyze(ISuperProvider provider, int subFileNumber); + void analyze(File file, long offset); void resetTab(); } diff --git a/src/main/java/konogonka/Controllers/MainController.java b/src/main/java/konogonka/Controllers/MainController.java index 198e53e..5b7f279 100644 --- a/src/main/java/konogonka/Controllers/MainController.java +++ b/src/main/java/konogonka/Controllers/MainController.java @@ -9,10 +9,12 @@ import konogonka.AppPreferences; import konogonka.Child.ChildWindow; import konogonka.Controllers.NCA.NCAController; import konogonka.Controllers.NSP.NSPController; +import konogonka.Controllers.TIK.TIKController; import konogonka.Controllers.XCI.XCIController; import konogonka.MediatorControl; import konogonka.Settings.SettingsWindow; import konogonka.Tools.ISuperProvider; +import konogonka.Tools.TIK.TIKProvider; import java.io.*; import java.net.URL; @@ -43,6 +45,8 @@ public class MainController implements Initializable { private XCIController XCITabController; @FXML private NCAController NCATabController; + @FXML + private TIKController TIKTabController; private File selectedFile; @@ -76,7 +80,7 @@ public class MainController implements Initializable { else fileChooser.setInitialDirectory(new File(System.getProperty("user.home"))); - fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NS ROM", "*.nsp", "*.xci", "*.nca")); + fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("NS files", "*.nsp", "*.xci", "*.nca", "*.tik")); this.selectedFile = fileChooser.showOpenDialog(analyzeBtn.getScene().getWindow()); @@ -84,6 +88,7 @@ public class MainController implements Initializable { NSPTabController.resetTab(); XCITabController.resetTab(); NCATabController.resetTab(); + TIKTabController.resetTab(); if (this.selectedFile != null && this.selectedFile.exists()) { filenameSelected.setText(this.selectedFile.getAbsolutePath()); @@ -95,6 +100,8 @@ public class MainController implements Initializable { tabPane.getSelectionModel().select(1); else if (this.selectedFile.getName().toLowerCase().endsWith(".nca")) tabPane.getSelectionModel().select(2); + else if (this.selectedFile.getName().toLowerCase().endsWith(".tik")) + tabPane.getSelectionModel().select(3); } logArea.clear(); @@ -109,6 +116,8 @@ public class MainController implements Initializable { XCITabController.analyze(selectedFile); else if (selectedFile.getName().toLowerCase().endsWith("nca")) NCATabController.analyze(selectedFile); + else if (selectedFile.getName().toLowerCase().endsWith("tik")) + TIKTabController.analyze(selectedFile); } @FXML private void showHideLogs(){ diff --git a/src/main/java/konogonka/Controllers/NCA/NCAController.java b/src/main/java/konogonka/Controllers/NCA/NCAController.java index fef36b7..63662b1 100644 --- a/src/main/java/konogonka/Controllers/NCA/NCAController.java +++ b/src/main/java/konogonka/Controllers/NCA/NCAController.java @@ -5,7 +5,6 @@ import javafx.scene.control.Label; import javafx.scene.control.TextField; import konogonka.AppPreferences; import konogonka.Controllers.ITabController; -import konogonka.Tools.ISuperProvider; import konogonka.Tools.NCA.NCAContentPFS0; import konogonka.Tools.NCA.NCAProvider; import konogonka.Workers.AnalyzerNCA; @@ -72,11 +71,8 @@ public class NCAController implements ITabController { public void initialize(URL url, ResourceBundle resourceBundle) { } - @Override - public void analyze(ISuperProvider provider, int subFileNumber){ - // TODO - } + @Override public void analyze(File file, long offset) { this.selectedFile = file; HashMap keysMap = new HashMap<>(); @@ -201,13 +197,13 @@ public class NCAController implements ITabController { // TODO: FIX: This code executes getNCAContentPFS0() method twice NCAContentPFS0 ncaContentPFS0; ncaContentPFS0 = ncaProvider.getNCAContentPFS0(0); - NCASectionContentFirstController.populateFields(ncaContentPFS0.getPfs0(), selectedFile, ncaContentPFS0.getSHA256hashes()); + NCASectionContentFirstController.populateFields(ncaContentPFS0.getPfs0(), ncaContentPFS0.getSHA256hashes()); ncaContentPFS0 = ncaProvider.getNCAContentPFS0(1); - NCASectionContentSecondController.populateFields(ncaContentPFS0.getPfs0(), selectedFile, ncaContentPFS0.getSHA256hashes()); + NCASectionContentSecondController.populateFields(ncaContentPFS0.getPfs0(), ncaContentPFS0.getSHA256hashes()); ncaContentPFS0 = ncaProvider.getNCAContentPFS0(2); - NCASectionContentThirdController.populateFields(ncaContentPFS0.getPfs0(), selectedFile, ncaContentPFS0.getSHA256hashes()); + NCASectionContentThirdController.populateFields(ncaContentPFS0.getPfs0(), ncaContentPFS0.getSHA256hashes()); ncaContentPFS0 = ncaProvider.getNCAContentPFS0(3); - NCASectionContentFourthController.populateFields(ncaContentPFS0.getPfs0(), selectedFile, ncaContentPFS0.getSHA256hashes()); + NCASectionContentFourthController.populateFields(ncaContentPFS0.getPfs0(), ncaContentPFS0.getSHA256hashes()); } } } diff --git a/src/main/java/konogonka/Controllers/NCA/NCASectionContentController.java b/src/main/java/konogonka/Controllers/NCA/NCASectionContentController.java index fe59ba4..fd70e48 100644 --- a/src/main/java/konogonka/Controllers/NCA/NCASectionContentController.java +++ b/src/main/java/konogonka/Controllers/NCA/NCASectionContentController.java @@ -9,7 +9,6 @@ import konogonka.Controllers.NSP.NSPController; import konogonka.LoperConverter; import konogonka.Tools.PFS0.IPFS0Provider; -import java.io.File; import java.util.LinkedList; public class NCASectionContentController{ @@ -23,9 +22,9 @@ public class NCASectionContentController{ sha256pane.getChildren().clear(); } - public void populateFields(IPFS0Provider pfs0, File file, LinkedList sha256hashList) { + public void populateFields(IPFS0Provider pfs0, LinkedList sha256hashList) { resetTab(); - SectionPFS0Controller.setData(pfs0, file); + SectionPFS0Controller.setData(pfs0, null); if (sha256hashList != null){ for (int i = 0; i < sha256hashList.size(); i++){ Label numberLblTmp = new Label(String.format("%10d", i)); diff --git a/src/main/java/konogonka/Controllers/NSP/NSPController.java b/src/main/java/konogonka/Controllers/NSP/NSPController.java index c6d417d..590f57c 100644 --- a/src/main/java/konogonka/Controllers/NSP/NSPController.java +++ b/src/main/java/konogonka/Controllers/NSP/NSPController.java @@ -51,7 +51,7 @@ public class NSPController implements ITabController { ISuperProvider provider = tableFilesListController.getProvider(); if (models != null && !models.isEmpty() && (provider != null)){ - File dir = new File(System.getProperty("user.dir")+File.separator+selectedFile.getName()+" extracted"); + File dir = new File(System.getProperty("user.dir")+File.separator+selectedFile.getName()+" extracted"); // todo: move option to settings try { dir.mkdir(); } @@ -92,17 +92,16 @@ public class NSPController implements ITabController { * Start analyze NSP * */ @Override - public void analyze(ISuperProvider provider, int subFileNumber){ + public void analyze(File selectedFile, long offset){ // TODO: IMPLEMENT return; } @Override public void analyze(File selectedFile){ - this.selectedFile = selectedFile; AnalyzerNSP analyzerNSP = new AnalyzerNSP(selectedFile); analyzerNSP.setOnSucceeded(e->{ PFS0Provider pfs0 = analyzerNSP.getValue(); - this.setData(pfs0, null); + this.setData(pfs0, selectedFile); }); Thread workThread = new Thread(analyzerNSP); workThread.setDaemon(true); @@ -112,27 +111,27 @@ public class NSPController implements ITabController { * Just populate fields by already analyzed PFS0 * */ public void setData(IPFS0Provider pfs0, File fileWithNca){ - if (pfs0 != null){ - if (fileWithNca != null) - this.selectedFile = fileWithNca; - filesCountLbl.setText(Integer.toString(pfs0.getFilesCount())); - RawDataStartLbl.setText(Long.toString(pfs0.getRawFileDataStart())); - rawFileDataStart = pfs0.getRawFileDataStart(); - tableFilesListController.setNSPToTable(pfs0); - if (fileWithNca != null) - NSPSizeLbl.setText("skipping calculation for in-file PFS0"); - else - NSPSizeLbl.setText(Long.toString(selectedFile.length())); + if (pfs0 == null) + return; + this.selectedFile = fileWithNca; - extractBtn.setDisable(false); - magicLbl.setText(pfs0.getMagic()); - stringTableSizeLbl.setText(Integer.toString(pfs0.getStringTableSize())); - paddingLbl.setText(byteArrToHexString(pfs0.getPadding())); + filesCountLbl.setText(Integer.toString(pfs0.getFilesCount())); + RawDataStartLbl.setText(Long.toString(pfs0.getRawFileDataStart())); + rawFileDataStart = pfs0.getRawFileDataStart(); + tableFilesListController.setNSPToTable(pfs0); + if (fileWithNca == null) + NSPSizeLbl.setText("skipping calculation for in-file PFS0"); + else + NSPSizeLbl.setText(Long.toString(selectedFile.length())); - fileEntryTableSizeLbl.setText(String.format("0x%02x", 0x18* pfs0.getFilesCount())); - stringsTableSizeLbl.setText(String.format("0x%02x", pfs0.getStringTableSize())); - stringsTableOffsetLbl.setText(String.format("0x%02x", 0x18* pfs0.getFilesCount()+0x10)); - rawFileDataOffsetLbl.setText(String.format("0x%02x", 0x18* pfs0.getFilesCount()+0x10+ pfs0.getStringTableSize())); // same to RawFileDataStart for NSP ONLY - } + extractBtn.setDisable(false); + magicLbl.setText(pfs0.getMagic()); + stringTableSizeLbl.setText(Integer.toString(pfs0.getStringTableSize())); + paddingLbl.setText(byteArrToHexString(pfs0.getPadding())); + + fileEntryTableSizeLbl.setText(String.format("0x%02x", 0x18* pfs0.getFilesCount())); + stringsTableSizeLbl.setText(String.format("0x%02x", pfs0.getStringTableSize())); + stringsTableOffsetLbl.setText(String.format("0x%02x", 0x18* pfs0.getFilesCount()+0x10)); + rawFileDataOffsetLbl.setText(String.format("0x%02x", 0x18* pfs0.getFilesCount()+0x10+ pfs0.getStringTableSize())); // same to RawFileDataStart for NSP ONLY } } diff --git a/src/main/java/konogonka/Controllers/TIK/TIKController.java b/src/main/java/konogonka/Controllers/TIK/TIKController.java new file mode 100644 index 0000000..88d367a --- /dev/null +++ b/src/main/java/konogonka/Controllers/TIK/TIKController.java @@ -0,0 +1,154 @@ +package konogonka.Controllers.TIK; + +import javafx.fxml.FXML; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import konogonka.Controllers.ITabController; +import konogonka.Tools.TIK.TIKProvider; +import konogonka.Workers.AnalyzerTIK; + +import java.io.File; +import java.net.URL; +import java.util.ResourceBundle; + +import static konogonka.LoperConverter.byteArrToHexString; + +public class TIKController implements ITabController { + + @FXML + private Label sigTypeLbl, + sigTypeStrLbl, + tikSizeLbl, + sSizeLbl, // cosmetic + pOffsetLbl, // cosmetic + pSizeLbl, // cosmetic + + unknown1Lbl, + titleKeyTypeLbl, + unknown2Lbl, + masterKeyRevisionLbl, + unknown3Lbl, + ticketIdLbl, + deviceIdLbl, + accountIdLbl, + unknown4Lbl; + @FXML + private TextField signatureTF, + issuerTf, + titleKeyBlockTf, + rightsIdTf; + + @Override + public void initialize(URL url, ResourceBundle resourceBundle) { } + + @Override + public void analyze(File file) { analyze(file, 0); } + + @Override + public void analyze(File file, long offset) { + AnalyzerTIK analyzerTIK = new AnalyzerTIK(file, offset); + analyzerTIK.setOnSucceeded(e->{ + TIKProvider tik = analyzerTIK.getValue(); + if (offset == 0) + setData(tik, file); + else + setData(tik, null); + }); + Thread workThread = new Thread(analyzerTIK); + workThread.setDaemon(true); + workThread.start(); + } + + private void setData(TIKProvider tikProvider, File file){ + if (tikProvider == null) + return; + + if (file != null) + tikSizeLbl.setText(Long.toString(file.length())); + else + tikSizeLbl.setText("skipping calculation for in-file ticket"); + + sigTypeLbl.setText(byteArrToHexString(tikProvider.getSigType())); + switch (sigTypeLbl.getText()){ + case "00000100": + sigTypeStrLbl.setText("RSA_4096 SHA1"); + sSizeLbl.setText("0x200"); + pOffsetLbl.setText("0x240"); + pSizeLbl.setText("0x3c"); + break; + case "01000100": + sigTypeStrLbl.setText("RSA_2048 SHA1"); + sSizeLbl.setText("0x100"); + pOffsetLbl.setText("0x104"); + pSizeLbl.setText("0x3c"); + break; + case "02000100": + sigTypeStrLbl.setText("ECDSA SHA1"); + sSizeLbl.setText("0x3c"); + pOffsetLbl.setText("0x40"); + pSizeLbl.setText("0x40"); + break; + case "03000100": + sigTypeStrLbl.setText("RSA_4096 SHA256"); + sSizeLbl.setText("0x200"); + pOffsetLbl.setText("0x240"); + pSizeLbl.setText("0x3c"); + break; + case "04000100": + sigTypeStrLbl.setText("RSA_2048 SHA256"); + sSizeLbl.setText("0x100"); + pOffsetLbl.setText("0x104"); + pSizeLbl.setText("0x3c"); + break; + case "05000100": + sigTypeStrLbl.setText("ECDSA SHA256"); + sSizeLbl.setText("0x3c"); + pOffsetLbl.setText("0x40"); + pSizeLbl.setText("0x40"); + break; + default: + sigTypeStrLbl.setText("???"); + sSizeLbl.setText("???"); + pOffsetLbl.setText("???"); + pSizeLbl.setText("???"); + break; + } + signatureTF.setText(byteArrToHexString(tikProvider.getSignature())); + + issuerTf.setText(byteArrToHexString(tikProvider.getIssuer())); + titleKeyBlockTf.setText(byteArrToHexString(tikProvider.getTitleKeyBlock())); + unknown1Lbl.setText(String.format("0x%02x", tikProvider.getUnknown1())); + titleKeyTypeLbl.setText(String.format("0x%02x", tikProvider.getTitleKeyType())); + unknown2Lbl.setText(byteArrToHexString(tikProvider.getUnknown2())); + masterKeyRevisionLbl.setText(String.format("0x%02x", tikProvider.getMasterKeyRevision())); + unknown3Lbl.setText(byteArrToHexString(tikProvider.getUnknown3())); + ticketIdLbl.setText(byteArrToHexString(tikProvider.getTicketId())); + deviceIdLbl.setText(byteArrToHexString(tikProvider.getDeviceId())); + rightsIdTf.setText(byteArrToHexString(tikProvider.getRightsId())); + accountIdLbl.setText(byteArrToHexString(tikProvider.getAccountId())); + unknown4Lbl.setText(byteArrToHexString(tikProvider.getUnknown4())); + } + @Override + public void resetTab() { + sigTypeLbl.setText("-"); + sigTypeStrLbl.setText("-"); + tikSizeLbl.setText("-"); + sSizeLbl.setText("..."); + pOffsetLbl.setText("..."); + pSizeLbl.setText("..."); + signatureTF.setText("-"); + + issuerTf.setText("-"); + titleKeyBlockTf.setText("-"); + unknown1Lbl.setText("-"); + titleKeyTypeLbl.setText("-"); + unknown2Lbl.setText("-"); + masterKeyRevisionLbl.setText("-"); + unknown3Lbl.setText("-"); + ticketIdLbl.setText("-"); + deviceIdLbl.setText("-"); + rightsIdTf.setText("-"); + accountIdLbl.setText("-"); + unknown4Lbl.setText("-"); + } +} diff --git a/src/main/java/konogonka/Controllers/XCI/XCIController.java b/src/main/java/konogonka/Controllers/XCI/XCIController.java index 9048669..3b31c50 100644 --- a/src/main/java/konogonka/Controllers/XCI/XCIController.java +++ b/src/main/java/konogonka/Controllers/XCI/XCIController.java @@ -90,7 +90,7 @@ public class XCIController implements ITabController { * Start analyze XCI * */ @Override - public void analyze(ISuperProvider provider, int subFileNumber){ + public void analyze(File selectedFile, long offset){ // TODO: IMPLEMENT return; } diff --git a/src/main/java/konogonka/Tools/NCA/NCAProvider.java b/src/main/java/konogonka/Tools/NCA/NCAProvider.java index b89a0f0..bf76293 100644 --- a/src/main/java/konogonka/Tools/NCA/NCAProvider.java +++ b/src/main/java/konogonka/Tools/NCA/NCAProvider.java @@ -244,7 +244,12 @@ public class NCAProvider { public NCASectionBlock getSectionBlock1() { return sectionBlock1; } public NCASectionBlock getSectionBlock2() { return sectionBlock2; } public NCASectionBlock getSectionBlock3() { return sectionBlock3; } - + public boolean isKeyAvailable(){ // TODO: USE + if (Arrays.equals(rightsId, new byte[0x10])) + return true; + else + return keys.containsKey(byteArrToHexString(rightsId)); + } /** * Get content for the selected section * @param sectionNumber should be 1-4 diff --git a/src/main/java/konogonka/Tools/TIK/TIKProvider.java b/src/main/java/konogonka/Tools/TIK/TIKProvider.java new file mode 100644 index 0000000..0906caa --- /dev/null +++ b/src/main/java/konogonka/Tools/TIK/TIKProvider.java @@ -0,0 +1,161 @@ +package konogonka.Tools.TIK; + +import konogonka.RainbowHexDump; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.lang.reflect.Array; +import java.util.Arrays; + +import static konogonka.LoperConverter.*; +/* + +DON'T TRUST WIKI. Ticket size always (?) equal 0x02c0 (704 bytes) + +File structure byte-by-byte parsing + +Starting: +0x4 - Signature type +Signature type == 00 00 01 00 ? +Next: +0x200 - Signature size +Signature type == 01 00 01 00 ? +0x100 - Signature size +Signature type == 02 00 01 00 ? +0x3c - Signature size +Signature type == 03 00 01 00 ? +0x200 - Signature size +Signature type == 04 00 01 00 ? +0x100 - Signature size +Signature type == 05 00 01 00 ? +0x3c - Signature size +Next: +Signature type == 01 00 01 00 ? +0x3c - padding +Signature type == 01 00 01 00 ? +0x3c - padding +Signature type == 02 00 01 00 ? +0x40 - padding +Signature type == 03 00 01 00 ? +0c3c - padding +Signature type == 04 00 01 00 ? +0c3c - padding +Signature type == 05 00 01 00 ? +0x40 - padding +Next: +0x02c0 - Signature data ????? WTF? MUST BE AND IMPLEMENTED AS 0x180 + */ +/** + * TIKProvider is not a container, thus not a content-provider but provider of values-only + * */ +public class TIKProvider { + // Signature-related + private byte[] sigType; + private byte[] signature; + // Ticket + private byte[] Issuer; + private byte[] TitleKeyBlock; // Actually 32 bytes. Check against WIKI + private byte Unknown1; + private byte TitleKeyType; + private byte[] Unknown2; + private byte MasterKeyRevision; + private byte[] Unknown3; + private byte[] TicketId; + private byte[] DeviceId; + private byte[] RightsId; + private byte[] AccountId; + private byte[] Unknown4; + + public TIKProvider(File file) throws Exception{ this(file, 0); } + + public TIKProvider(File file, long offset) throws Exception { + + if (file.length() - offset < 0x02c0) + throw new Exception("TIKProvider: File is too small."); + + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + if (bis.skip(offset) != offset) { + bis.close(); + throw new Exception("TIKProvider: Unable to skip requested range - " + offset); + } + + sigType = new byte[0x4]; + if (bis.read(sigType) != 4) { + bis.close(); + throw new Exception("TIKProvider: Unable to read requested range - " + offset); + } + + byte[] readChunk; + + switch (getLEint(sigType, 0)){ + case 65536: // RSA_4096 SHA1 + case 65539: // RSA_4096 SHA256 + readChunk = new byte[0x23c]; + if (bis.read(readChunk) != 0x23c) { + bis.close(); + throw new Exception("TIKProvider: Unable to read requested range - 0x23c"); + } + signature = Arrays.copyOfRange(readChunk, 0, 0x200); + break; + case 65537: // RSA_2048 SHA1 + case 65540: // RSA_2048 SHA256 + readChunk = new byte[0x13c]; + if (bis.read(readChunk) != 0x13c) { + bis.close(); + throw new Exception("TIKProvider: Unable to read requested range - 0x13c"); + } + signature = Arrays.copyOfRange(readChunk, 0, 0x100); + break; + case 65538: // ECDSA SHA1 + case 65541: // ECDSA SHA256 + readChunk = new byte[0x7c]; + if (bis.read(readChunk) != 0x7c) { + bis.close(); + throw new Exception("TIKProvider: Unable to read requested range - 0x7c"); + } + signature = Arrays.copyOfRange(readChunk, 0, 0x3c); + break; + default: + bis.close(); + throw new Exception("TIKProvider: Unknown ticket (Signature) type. Aborting."); + } + // Let's read ticket body itself + readChunk = new byte[0x180]; + + if (bis.read(readChunk) != 0x180) { + bis.close(); + throw new Exception("TIKProvider: Unable to read requested range - Ticket data"); + } + bis.close(); + + Issuer = Arrays.copyOfRange(readChunk, 0, 0x40); + TitleKeyBlock = Arrays.copyOfRange(readChunk, 0x40, 0x140); + Unknown1 = readChunk[0x140]; + TitleKeyType = readChunk[0x141]; + Unknown2 = Arrays.copyOfRange(readChunk, 0x142, 0x145); + MasterKeyRevision = readChunk[0x145]; + Unknown3 = Arrays.copyOfRange(readChunk, 0x146, 0x150); + TicketId = Arrays.copyOfRange(readChunk, 0x150, 0x158); + DeviceId = Arrays.copyOfRange(readChunk, 0x158, 0x160); + RightsId = Arrays.copyOfRange(readChunk, 0x160, 0x170); + AccountId = Arrays.copyOfRange(readChunk,0x170, 0x174); + Unknown4 = Arrays.copyOfRange(readChunk, 0x174, 0x180); + } + + public byte[] getSigType() { return sigType; } + public byte[] getSignature() { return signature; } + + public byte[] getIssuer() { return Issuer; } + public byte[] getTitleKeyBlock() { return TitleKeyBlock; } + public byte getUnknown1() { return Unknown1; } + public byte getTitleKeyType() { return TitleKeyType; } + public byte[] getUnknown2() { return Unknown2; } + public byte getMasterKeyRevision() { return MasterKeyRevision; } + public byte[] getUnknown3() { return Unknown3; } + public byte[] getTicketId() { return TicketId; } + public byte[] getDeviceId() { return DeviceId; } + public byte[] getRightsId() { return RightsId; } + public byte[] getAccountId() { return AccountId; } + public byte[] getUnknown4() { return Unknown4; } +} diff --git a/src/main/java/konogonka/Workers/AnalyzerTIK.java b/src/main/java/konogonka/Workers/AnalyzerTIK.java new file mode 100644 index 0000000..568421b --- /dev/null +++ b/src/main/java/konogonka/Workers/AnalyzerTIK.java @@ -0,0 +1,45 @@ +package konogonka.Workers; + +import javafx.concurrent.Task; +import konogonka.ModelControllers.EMsgType; +import konogonka.ModelControllers.LogPrinter; +import konogonka.Tools.TIK.TIKProvider; + +import java.io.File; + +public class AnalyzerTIK extends Task { + + private File file; + private long offset; + private LogPrinter logPrinter; + + public AnalyzerTIK(File file){ + this(file, 0); + } + + public AnalyzerTIK(File file, long offset){ + this.file = file; + this.offset = offset; + this.logPrinter = new LogPrinter(); + } + + @Override + protected TIKProvider call() { + logPrinter.print("\tStart chain: TIK", EMsgType.INFO); + try{ + return new TIKProvider(file, offset); + } + catch (Exception e){ + logPrinter.print("\tException: "+e.getMessage(), EMsgType.FAIL); + return null; + } + finally { + close(); + } + } + + private void close(){ + logPrinter.print("\tEnd chain: TIK", EMsgType.INFO); + logPrinter.close(); + } +} diff --git a/src/main/java/konogonka/Workers/NspXciExtractor.java b/src/main/java/konogonka/Workers/NspXciExtractor.java index 421b40a..144da85 100644 --- a/src/main/java/konogonka/Workers/NspXciExtractor.java +++ b/src/main/java/konogonka/Workers/NspXciExtractor.java @@ -27,7 +27,7 @@ public class NspXciExtractor extends Task { @Override protected Void call() { for (IRowModel model : models) { - logPrinter.print("\tStart extracting: "+model.getFileName(), EMsgType.INFO); + logPrinter.print("\tStart extracting: \n"+filesDestPath+model.getFileName(), EMsgType.INFO); File contentFile = new File(filesDestPath + model.getFileName()); try { BufferedOutputStream extractedFileBOS = new BufferedOutputStream(new FileOutputStream(contentFile)); diff --git a/src/main/resources/FXML/TIK/TIKTab.fxml b/src/main/resources/FXML/TIK/TIKTab.fxml new file mode 100644 index 0000000..014c2d2 --- /dev/null +++ b/src/main/resources/FXML/TIK/TIKTab.fxml @@ -0,0 +1,705 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/FXML/landingPage.fxml b/src/main/resources/FXML/landingPage.fxml index 6afc277..aec93a3 100644 --- a/src/main/resources/FXML/landingPage.fxml +++ b/src/main/resources/FXML/landingPage.fxml @@ -71,6 +71,14 @@