From 95802c7f5df0f490694c08ff4658791067edc787 Mon Sep 17 00:00:00 2001 From: Maschell Date: Sat, 4 May 2019 12:05:34 +0200 Subject: [PATCH] Fix woomy support. --- src/de/mas/wiiu/jnus/NUSTitleConfig.java | 1 + src/de/mas/wiiu/jnus/NUSTitleLoader.java | 21 ++++++++------- src/de/mas/wiiu/jnus/NUSTitleLoaderWoomy.java | 2 ++ .../FSTDataProviderNUSTitle.java | 22 +++++++++++----- .../implementations/NUSDataProviderWoomy.java | 26 ++++++++++++++----- src/de/mas/wiiu/jnus/utils/StreamUtils.java | 6 ++--- .../utils/cryptography/NUSDecryption.java | 11 -------- 7 files changed, 54 insertions(+), 35 deletions(-) diff --git a/src/de/mas/wiiu/jnus/NUSTitleConfig.java b/src/de/mas/wiiu/jnus/NUSTitleConfig.java index b68bbcb..9f0ef43 100644 --- a/src/de/mas/wiiu/jnus/NUSTitleConfig.java +++ b/src/de/mas/wiiu/jnus/NUSTitleConfig.java @@ -22,6 +22,7 @@ import lombok.Data; @Data public class NUSTitleConfig { private Ticket ticket; + private boolean ticketNeeded = true; private boolean noDecryption; private byte[] commonKey; } diff --git a/src/de/mas/wiiu/jnus/NUSTitleLoader.java b/src/de/mas/wiiu/jnus/NUSTitleLoader.java index 4377f2f..9bbacf6 100644 --- a/src/de/mas/wiiu/jnus/NUSTitleLoader.java +++ b/src/de/mas/wiiu/jnus/NUSTitleLoader.java @@ -46,17 +46,20 @@ public class NUSTitleLoader { return result; } - Ticket ticket = config.getTicket(); - if (ticket == null) { - Optional ticketOpt = dataProvider.getRawTicket(); - if (ticketOpt.isPresent()) { - ticket = Ticket.parseTicket(ticketOpt.get(), config.getCommonKey()); + Ticket ticket = null; + if (config.isTicketNeeded()) { + ticket = config.getTicket(); + if (ticket == null) { + Optional ticketOpt = dataProvider.getRawTicket(); + if (ticketOpt.isPresent()) { + ticket = Ticket.parseTicket(ticketOpt.get(), config.getCommonKey()); + } } + if (ticket == null) { + new ParseException("Failed to get ticket data", 0); + } + result.setTicket(Optional.of(ticket)); } - if (ticket == null) { - new ParseException("Failed to get ticket data", 0); - } - result.setTicket(Optional.of(ticket)); // If we have just content, we don't have a FST. if (result.getTMD().getAllContents().size() == 1) { diff --git a/src/de/mas/wiiu/jnus/NUSTitleLoaderWoomy.java b/src/de/mas/wiiu/jnus/NUSTitleLoaderWoomy.java index dfdcf8c..d66b6b9 100644 --- a/src/de/mas/wiiu/jnus/NUSTitleLoaderWoomy.java +++ b/src/de/mas/wiiu/jnus/NUSTitleLoaderWoomy.java @@ -37,6 +37,8 @@ public final class NUSTitleLoaderWoomy { public static NUSTitle loadNUSTitle(String inputFile) throws IOException, ParserConfigurationException, SAXException, ParseException { NUSTitleConfig config = new NUSTitleConfig(); + config.setTicketNeeded(false); + WoomyInfo woomyInfo = WoomyParser.createWoomyInfo(new File(inputFile)); return NUSTitleLoader.loadNusTitle(config, () -> new NUSDataProviderWoomy(woomyInfo)); diff --git a/src/de/mas/wiiu/jnus/implementations/FSTDataProviderNUSTitle.java b/src/de/mas/wiiu/jnus/implementations/FSTDataProviderNUSTitle.java index bc53b77..39bcbf8 100644 --- a/src/de/mas/wiiu/jnus/implementations/FSTDataProviderNUSTitle.java +++ b/src/de/mas/wiiu/jnus/implementations/FSTDataProviderNUSTitle.java @@ -30,6 +30,7 @@ import de.mas.wiiu.jnus.interfaces.FSTDataProvider; import de.mas.wiiu.jnus.interfaces.HasNUSTitle; import de.mas.wiiu.jnus.interfaces.NUSDataProvider; import de.mas.wiiu.jnus.utils.CheckSumWrongException; +import de.mas.wiiu.jnus.utils.StreamUtils; import de.mas.wiiu.jnus.utils.Utils; import de.mas.wiiu.jnus.utils.cryptography.NUSDecryption; import lombok.Getter; @@ -157,10 +158,8 @@ public class FSTDataProviderNUSTitle implements FSTDataProvider, HasNUSTitle { private boolean decryptFSTEntryToStream(FSTEntry entry, OutputStream outputStream, long offset, long size) throws IOException, CheckSumWrongException, NoSuchAlgorithmException { - if (entry.isNotInPackage() || !title.getTicket().isPresent()) { - if (!title.getTicket().isPresent()) { - log.info("Decryption not possible because no ticket was set."); - } else if (entry.isNotInPackage()) { + if (entry.isNotInPackage()) { + if (entry.isNotInPackage()) { log.info("Decryption not possible because the FSTEntry is not in this package"); } outputStream.close(); @@ -174,15 +173,26 @@ public class FSTDataProviderNUSTitle implements FSTDataProvider, HasNUSTitle { try { if (c.isEncrypted()) { + if (!title.getTicket().isPresent()) { + log.info("Decryption not possible because no ticket was set."); + outputStream.close(); + return false; + } if (c.isHashed()) { return decryptFSTEntryToStreamHashed(entry, outputStream, offset, size); } else { return decryptFSTEntryToStreamNonHashed(entry, outputStream, offset, size); } } else { - NUSDecryption nusdecryption = new NUSDecryption(title.getTicket().get()); InputStream in = title.getDataProvider().readContentAsStream(c, offset, size); - return nusdecryption.decryptStreamsNonEncrypted(in, outputStream, offset, size, c); + + try { + StreamUtils.saveInputStreamToOutputStreamWithHash(in, outputStream, size, c.getSHA2Hash(), c.getEncryptedFileSize(), + size != entry.getFileSize()); + return true; + } finally { + StreamUtils.closeAll(in, outputStream); + } } } catch (CheckSumWrongException e) { if (c.isUNKNWNFlag1Set()) { diff --git a/src/de/mas/wiiu/jnus/implementations/NUSDataProviderWoomy.java b/src/de/mas/wiiu/jnus/implementations/NUSDataProviderWoomy.java index 24ec43c..424ccc2 100644 --- a/src/de/mas/wiiu/jnus/implementations/NUSDataProviderWoomy.java +++ b/src/de/mas/wiiu/jnus/implementations/NUSDataProviderWoomy.java @@ -16,6 +16,7 @@ ****************************************************************************/ package de.mas.wiiu.jnus.implementations; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -28,6 +29,7 @@ import de.mas.wiiu.jnus.entities.content.Content; import de.mas.wiiu.jnus.implementations.woomy.WoomyInfo; import de.mas.wiiu.jnus.implementations.woomy.WoomyZipFile; import de.mas.wiiu.jnus.interfaces.NUSDataProvider; +import de.mas.wiiu.jnus.utils.StreamUtils; import lombok.AccessLevel; import lombok.Getter; import lombok.NonNull; @@ -44,14 +46,16 @@ public class NUSDataProviderWoomy implements NUSDataProvider { } @Override - public InputStream readContentAsStream(@NonNull Content content, long fileOffsetBlock, long size) throws IOException { + public InputStream readContentAsStream(@NonNull Content content, long offset, long size) throws IOException { WoomyZipFile zipFile = getSharedWoomyZipFile(); ZipEntry entry = getWoomyInfo().getContentFiles().get(content.getFilename().toLowerCase()); if (entry == null) { log.warning("Inputstream for " + content.getFilename() + " not found"); throw new FileNotFoundException("Inputstream for " + content.getFilename() + " not found"); } - return zipFile.getInputStream(entry); + InputStream in = zipFile.getInputStream(entry); + StreamUtils.skipExactly(in, offset); + return in; } @Override @@ -79,6 +83,20 @@ public class NUSDataProviderWoomy implements NUSDataProvider { return Optional.of(result); } + @Override + public Optional getRawCert() throws IOException { + ZipEntry entry = getWoomyInfo().getContentFiles().get(Settings.CERT_FILENAME); + if (entry == null) { + log.warning(Settings.TICKET_FILENAME + " not found in woomy file"); + throw new FileNotFoundException(Settings.TICKET_FILENAME + " not found in woomy file"); + } + + WoomyZipFile zipFile = getNewWoomyZipFile(); + byte[] result = zipFile.getEntryAsByte(entry); + zipFile.close(); + return Optional.of(result); + } + @Override public Optional getRawTicket() throws IOException { ZipEntry entry = getWoomyInfo().getContentFiles().get(Settings.TICKET_FILENAME); @@ -111,8 +129,4 @@ public class NUSDataProviderWoomy implements NUSDataProvider { } } - @Override - public Optional getRawCert() throws IOException { - return Optional.empty(); - } } diff --git a/src/de/mas/wiiu/jnus/utils/StreamUtils.java b/src/de/mas/wiiu/jnus/utils/StreamUtils.java index afed5c5..1cf4286 100644 --- a/src/de/mas/wiiu/jnus/utils/StreamUtils.java +++ b/src/de/mas/wiiu/jnus/utils/StreamUtils.java @@ -126,7 +126,7 @@ public final class StreamUtils { public static void saveInputStreamToOutputStream(InputStream inputStream, OutputStream outputStream, long filesize) throws IOException { try { - saveInputStreamToOutputStreamWithHash(inputStream, outputStream, filesize, null, 0L); + saveInputStreamToOutputStreamWithHash(inputStream, outputStream, filesize, null, 0L, true); } catch (CheckSumWrongException e) { // Should never happen because the hash is not set. Lets print it anyway. e.printStackTrace(); @@ -134,11 +134,11 @@ public final class StreamUtils { } public static void saveInputStreamToOutputStreamWithHash(InputStream inputStream, OutputStream outputStream, long filesize, byte[] hash, - long expectedSizeForHash) throws IOException, CheckSumWrongException { + long expectedSizeForHash, boolean partial) throws IOException, CheckSumWrongException { synchronized (inputStream) { MessageDigest sha1 = null; - if (hash != null) { + if (hash != null && !partial) { try { sha1 = MessageDigest.getInstance("SHA1"); } catch (NoSuchAlgorithmException e) { diff --git a/src/de/mas/wiiu/jnus/utils/cryptography/NUSDecryption.java b/src/de/mas/wiiu/jnus/utils/cryptography/NUSDecryption.java index 2d8e8fa..f46ffa0 100644 --- a/src/de/mas/wiiu/jnus/utils/cryptography/NUSDecryption.java +++ b/src/de/mas/wiiu/jnus/utils/cryptography/NUSDecryption.java @@ -244,17 +244,6 @@ public class NUSDecryption extends AESDecryption { return true; } - public boolean decryptStreamsNonEncrypted(InputStream inputStream, OutputStream outputStream, long offset, long size, Content content) - throws IOException, CheckSumWrongException, NoSuchAlgorithmException { - try { - StreamUtils.saveInputStreamToOutputStreamWithHash(inputStream, outputStream, size, content.getSHA2Hash(), content.getEncryptedFileSize()); - } finally { - StreamUtils.closeAll(inputStream, outputStream); - } - - return true; - } - public boolean decryptStreamsNonHashed(InputStream inputStream, OutputStream outputStream, long offset, long size, Content content, byte[] IV, boolean partial) throws IOException, CheckSumWrongException { try {