Finish NCAContent refactoring
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
0238cb4d2c
commit
c878992cb6
1 changed files with 45 additions and 111 deletions
|
@ -18,23 +18,22 @@
|
||||||
*/
|
*/
|
||||||
package libKonogonka.Tools.NCA;
|
package libKonogonka.Tools.NCA;
|
||||||
|
|
||||||
import libKonogonka.Converter;
|
|
||||||
import libKonogonka.Tools.NCA.NCASectionTableBlock.NcaFsHeader;
|
import libKonogonka.Tools.NCA.NCASectionTableBlock.NcaFsHeader;
|
||||||
import libKonogonka.Tools.PFS0.IPFS0Provider;
|
import libKonogonka.Tools.PFS0.IPFS0Provider;
|
||||||
import libKonogonka.Tools.PFS0.PFS0Provider;
|
import libKonogonka.Tools.PFS0.PFS0Provider;
|
||||||
import libKonogonka.Tools.RomFs.IRomFsProvider;
|
import libKonogonka.Tools.RomFs.IRomFsProvider;
|
||||||
import libKonogonka.Tools.RomFs.RomFsEncryptedProvider;
|
import libKonogonka.Tools.RomFs.RomFsEncryptedProvider;
|
||||||
|
import libKonogonka.ctraes.AesCtrBufferedInputStream;
|
||||||
import libKonogonka.ctraes.AesCtrDecryptSimple;
|
import libKonogonka.ctraes.AesCtrDecryptSimple;
|
||||||
import libKonogonka.exceptions.EmptySectionException;
|
import libKonogonka.exceptions.EmptySectionException;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
/**
|
|
||||||
* THIS CLASS BECOMES MORE UGLY AFTER EACH ITERATION OF REFACTORING.
|
|
||||||
* TODO: MAKE SOME DECOMPOSITION
|
|
||||||
* */
|
|
||||||
public class NCAContent {
|
public class NCAContent {
|
||||||
private final static Logger log = LogManager.getLogger(NCAContent.class);
|
private final static Logger log = LogManager.getLogger(NCAContent.class);
|
||||||
|
|
||||||
|
@ -48,7 +47,7 @@ public class NCAContent {
|
||||||
private IPFS0Provider pfs0;
|
private IPFS0Provider pfs0;
|
||||||
private IRomFsProvider romfs;
|
private IRomFsProvider romfs;
|
||||||
|
|
||||||
// TODO: if decryptedKey is empty, throw exception ??
|
// TODO: if decryptedKey is empty, throw exception?
|
||||||
public NCAContent(File file,
|
public NCAContent(File file,
|
||||||
long ncaOffsetPosition,
|
long ncaOffsetPosition,
|
||||||
NcaFsHeader ncaFsHeader,
|
NcaFsHeader ncaFsHeader,
|
||||||
|
@ -76,14 +75,14 @@ public class NCAContent {
|
||||||
|
|
||||||
private void proceedPFS0() throws Exception {
|
private void proceedPFS0() throws Exception {
|
||||||
switch (ncaFsHeader.getCryptoType()){
|
switch (ncaFsHeader.getCryptoType()){
|
||||||
case 0x01:
|
case 0x01: // IF NO ENCRYPTION
|
||||||
proceedPFS0NotEncrypted(); // IF NO ENCRYPTION
|
proceedPFS0NotEncrypted();
|
||||||
break;
|
break;
|
||||||
case 0x03:
|
case 0x03:
|
||||||
proceedPFS0Encrypted(); // If encrypted regular [ 0x03 ]
|
proceedPFS0Encrypted();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Exception("NCAContent() -> proceedPFS0(): Non-supported 'Crypto type'");
|
throw new Exception("'Crypto type' not supported: "+ncaFsHeader.getCryptoType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void proceedPFS0NotEncrypted() throws Exception{
|
private void proceedPFS0NotEncrypted() throws Exception{
|
||||||
|
@ -135,120 +134,55 @@ public class NCAContent {
|
||||||
ncaHeaderTableEntry.getMediaStartOffset(),
|
ncaHeaderTableEntry.getMediaStartOffset(),
|
||||||
ncaHeaderTableEntry.getMediaEndOffset());
|
ncaHeaderTableEntry.getMediaEndOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
public LinkedList<byte[]> getPfs0SHA256hashes() { return Pfs0SHA256hashes; }
|
|
||||||
public IPFS0Provider getPfs0() { return pfs0; }
|
public IPFS0Provider getPfs0() { return pfs0; }
|
||||||
public IRomFsProvider getRomfs() { return romfs; }
|
public IRomFsProvider getRomfs() { return romfs; }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export NCA content AS IS.
|
* Export NCA content AS IS.
|
||||||
* Not so good for PFS0 since there are SHAs list that discourages but good for 'romfs' and things like that
|
* Not so good for PFS0 since there are SHAs list that discourages but good for 'romfs' and things like that
|
||||||
* */
|
* */
|
||||||
public PipedInputStream getRawDataContentPipedInpStream() throws Exception {
|
public boolean exportMediaBlock(String saveToLocation){
|
||||||
long mediaStartBlocksOffset = ncaHeaderTableEntry.getMediaStartOffset();
|
File location = new File(saveToLocation);
|
||||||
long mediaEndBlocksOffset = ncaHeaderTableEntry.getMediaEndOffset();
|
location.mkdirs();
|
||||||
long mediaBlocksSize = mediaEndBlocksOffset - mediaStartBlocksOffset;
|
BufferedInputStream stream;
|
||||||
|
|
||||||
RandomAccessFile raf = new RandomAccessFile(file, "r");
|
long mediaStartOffset = ncaHeaderTableEntry.getMediaStartOffset();
|
||||||
///--------------------------------------------------------------------------------------------------
|
long mediaEndOffset = ncaHeaderTableEntry.getMediaEndOffset();
|
||||||
log.debug("NCAContent() -> exportEncryptedSectionType03() information" + "\n" +
|
long mediaBlocksCount = mediaEndOffset - mediaStartOffset;
|
||||||
"Media start location: " + mediaStartBlocksOffset + "\n" +
|
|
||||||
"Media end location: " + mediaEndBlocksOffset + "\n" +
|
|
||||||
"Media size : " + (mediaEndBlocksOffset-mediaStartBlocksOffset) + "\n" +
|
|
||||||
"Media act. location: " + (ncaOffsetPosition + (mediaStartBlocksOffset * 0x200)) + "\n" +
|
|
||||||
"KEY: " + Converter.byteArrToHexString(decryptedKey) + "\n" +
|
|
||||||
"CTR: " + Converter.byteArrToHexString(ncaFsHeader.getSectionCTR()) + "\n");
|
|
||||||
//---------------------------------------------------------------------------------------------------/
|
|
||||||
|
|
||||||
|
try (BufferedOutputStream extractedFileBOS = new BufferedOutputStream(
|
||||||
|
Files.newOutputStream(Paths.get(saveToLocation+File.separator+file.getName()+"_MediaBlock.bin")))){
|
||||||
if(ncaFsHeader.getCryptoType()==0x01){
|
if(ncaFsHeader.getCryptoType()==0x01){
|
||||||
log.trace("NCAContent -> getRawDataContentPipedInpStream (Zero encryption section type 01): Thread started");
|
stream = new BufferedInputStream(Files.newInputStream(file.toPath()));
|
||||||
|
|
||||||
Thread workerThread;
|
|
||||||
PipedOutputStream streamOut = new PipedOutputStream();
|
|
||||||
|
|
||||||
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
|
||||||
workerThread = new Thread(() -> {
|
|
||||||
try {
|
|
||||||
byte[] rawDataBlock;
|
|
||||||
for (int i = 0; i < mediaBlocksSize; i++){
|
|
||||||
rawDataBlock = new byte[0x200];
|
|
||||||
if (raf.read(rawDataBlock) != -1)
|
|
||||||
streamOut.write(rawDataBlock);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e){
|
|
||||||
log.error("NCAContent -> exportRawData() failure", e);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
try {
|
|
||||||
raf.close();
|
|
||||||
}catch (Exception ignored) {}
|
|
||||||
try {
|
|
||||||
streamOut.close();
|
|
||||||
}catch (Exception ignored) {}
|
|
||||||
}
|
|
||||||
log.trace("NCAContent -> exportRawData(): Thread died");
|
|
||||||
});
|
|
||||||
workerThread.start();
|
|
||||||
return streamIn;
|
|
||||||
}
|
}
|
||||||
else if(ncaFsHeader.getCryptoType()==0x03) {
|
else if(ncaFsHeader.getCryptoType()==0x03) {
|
||||||
log.trace("NCAContent -> getRawDataContentPipedInpStream (Encrypted Section Type 03): Thread started");
|
|
||||||
|
|
||||||
if (decryptedKey == null)
|
|
||||||
throw new Exception("NCAContent -> exportRawData(): unable to proceed. No decrypted key provided.");
|
|
||||||
|
|
||||||
Thread workerThread;
|
|
||||||
PipedOutputStream streamOut = new PipedOutputStream();
|
|
||||||
|
|
||||||
PipedInputStream streamIn = new PipedInputStream(streamOut);
|
|
||||||
workerThread = new Thread(() -> {
|
|
||||||
try {
|
|
||||||
//RandomAccessFile raf = new RandomAccessFile(file, "r");
|
|
||||||
long abosluteOffsetPosition = ncaOffsetPosition + (mediaStartBlocksOffset * 0x200);
|
|
||||||
raf.seek(abosluteOffsetPosition);
|
|
||||||
|
|
||||||
AesCtrDecryptSimple decryptor = new AesCtrDecryptSimple(decryptedKey,
|
AesCtrDecryptSimple decryptor = new AesCtrDecryptSimple(decryptedKey,
|
||||||
ncaFsHeader.getSectionCTR(),
|
ncaFsHeader.getSectionCTR(),
|
||||||
mediaStartBlocksOffset * 0x200);
|
mediaStartOffset * 0x200);
|
||||||
|
|
||||||
byte[] encryptedBlock;
|
stream = new AesCtrBufferedInputStream(decryptor,
|
||||||
byte[] dectyptedBlock;
|
ncaOffsetPosition,
|
||||||
|
mediaStartOffset,
|
||||||
// Decrypt data
|
mediaEndOffset,
|
||||||
for (int i = 0; i < mediaBlocksSize; i++){
|
Files.newInputStream(file.toPath()));
|
||||||
encryptedBlock = new byte[0x200];
|
|
||||||
if (raf.read(encryptedBlock) != -1){
|
|
||||||
dectyptedBlock = decryptor.decryptNext(encryptedBlock);
|
|
||||||
// Writing decrypted data to pipe
|
|
||||||
streamOut.write(dectyptedBlock);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break;
|
throw new Exception("Crypto type not supported");
|
||||||
|
|
||||||
|
for (int i = 0; i < mediaBlocksCount; i++){
|
||||||
|
byte[] block = new byte[0x200];
|
||||||
|
if (0x200 != stream.read(block))
|
||||||
|
throw new Exception("Read failure");
|
||||||
|
extractedFileBOS.write(block);
|
||||||
}
|
}
|
||||||
|
stream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to export MediaBlock", e);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
catch (Exception e){
|
return true;
|
||||||
log.error("NCAContent -> exportRawData(): ", e);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
try {
|
|
||||||
raf.close();
|
|
||||||
}catch (Exception ignored) {}
|
|
||||||
try {
|
|
||||||
streamOut.close();
|
|
||||||
}catch (Exception ignored) {}
|
|
||||||
}
|
|
||||||
log.trace("NCAContent -> exportRawData(): Thread died");
|
|
||||||
});
|
|
||||||
workerThread.start();
|
|
||||||
return streamIn;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getRawDataContentSize(){
|
public long getRawDataContentSize(){
|
||||||
return (ncaHeaderTableEntry.getMediaEndOffset() - ncaHeaderTableEntry.getMediaStartOffset()) * 0x200;
|
return (ncaHeaderTableEntry.getMediaEndOffset() - ncaHeaderTableEntry.getMediaStartOffset()) * 0x200;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue