Add some sugar for AesCtr CipherInputStream.
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
Add INI1 export sketch (incorrect for now)
This commit is contained in:
parent
d2358758c6
commit
83cf199beb
2 changed files with 77 additions and 24 deletions
|
@ -21,14 +21,17 @@ package libKonogonka.Tools.other.System2;
|
||||||
import libKonogonka.KeyChainHolder;
|
import libKonogonka.KeyChainHolder;
|
||||||
import libKonogonka.RainbowDump;
|
import libKonogonka.RainbowDump;
|
||||||
import libKonogonka.ctraes.AesCtrClassic;
|
import libKonogonka.ctraes.AesCtrClassic;
|
||||||
|
import libKonogonka.ctraes.AesCtrStream;
|
||||||
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.BufferedInputStream;
|
import javax.crypto.CipherInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.*;
|
||||||
import java.io.File;
|
import java.math.BigInteger;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
public class System2Provider {
|
public class System2Provider {
|
||||||
private final static Logger log = LogManager.getLogger(System2Provider.class);
|
private final static Logger log = LogManager.getLogger(System2Provider.class);
|
||||||
|
@ -45,8 +48,6 @@ public class System2Provider {
|
||||||
this.keyChainHolder = keyChainHolder;
|
this.keyChainHolder = keyChainHolder;
|
||||||
|
|
||||||
readHeaderCtr();
|
readHeaderCtr();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readHeaderCtr() throws Exception{
|
private void readHeaderCtr() throws Exception{
|
||||||
|
@ -59,22 +60,22 @@ public class System2Provider {
|
||||||
this.header = new System2Header(headerBytes, keyChainHolder.getRawKeySet());
|
this.header = new System2Header(headerBytes, keyChainHolder.getRawKeySet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean exportKernel(String saveTo) throws Exception{
|
public boolean exportKernel(String saveTo) throws Exception{
|
||||||
AesCtrClassic aesCtrClassic = new AesCtrClassic(header.getKey(), header.getSection0Ctr()); // TODO: DELETE
|
|
||||||
|
|
||||||
File location = new File(saveTo);
|
File location = new File(saveTo);
|
||||||
location.mkdirs();
|
location.mkdirs();
|
||||||
|
|
||||||
try (BufferedInputStream stream = new BufferedInputStream(Files.newInputStream(Paths.get(pathToFile)));
|
InputStream fis = Files.newInputStream(Paths.get(pathToFile));
|
||||||
BufferedOutputStream extractedFileBOS = new BufferedOutputStream(
|
// Encrypted section comes next
|
||||||
Files.newOutputStream(Paths.get(saveTo+File.separator+"Kernel.bin")))){
|
long toSkip = 0x200;
|
||||||
|
if (toSkip != fis.skip(toSkip))
|
||||||
|
throw new Exception("Unable to skip offset: "+toSkip);
|
||||||
|
|
||||||
|
try (CipherInputStream stream = AesCtrStream.getStream(header.getKey(), header.getSection0Ctr(), fis);
|
||||||
|
BufferedOutputStream extractedFileBOS = new BufferedOutputStream(
|
||||||
|
Files.newOutputStream(Paths.get(saveTo+File.separator+"Kernel.bin")))){
|
||||||
|
|
||||||
long kernelSize = header.getSection0size();
|
long kernelSize = header.getSection0size();
|
||||||
|
|
||||||
long toSkip = 0x200;
|
|
||||||
if (toSkip != stream.skip(toSkip))
|
|
||||||
throw new Exception("Unable to skip offset: "+toSkip);
|
|
||||||
int blockSize = 0x200;
|
int blockSize = 0x200;
|
||||||
if (kernelSize < 0x200)
|
if (kernelSize < 0x200)
|
||||||
blockSize = (int) kernelSize;
|
blockSize = (int) kernelSize;
|
||||||
|
@ -86,14 +87,7 @@ public class System2Provider {
|
||||||
while (true) {
|
while (true) {
|
||||||
if ((actuallyRead = stream.read(block)) != blockSize)
|
if ((actuallyRead = stream.read(block)) != blockSize)
|
||||||
throw new Exception("Read failure. Block Size: "+blockSize+", actuallyRead: "+actuallyRead);
|
throw new Exception("Read failure. Block Size: "+blockSize+", actuallyRead: "+actuallyRead);
|
||||||
byte[] decrypted = aesCtrClassic.decryptNext(block);
|
extractedFileBOS.write(block);
|
||||||
if (i > 0 && i <= 0x201){
|
|
||||||
RainbowDump.hexDumpUTF8(decrypted);
|
|
||||||
}
|
|
||||||
if (i == 0){
|
|
||||||
RainbowDump.hexDumpUTF8(decrypted);
|
|
||||||
}
|
|
||||||
extractedFileBOS.write(decrypted);
|
|
||||||
i += blockSize;
|
i += blockSize;
|
||||||
if ((i + blockSize) > kernelSize) {
|
if ((i + blockSize) > kernelSize) {
|
||||||
blockSize = (int) (kernelSize - i);
|
blockSize = (int) (kernelSize - i);
|
||||||
|
@ -109,6 +103,61 @@ public class System2Provider {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
public boolean exportIni1(String saveTo) throws Exception{
|
||||||
|
File location = new File(saveTo);
|
||||||
|
location.mkdirs();
|
||||||
|
InputStream fis = Files.newInputStream(Paths.get(pathToFile));
|
||||||
|
// Encrypted section comes next
|
||||||
|
long toSkip = 0x200 + header.getSection0offset();
|
||||||
|
if (toSkip != fis.skip(toSkip))
|
||||||
|
throw new Exception("Unable to skip offset: "+toSkip);
|
||||||
|
|
||||||
|
try (CipherInputStream stream = AesCtrStream.getStream(header.getKey(), calcIni1Ctr(), fis);
|
||||||
|
BufferedOutputStream extractedFileBOS = new BufferedOutputStream(
|
||||||
|
Files.newOutputStream(Paths.get(saveTo+File.separator+"INI1.bin")))){
|
||||||
|
|
||||||
|
long iniSize = header.getSection0size()-header.getSection0offset();
|
||||||
|
|
||||||
|
int blockSize = 0x200;
|
||||||
|
if (iniSize < 0x200)
|
||||||
|
blockSize = (int) iniSize;
|
||||||
|
|
||||||
|
long i = 0;
|
||||||
|
byte[] block = new byte[blockSize];
|
||||||
|
|
||||||
|
boolean skipMode = true;
|
||||||
|
final byte[] zeroes = new byte[blockSize];
|
||||||
|
|
||||||
|
int actuallyRead;
|
||||||
|
while (true) {
|
||||||
|
if ((actuallyRead = stream.read(block)) != blockSize)
|
||||||
|
throw new Exception("Read failure. Block Size: "+blockSize+", actuallyRead: "+actuallyRead);
|
||||||
|
if (skipMode && Arrays.equals(block, zeroes))
|
||||||
|
;
|
||||||
|
else {
|
||||||
|
skipMode = false;
|
||||||
|
extractedFileBOS.write(block);
|
||||||
|
}
|
||||||
|
i += blockSize;
|
||||||
|
if ((i + blockSize) > iniSize) {
|
||||||
|
blockSize = (int) (iniSize - i);
|
||||||
|
if (blockSize == 0)
|
||||||
|
break;
|
||||||
|
block = new byte[blockSize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e){
|
||||||
|
log.error("File export failure", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private byte[] calcIni1Ctr(){
|
||||||
|
BigInteger ctr = new BigInteger(header.getSection0Ctr());
|
||||||
|
BigInteger updateTo = BigInteger.valueOf(header.getSection0offset() / 0x10L);
|
||||||
|
return ctr.add(updateTo).toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
public System2Header getHeader() {
|
public System2Header getHeader() {
|
||||||
return header;
|
return header;
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class Package2UnpackedTest {
|
||||||
private static final String xci_header_keyFileLocation = "./FilesForTests/xci_header_key.txt";
|
private static final String xci_header_keyFileLocation = "./FilesForTests/xci_header_key.txt";
|
||||||
private static KeyChainHolder keyChainHolder;
|
private static KeyChainHolder keyChainHolder;
|
||||||
|
|
||||||
private static final String fileLocation = "/home/loper/Projects/libKonogonka/FilesForTests/6*cc.nca_extracted/ROOT/nx/package2";
|
private static final String fileLocation = "/home/loper/Projects/libKonogonka/FilesForTests/6b7abe7efa17ad065b18e62d1c87a5cc.nca_extracted/ROOT/nx/package2";
|
||||||
|
|
||||||
@DisplayName("Package2 unpacked test")
|
@DisplayName("Package2 unpacked test")
|
||||||
@Test
|
@Test
|
||||||
|
@ -97,7 +97,11 @@ public class Package2UnpackedTest {
|
||||||
System2Provider provider = new System2Provider(fileLocation, keyChainHolder);
|
System2Provider provider = new System2Provider(fileLocation, keyChainHolder);
|
||||||
provider.getHeader().printDebug();
|
provider.getHeader().printDebug();
|
||||||
|
|
||||||
boolean exported = provider.exportKernel("/tmp");
|
boolean exported = provider.exportKernel("/home/loper/Projects/libKonogonka/FilesForTests/own/");
|
||||||
System.out.println("Exported = "+exported);
|
System.out.println("Exported = "+exported);
|
||||||
|
|
||||||
|
exported = provider.exportIni1("/home/loper/Projects/libKonogonka/FilesForTests/own/");
|
||||||
|
System.out.println("Exported INI1 = "+exported);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue