nstool/lib/libnx/source/NcaHeader.cpp

327 lines
7.2 KiB
C++
Raw Normal View History

#include <nx/NcaHeader.h>
2017-07-05 08:57:14 +00:00
nx::NcaHeader::NcaHeader()
2018-06-24 08:18:54 +00:00
{
clear();
}
nx::NcaHeader::NcaHeader(const NcaHeader & other)
2018-06-24 08:18:54 +00:00
{
*this = other;
}
bool nx::NcaHeader::operator==(const NcaHeader & other) const
2018-06-24 08:18:54 +00:00
{
return (mDistributionType == other.mDistributionType) \
&& (mContentType == other.mContentType) \
&& (mKeyGeneration == other.mKeyGeneration) \
&& (mKaekIndex == other.mKaekIndex) \
&& (mContentSize == other.mContentSize) \
&& (mProgramId == other.mProgramId) \
&& (mContentIndex == other.mContentIndex) \
&& (mSdkAddonVersion == other.mSdkAddonVersion) \
&& (mPartitions == other.mPartitions) \
&& (mEncAesKeys == other.mEncAesKeys);
}
2017-07-06 11:17:21 +00:00
bool nx::NcaHeader::operator!=(const NcaHeader & other) const
2017-07-05 08:57:14 +00:00
{
2018-06-24 08:18:54 +00:00
return !(*this == other);
}
void nx::NcaHeader::operator=(const NcaHeader & other)
2018-06-24 08:18:54 +00:00
{
if (other.getBytes().size())
{
fromBytes(other.getBytes().data(), other.getBytes().size());
}
else
{
mRawBinary.clear();
mDistributionType = other.mDistributionType;
mContentType = other.mContentType;
mKeyGeneration = other.mKeyGeneration;
mKaekIndex = other.mKaekIndex;
mContentSize = other.mContentSize;
mProgramId = other.mProgramId;
mContentIndex = other.mContentIndex;
mSdkAddonVersion = other.mSdkAddonVersion;
mPartitions = other.mPartitions;
mEncAesKeys = other.mEncAesKeys;
}
}
void nx::NcaHeader::toBytes()
2018-06-24 08:18:54 +00:00
{
mRawBinary.alloc(sizeof(sNcaHeader));
sNcaHeader* hdr = (sNcaHeader*)mRawBinary.data();
2018-03-18 09:08:42 +00:00
switch(mFormatVersion)
{
case (NCA2_FORMAT):
2018-06-26 13:13:28 +00:00
hdr->st_magic = nca::kNca2StructMagic;
2018-03-18 09:08:42 +00:00
break;
case (NCA3_FORMAT):
2018-06-26 13:13:28 +00:00
hdr->st_magic = nca::kNca3StructMagic;
2018-03-18 09:08:42 +00:00
break;
default:
throw fnd::Exception(kModuleName, "Unsupported format version");
}
hdr->distribution_type = mDistributionType;
hdr->content_type = mContentType;
if (mKeyGeneration > 2)
{
hdr->key_generation = 2;
hdr->key_generation_2 = mKeyGeneration;
}
else
{
hdr->key_generation = mKeyGeneration;
hdr->key_generation_2 = 0;
}
2018-03-18 09:08:42 +00:00
hdr->key_area_encryption_key_index = mKaekIndex;
hdr->content_size = mContentSize;
hdr->program_id = mProgramId;
hdr->content_index = mContentIndex;
hdr->sdk_addon_version = mSdkAddonVersion;
memcpy(hdr->rights_id, mRightsId, nca::kRightsIdLen);
// TODO: properly reconstruct NCA layout? atm in hands of user
2018-06-24 08:18:54 +00:00
for (size_t i = 0; i < mPartitions.size(); i++)
{
// determine partition index
byte_t idx = mPartitions[i].index;
if (mPartitions[i].index >= nca::kPartitionNum || hdr->partition[idx].enabled) continue;
hdr->partition[idx].start = sizeToBlockNum(mPartitions[i].offset);
hdr->partition[idx].end = (sizeToBlockNum(mPartitions[i].offset) + sizeToBlockNum(mPartitions[i].size));
hdr->partition[idx].enabled = true;
hdr->partition_hash[idx] = mPartitions[i].hash;
}
for (size_t i = 0; i < nca::kAesKeyNum; i++)
{
hdr->enc_aes_key[i] = mEncAesKeys[i];
}
2017-07-05 08:57:14 +00:00
}
void nx::NcaHeader::fromBytes(const byte_t * data, size_t len)
2017-07-05 08:57:14 +00:00
{
if (len < sizeof(sNcaHeader))
{
throw fnd::Exception(kModuleName, "NCA header size is too small");
}
clear();
2018-06-24 08:18:54 +00:00
mRawBinary.alloc(sizeof(sNcaHeader));
memcpy(mRawBinary.data(), data, sizeof(sNcaHeader));
2017-07-05 08:57:14 +00:00
2018-06-24 08:18:54 +00:00
sNcaHeader* hdr = (sNcaHeader*)mRawBinary.data();
2017-07-05 08:57:14 +00:00
switch(hdr->st_magic.get())
2017-07-05 08:57:14 +00:00
{
2018-06-26 13:13:28 +00:00
case (nca::kNca2StructMagic) :
mFormatVersion = NCA2_FORMAT;
break;
2018-06-26 13:13:28 +00:00
case (nca::kNca3StructMagic) :
mFormatVersion = NCA3_FORMAT;
break;
2017-07-05 08:57:14 +00:00
throw fnd::Exception(kModuleName, "NCA header corrupt");
}
mDistributionType = (nca::DistributionType)hdr->distribution_type;
mContentType = (nca::ContentType)hdr->content_type;
mKeyGeneration = _MAX(hdr->key_generation, hdr->key_generation_2);
2018-03-18 09:08:42 +00:00
mKaekIndex = hdr->key_area_encryption_key_index;
mContentSize = *hdr->content_size;
mProgramId = *hdr->program_id;
mContentIndex = *hdr->content_index;
mSdkAddonVersion = *hdr->sdk_addon_version;
memcpy(mRightsId, hdr->rights_id, nca::kRightsIdLen);
2017-07-05 08:57:14 +00:00
for (size_t i = 0; i < nca::kPartitionNum; i++)
2017-07-05 08:57:14 +00:00
{
// skip sections that don't exist
if (hdr->partition[i].enabled == 0) continue;
2017-07-05 08:57:14 +00:00
// add high level struct
mPartitions.addElement({(byte_t)i, blockNumToSize(hdr->partition[i].start.get()), blockNumToSize(hdr->partition[i].end.get() - hdr->partition[i].start.get()), hdr->partition_hash[i] });
2017-07-05 08:57:14 +00:00
}
for (size_t i = 0; i < nca::kAesKeyNum; i++)
2017-07-05 08:57:14 +00:00
{
mEncAesKeys.addElement(hdr->enc_aes_key[i]);
2017-07-05 08:57:14 +00:00
}
}
const fnd::Vec<byte_t>& nx::NcaHeader::getBytes() const
2018-06-24 08:18:54 +00:00
{
return mRawBinary;
}
void nx::NcaHeader::clear()
{
2018-03-18 09:08:42 +00:00
mFormatVersion = NCA3_FORMAT;
mDistributionType = nca::DIST_DOWNLOAD;
mContentType = nca::TYPE_PROGRAM;
mKeyGeneration = 0;
2018-03-18 09:08:42 +00:00
mKaekIndex = 0;
mContentSize = 0;
mProgramId = 0;
2017-07-18 14:17:32 +00:00
mContentIndex = 0;
mSdkAddonVersion = 0;
mPartitions.clear();
2017-07-18 14:17:32 +00:00
mEncAesKeys.clear();
}
2018-03-18 09:08:42 +00:00
nx::NcaHeader::FormatVersion nx::NcaHeader::getFormatVersion() const
{
return mFormatVersion;
}
void nx::NcaHeader::setFormatVersion(FormatVersion version)
{
mFormatVersion = version;
}
nx::nca::DistributionType nx::NcaHeader::getDistributionType() const
2017-07-18 14:17:32 +00:00
{
return mDistributionType;
}
void nx::NcaHeader::setDistributionType(nca::DistributionType type)
2017-07-18 14:17:32 +00:00
{
mDistributionType = type;
}
nx::nca::ContentType nx::NcaHeader::getContentType() const
2017-07-18 14:17:32 +00:00
{
return mContentType;
}
void nx::NcaHeader::setContentType(nca::ContentType type)
2017-07-18 14:17:32 +00:00
{
mContentType = type;
}
byte_t nx::NcaHeader::getKeyGeneration() const
2017-07-18 14:17:32 +00:00
{
return mKeyGeneration;
2017-07-18 14:17:32 +00:00
}
void nx::NcaHeader::setKeyGeneration(byte_t gen)
2017-07-18 14:17:32 +00:00
{
mKeyGeneration = gen;
2017-07-18 14:17:32 +00:00
}
2018-03-18 09:08:42 +00:00
byte_t nx::NcaHeader::getKaekIndex() const
2017-07-18 14:17:32 +00:00
{
2018-03-18 09:08:42 +00:00
return mKaekIndex;
2017-07-18 14:17:32 +00:00
}
2018-03-18 09:08:42 +00:00
void nx::NcaHeader::setKaekIndex(byte_t index)
2017-07-18 14:17:32 +00:00
{
2018-03-18 09:08:42 +00:00
mKaekIndex = index;
}
uint64_t nx::NcaHeader::getContentSize() const
2017-07-05 08:57:14 +00:00
{
return mContentSize;
2017-07-05 08:57:14 +00:00
}
void nx::NcaHeader::setContentSize(uint64_t size)
2017-07-05 08:57:14 +00:00
{
mContentSize = size;
2017-07-05 08:57:14 +00:00
}
uint64_t nx::NcaHeader::getProgramId() const
2017-07-05 08:57:14 +00:00
{
return mProgramId;
2017-07-05 08:57:14 +00:00
}
void nx::NcaHeader::setProgramId(uint64_t program_id)
2017-07-05 08:57:14 +00:00
{
mProgramId = program_id;
2017-07-05 08:57:14 +00:00
}
2018-03-22 05:26:22 +00:00
uint32_t nx::NcaHeader::getContentIndex() const
2017-07-18 14:17:32 +00:00
{
return mContentIndex;
}
2018-03-22 05:26:22 +00:00
void nx::NcaHeader::setContentIndex(uint32_t index)
2017-07-18 14:17:32 +00:00
{
mContentIndex = index;
}
2018-03-22 05:26:22 +00:00
uint32_t nx::NcaHeader::getSdkAddonVersion() const
2017-07-18 14:17:32 +00:00
{
return mSdkAddonVersion;
}
2018-03-22 05:26:22 +00:00
void nx::NcaHeader::setSdkAddonVersion(uint32_t version)
2017-07-05 08:57:14 +00:00
{
2017-07-18 14:17:32 +00:00
mSdkAddonVersion = version;
2017-07-05 08:57:14 +00:00
}
2018-05-01 05:17:25 +00:00
bool nx::NcaHeader::hasRightsId() const
{
bool rightsIdIsSet = false;
for (size_t i = 0; i < nca::kRightsIdLen; i++)
{
if (mRightsId[i] != 0)
rightsIdIsSet = true;
}
return rightsIdIsSet;
}
const byte_t* nx::NcaHeader::getRightsId() const
2017-07-05 08:57:14 +00:00
{
return mRightsId;
2017-07-05 08:57:14 +00:00
}
void nx::NcaHeader::setRightsId(const byte_t* rights_id)
2017-07-05 08:57:14 +00:00
{
memcpy(mRightsId, rights_id, nca::kRightsIdLen);
}
const fnd::List<nx::NcaHeader::sPartition>& nx::NcaHeader::getPartitions() const
{
return mPartitions;
}
void nx::NcaHeader::setPartitions(const fnd::List<nx::NcaHeader::sPartition>& partitions)
{
mPartitions = partitions;
2018-06-24 08:18:54 +00:00
if (mPartitions.size() >= nca::kPartitionNum)
2017-07-05 08:57:14 +00:00
{
throw fnd::Exception(kModuleName, "Too many NCA partitions");
2017-07-05 08:57:14 +00:00
}
}
const fnd::List<crypto::aes::sAes128Key>& nx::NcaHeader::getEncAesKeys() const
2017-07-05 08:57:14 +00:00
{
2017-07-18 14:17:32 +00:00
return mEncAesKeys;
2017-07-05 08:57:14 +00:00
}
void nx::NcaHeader::setEncAesKeys(const fnd::List<crypto::aes::sAes128Key>& keys)
2017-07-05 08:57:14 +00:00
{
mEncAesKeys = keys;
2017-07-05 08:57:14 +00:00
}
uint64_t nx::NcaHeader::blockNumToSize(uint32_t block_num) const
2017-07-05 08:57:14 +00:00
{
return block_num*nca::kSectorSize;
2017-07-05 08:57:14 +00:00
}
uint32_t nx::NcaHeader::sizeToBlockNum(uint64_t real_size) const
2017-07-05 08:57:14 +00:00
{
return (uint32_t)(align(real_size, nca::kSectorSize) / nca::kSectorSize);
2017-07-05 08:57:14 +00:00
}