mirror of
https://github.com/Maschell/JNUSLib.git
synced 2024-11-25 17:36:55 +01:00
Fix woomy support.
This commit is contained in:
parent
96e048b4b5
commit
95802c7f5d
@ -22,6 +22,7 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class NUSTitleConfig {
|
public class NUSTitleConfig {
|
||||||
private Ticket ticket;
|
private Ticket ticket;
|
||||||
|
private boolean ticketNeeded = true;
|
||||||
private boolean noDecryption;
|
private boolean noDecryption;
|
||||||
private byte[] commonKey;
|
private byte[] commonKey;
|
||||||
}
|
}
|
||||||
|
@ -46,17 +46,20 @@ public class NUSTitleLoader {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ticket ticket = config.getTicket();
|
Ticket ticket = null;
|
||||||
if (ticket == null) {
|
if (config.isTicketNeeded()) {
|
||||||
Optional<byte[]> ticketOpt = dataProvider.getRawTicket();
|
ticket = config.getTicket();
|
||||||
if (ticketOpt.isPresent()) {
|
if (ticket == null) {
|
||||||
ticket = Ticket.parseTicket(ticketOpt.get(), config.getCommonKey());
|
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 we have just content, we don't have a FST.
|
||||||
if (result.getTMD().getAllContents().size() == 1) {
|
if (result.getTMD().getAllContents().size() == 1) {
|
||||||
|
@ -37,6 +37,8 @@ public final class NUSTitleLoaderWoomy {
|
|||||||
public static NUSTitle loadNUSTitle(String inputFile) throws IOException, ParserConfigurationException, SAXException, ParseException {
|
public static NUSTitle loadNUSTitle(String inputFile) throws IOException, ParserConfigurationException, SAXException, ParseException {
|
||||||
NUSTitleConfig config = new NUSTitleConfig();
|
NUSTitleConfig config = new NUSTitleConfig();
|
||||||
|
|
||||||
|
config.setTicketNeeded(false);
|
||||||
|
|
||||||
WoomyInfo woomyInfo = WoomyParser.createWoomyInfo(new File(inputFile));
|
WoomyInfo woomyInfo = WoomyParser.createWoomyInfo(new File(inputFile));
|
||||||
|
|
||||||
return NUSTitleLoader.loadNusTitle(config, () -> new NUSDataProviderWoomy(woomyInfo));
|
return NUSTitleLoader.loadNusTitle(config, () -> new NUSDataProviderWoomy(woomyInfo));
|
||||||
|
@ -30,6 +30,7 @@ import de.mas.wiiu.jnus.interfaces.FSTDataProvider;
|
|||||||
import de.mas.wiiu.jnus.interfaces.HasNUSTitle;
|
import de.mas.wiiu.jnus.interfaces.HasNUSTitle;
|
||||||
import de.mas.wiiu.jnus.interfaces.NUSDataProvider;
|
import de.mas.wiiu.jnus.interfaces.NUSDataProvider;
|
||||||
import de.mas.wiiu.jnus.utils.CheckSumWrongException;
|
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.Utils;
|
||||||
import de.mas.wiiu.jnus.utils.cryptography.NUSDecryption;
|
import de.mas.wiiu.jnus.utils.cryptography.NUSDecryption;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@ -157,10 +158,8 @@ public class FSTDataProviderNUSTitle implements FSTDataProvider, HasNUSTitle {
|
|||||||
|
|
||||||
private boolean decryptFSTEntryToStream(FSTEntry entry, OutputStream outputStream, long offset, long size)
|
private boolean decryptFSTEntryToStream(FSTEntry entry, OutputStream outputStream, long offset, long size)
|
||||||
throws IOException, CheckSumWrongException, NoSuchAlgorithmException {
|
throws IOException, CheckSumWrongException, NoSuchAlgorithmException {
|
||||||
if (entry.isNotInPackage() || !title.getTicket().isPresent()) {
|
if (entry.isNotInPackage()) {
|
||||||
if (!title.getTicket().isPresent()) {
|
if (entry.isNotInPackage()) {
|
||||||
log.info("Decryption not possible because no ticket was set.");
|
|
||||||
} else if (entry.isNotInPackage()) {
|
|
||||||
log.info("Decryption not possible because the FSTEntry is not in this package");
|
log.info("Decryption not possible because the FSTEntry is not in this package");
|
||||||
}
|
}
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
@ -174,15 +173,26 @@ public class FSTDataProviderNUSTitle implements FSTDataProvider, HasNUSTitle {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (c.isEncrypted()) {
|
if (c.isEncrypted()) {
|
||||||
|
if (!title.getTicket().isPresent()) {
|
||||||
|
log.info("Decryption not possible because no ticket was set.");
|
||||||
|
outputStream.close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (c.isHashed()) {
|
if (c.isHashed()) {
|
||||||
return decryptFSTEntryToStreamHashed(entry, outputStream, offset, size);
|
return decryptFSTEntryToStreamHashed(entry, outputStream, offset, size);
|
||||||
} else {
|
} else {
|
||||||
return decryptFSTEntryToStreamNonHashed(entry, outputStream, offset, size);
|
return decryptFSTEntryToStreamNonHashed(entry, outputStream, offset, size);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NUSDecryption nusdecryption = new NUSDecryption(title.getTicket().get());
|
|
||||||
InputStream in = title.getDataProvider().readContentAsStream(c, offset, size);
|
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) {
|
} catch (CheckSumWrongException e) {
|
||||||
if (c.isUNKNWNFlag1Set()) {
|
if (c.isUNKNWNFlag1Set()) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
package de.mas.wiiu.jnus.implementations;
|
package de.mas.wiiu.jnus.implementations;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
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.WoomyInfo;
|
||||||
import de.mas.wiiu.jnus.implementations.woomy.WoomyZipFile;
|
import de.mas.wiiu.jnus.implementations.woomy.WoomyZipFile;
|
||||||
import de.mas.wiiu.jnus.interfaces.NUSDataProvider;
|
import de.mas.wiiu.jnus.interfaces.NUSDataProvider;
|
||||||
|
import de.mas.wiiu.jnus.utils.StreamUtils;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
@ -44,14 +46,16 @@ public class NUSDataProviderWoomy implements NUSDataProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
WoomyZipFile zipFile = getSharedWoomyZipFile();
|
||||||
ZipEntry entry = getWoomyInfo().getContentFiles().get(content.getFilename().toLowerCase());
|
ZipEntry entry = getWoomyInfo().getContentFiles().get(content.getFilename().toLowerCase());
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
log.warning("Inputstream for " + content.getFilename() + " not found");
|
log.warning("Inputstream for " + content.getFilename() + " not found");
|
||||||
throw new FileNotFoundException("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
|
@Override
|
||||||
@ -79,6 +83,20 @@ public class NUSDataProviderWoomy implements NUSDataProvider {
|
|||||||
return Optional.of(result);
|
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
|
@Override
|
||||||
public Optional<byte[]> getRawTicket() throws IOException {
|
public Optional<byte[]> getRawTicket() throws IOException {
|
||||||
ZipEntry entry = getWoomyInfo().getContentFiles().get(Settings.TICKET_FILENAME);
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ public final class StreamUtils {
|
|||||||
|
|
||||||
public static void saveInputStreamToOutputStream(InputStream inputStream, OutputStream outputStream, long filesize) throws IOException {
|
public static void saveInputStreamToOutputStream(InputStream inputStream, OutputStream outputStream, long filesize) throws IOException {
|
||||||
try {
|
try {
|
||||||
saveInputStreamToOutputStreamWithHash(inputStream, outputStream, filesize, null, 0L);
|
saveInputStreamToOutputStreamWithHash(inputStream, outputStream, filesize, null, 0L, true);
|
||||||
} catch (CheckSumWrongException e) {
|
} catch (CheckSumWrongException e) {
|
||||||
// Should never happen because the hash is not set. Lets print it anyway.
|
// Should never happen because the hash is not set. Lets print it anyway.
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -134,11 +134,11 @@ public final class StreamUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void saveInputStreamToOutputStreamWithHash(InputStream inputStream, OutputStream outputStream, long filesize, byte[] hash,
|
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) {
|
synchronized (inputStream) {
|
||||||
|
|
||||||
MessageDigest sha1 = null;
|
MessageDigest sha1 = null;
|
||||||
if (hash != null) {
|
if (hash != null && !partial) {
|
||||||
try {
|
try {
|
||||||
sha1 = MessageDigest.getInstance("SHA1");
|
sha1 = MessageDigest.getInstance("SHA1");
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
@ -244,17 +244,6 @@ public class NUSDecryption extends AESDecryption {
|
|||||||
return true;
|
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,
|
public boolean decryptStreamsNonHashed(InputStream inputStream, OutputStream outputStream, long offset, long size, Content content, byte[] IV,
|
||||||
boolean partial) throws IOException, CheckSumWrongException {
|
boolean partial) throws IOException, CheckSumWrongException {
|
||||||
try {
|
try {
|
||||||
|
Loading…
Reference in New Issue
Block a user