2018-04-21 09:37:30 +00:00
|
|
|
#include <nx/XciHeader.h>
|
|
|
|
|
2018-06-24 08:18:54 +00:00
|
|
|
nx::XciHeader::XciHeader()
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
nx::XciHeader::XciHeader(const XciHeader& other)
|
2018-04-21 09:37:30 +00:00
|
|
|
{
|
2018-06-24 08:18:54 +00:00
|
|
|
*this = other;
|
2018-04-21 09:37:30 +00:00
|
|
|
}
|
|
|
|
|
2018-06-24 08:18:54 +00:00
|
|
|
void nx::XciHeader::operator=(const XciHeader& other)
|
2018-04-21 09:37:30 +00:00
|
|
|
{
|
|
|
|
mRomAreaStartPage = other.mRomAreaStartPage;
|
|
|
|
mBackupAreaStartPage = other.mBackupAreaStartPage;
|
|
|
|
mKekIndex = other.mKekIndex;
|
|
|
|
mTitleKeyDecIndex = other.mTitleKeyDecIndex;
|
|
|
|
mRomSize = other.mRomSize;
|
|
|
|
mCardHeaderVersion = other.mCardHeaderVersion;
|
|
|
|
mFlags = other.mFlags;
|
|
|
|
mPackageId = other.mPackageId;
|
|
|
|
mValidDataEndPage = other.mValidDataEndPage;
|
|
|
|
mAesCbcIv = other.mAesCbcIv;
|
|
|
|
mPartitionFsHeaderAddress = other.mPartitionFsHeaderAddress;
|
|
|
|
mPartitionFsHeaderSize = other.mPartitionFsHeaderSize;
|
|
|
|
mPartitionFsHeaderHash = other.mPartitionFsHeaderHash;
|
|
|
|
mInitialDataHash = other.mInitialDataHash;
|
|
|
|
mSelSec = other.mSelSec;
|
|
|
|
mSelT1Key = other.mSelT1Key;
|
|
|
|
mSelKey = other.mSelKey;
|
|
|
|
mLimAreaPage = other.mLimAreaPage;
|
|
|
|
mFwVersion[0] = other.mFwVersion[0];
|
|
|
|
mFwVersion[1] = other.mFwVersion[1];
|
|
|
|
mAccCtrl1 = other.mAccCtrl1;
|
|
|
|
mWait1TimeRead = other.mWait1TimeRead;
|
|
|
|
mWait2TimeRead = other.mWait2TimeRead;
|
|
|
|
mWait1TimeWrite = other.mWait1TimeWrite;
|
|
|
|
mWait2TimeWrite = other.mWait2TimeWrite;
|
|
|
|
mFwMode = other.mFwMode;
|
|
|
|
mUppVersion = other.mUppVersion;
|
|
|
|
memcpy(mUppHash, other.mUppHash, xci::kUppHashLen);
|
|
|
|
mUppId = other.mUppId;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool nx::XciHeader::operator==(const XciHeader& other) const
|
|
|
|
{
|
2018-06-24 15:01:16 +00:00
|
|
|
return (mRomAreaStartPage == other.mRomAreaStartPage)
|
|
|
|
&& (mBackupAreaStartPage == other.mBackupAreaStartPage)
|
|
|
|
&& (mKekIndex == other.mKekIndex)
|
|
|
|
&& (mTitleKeyDecIndex == other.mTitleKeyDecIndex)
|
|
|
|
&& (mRomSize == other.mRomSize)
|
|
|
|
&& (mCardHeaderVersion == other.mCardHeaderVersion)
|
|
|
|
&& (mFlags == other.mFlags)
|
|
|
|
&& (mPackageId == other.mPackageId)
|
|
|
|
&& (mValidDataEndPage == other.mValidDataEndPage)
|
|
|
|
&& (mAesCbcIv == other.mAesCbcIv)
|
|
|
|
&& (mPartitionFsHeaderAddress == other.mPartitionFsHeaderAddress)
|
|
|
|
&& (mPartitionFsHeaderSize == other.mPartitionFsHeaderSize)
|
|
|
|
&& (mPartitionFsHeaderHash == other.mPartitionFsHeaderHash)
|
|
|
|
&& (mInitialDataHash == other.mInitialDataHash)
|
|
|
|
&& (mSelSec == other.mSelSec)
|
|
|
|
&& (mSelT1Key == other.mSelT1Key)
|
|
|
|
&& (mSelKey == other.mSelKey)
|
|
|
|
&& (mLimAreaPage == other.mLimAreaPage)
|
|
|
|
&& (mFwVersion[0] == other.mFwVersion[0])
|
|
|
|
&& (mFwVersion[1] == other.mFwVersion[1])
|
|
|
|
&& (mAccCtrl1 == other.mAccCtrl1)
|
|
|
|
&& (mWait1TimeRead == other.mWait1TimeRead)
|
|
|
|
&& (mWait2TimeRead == other.mWait2TimeRead)
|
|
|
|
&& (mWait1TimeWrite == other.mWait1TimeWrite)
|
|
|
|
&& (mWait2TimeWrite == other.mWait2TimeWrite)
|
|
|
|
&& (mFwMode == other.mFwMode)
|
|
|
|
&& (mUppVersion == other.mUppVersion)
|
|
|
|
&& (memcmp(mUppHash, other.mUppHash, xci::kUppHashLen) == 0)
|
|
|
|
&& (mUppId == other.mUppId);
|
2018-04-21 09:37:30 +00:00
|
|
|
}
|
|
|
|
|
2018-06-24 08:18:54 +00:00
|
|
|
bool nx::XciHeader::operator!=(const XciHeader& other) const
|
2018-04-21 09:37:30 +00:00
|
|
|
{
|
2018-06-24 08:18:54 +00:00
|
|
|
return !(*this == other);
|
2018-04-21 09:37:30 +00:00
|
|
|
}
|
|
|
|
|
2018-06-24 08:18:54 +00:00
|
|
|
void nx::XciHeader::toBytes()
|
2018-04-21 09:37:30 +00:00
|
|
|
{
|
|
|
|
fnd::Exception(kModuleName, "exportBinary() not implemented");
|
|
|
|
}
|
|
|
|
|
2018-06-24 08:18:54 +00:00
|
|
|
void nx::XciHeader::fromBytes(const byte_t* data, size_t len)
|
2018-04-21 09:37:30 +00:00
|
|
|
{
|
|
|
|
// check input data size
|
|
|
|
if (len < sizeof(sXciHeader))
|
|
|
|
{
|
|
|
|
throw fnd::Exception(kModuleName, "XCI header size is too small");
|
|
|
|
}
|
|
|
|
|
|
|
|
// clear internal members
|
|
|
|
clear();
|
|
|
|
|
|
|
|
// allocate internal local binary copy
|
2018-06-24 08:18:54 +00:00
|
|
|
mRawBinary.alloc(sizeof(sXciHeader));
|
|
|
|
memcpy(mRawBinary.data(), data, mRawBinary.size());
|
2018-04-21 09:37:30 +00:00
|
|
|
|
|
|
|
// get sXciHeader ptr
|
2018-06-24 08:18:54 +00:00
|
|
|
const nx::sXciHeader* hdr = (const nx::sXciHeader*)mRawBinary.data();
|
2018-04-21 09:37:30 +00:00
|
|
|
|
|
|
|
// check XCI signature
|
2018-06-26 04:23:40 +00:00
|
|
|
if (hdr->st_magic.get() != xci::kXciStructMagic)
|
2018-04-21 09:37:30 +00:00
|
|
|
{
|
|
|
|
throw fnd::Exception(kModuleName, "XCI header corrupt");
|
|
|
|
}
|
|
|
|
|
|
|
|
mRomAreaStartPage = hdr->rom_area_start_page.get();
|
|
|
|
mBackupAreaStartPage = hdr->backup_area_start_page.get();
|
|
|
|
mKekIndex = hdr->key_flag & 7;
|
|
|
|
mTitleKeyDecIndex = (hdr->key_flag >> 4) & 7;
|
|
|
|
mRomSize = hdr->rom_size;
|
|
|
|
mCardHeaderVersion = hdr->card_header_version;
|
|
|
|
mFlags = hdr->flags;
|
|
|
|
mPackageId = hdr->package_id.get();
|
|
|
|
mValidDataEndPage = hdr->valid_data_end_page.get();
|
|
|
|
for (size_t i = 0; i < crypto::aes::kAesBlockSize; i++)
|
|
|
|
mAesCbcIv.iv[i] = hdr->aescbc_iv.iv[15-i];
|
|
|
|
mPartitionFsHeaderAddress = hdr->partition_fs_header_address.get();
|
|
|
|
mPartitionFsHeaderSize = hdr->partition_fs_header_size.get();
|
|
|
|
mPartitionFsHeaderHash = hdr->partition_fs_header_hash;
|
|
|
|
mInitialDataHash = hdr->initial_data_hash;
|
|
|
|
mSelSec = hdr->sel_sec.get();
|
|
|
|
mSelT1Key = hdr->sel_t1_key.get();
|
|
|
|
mSelKey = hdr->sel_key.get();
|
|
|
|
mLimAreaPage = hdr->lim_area.get();
|
|
|
|
|
|
|
|
// if decrypted
|
|
|
|
if (hdr->reserved_02[sizeof(hdr->reserved_02)-1] == 0x00 && hdr->reserved_02[sizeof(hdr->reserved_02)-2] == 0x00)
|
|
|
|
{
|
|
|
|
mFwVersion[xci::FWVER_MAJOR] = hdr->fw_version[xci::FWVER_MAJOR].get();
|
|
|
|
mFwVersion[xci::FWVER_MINOR] = hdr->fw_version[xci::FWVER_MINOR].get();
|
|
|
|
mAccCtrl1 = hdr->acc_ctrl_1.get();
|
|
|
|
mWait1TimeRead = hdr->wait_1_time_read.get();
|
|
|
|
mWait2TimeRead = hdr->wait_2_time_read.get();
|
|
|
|
mWait1TimeWrite = hdr->wait_1_time_write.get();
|
|
|
|
mWait2TimeWrite = hdr->wait_2_time_write.get();
|
|
|
|
mFwMode = hdr->fw_mode.get();
|
|
|
|
mUppVersion = hdr->upp_version.get();
|
|
|
|
memcpy(mUppHash, hdr->upp_hash, xci::kUppHashLen);
|
|
|
|
mUppId = hdr->upp_id.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-06-24 08:18:54 +00:00
|
|
|
const fnd::Vec<byte_t>& nx::XciHeader::getBytes() const
|
|
|
|
{
|
|
|
|
return mRawBinary;
|
|
|
|
}
|
|
|
|
|
2018-04-21 09:37:30 +00:00
|
|
|
// variables
|
|
|
|
void nx::XciHeader::clear()
|
|
|
|
{
|
|
|
|
mRomAreaStartPage = 0;
|
|
|
|
mBackupAreaStartPage = 0;
|
|
|
|
mKekIndex = 0;
|
|
|
|
mTitleKeyDecIndex = 0;
|
|
|
|
mRomSize = 0;
|
|
|
|
mCardHeaderVersion = 0;
|
|
|
|
mFlags = 0;
|
|
|
|
mPackageId = 0;
|
|
|
|
mValidDataEndPage = 0;
|
|
|
|
memset(mAesCbcIv.iv, 0, sizeof(mAesCbcIv));
|
|
|
|
mPartitionFsHeaderAddress = 0;
|
|
|
|
mPartitionFsHeaderSize = 0;
|
|
|
|
memset(mPartitionFsHeaderHash.bytes, 0, sizeof(mPartitionFsHeaderHash));
|
|
|
|
memset(mInitialDataHash.bytes, 0, sizeof(mInitialDataHash));
|
|
|
|
mSelSec = 0;
|
|
|
|
mSelT1Key = 0;
|
|
|
|
mSelKey = 0;
|
|
|
|
mLimAreaPage = 0;
|
|
|
|
mFwVersion[0] = 0;
|
|
|
|
mFwVersion[1] = 0;
|
|
|
|
mAccCtrl1 = 0;
|
|
|
|
mWait1TimeRead = 0;
|
|
|
|
mWait2TimeRead = 0;
|
|
|
|
mWait1TimeWrite = 0;
|
|
|
|
mWait2TimeWrite = 0;
|
|
|
|
mFwMode = 0;
|
|
|
|
mUppVersion = 0;
|
|
|
|
memset(mUppHash, 0, xci::kUppHashLen);
|
|
|
|
mUppId = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getRomAreaStartPage() const
|
|
|
|
{
|
|
|
|
return mRomAreaStartPage;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setRomAreaStartPage(uint32_t startPage)
|
|
|
|
{
|
|
|
|
mRomAreaStartPage = startPage;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getBackupAreaStartPage() const
|
|
|
|
{
|
|
|
|
return mBackupAreaStartPage;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setBackupAreaStartPage(uint32_t startPage)
|
|
|
|
{
|
|
|
|
mBackupAreaStartPage = startPage;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte_t nx::XciHeader::getKekIndex() const
|
|
|
|
{
|
|
|
|
return mKekIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setKekIndex(byte_t kekIndex)
|
|
|
|
{
|
|
|
|
mKekIndex = kekIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte_t nx::XciHeader::getTitleKeyDecIndex() const
|
|
|
|
{
|
|
|
|
return mTitleKeyDecIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setTitleKeyDecIndex(byte_t index)
|
|
|
|
{
|
|
|
|
mTitleKeyDecIndex = index;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte_t nx::XciHeader::getRomSizeType() const
|
|
|
|
{
|
|
|
|
return mRomSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setRomSizeType(byte_t romSizeType)
|
|
|
|
{
|
|
|
|
mRomSize = romSizeType;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte_t nx::XciHeader::getCardHeaderVersion() const
|
|
|
|
{
|
|
|
|
return mCardHeaderVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setCardHeaderVersion(byte_t version)
|
|
|
|
{
|
|
|
|
mCardHeaderVersion = version;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte_t nx::XciHeader::getFlags() const
|
|
|
|
{
|
|
|
|
return mFlags;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setFlags(byte_t flags)
|
|
|
|
{
|
|
|
|
mFlags = flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t nx::XciHeader::getPackageId() const
|
|
|
|
{
|
|
|
|
return mPackageId;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setPackageId(uint64_t id)
|
|
|
|
{
|
|
|
|
mPackageId = id;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getValidDataEndPage() const
|
|
|
|
{
|
|
|
|
return mValidDataEndPage;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setValidDataEndPage(uint32_t page)
|
|
|
|
{
|
|
|
|
mValidDataEndPage = page;
|
|
|
|
}
|
|
|
|
|
|
|
|
const crypto::aes::sAesIvCtr& nx::XciHeader::getAesCbcIv() const
|
|
|
|
{
|
|
|
|
return mAesCbcIv;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setAesCbcIv(const crypto::aes::sAesIvCtr& iv)
|
|
|
|
{
|
|
|
|
mAesCbcIv = iv;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t nx::XciHeader::getPartitionFsAddress() const
|
|
|
|
{
|
|
|
|
return mPartitionFsHeaderAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setPartitionFsAddress(uint64_t address)
|
|
|
|
{
|
|
|
|
mPartitionFsHeaderAddress = address;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t nx::XciHeader::getPartitionFsSize() const
|
|
|
|
{
|
|
|
|
return mPartitionFsHeaderSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setPartitionFsSize(uint64_t size)
|
|
|
|
{
|
|
|
|
mPartitionFsHeaderSize = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
const crypto::sha::sSha256Hash& nx::XciHeader::getPartitionFsHash() const
|
|
|
|
{
|
|
|
|
return mPartitionFsHeaderHash;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setPartitionFsHash(const crypto::sha::sSha256Hash& hash)
|
|
|
|
{
|
|
|
|
mPartitionFsHeaderHash = hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
const crypto::sha::sSha256Hash& nx::XciHeader::getInitialDataHash() const
|
|
|
|
{
|
|
|
|
return mInitialDataHash;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setInitialDataHash(const crypto::sha::sSha256Hash& hash)
|
|
|
|
{
|
|
|
|
mInitialDataHash = hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getSelSec() const
|
|
|
|
{
|
|
|
|
return mSelSec;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setSelSec(uint32_t sel_sec)
|
|
|
|
{
|
|
|
|
mSelSec = sel_sec;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getSelT1Key() const
|
|
|
|
{
|
|
|
|
return mSelT1Key;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setSelT1Key(uint32_t sel_t1_key)
|
|
|
|
{
|
|
|
|
mSelT1Key = sel_t1_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getSelKey() const
|
|
|
|
{
|
|
|
|
return mSelKey;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setSelKey(uint32_t sel_key)
|
|
|
|
{
|
|
|
|
mSelKey = sel_key;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getLimAreaPage() const
|
|
|
|
{
|
|
|
|
return mLimAreaPage;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setLimAreaPage(uint32_t page)
|
|
|
|
{
|
|
|
|
mLimAreaPage = page;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getFwVerMajor() const
|
|
|
|
{
|
|
|
|
return mFwVersion[xci::FWVER_MAJOR];
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setFwVerMajor(uint32_t ver)
|
|
|
|
{
|
|
|
|
mFwVersion[xci::FWVER_MAJOR] = ver;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getFwVerMinor() const
|
|
|
|
{
|
|
|
|
return mFwVersion[xci::FWVER_MINOR];
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setFwVerMinor(uint32_t ver)
|
|
|
|
{
|
|
|
|
mFwVersion[xci::FWVER_MINOR] = ver;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getAccCtrl1() const
|
|
|
|
{
|
|
|
|
return mAccCtrl1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setAccCtrl1(uint32_t acc_ctrl_1)
|
|
|
|
{
|
|
|
|
mAccCtrl1 = acc_ctrl_1;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getWait1TimeRead() const
|
|
|
|
{
|
|
|
|
return mWait1TimeRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setWait1TimeRead(uint32_t seconds)
|
|
|
|
{
|
|
|
|
mWait1TimeRead = seconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getWait2TimeRead() const
|
|
|
|
{
|
|
|
|
return mWait2TimeRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setWait2TimeRead(uint32_t seconds)
|
|
|
|
{
|
|
|
|
mWait2TimeRead = seconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getWait1TimeWrite() const
|
|
|
|
{
|
|
|
|
return mWait1TimeWrite;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setWait1TimeWrite(uint32_t seconds)
|
|
|
|
{
|
|
|
|
mWait1TimeWrite = seconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getWait2TimeWrite() const
|
|
|
|
{
|
|
|
|
return mWait2TimeWrite;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setWait2TimeWrite(uint32_t seconds)
|
|
|
|
{
|
|
|
|
mWait2TimeWrite = seconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getFwMode() const
|
|
|
|
{
|
|
|
|
return mFwMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setFwMode(uint32_t fw_mode)
|
|
|
|
{
|
|
|
|
mFwMode = fw_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t nx::XciHeader::getUppVersion() const
|
|
|
|
{
|
|
|
|
return mUppVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setUppVersion(uint32_t version)
|
|
|
|
{
|
|
|
|
mUppVersion = version;
|
|
|
|
}
|
|
|
|
|
|
|
|
const byte_t* nx::XciHeader::getUppHash() const
|
|
|
|
{
|
|
|
|
return mUppHash;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setUppHash(const byte_t* hash)
|
|
|
|
{
|
|
|
|
memcpy(mUppHash, hash, xci::kUppHashLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t nx::XciHeader::getUppId() const
|
|
|
|
{
|
|
|
|
return mUppId;
|
|
|
|
}
|
|
|
|
|
|
|
|
void nx::XciHeader::setUppId(uint64_t id)
|
|
|
|
{
|
|
|
|
mUppId = id;
|
|
|
|
}
|
|
|
|
|