Fix woomy support.

This commit is contained in:
Maschell 2019-05-04 12:05:34 +02:00
parent 96e048b4b5
commit 95802c7f5d
7 changed files with 54 additions and 35 deletions

View File

@ -22,6 +22,7 @@ import lombok.Data;
@Data
public class NUSTitleConfig {
private Ticket ticket;
private boolean ticketNeeded = true;
private boolean noDecryption;
private byte[] commonKey;
}

View File

@ -46,17 +46,20 @@ public class NUSTitleLoader {
return result;
}
Ticket ticket = config.getTicket();
if (ticket == null) {
Optional<byte[]> 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<byte[]> 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) {

View File

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

View File

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

View File

@ -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<byte[]> 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<byte[]> getRawTicket() throws IOException {
ZipEntry entry = getWoomyInfo().getContentFiles().get(Settings.TICKET_FILENAME);
@ -111,8 +129,4 @@ public class NUSDataProviderWoomy implements NUSDataProvider {
}
}
@Override
public Optional<byte[]> getRawCert() throws IOException {
return Optional.empty();
}
}

View File

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

View File

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