libKonogonka/src/main/java/libKonogonka/Tools/XCI/XCIGamecardHeader.java

149 lines
5.2 KiB
Java

/*
Copyright 2019-2020 Dmitry Isaenko
This file is part of Konogonka.
Konogonka 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.
Konogonka 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 Konogonka. If not, see <https://www.gnu.org/licenses/>.
*/
package libKonogonka.Tools.XCI;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static libKonogonka.LoperConverter.getLEint;
import static libKonogonka.LoperConverter.getLElong;
/**
* Header information
* */
public class XCIGamecardHeader{
private byte[] rsa2048PKCS1sig;
private boolean magicHead;
private byte[] SecureAreaStartAddr;
private boolean bkupAreaStartAddr;
private byte titleKEKIndexBoth;
private byte titleKEKIndex;
private byte KEKIndex;
private byte gcSize;
private byte gcVersion;
private byte gcFlags;
private byte[] pkgID;
private long valDataEndAddr;
private byte[] gcInfoIV;
private long hfs0partOffset;
private long hfs0headerSize;
private byte[] hfs0headerSHA256;
private byte[] hfs0initDataSHA256 ;
private int secureModeFlag;
private int titleKeyFlag;
private int keyFlag;
private byte[] normAreaEndAddr;
XCIGamecardHeader(byte[] headerBytes) throws Exception{
if (headerBytes.length != 400)
throw new Exception("XCIGamecardHeader Incorrect array size. Expected 400 bytes while received "+headerBytes.length);
rsa2048PKCS1sig = Arrays.copyOfRange(headerBytes, 0, 256);
magicHead = Arrays.equals(Arrays.copyOfRange(headerBytes, 256, 260), new byte[]{0x48, 0x45, 0x41, 0x44});
SecureAreaStartAddr = Arrays.copyOfRange(headerBytes, 260, 264);
bkupAreaStartAddr = Arrays.equals(Arrays.copyOfRange(headerBytes, 264, 268), new byte[]{(byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff});
titleKEKIndexBoth = headerBytes[268];
titleKEKIndex = (byte) ((titleKEKIndexBoth >> 4) & (byte) 0x0F);
KEKIndex = (byte) (titleKEKIndexBoth & 0x0F);
gcSize = headerBytes[269];
gcVersion = headerBytes[270];
gcFlags = headerBytes[271];
pkgID = Arrays.copyOfRange(headerBytes, 272, 280);
valDataEndAddr = getLElong(headerBytes, 280); //TODO: FIX/simplify //
gcInfoIV = reverseBytes(Arrays.copyOfRange(headerBytes, 288, 304));
hfs0partOffset = getLElong(headerBytes, 304);
hfs0headerSize = getLElong(headerBytes, 312);
hfs0headerSHA256 = Arrays.copyOfRange(headerBytes, 320, 352);
hfs0initDataSHA256 = Arrays.copyOfRange(headerBytes, 352, 384);
secureModeFlag = getLEint(headerBytes, 384);
titleKeyFlag = getLEint(headerBytes, 388);
keyFlag = getLEint(headerBytes, 392);
normAreaEndAddr = Arrays.copyOfRange(headerBytes, 396, 400);
}
public byte[] getRsa2048PKCS1sig() { return rsa2048PKCS1sig; }
public boolean isMagicHeadOk() { return magicHead; }
public byte[] getSecureAreaStartAddr() { return SecureAreaStartAddr; }
public boolean isBkupAreaStartAddrOk() { return bkupAreaStartAddr; }
public byte getTitleKEKIndexBoth() { return titleKEKIndexBoth; }
public byte getTitleKEKIndex() { return titleKEKIndex; }
public byte getKEKIndex() { return KEKIndex; }
public byte getGcSize() {
return gcSize;
}
public byte getGcVersion() {
return gcVersion;
}
public byte getGcFlags() {
return gcFlags;
}
public byte[] getPkgID() {
return pkgID;
}
public long getValDataEndAddr() {
return valDataEndAddr;
}
public byte[] getGcInfoIV() {
return gcInfoIV;
}
public long getHfs0partOffset() {
return hfs0partOffset;
}
public long getHfs0headerSize() {
return hfs0headerSize;
}
public byte[] getHfs0headerSHA256() {
return hfs0headerSHA256;
}
public byte[] getHfs0initDataSHA256() {
return hfs0initDataSHA256;
}
public int getSecureModeFlag() {
return secureModeFlag;
}
public boolean isSecureModeFlagOk(){
return secureModeFlag == 1;
}
public int getTitleKeyFlag() {
return titleKeyFlag;
}
public boolean istitleKeyFlagOk(){
return titleKeyFlag == 2;
}
public int getKeyFlag() {
return keyFlag;
}
public boolean iskeyFlagOk(){
return keyFlag == 0;
}
public byte[] getNormAreaEndAddr() {
return normAreaEndAddr;
}
private byte[] reverseBytes(byte[] bArr){
Byte[] objArr = new Byte[bArr.length];
for (int i=0;i < bArr.length; i++)
objArr[i] = bArr[i];
List<Byte> bytesList = Arrays.asList(objArr);
Collections.reverse(bytesList);
for (int i=0;i < bArr.length; i++)
bArr[i] = objArr[i];
return bArr;
}
}