Fix AesCtrBufferedInputStream bug, add few tests
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
923fbcb5fc
commit
119b615797
14 changed files with 187 additions and 39 deletions
|
@ -57,13 +57,26 @@ public class Converter {
|
|||
}
|
||||
|
||||
public static String intToBinaryString(int value){
|
||||
return String.format("%32s", Integer.toBinaryString( value )).replace(' ', '0')+" | "+value;
|
||||
return String.format("%32s", Integer.toBinaryString( value )).replace(' ', '0');
|
||||
}
|
||||
|
||||
public static String longToOctString(long value){
|
||||
return String.format("%64s", Long.toBinaryString( value )).replace(' ', '0');
|
||||
}
|
||||
|
||||
public static byte[] hexStringToByteArray(String string){
|
||||
if (string.length() % 2 != 0)
|
||||
string = "0" + string;
|
||||
|
||||
int resultSize = string.length() / 2;
|
||||
byte[] resultingArray = new byte[resultSize];
|
||||
|
||||
for (int i = 0; i < resultSize; i++){
|
||||
resultingArray[i] = (byte) Integer.parseInt(string.substring(i*2, i*2+2), 16);
|
||||
}
|
||||
return resultingArray;
|
||||
}
|
||||
|
||||
public static byte[] flip(byte[] bytes){
|
||||
int size = bytes.length;
|
||||
byte[] ret = new byte[size];
|
||||
|
|
|
@ -154,7 +154,8 @@ public class NCAContent {
|
|||
ncaOffsetPosition,
|
||||
mediaStartOffset,
|
||||
mediaEndOffset,
|
||||
Files.newInputStream(file.toPath()));
|
||||
Files.newInputStream(file.toPath()),
|
||||
Files.size(file.toPath()));
|
||||
}
|
||||
else
|
||||
throw new Exception("Crypto type not supported");
|
||||
|
|
|
@ -286,7 +286,7 @@ public class NCAProvider {
|
|||
}
|
||||
catch (EmptySectionException ignored){}
|
||||
catch (Exception e){
|
||||
log.debug("Unable to get NCA Content "+number, e);
|
||||
log.debug("Unable to get NCA Content "+number+" ("+file.getParentFile().getName()+"/"+file.getName()+")", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,4 +391,8 @@ public class NCAProvider {
|
|||
throw new Exception("NCA Content must be requested in range of 0-3, while 'Section Number "+sectionNumber+"' requested");
|
||||
}
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
}
|
|
@ -85,7 +85,7 @@ public class PFS0Header {
|
|||
throw new Exception("Read PFS0Provider String table failure. Can't read requested string table size ("+stringTableSize+")");
|
||||
}
|
||||
|
||||
for (int i=0; i < filesCount; i++){
|
||||
for (int i = 0; i < filesCount; i++){
|
||||
int j = 0;
|
||||
while (stringTbl[strTableOffsets[i]+j] != (byte)0x00)
|
||||
j++;
|
||||
|
|
|
@ -196,7 +196,7 @@ public class FileSystemEntry {
|
|||
fileName = new String(Arrays.copyOfRange(filesMetadataTable, i, i + fileNameLength), StandardCharsets.UTF_8);
|
||||
}
|
||||
catch (Exception e){
|
||||
log.debug("fileName sizes are: "+filesMetadataTable.length+"\t"+i+"\t"+i + fileNameLength+"\t\t"+nextHashTableBucketFileOffset);
|
||||
log.debug("fileName sizes are: "+filesMetadataTable.length+"\t"+i+"\t"+i + fileNameLength+"\t\t"+nextHashTableBucketFileOffset, e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
package libKonogonka.ctraes;
|
||||
|
||||
import libKonogonka.Converter;
|
||||
import libKonogonka.RainbowDump;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
@ -30,16 +31,19 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
|||
private final AesCtrDecryptSimple decryptor;
|
||||
private final long mediaOffsetPositionStart;
|
||||
private final long mediaOffsetPositionEnd;
|
||||
private final long fileSize;
|
||||
|
||||
public AesCtrBufferedInputStream(AesCtrDecryptSimple decryptor,
|
||||
long ncaOffsetPosition,
|
||||
long mediaStartOffset,
|
||||
long mediaEndOffset,
|
||||
InputStream inputStream){
|
||||
InputStream inputStream,
|
||||
long fileSize){
|
||||
super(inputStream);
|
||||
this.decryptor = decryptor;
|
||||
this.mediaOffsetPositionStart = ncaOffsetPosition + (mediaStartOffset * 0x200);
|
||||
this.mediaOffsetPositionEnd = ncaOffsetPosition + (mediaEndOffset * 0x200);
|
||||
this.fileSize = fileSize;
|
||||
|
||||
log.trace("\n Offset Position "+ncaOffsetPosition+
|
||||
"\n MediaOffsetPositionStart "+RainbowDump.formatDecHexString(mediaOffsetPositionStart)+
|
||||
|
@ -75,9 +79,11 @@ public class AesCtrBufferedInputStream extends BufferedInputStream {
|
|||
fillDecryptedCache();
|
||||
System.arraycopy(decryptedBytes, 0, b, bytesFromFirstBlock+i*0x200, 0x200);
|
||||
}
|
||||
//3 // TODO: ONLY IF NON-NULL??
|
||||
fillDecryptedCache();
|
||||
System.arraycopy(decryptedBytes, 0, b, bytesFromFirstBlock+middleBlocksCount*0x200, bytesFromLastBlock);
|
||||
//3
|
||||
if(fileSize > (pseudoPos+bytesToRead)) {
|
||||
fillDecryptedCache();
|
||||
System.arraycopy(decryptedBytes, 0, b, bytesFromFirstBlock + middleBlocksCount * 0x200, bytesFromLastBlock);
|
||||
}
|
||||
pseudoPos += bytesToRead;
|
||||
pointerInsideDecryptedSection = bytesFromLastBlock;
|
||||
return b.length;
|
||||
|
|
|
@ -70,7 +70,8 @@ public class InFileStreamProducer {
|
|||
initialOffset,
|
||||
mediaStartOffset,
|
||||
mediaEndOffset,
|
||||
Files.newInputStream(file.toPath()));
|
||||
Files.newInputStream(file.toPath()),
|
||||
Files.size(file.toPath()));
|
||||
skipBytesTillBeginning(stream, subOffset);
|
||||
return stream;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of libKonogonka.
|
||||
|
||||
libKonogonka is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
libKonogonka is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with libKonogonka. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package libKonogonka.RomFsDecrypted;
|
||||
|
||||
import libKonogonka.KeyChainHolder;
|
||||
import libKonogonka.Tools.NCA.NCAProvider;
|
||||
import libKonogonka.Tools.NSO.NSO0Provider;
|
||||
import libKonogonka.Tools.PFS0.PFS0Provider;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
|
||||
public class ExportNso0FromNcaTest {
|
||||
private static final String keysFileLocation = "./FilesForTests/prod.keys";
|
||||
private static final String xci_header_keyFileLocation = "./FilesForTests/xci_header_key.txt";
|
||||
private static final String ncaFileLocation = "./FilesForTests/nso_container.nca";
|
||||
private static final String exportDecompressedNsoTo = "/tmp";
|
||||
|
||||
@Disabled
|
||||
@DisplayName("Exports decompressed NSO0 example")
|
||||
@Test
|
||||
void nso0Test() throws Exception{
|
||||
BufferedReader br = new BufferedReader(new FileReader(xci_header_keyFileLocation));
|
||||
String keyValue = br.readLine();
|
||||
br.close();
|
||||
|
||||
if (keyValue == null)
|
||||
throw new Exception("Unable to retrieve xci_header_key");
|
||||
|
||||
keyValue = keyValue.trim();
|
||||
KeyChainHolder keyChainHolder = new KeyChainHolder(keysFileLocation, keyValue);
|
||||
|
||||
NCAProvider ncaProvider = new NCAProvider(new File(ncaFileLocation), keyChainHolder.getRawKeySet());
|
||||
|
||||
PFS0Provider pfs0Provider = ncaProvider.getNCAContentProvider(0).getPfs0();
|
||||
pfs0Provider.printDebug();
|
||||
|
||||
NSO0Provider nso0Provider = new NSO0Provider(pfs0Provider.getStreamProducer(0));
|
||||
nso0Provider.printDebug();
|
||||
nso0Provider.exportAsDecompressedNSO0(exportDecompressedNsoTo);
|
||||
|
||||
System.out.println("__--++ SDK VERSION ++--__\n"
|
||||
+ ncaProvider.getSdkVersion()[3]
|
||||
+"."+ ncaProvider.getSdkVersion()[2]
|
||||
+"."+ ncaProvider.getSdkVersion()[1]
|
||||
+"."+ ncaProvider.getSdkVersion()[0]);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright 2018-2022 Dmitry Isaenko
|
||||
|
||||
This file is part of libKonogonka.
|
||||
|
||||
libKonogonka is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
libKonogonka is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with libKonogonka. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package libKonogonka.RomFsDecrypted;
|
||||
|
||||
import libKonogonka.KeyChainHolder;
|
||||
import libKonogonka.Tools.NCA.NCAProvider;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class NCAProviderSimpleTest {
|
||||
private static final String keysFileLocation = "./FilesForTests/prod.keys";
|
||||
private static final String xci_header_keyFileLocation = "./FilesForTests/xci_header_key.txt";
|
||||
private static final String ncaFileLocation = "./FilesForTests/simple.nca";
|
||||
//private static final String ncaFileLocation = "./FilesForTests/4pfs.nca";
|
||||
private static KeyChainHolder keyChainHolder;
|
||||
private static NCAProvider ncaProvider;
|
||||
|
||||
//@Disabled
|
||||
@Order(1)
|
||||
@DisplayName("KeyChain loac test")
|
||||
@Test
|
||||
void keysChain() throws Exception{
|
||||
BufferedReader br = new BufferedReader(new FileReader(xci_header_keyFileLocation));
|
||||
String keyValue = br.readLine();
|
||||
br.close();
|
||||
|
||||
if (keyValue == null)
|
||||
throw new Exception("Unable to retrieve xci_header_key");
|
||||
|
||||
keyValue = keyValue.trim();
|
||||
keyChainHolder = new KeyChainHolder(keysFileLocation, keyValue);
|
||||
}
|
||||
|
||||
//@Disabled
|
||||
@Order(2)
|
||||
@DisplayName("NCA provider test")
|
||||
@Test
|
||||
void ncaProvider() throws Exception{
|
||||
ncaProvider = new NCAProvider(new File(ncaFileLocation), keyChainHolder.getRawKeySet());
|
||||
}
|
||||
}
|
|
@ -26,18 +26,18 @@ import org.junit.jupiter.api.Test;
|
|||
import java.io.File;
|
||||
|
||||
public class NSODecompressTest {
|
||||
private static final String ncaExtractedFileLocation = "./FilesForTests/NSO0/main";
|
||||
private static final String ncaExtractedFileLocationDec = "./FilesForTests/NSO0/main_d";
|
||||
private static final String nsoExtractedFileLocation = "./FilesForTests/NSO0/main";
|
||||
private static final String nsoExtractedFileLocationDec = "./FilesForTests/NSO0/main_d";
|
||||
|
||||
@Disabled
|
||||
@DisplayName("NSO0 Decompression test")
|
||||
@Test
|
||||
void nso0DecompressionTest() throws Exception {
|
||||
NSO0Provider nso0Provider = new NSO0Provider(new File(ncaExtractedFileLocation));
|
||||
NSO0Provider nso0Provider = new NSO0Provider(new File(nsoExtractedFileLocation));
|
||||
//nso0Provider.exportAsDecompressedNSO0("./FilesForTests/NSO0");
|
||||
nso0Provider.printDebug();
|
||||
|
||||
NSO0Provider nso0Provider1 = new NSO0Provider(new File(ncaExtractedFileLocationDec));
|
||||
NSO0Provider nso0Provider1 = new NSO0Provider(new File(nsoExtractedFileLocationDec));
|
||||
nso0Provider1.printDebug();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ import libKonogonka.Tools.NCA.NCAProvider;
|
|||
import libKonogonka.Tools.NSO.NSO0Provider;
|
||||
import libKonogonka.Tools.PFS0.PFS0Provider;
|
||||
import libKonogonka.Tools.PFS0.PFS0subFile;
|
||||
import libKonogonka.ctraes.AesCtrDecryptSimple;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -74,19 +73,13 @@ public class NSOTest {
|
|||
}
|
||||
}
|
||||
|
||||
long ACBISoffsetPosition;
|
||||
long ACBISmediaStartOffset;
|
||||
long ACBISmediaEndOffset;
|
||||
|
||||
long offsetPosition;
|
||||
|
||||
|
||||
void nso0Validation() throws Exception{
|
||||
File nca = new File(ncaFileLocation);
|
||||
PFS0subFile[] subfiles = ncaProvider.getNCAContentProvider(0).getPfs0().getHeader().getPfs0subFiles();
|
||||
|
||||
offsetPosition = ncaProvider.getTableEntry0().getMediaStartOffset()*0x200 +
|
||||
long offsetPosition = ncaProvider.getTableEntry0().getMediaStartOffset()*0x200 +
|
||||
ncaProvider.getNCAContentProvider(0).getPfs0().getRawFileDataStart();
|
||||
|
||||
System.out.println("\t=============================================================");
|
||||
System.out.println("\tNCA SIZE: "+ RainbowDump.formatDecHexString(nca.length()));
|
||||
System.out.println("\tPFS0 Offset(get) "+RainbowDump.formatDecHexString(ncaProvider.getSectionBlock0().getSuperBlockPFS0().getPfs0offset()));
|
||||
|
@ -102,15 +95,6 @@ public class NSOTest {
|
|||
}
|
||||
System.out.println("\t=============================================================");
|
||||
|
||||
ACBISoffsetPosition = 0;
|
||||
ACBISmediaStartOffset = ncaProvider.getTableEntry0().getMediaStartOffset();
|
||||
ACBISmediaEndOffset = ncaProvider.getTableEntry0().getMediaEndOffset();
|
||||
|
||||
AesCtrDecryptSimple decryptSimple = new AesCtrDecryptSimple(
|
||||
ncaProvider.getDecryptedKey2(),
|
||||
ncaProvider.getSectionBlock0().getSectionCTR(),
|
||||
ncaProvider.getTableEntry0().getMediaStartOffset() * 0x200);
|
||||
|
||||
PFS0Provider pfs0Provider = ncaProvider.getNCAContentProvider(0).getPfs0();
|
||||
pfs0Provider.printDebug();
|
||||
|
||||
|
@ -118,7 +102,7 @@ public class NSOTest {
|
|||
nso0Provider.printDebug();
|
||||
nso0Provider.exportAsDecompressedNSO0("./tmp");
|
||||
|
||||
// NPDMProvider npdmProvider = new NPDMProvider(pfs0Provider.getProviderSubFilePipedInpStream(1));
|
||||
//NPDMProvider npdmProvider = new NPDMProvider(pfs0Provider.getStreamProducer(1));
|
||||
|
||||
System.out.println("__--++ SDK VERSION ++--__\n"
|
||||
+ncaProvider.getSdkVersion()[3]
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class NSPpfs0EncryptedTest {
|
||||
|
@ -153,14 +154,16 @@ public class NSPpfs0EncryptedTest {
|
|||
|
||||
BufferedOutputStream extractedFileBOS = new BufferedOutputStream(Files.newOutputStream(contentFile.toPath()));
|
||||
//---
|
||||
InputStream is = Files.newInputStream(new File(nspFileLocation).toPath()); //TODO: NOTICE
|
||||
Path filePath = new File(nspFileLocation).toPath();
|
||||
InputStream is = Files.newInputStream(filePath);
|
||||
|
||||
AesCtrBufferedInputStream aesCtrBufferedInputStream = new AesCtrBufferedInputStream(
|
||||
decryptSimple,
|
||||
ACBISoffsetPosition,
|
||||
ACBISmediaStartOffset,
|
||||
ACBISmediaEndOffset,
|
||||
is);
|
||||
is,
|
||||
Files.size(filePath));
|
||||
|
||||
//long offsetToSkip = entry.getOffset() + ncaProvider.getNCAContentProvider(0).getPfs0().getRawFileDataStart();
|
||||
long offsetToSkip = offsetPosition+entry.getOffset();
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.junit.jupiter.api.*;
|
|||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class Pfs0EncryptedTest {
|
||||
private static final String keysFileLocation = "./FilesForTests/prod.keys";
|
||||
|
@ -127,14 +128,16 @@ public class Pfs0EncryptedTest {
|
|||
|
||||
BufferedOutputStream extractedFileBOS = new BufferedOutputStream(Files.newOutputStream(contentFile.toPath()));
|
||||
//---
|
||||
InputStream is = Files.newInputStream(new File(ncaFileLocation).toPath());
|
||||
Path filePath = new File(ncaFileLocation).toPath();
|
||||
InputStream is = Files.newInputStream(filePath);
|
||||
|
||||
AesCtrBufferedInputStream aesCtrBufferedInputStream = new AesCtrBufferedInputStream(
|
||||
decryptSimple,
|
||||
ACBISoffsetPosition,
|
||||
ACBISmediaStartOffset,
|
||||
ACBISmediaEndOffset,
|
||||
is);
|
||||
is,
|
||||
Files.size(filePath));
|
||||
|
||||
//long offsetToSkip = entry.getOffset() + ncaProvider.getNCAContentProvider(0).getPfs0().getRawFileDataStart();
|
||||
long offsetToSkip = offsetPosition+entry.getOffset();
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.junit.jupiter.api.*;
|
|||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class RomFsEncryptedTest {
|
||||
|
@ -136,14 +137,16 @@ public class RomFsEncryptedTest {
|
|||
|
||||
BufferedOutputStream extractedFileBOS = new BufferedOutputStream(Files.newOutputStream(contentFile.toPath()));
|
||||
//---
|
||||
InputStream is = Files.newInputStream(new File(ncaFileLocation).toPath());
|
||||
Path filePath = new File(ncaFileLocation).toPath();
|
||||
InputStream is = Files.newInputStream(filePath);
|
||||
|
||||
AesCtrBufferedInputStream aesCtrBufferedInputStream = new AesCtrBufferedInputStream(
|
||||
decryptSimple,
|
||||
ACBISoffsetPosition,
|
||||
ACBISmediaStartOffset,
|
||||
ACBISmediaEndOffset,
|
||||
is);
|
||||
is,
|
||||
Files.size(filePath));
|
||||
|
||||
long skipBytes = entry.getOffset()
|
||||
+ncaProvider.getTableEntry1().getMediaStartOffset()*0x200
|
||||
|
|
Loading…
Reference in a new issue