mirror of
https://github.com/jakcron/nstool
synced 2024-11-23 05:59:29 +00:00
Merge pull request #53 from jakcron/master
Bring code improvements from the master branch.
This commit is contained in:
commit
016ff48601
60 changed files with 846 additions and 912 deletions
9
.vscode/c_cpp_properties.json
vendored
9
.vscode/c_cpp_properties.json
vendored
|
@ -65,7 +65,14 @@
|
||||||
"name": "Win32",
|
"name": "Win32",
|
||||||
"includePath": [
|
"includePath": [
|
||||||
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include",
|
"C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/include",
|
||||||
"${workspaceRoot}"
|
"${workspaceRoot}",
|
||||||
|
"${workspaceRoot}/lib/libfnd/include",
|
||||||
|
"${workspaceRoot}/lib/libpolarssl/include",
|
||||||
|
"${workspaceRoot}/lib/liblz4/include",
|
||||||
|
"${workspaceRoot}/lib/libes/include",
|
||||||
|
"${workspaceRoot}/lib/libpki/include",
|
||||||
|
"${workspaceRoot}/lib/libhac/include",
|
||||||
|
"${workspaceRoot}/lib/libhac-hb/include"
|
||||||
],
|
],
|
||||||
"defines": [
|
"defines": [
|
||||||
"_DEBUG",
|
"_DEBUG",
|
||||||
|
|
|
@ -33,7 +33,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
OUTPUT = $(shell basename $(CURDIR)).a
|
OUTPUT = $(shell basename "$(CURDIR)").a
|
||||||
|
|
||||||
main: build
|
main: build
|
||||||
|
|
||||||
|
|
32
lib/libfnd/include/fnd/AesCtrWrappedIFile.h
Normal file
32
lib/libfnd/include/fnd/AesCtrWrappedIFile.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
|
#include <fnd/Vec.h>
|
||||||
|
#include <fnd/aes.h>
|
||||||
|
|
||||||
|
namespace fnd
|
||||||
|
{
|
||||||
|
class AesCtrWrappedIFile : public fnd::IFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AesCtrWrappedIFile(const fnd::SharedPtr<fnd::IFile>& file, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr);
|
||||||
|
|
||||||
|
size_t size();
|
||||||
|
void seek(size_t offset);
|
||||||
|
void read(byte_t* out, size_t len);
|
||||||
|
void read(byte_t* out, size_t offset, size_t len);
|
||||||
|
void write(const byte_t* out, size_t len);
|
||||||
|
void write(const byte_t* out, size_t offset, size_t len);
|
||||||
|
private:
|
||||||
|
const std::string kModuleName = "AesCtrWrappedIFile";
|
||||||
|
static const size_t kCacheSize = 0x10000;
|
||||||
|
static const size_t kCacheSizeAllocSize = kCacheSize + fnd::aes::kAesBlockSize;
|
||||||
|
|
||||||
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
|
fnd::aes::sAes128Key mKey;
|
||||||
|
fnd::aes::sAesIvCtr mBaseCtr, mCurrentCtr;
|
||||||
|
size_t mFileOffset;
|
||||||
|
|
||||||
|
fnd::Vec<byte_t> mCache;
|
||||||
|
};
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ namespace fnd
|
||||||
class IFile
|
class IFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline virtual ~IFile() {}
|
virtual ~IFile() = default;
|
||||||
|
|
||||||
virtual size_t size() = 0;
|
virtual size_t size() = 0;
|
||||||
virtual void seek(size_t offset) = 0;
|
virtual void seek(size_t offset) = 0;
|
||||||
|
|
|
@ -7,6 +7,8 @@ namespace fnd
|
||||||
class ISerialisable
|
class ISerialisable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~ISerialisable() = default;
|
||||||
|
|
||||||
// serialise
|
// serialise
|
||||||
virtual void toBytes() = 0;
|
virtual void toBytes() = 0;
|
||||||
// deserialise
|
// deserialise
|
||||||
|
|
59
lib/libfnd/include/fnd/LayeredIntegrityMetadata.h
Normal file
59
lib/libfnd/include/fnd/LayeredIntegrityMetadata.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#pragma once
|
||||||
|
#include <fnd/types.h>
|
||||||
|
#include <fnd/List.h>
|
||||||
|
#include <fnd/sha.h>
|
||||||
|
|
||||||
|
namespace fnd
|
||||||
|
{
|
||||||
|
class LayeredIntegrityMetadata
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct sLayer
|
||||||
|
{
|
||||||
|
size_t offset;
|
||||||
|
size_t size;
|
||||||
|
size_t block_size;
|
||||||
|
|
||||||
|
void operator=(const sLayer& other)
|
||||||
|
{
|
||||||
|
offset = other.offset;
|
||||||
|
size = other.size;
|
||||||
|
block_size = other.block_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const sLayer& other) const
|
||||||
|
{
|
||||||
|
return (offset == other.offset && size == other.size && block_size == other.block_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const sLayer& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
LayeredIntegrityMetadata();
|
||||||
|
|
||||||
|
void operator=(const LayeredIntegrityMetadata& other);
|
||||||
|
bool operator==(const LayeredIntegrityMetadata& other) const;
|
||||||
|
bool operator!=(const LayeredIntegrityMetadata& other) const;
|
||||||
|
|
||||||
|
const fnd::List<sLayer>& getHashLayerInfo() const;
|
||||||
|
void setHashLayerInfo(const fnd::List<sLayer>& layer_info);
|
||||||
|
|
||||||
|
const sLayer& getDataLayer() const;
|
||||||
|
void setDataLayerInfo(const sLayer& data_info);
|
||||||
|
|
||||||
|
const fnd::List<fnd::sha::sSha256Hash>& getMasterHashList() const;
|
||||||
|
void setMasterHashList(const fnd::List<fnd::sha::sSha256Hash>& master_hash_list);
|
||||||
|
|
||||||
|
bool getAlignHashToBlock() const;
|
||||||
|
void setAlignHashToBlock(bool doAlign);
|
||||||
|
private:
|
||||||
|
// data
|
||||||
|
fnd::List<sLayer> mLayerInfo;
|
||||||
|
sLayer mDataLayer;
|
||||||
|
fnd::List<fnd::sha::sSha256Hash> mMasterHashList;
|
||||||
|
bool mDoAlignHashToBlock;
|
||||||
|
};
|
||||||
|
}
|
47
lib/libfnd/include/fnd/LayeredIntegrityWrappedIFile.h
Normal file
47
lib/libfnd/include/fnd/LayeredIntegrityWrappedIFile.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#pragma once
|
||||||
|
#include <sstream>
|
||||||
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
|
#include <fnd/Vec.h>
|
||||||
|
#include <fnd/List.h>
|
||||||
|
#include <fnd/LayeredIntegrityMetadata.h>
|
||||||
|
|
||||||
|
namespace fnd
|
||||||
|
{
|
||||||
|
class LayeredIntegrityWrappedIFile : public fnd::IFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LayeredIntegrityWrappedIFile(const fnd::SharedPtr<fnd::IFile>& file, const LayeredIntegrityMetadata& hdr);
|
||||||
|
|
||||||
|
size_t size();
|
||||||
|
void seek(size_t offset);
|
||||||
|
void read(byte_t* out, size_t len);
|
||||||
|
void read(byte_t* out, size_t offset, size_t len);
|
||||||
|
void write(const byte_t* out, size_t len);
|
||||||
|
void write(const byte_t* out, size_t offset, size_t len);
|
||||||
|
private:
|
||||||
|
const std::string kModuleName = "LayeredIntegrityWrappedIFile";
|
||||||
|
static const size_t kDefaultCacheSize = 0x10000;
|
||||||
|
std::stringstream mErrorSs;
|
||||||
|
|
||||||
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
|
|
||||||
|
// data file
|
||||||
|
fnd::SharedPtr<fnd::IFile> mData;
|
||||||
|
size_t mDataOffset;
|
||||||
|
size_t mDataBlockSize;
|
||||||
|
fnd::List<fnd::sha::sSha256Hash> mDataHashLayer;
|
||||||
|
bool mAlignHashCalcToBlock;
|
||||||
|
|
||||||
|
fnd::Vec<byte_t> mCache;
|
||||||
|
size_t mCacheBlockNum;
|
||||||
|
|
||||||
|
inline size_t getOffsetBlock(size_t offset) const { return offset / mDataBlockSize; }
|
||||||
|
inline size_t getOffsetInBlock(size_t offset) const { return offset % mDataBlockSize; }
|
||||||
|
inline size_t getRemanderBlockReadSize(size_t total_size) const { return total_size % mDataBlockSize; }
|
||||||
|
inline size_t getBlockNum(size_t total_size) const { return (total_size / mDataBlockSize) + (getRemanderBlockReadSize(total_size) > 0); }
|
||||||
|
|
||||||
|
void initialiseDataLayer(const LayeredIntegrityMetadata& hdr);
|
||||||
|
void readData(size_t block_offset, size_t block_num);
|
||||||
|
};
|
||||||
|
}
|
23
lib/libfnd/include/fnd/OffsetAdjustedIFile.h
Normal file
23
lib/libfnd/include/fnd/OffsetAdjustedIFile.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
|
|
||||||
|
namespace fnd
|
||||||
|
{
|
||||||
|
class OffsetAdjustedIFile : public fnd::IFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OffsetAdjustedIFile(const fnd::SharedPtr<fnd::IFile>& file, size_t offset, size_t size);
|
||||||
|
|
||||||
|
size_t size();
|
||||||
|
void seek(size_t offset);
|
||||||
|
void read(byte_t* out, size_t len);
|
||||||
|
void read(byte_t* out, size_t offset, size_t len);
|
||||||
|
void write(const byte_t* out, size_t len);
|
||||||
|
void write(const byte_t* out, size_t offset, size_t len);
|
||||||
|
private:
|
||||||
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
|
size_t mBaseOffset, mCurrentOffset;
|
||||||
|
size_t mSize;
|
||||||
|
};
|
||||||
|
}
|
141
lib/libfnd/include/fnd/SharedPtr.h
Normal file
141
lib/libfnd/include/fnd/SharedPtr.h
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
#pragma once
|
||||||
|
#include <fnd/types.h>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
namespace fnd
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
class SharedPtr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SharedPtr();
|
||||||
|
|
||||||
|
// constructor for creating owner object
|
||||||
|
SharedPtr(T* ptr);
|
||||||
|
|
||||||
|
// copy constructor
|
||||||
|
SharedPtr(const SharedPtr<T>& other);
|
||||||
|
|
||||||
|
// destructor
|
||||||
|
~SharedPtr();
|
||||||
|
|
||||||
|
// own operator
|
||||||
|
void operator=(T* ptr);
|
||||||
|
|
||||||
|
// copy operator
|
||||||
|
void operator=(const SharedPtr<T>& other);
|
||||||
|
|
||||||
|
// access ptr
|
||||||
|
const T* operator*() const;
|
||||||
|
T* operator*();
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* mPtr;
|
||||||
|
size_t* mRefCnt;
|
||||||
|
|
||||||
|
void deletePtr();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline SharedPtr<T>::SharedPtr() :
|
||||||
|
mPtr(nullptr),
|
||||||
|
mRefCnt(new size_t)
|
||||||
|
{
|
||||||
|
*mRefCnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline SharedPtr<T>::SharedPtr(T* ptr) :
|
||||||
|
SharedPtr()
|
||||||
|
{
|
||||||
|
*this = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline SharedPtr<T>::SharedPtr(const SharedPtr<T>& other) :
|
||||||
|
SharedPtr()
|
||||||
|
{
|
||||||
|
*this = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline SharedPtr<T>::~SharedPtr()
|
||||||
|
{
|
||||||
|
deletePtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline void SharedPtr<T>::operator=(T* ptr)
|
||||||
|
{
|
||||||
|
deletePtr();
|
||||||
|
if (ptr != nullptr)
|
||||||
|
{
|
||||||
|
mPtr = ptr;
|
||||||
|
mRefCnt = new size_t;
|
||||||
|
*mRefCnt = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mPtr = nullptr;
|
||||||
|
mRefCnt = new size_t;
|
||||||
|
*mRefCnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline void SharedPtr<T>::operator=(const SharedPtr<T>& other)
|
||||||
|
{
|
||||||
|
deletePtr();
|
||||||
|
|
||||||
|
mPtr = other.mPtr;
|
||||||
|
mRefCnt = other.mRefCnt;
|
||||||
|
*mRefCnt += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline const T* SharedPtr<T>::operator*() const
|
||||||
|
{
|
||||||
|
return mPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline T* SharedPtr<T>::operator*()
|
||||||
|
{
|
||||||
|
return mPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline void SharedPtr<T>::deletePtr()
|
||||||
|
{
|
||||||
|
// if this is not the last reference
|
||||||
|
if (*mRefCnt > 1)
|
||||||
|
{
|
||||||
|
// decrement reference count
|
||||||
|
*mRefCnt -= 1;
|
||||||
|
|
||||||
|
// make ptrs null
|
||||||
|
mPtr = nullptr;
|
||||||
|
mRefCnt = nullptr;
|
||||||
|
}
|
||||||
|
// if this is the last refeference
|
||||||
|
else if (*mRefCnt == 1)
|
||||||
|
{
|
||||||
|
// delete memory
|
||||||
|
delete mPtr;
|
||||||
|
delete mRefCnt;
|
||||||
|
|
||||||
|
// make ptrs null
|
||||||
|
mPtr = nullptr;
|
||||||
|
mRefCnt = nullptr;
|
||||||
|
}
|
||||||
|
// else if this is an empty refernce
|
||||||
|
else if (*mRefCnt == 0)
|
||||||
|
{
|
||||||
|
delete mRefCnt;
|
||||||
|
|
||||||
|
mPtr = nullptr;
|
||||||
|
mRefCnt = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -122,6 +122,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="include\fnd\aes.h" />
|
<ClInclude Include="include\fnd\aes.h" />
|
||||||
|
<ClInclude Include="include\fnd\AesCtrWrappedIFile.h" />
|
||||||
<ClInclude Include="include\fnd\base64.h" />
|
<ClInclude Include="include\fnd\base64.h" />
|
||||||
<ClInclude Include="include\fnd\BitMath.h" />
|
<ClInclude Include="include\fnd\BitMath.h" />
|
||||||
<ClInclude Include="include\fnd\ecdsa.h" />
|
<ClInclude Include="include\fnd\ecdsa.h" />
|
||||||
|
@ -131,11 +132,15 @@
|
||||||
<ClInclude Include="include\fnd\IFile.h" />
|
<ClInclude Include="include\fnd\IFile.h" />
|
||||||
<ClInclude Include="include\fnd\io.h" />
|
<ClInclude Include="include\fnd\io.h" />
|
||||||
<ClInclude Include="include\fnd\ISerialisable.h" />
|
<ClInclude Include="include\fnd\ISerialisable.h" />
|
||||||
|
<ClInclude Include="include\fnd\LayeredIntegrityMetadata.h" />
|
||||||
|
<ClInclude Include="include\fnd\LayeredIntegrityWrappedIFile.h" />
|
||||||
<ClInclude Include="include\fnd\List.h" />
|
<ClInclude Include="include\fnd\List.h" />
|
||||||
<ClInclude Include="include\fnd\lz4.h" />
|
<ClInclude Include="include\fnd\lz4.h" />
|
||||||
|
<ClInclude Include="include\fnd\OffsetAdjustedIFile.h" />
|
||||||
<ClInclude Include="include\fnd\ResourceFileReader.h" />
|
<ClInclude Include="include\fnd\ResourceFileReader.h" />
|
||||||
<ClInclude Include="include\fnd\rsa.h" />
|
<ClInclude Include="include\fnd\rsa.h" />
|
||||||
<ClInclude Include="include\fnd\sha.h" />
|
<ClInclude Include="include\fnd\sha.h" />
|
||||||
|
<ClInclude Include="include\fnd\SharedPtr.h" />
|
||||||
<ClInclude Include="include\fnd\SimpleFile.h" />
|
<ClInclude Include="include\fnd\SimpleFile.h" />
|
||||||
<ClInclude Include="include\fnd\SimpleTextOutput.h" />
|
<ClInclude Include="include\fnd\SimpleTextOutput.h" />
|
||||||
<ClInclude Include="include\fnd\StringConv.h" />
|
<ClInclude Include="include\fnd\StringConv.h" />
|
||||||
|
@ -143,11 +148,15 @@
|
||||||
<ClInclude Include="include\fnd\Vec.h" />
|
<ClInclude Include="include\fnd\Vec.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="source\AesCtrWrappedIFile.cpp" />
|
||||||
<ClCompile Include="source\aes_wrapper.cpp" />
|
<ClCompile Include="source\aes_wrapper.cpp" />
|
||||||
<ClCompile Include="source\base64_wrapper.cpp" />
|
<ClCompile Include="source\base64_wrapper.cpp" />
|
||||||
<ClCompile Include="source\Exception.cpp" />
|
<ClCompile Include="source\Exception.cpp" />
|
||||||
<ClCompile Include="source\io.cpp" />
|
<ClCompile Include="source\io.cpp" />
|
||||||
|
<ClCompile Include="source\LayeredIntegrityMetadata.cpp" />
|
||||||
|
<ClCompile Include="source\LayeredIntegrityWrappedIFile.cpp" />
|
||||||
<ClCompile Include="source\lz4_wrapper.cpp" />
|
<ClCompile Include="source\lz4_wrapper.cpp" />
|
||||||
|
<ClCompile Include="source\OffsetAdjustedIFile.cpp" />
|
||||||
<ClCompile Include="source\ResourceFileReader.cpp" />
|
<ClCompile Include="source\ResourceFileReader.cpp" />
|
||||||
<ClCompile Include="source\rsa_wrapper.cpp" />
|
<ClCompile Include="source\rsa_wrapper.cpp" />
|
||||||
<ClCompile Include="source\sha_wrapper.cpp" />
|
<ClCompile Include="source\sha_wrapper.cpp" />
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
<ClInclude Include="include\fnd\aes.h">
|
<ClInclude Include="include\fnd\aes.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\fnd\AesCtrWrappedIFile.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="include\fnd\base64.h">
|
<ClInclude Include="include\fnd\base64.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -48,12 +51,21 @@
|
||||||
<ClInclude Include="include\fnd\ISerialisable.h">
|
<ClInclude Include="include\fnd\ISerialisable.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\fnd\LayeredIntegrityMetadata.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\fnd\LayeredIntegrityWrappedIFile.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="include\fnd\List.h">
|
<ClInclude Include="include\fnd\List.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="include\fnd\lz4.h">
|
<ClInclude Include="include\fnd\lz4.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\fnd\OffsetAdjustedIFile.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="include\fnd\ResourceFileReader.h">
|
<ClInclude Include="include\fnd\ResourceFileReader.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -63,6 +75,9 @@
|
||||||
<ClInclude Include="include\fnd\sha.h">
|
<ClInclude Include="include\fnd\sha.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="include\fnd\SharedPtr.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="include\fnd\SimpleFile.h">
|
<ClInclude Include="include\fnd\SimpleFile.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -83,6 +98,9 @@
|
||||||
<ClCompile Include="source\aes_wrapper.cpp">
|
<ClCompile Include="source\aes_wrapper.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\AesCtrWrappedIFile.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="source\base64_wrapper.cpp">
|
<ClCompile Include="source\base64_wrapper.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -92,9 +110,18 @@
|
||||||
<ClCompile Include="source\io.cpp">
|
<ClCompile Include="source\io.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\LayeredIntegrityMetadata.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\LayeredIntegrityWrappedIFile.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="source\lz4_wrapper.cpp">
|
<ClCompile Include="source\lz4_wrapper.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="source\OffsetAdjustedIFile.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="source\ResourceFileReader.cpp">
|
<ClCompile Include="source\ResourceFileReader.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -33,7 +33,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
OUTPUT = $(shell basename $(CURDIR)).a
|
OUTPUT = $(shell basename "$(CURDIR)").a
|
||||||
|
|
||||||
main: build
|
main: build
|
||||||
|
|
||||||
|
|
80
lib/libfnd/source/AesCtrWrappedIFile.cpp
Normal file
80
lib/libfnd/source/AesCtrWrappedIFile.cpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#include <fnd/AesCtrWrappedIFile.h>
|
||||||
|
|
||||||
|
fnd::AesCtrWrappedIFile::AesCtrWrappedIFile(const fnd::SharedPtr<fnd::IFile>& file, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr) :
|
||||||
|
mFile(file),
|
||||||
|
mKey(key),
|
||||||
|
mBaseCtr(ctr),
|
||||||
|
mFileOffset(0)
|
||||||
|
{
|
||||||
|
mCache.alloc(kCacheSizeAllocSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fnd::AesCtrWrappedIFile::size()
|
||||||
|
{
|
||||||
|
return (*mFile)->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::AesCtrWrappedIFile::seek(size_t offset)
|
||||||
|
{
|
||||||
|
mFileOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::AesCtrWrappedIFile::read(byte_t* out, size_t len)
|
||||||
|
{
|
||||||
|
size_t read_len;
|
||||||
|
size_t read_pos;
|
||||||
|
|
||||||
|
size_t cache_reads = (len / kCacheSize) + ((len % kCacheSize) != 0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < cache_reads; i++)
|
||||||
|
{
|
||||||
|
read_len = _MIN(len - (i * kCacheSize), kCacheSize);
|
||||||
|
read_pos = ((mFileOffset >> 4) << 4) + (i * kCacheSize);
|
||||||
|
|
||||||
|
(*mFile)->seek(read_pos);
|
||||||
|
(*mFile)->read(mCache.data(), kCacheSizeAllocSize);
|
||||||
|
|
||||||
|
fnd::aes::AesIncrementCounter(mBaseCtr.iv, read_pos>>4, mCurrentCtr.iv);
|
||||||
|
fnd::aes::AesCtr(mCache.data(), kCacheSizeAllocSize, mKey.key, mCurrentCtr.iv, mCache.data());
|
||||||
|
|
||||||
|
memcpy(out + (i * kCacheSize), mCache.data() + (mFileOffset & 0xf), read_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
seek(mFileOffset + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::AesCtrWrappedIFile::read(byte_t* out, size_t offset, size_t len)
|
||||||
|
{
|
||||||
|
seek(offset);
|
||||||
|
read(out, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::AesCtrWrappedIFile::write(const byte_t* in, size_t len)
|
||||||
|
{
|
||||||
|
size_t write_len;
|
||||||
|
size_t write_pos;
|
||||||
|
|
||||||
|
size_t cache_writes = (len / kCacheSize) + ((len % kCacheSize) != 0);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < cache_writes; i++)
|
||||||
|
{
|
||||||
|
write_len = _MIN(len - (i * kCacheSize), kCacheSize);
|
||||||
|
write_pos = ((mFileOffset >> 4) << 4) + (i * kCacheSize);
|
||||||
|
|
||||||
|
memcpy(mCache.data() + (mFileOffset & 0xf), in + (i * kCacheSize), write_len);
|
||||||
|
|
||||||
|
fnd::aes::AesIncrementCounter(mBaseCtr.iv, write_pos>>4, mCurrentCtr.iv);
|
||||||
|
fnd::aes::AesCtr(mCache.data(), kCacheSizeAllocSize, mKey.key, mCurrentCtr.iv, mCache.data());
|
||||||
|
|
||||||
|
(*mFile)->seek(write_pos);
|
||||||
|
(*mFile)->write(mCache.data(), kCacheSizeAllocSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
seek(mFileOffset + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::AesCtrWrappedIFile::write(const byte_t* in, size_t offset, size_t len)
|
||||||
|
{
|
||||||
|
seek(offset);
|
||||||
|
write(in, len);
|
||||||
|
}
|
71
lib/libfnd/source/LayeredIntegrityMetadata.cpp
Normal file
71
lib/libfnd/source/LayeredIntegrityMetadata.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include <fnd/LayeredIntegrityMetadata.h>
|
||||||
|
|
||||||
|
fnd::LayeredIntegrityMetadata::LayeredIntegrityMetadata() :
|
||||||
|
mLayerInfo(),
|
||||||
|
mDataLayer(),
|
||||||
|
mMasterHashList(),
|
||||||
|
mDoAlignHashToBlock(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::LayeredIntegrityMetadata::operator=(const LayeredIntegrityMetadata& other)
|
||||||
|
{
|
||||||
|
mLayerInfo = other.mLayerInfo;
|
||||||
|
mDataLayer = other.mDataLayer;
|
||||||
|
mMasterHashList = other.mMasterHashList;
|
||||||
|
mDoAlignHashToBlock = other.mDoAlignHashToBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fnd::LayeredIntegrityMetadata::operator==(const LayeredIntegrityMetadata& other) const
|
||||||
|
{
|
||||||
|
return (mLayerInfo == other.mLayerInfo) \
|
||||||
|
&& (mDataLayer == other.mDataLayer) \
|
||||||
|
&& (mMasterHashList == other.mMasterHashList) \
|
||||||
|
&& (mDoAlignHashToBlock == other.mDoAlignHashToBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fnd::LayeredIntegrityMetadata::operator!=(const LayeredIntegrityMetadata& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fnd::List<fnd::LayeredIntegrityMetadata::sLayer>& fnd::LayeredIntegrityMetadata::getHashLayerInfo() const
|
||||||
|
{
|
||||||
|
return mLayerInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::LayeredIntegrityMetadata::setHashLayerInfo(const fnd::List<sLayer>& layer_info)
|
||||||
|
{
|
||||||
|
mLayerInfo = layer_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fnd::LayeredIntegrityMetadata::sLayer& fnd::LayeredIntegrityMetadata::getDataLayer() const
|
||||||
|
{
|
||||||
|
return mDataLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::LayeredIntegrityMetadata::setDataLayerInfo(const sLayer& data_info)
|
||||||
|
{
|
||||||
|
mDataLayer = data_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fnd::List<fnd::sha::sSha256Hash>& fnd::LayeredIntegrityMetadata::getMasterHashList() const
|
||||||
|
{
|
||||||
|
return mMasterHashList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::LayeredIntegrityMetadata::setMasterHashList(const fnd::List<fnd::sha::sSha256Hash>& master_hash_list)
|
||||||
|
{
|
||||||
|
mMasterHashList = master_hash_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fnd::LayeredIntegrityMetadata::getAlignHashToBlock() const
|
||||||
|
{
|
||||||
|
return mDoAlignHashToBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::LayeredIntegrityMetadata::setAlignHashToBlock(bool doAlign)
|
||||||
|
{
|
||||||
|
mDoAlignHashToBlock = doAlign;
|
||||||
|
}
|
|
@ -1,9 +1,7 @@
|
||||||
#include "common.h"
|
#include <fnd/LayeredIntegrityWrappedIFile.h>
|
||||||
#include "HashTreeWrappedIFile.h"
|
#include <fnd/OffsetAdjustedIFile.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
|
||||||
|
|
||||||
HashTreeWrappedIFile::HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, const HashTreeMeta& hdr) :
|
fnd::LayeredIntegrityWrappedIFile::LayeredIntegrityWrappedIFile(const fnd::SharedPtr<fnd::IFile>& file, const fnd::LayeredIntegrityMetadata& hdr) :
|
||||||
mOwnIFile(ownIFile),
|
|
||||||
mFile(file),
|
mFile(file),
|
||||||
mData(nullptr),
|
mData(nullptr),
|
||||||
mDataHashLayer(),
|
mDataHashLayer(),
|
||||||
|
@ -12,89 +10,84 @@ HashTreeWrappedIFile::HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, cons
|
||||||
initialiseDataLayer(hdr);
|
initialiseDataLayer(hdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
HashTreeWrappedIFile::~HashTreeWrappedIFile()
|
size_t fnd::LayeredIntegrityWrappedIFile::size()
|
||||||
{
|
{
|
||||||
if (mOwnIFile)
|
return (*mData)->size();
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
delete mData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HashTreeWrappedIFile::size()
|
void fnd::LayeredIntegrityWrappedIFile::seek(size_t offset)
|
||||||
{
|
|
||||||
return mData->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HashTreeWrappedIFile::seek(size_t offset)
|
|
||||||
{
|
{
|
||||||
mDataOffset = offset;
|
mDataOffset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HashTreeWrappedIFile::read(byte_t* out, size_t len)
|
void fnd::LayeredIntegrityWrappedIFile::read(byte_t* out, size_t len)
|
||||||
{
|
{
|
||||||
size_t offset_in_start_block = getOffsetInBlock(mDataOffset);
|
struct sBlockPosition
|
||||||
size_t offset_in_end_block = getOffsetInBlock(offset_in_start_block + len);
|
|
||||||
|
|
||||||
size_t start_block = getOffsetBlock(mDataOffset);
|
|
||||||
size_t block_num = align(offset_in_start_block + len, mDataBlockSize) / mDataBlockSize;
|
|
||||||
|
|
||||||
size_t partial_last_block_num = block_num % mCacheBlockNum;
|
|
||||||
bool has_partial_block_num = partial_last_block_num > 0;
|
|
||||||
size_t read_iterations = (block_num / mCacheBlockNum) + has_partial_block_num;
|
|
||||||
|
|
||||||
size_t block_read_len;
|
|
||||||
size_t block_export_offset;
|
|
||||||
size_t block_export_size;
|
|
||||||
size_t block_export_pos = 0;
|
|
||||||
for (size_t i = 0; i < read_iterations; i++)
|
|
||||||
{
|
{
|
||||||
// how many blocks to read from source file
|
size_t index;
|
||||||
block_read_len = (i+1 == read_iterations && has_partial_block_num) ? partial_last_block_num : mCacheBlockNum;
|
size_t pos;
|
||||||
|
} start_blk, end_blk;
|
||||||
|
|
||||||
// offset in this current read to copy from
|
start_blk.index = getOffsetBlock(mDataOffset);
|
||||||
block_export_offset = (i == 0) ? offset_in_start_block : 0;
|
start_blk.pos = getOffsetInBlock(mDataOffset);
|
||||||
|
|
||||||
// size of current read to copy
|
end_blk.index = getOffsetBlock(mDataOffset + len);
|
||||||
block_export_size = (block_read_len * mDataBlockSize) - block_export_offset;
|
end_blk.pos = getOffsetInBlock(mDataOffset + len);
|
||||||
|
if (end_blk.pos == 0 && len != 0)
|
||||||
|
{
|
||||||
|
end_blk.index -= 1;
|
||||||
|
end_blk.pos = mDataBlockSize;
|
||||||
|
}
|
||||||
|
|
||||||
// if last read, reduce the export size by one block less offset_in_end_block
|
size_t total_blk_num = (end_blk.index - start_blk.index) + 1;
|
||||||
if (i+1 == read_iterations)
|
|
||||||
{
|
|
||||||
block_export_size -= (mDataBlockSize - offset_in_end_block);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read the blocks
|
size_t read_blk_num = 0;
|
||||||
readData(start_block + (i * mCacheBlockNum), block_read_len);
|
size_t cache_export_start_pos, cache_export_end_pos, cache_export_size;
|
||||||
|
size_t export_pos = 0;
|
||||||
|
for (size_t i = 0; i < total_blk_num; i += read_blk_num, export_pos += cache_export_size)
|
||||||
|
{
|
||||||
|
read_blk_num = _MIN(mCacheBlockNum, (total_blk_num - i));
|
||||||
|
readData(start_blk.index + i, read_blk_num);
|
||||||
|
|
||||||
// export the section of data that is relevant
|
// if this is the first read, adjust offset
|
||||||
memcpy(out + block_export_pos, mCache.data() + block_export_offset, block_export_size);
|
if (i == 0)
|
||||||
|
cache_export_start_pos = start_blk.pos;
|
||||||
|
else
|
||||||
|
cache_export_start_pos = 0;
|
||||||
|
|
||||||
// update export position
|
// if this is the last block, adjust end offset
|
||||||
block_export_pos += block_export_size;
|
if ((i + read_blk_num) == total_blk_num)
|
||||||
|
cache_export_end_pos = ((read_blk_num - 1) * mDataBlockSize) + end_blk.pos;
|
||||||
|
else
|
||||||
|
cache_export_end_pos = read_blk_num * mDataBlockSize;
|
||||||
|
|
||||||
|
// determine cache export size
|
||||||
|
cache_export_size = cache_export_end_pos - cache_export_start_pos;
|
||||||
|
|
||||||
|
memcpy(out + export_pos, mCache.data() + cache_export_start_pos, cache_export_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update offset
|
// update offset
|
||||||
seek(mDataOffset + len);
|
seek(mDataOffset + len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HashTreeWrappedIFile::read(byte_t* out, size_t offset, size_t len)
|
void fnd::LayeredIntegrityWrappedIFile::read(byte_t* out, size_t offset, size_t len)
|
||||||
{
|
{
|
||||||
seek(offset);
|
seek(offset);
|
||||||
read(out, len);
|
read(out, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HashTreeWrappedIFile::write(const byte_t* out, size_t len)
|
void fnd::LayeredIntegrityWrappedIFile::write(const byte_t* out, size_t len)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "write() not supported");
|
throw fnd::Exception(kModuleName, "write() not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
void HashTreeWrappedIFile::write(const byte_t* out, size_t offset, size_t len)
|
void fnd::LayeredIntegrityWrappedIFile::write(const byte_t* out, size_t offset, size_t len)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "write() not supported");
|
throw fnd::Exception(kModuleName, "write() not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
void HashTreeWrappedIFile::initialiseDataLayer(const HashTreeMeta& hdr)
|
void fnd::LayeredIntegrityWrappedIFile::initialiseDataLayer(const fnd::LayeredIntegrityMetadata& hdr)
|
||||||
{
|
{
|
||||||
fnd::sha::sSha256Hash hash;
|
fnd::sha::sSha256Hash hash;
|
||||||
fnd::Vec<byte_t> cur, prev;
|
fnd::Vec<byte_t> cur, prev;
|
||||||
|
@ -112,13 +105,13 @@ void HashTreeWrappedIFile::initialiseDataLayer(const HashTreeMeta& hdr)
|
||||||
for (size_t i = 0; i < hdr.getHashLayerInfo().size(); i++)
|
for (size_t i = 0; i < hdr.getHashLayerInfo().size(); i++)
|
||||||
{
|
{
|
||||||
// get block size
|
// get block size
|
||||||
const HashTreeMeta::sLayer& layer = hdr.getHashLayerInfo()[i];
|
const fnd::LayeredIntegrityMetadata::sLayer& layer = hdr.getHashLayerInfo()[i];
|
||||||
|
|
||||||
// allocate layer
|
// allocate layer
|
||||||
cur.alloc(align(layer.size, layer.block_size));
|
cur.alloc(align(layer.size, layer.block_size));
|
||||||
|
|
||||||
// read layer
|
// read layer
|
||||||
mFile->read(cur.data(), layer.offset, layer.size);
|
(*mFile)->read(cur.data(), layer.offset, layer.size);
|
||||||
|
|
||||||
// validate blocks
|
// validate blocks
|
||||||
size_t validate_size;
|
size_t validate_size;
|
||||||
|
@ -145,32 +138,28 @@ void HashTreeWrappedIFile::initialiseDataLayer(const HashTreeMeta& hdr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate reader for data layer
|
// generate reader for data layer
|
||||||
mData = new OffsetAdjustedIFile(mFile, SHARED_IFILE, hdr.getDataLayer().offset, hdr.getDataLayer().size);
|
mData = new fnd::OffsetAdjustedIFile(mFile, hdr.getDataLayer().offset, hdr.getDataLayer().size);
|
||||||
mDataOffset = 0;
|
mDataOffset = 0;
|
||||||
mDataBlockSize = hdr.getDataLayer().block_size;
|
mDataBlockSize = hdr.getDataLayer().block_size;
|
||||||
|
|
||||||
// allocate scratchpad
|
// allocate cache
|
||||||
//mScratch.alloc(mDataBlockSize * 0x10);
|
|
||||||
size_t cache_size = align(kDefaultCacheSize, mDataBlockSize);
|
size_t cache_size = align(kDefaultCacheSize, mDataBlockSize);
|
||||||
mCacheBlockNum = cache_size / mDataBlockSize;
|
mCacheBlockNum = cache_size / mDataBlockSize;
|
||||||
//printf("Block Size: 0x%" PRIx64 "\n", mDataBlockSize);
|
|
||||||
//printf("Cache size: 0x%" PRIx64 ", (block_num: %" PRId64 ")\n", cache_size, mCacheBlockNum);
|
|
||||||
mCache.alloc(cache_size);
|
mCache.alloc(cache_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HashTreeWrappedIFile::readData(size_t block_offset, size_t block_num)
|
void fnd::LayeredIntegrityWrappedIFile::readData(size_t block_offset, size_t block_num)
|
||||||
{
|
{
|
||||||
mData->seek(block_offset * mDataBlockSize);
|
|
||||||
fnd::sha::sSha256Hash hash;
|
fnd::sha::sSha256Hash hash;
|
||||||
|
|
||||||
// determine read size
|
// determine read size
|
||||||
size_t read_len = 0;
|
size_t read_len = 0;
|
||||||
if ((block_offset + block_num) == getBlockNum(mData->size()))
|
if ((block_offset + block_num) == getBlockNum((*mData)->size()))
|
||||||
{
|
{
|
||||||
read_len = (block_num-1) * mDataBlockSize + getRemanderBlockReadSize(mData->size());
|
read_len = (block_num-1) * mDataBlockSize + getRemanderBlockReadSize((*mData)->size());
|
||||||
memset(mCache.data(), 0, block_num * mDataBlockSize);
|
memset(mCache.data(), 0, block_num * mDataBlockSize);
|
||||||
}
|
}
|
||||||
else if ((block_offset + block_num) < getBlockNum(mData->size()))
|
else if ((block_offset + block_num) < getBlockNum((*mData)->size()))
|
||||||
{
|
{
|
||||||
read_len = block_num * mDataBlockSize;
|
read_len = block_num * mDataBlockSize;
|
||||||
}
|
}
|
||||||
|
@ -180,15 +169,13 @@ void HashTreeWrappedIFile::readData(size_t block_offset, size_t block_num)
|
||||||
}
|
}
|
||||||
|
|
||||||
// read
|
// read
|
||||||
mData->read(mCache.data(), block_offset * mDataBlockSize, read_len);
|
(*mData)->read(mCache.data(), block_offset * mDataBlockSize, read_len);
|
||||||
|
|
||||||
if (block_num > mCacheBlockNum)
|
if (block_num > mCacheBlockNum)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "Read excessive of cache size");
|
throw fnd::Exception(kModuleName, "Read excessive of cache size");
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("readlen=0x%" PRIx64 "\n", read_len);
|
|
||||||
|
|
||||||
// validate blocks
|
// validate blocks
|
||||||
size_t validate_size;
|
size_t validate_size;
|
||||||
for (size_t i = 0; i < block_num; i++)
|
for (size_t i = 0; i < block_num; i++)
|
47
lib/libfnd/source/OffsetAdjustedIFile.cpp
Normal file
47
lib/libfnd/source/OffsetAdjustedIFile.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include <fnd/OffsetAdjustedIFile.h>
|
||||||
|
|
||||||
|
fnd::OffsetAdjustedIFile::OffsetAdjustedIFile(const fnd::SharedPtr<fnd::IFile>& file, size_t offset, size_t size) :
|
||||||
|
mFile(file),
|
||||||
|
mBaseOffset(offset),
|
||||||
|
mCurrentOffset(0),
|
||||||
|
mSize(size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fnd::OffsetAdjustedIFile::size()
|
||||||
|
{
|
||||||
|
return mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::OffsetAdjustedIFile::seek(size_t offset)
|
||||||
|
{
|
||||||
|
mCurrentOffset = _MIN(offset, mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::OffsetAdjustedIFile::read(byte_t* out, size_t len)
|
||||||
|
{
|
||||||
|
// assert proper position in file
|
||||||
|
(*mFile)->seek(mCurrentOffset + mBaseOffset);
|
||||||
|
(*mFile)->read(out, len);
|
||||||
|
seek(mCurrentOffset + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::OffsetAdjustedIFile::read(byte_t* out, size_t offset, size_t len)
|
||||||
|
{
|
||||||
|
seek(offset);
|
||||||
|
read(out, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::OffsetAdjustedIFile::write(const byte_t* out, size_t len)
|
||||||
|
{
|
||||||
|
// assert proper position in file
|
||||||
|
(*mFile)->seek(mCurrentOffset + mBaseOffset);
|
||||||
|
(*mFile)->write(out, len);
|
||||||
|
seek(mCurrentOffset + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fnd::OffsetAdjustedIFile::write(const byte_t* out, size_t offset, size_t len)
|
||||||
|
{
|
||||||
|
seek(offset);
|
||||||
|
write(out, len);
|
||||||
|
}
|
|
@ -33,7 +33,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
OUTPUT = $(shell basename $(CURDIR)).a
|
OUTPUT = $(shell basename "$(CURDIR)").a
|
||||||
|
|
||||||
main: build
|
main: build
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
OUTPUT = $(shell basename $(CURDIR)).a
|
OUTPUT = $(shell basename "$(CURDIR)").a
|
||||||
|
|
||||||
main: build
|
main: build
|
||||||
|
|
||||||
|
|
|
@ -132,16 +132,8 @@ void nn::hac::NpdmBinary::fromBytes(const byte_t* data, size_t len)
|
||||||
mMainThreadCpuId = hdr.main_thread_cpu_id;
|
mMainThreadCpuId = hdr.main_thread_cpu_id;
|
||||||
mVersion = hdr.version.get();
|
mVersion = hdr.version.get();
|
||||||
mMainThreadStackSize = hdr.main_thread_stack_size.get();
|
mMainThreadStackSize = hdr.main_thread_stack_size.get();
|
||||||
mName = std::string(hdr.name, npdm::kNameMaxLen);
|
mName = std::string(hdr.name, _MIN(strlen(hdr.name), npdm::kNameMaxLen));
|
||||||
if (mName[0] == '\0')
|
mProductCode = std::string(hdr.product_code, _MIN(strlen(hdr.product_code), npdm::kProductCodeMaxLen));
|
||||||
{
|
|
||||||
mName.clear();
|
|
||||||
}
|
|
||||||
mProductCode = std::string(hdr.product_code, npdm::kProductCodeMaxLen);
|
|
||||||
if (mProductCode[0] == '\0')
|
|
||||||
{
|
|
||||||
mProductCode.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// total size
|
// total size
|
||||||
size_t total_size = _MAX(_MAX(hdr.acid.offset.get() + hdr.acid.size.get(), hdr.aci.offset.get() + hdr.aci.size.get()), sizeof(sNpdmHeader));
|
size_t total_size = _MAX(_MAX(hdr.acid.offset.get() + hdr.acid.size.get(), hdr.aci.offset.get() + hdr.aci.size.get()), sizeof(sNpdmHeader));
|
||||||
|
|
|
@ -32,7 +32,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
OUTPUT = $(shell basename $(CURDIR)).a
|
OUTPUT = $(shell basename "$(CURDIR)").a
|
||||||
|
|
||||||
main: build
|
main: build
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
OUTPUT = $(shell basename $(CURDIR)).a
|
OUTPUT = $(shell basename "$(CURDIR)").a
|
||||||
|
|
||||||
main: build
|
main: build
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Output
|
# Output
|
||||||
OUTPUT = $(shell basename $(CURDIR)).a
|
OUTPUT = $(shell basename "$(CURDIR)").a
|
||||||
|
|
||||||
main: build
|
main: build
|
||||||
|
|
||||||
|
|
2
makefile
2
makefile
|
@ -1,4 +1,4 @@
|
||||||
PROJECT_DIR = $(CURDIR)
|
PROJECT_DIR = "$(CURDIR)"
|
||||||
LIB_DIR = $(PROJECT_DIR)/lib
|
LIB_DIR = $(PROJECT_DIR)/lib
|
||||||
PROGRAM_DIR = $(PROJECT_DIR)/programs
|
PROGRAM_DIR = $(PROJECT_DIR)/programs
|
||||||
BIN_DIR = $(PROJECT_DIR)/bin
|
BIN_DIR = $(PROJECT_DIR)/bin
|
||||||
|
|
|
@ -34,7 +34,7 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
BIN_DIR = bin
|
BIN_DIR = bin
|
||||||
OUTPUT = $(BIN_DIR)/$(shell basename $(CURDIR))
|
OUTPUT = $(BIN_DIR)/$(shell basename "$(CURDIR)")
|
||||||
|
|
||||||
all: build
|
all: build
|
||||||
|
|
||||||
|
|
|
@ -178,21 +178,17 @@
|
||||||
<None Include="README.md" />
|
<None Include="README.md" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="source\AesCtrWrappedIFile.h" />
|
|
||||||
<ClInclude Include="source\AssetProcess.h" />
|
<ClInclude Include="source\AssetProcess.h" />
|
||||||
<ClInclude Include="source\CnmtProcess.h" />
|
<ClInclude Include="source\CnmtProcess.h" />
|
||||||
|
<ClInclude Include="source\common.h" />
|
||||||
<ClInclude Include="source\ElfSymbolParser.h" />
|
<ClInclude Include="source\ElfSymbolParser.h" />
|
||||||
<ClInclude Include="source\EsTikProcess.h" />
|
<ClInclude Include="source\EsTikProcess.h" />
|
||||||
<ClInclude Include="source\HashTreeMeta.h" />
|
|
||||||
<ClInclude Include="source\HashTreeWrappedIFile.h" />
|
|
||||||
<ClInclude Include="source\KeyConfiguration.h" />
|
<ClInclude Include="source\KeyConfiguration.h" />
|
||||||
<ClInclude Include="source\NacpProcess.h" />
|
<ClInclude Include="source\NacpProcess.h" />
|
||||||
<ClInclude Include="source\NcaProcess.h" />
|
<ClInclude Include="source\NcaProcess.h" />
|
||||||
<ClInclude Include="source\NpdmProcess.h" />
|
<ClInclude Include="source\NpdmProcess.h" />
|
||||||
<ClInclude Include="source\NroProcess.h" />
|
<ClInclude Include="source\NroProcess.h" />
|
||||||
<ClInclude Include="source\NsoProcess.h" />
|
<ClInclude Include="source\NsoProcess.h" />
|
||||||
<ClInclude Include="source\nstool.h" />
|
|
||||||
<ClInclude Include="source\OffsetAdjustedIFile.h" />
|
|
||||||
<ClInclude Include="source\PfsProcess.h" />
|
<ClInclude Include="source\PfsProcess.h" />
|
||||||
<ClInclude Include="source\PkiCertProcess.h" />
|
<ClInclude Include="source\PkiCertProcess.h" />
|
||||||
<ClInclude Include="source\PkiValidator.h" />
|
<ClInclude Include="source\PkiValidator.h" />
|
||||||
|
@ -204,13 +200,10 @@
|
||||||
<ClInclude Include="source\XciProcess.h" />
|
<ClInclude Include="source\XciProcess.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="source\AesCtrWrappedIFile.cpp" />
|
|
||||||
<ClCompile Include="source\AssetProcess.cpp" />
|
<ClCompile Include="source\AssetProcess.cpp" />
|
||||||
<ClCompile Include="source\CnmtProcess.cpp" />
|
<ClCompile Include="source\CnmtProcess.cpp" />
|
||||||
<ClCompile Include="source\ElfSymbolParser.cpp" />
|
<ClCompile Include="source\ElfSymbolParser.cpp" />
|
||||||
<ClCompile Include="source\EsTikProcess.cpp" />
|
<ClCompile Include="source\EsTikProcess.cpp" />
|
||||||
<ClCompile Include="source\HashTreeMeta.cpp" />
|
|
||||||
<ClCompile Include="source\HashTreeWrappedIFile.cpp" />
|
|
||||||
<ClCompile Include="source\KeyConfiguration.cpp" />
|
<ClCompile Include="source\KeyConfiguration.cpp" />
|
||||||
<ClCompile Include="source\main.cpp" />
|
<ClCompile Include="source\main.cpp" />
|
||||||
<ClCompile Include="source\NacpProcess.cpp" />
|
<ClCompile Include="source\NacpProcess.cpp" />
|
||||||
|
@ -218,7 +211,6 @@
|
||||||
<ClCompile Include="source\NpdmProcess.cpp" />
|
<ClCompile Include="source\NpdmProcess.cpp" />
|
||||||
<ClCompile Include="source\NroProcess.cpp" />
|
<ClCompile Include="source\NroProcess.cpp" />
|
||||||
<ClCompile Include="source\NsoProcess.cpp" />
|
<ClCompile Include="source\NsoProcess.cpp" />
|
||||||
<ClCompile Include="source\OffsetAdjustedIFile.cpp" />
|
|
||||||
<ClCompile Include="source\PfsProcess.cpp" />
|
<ClCompile Include="source\PfsProcess.cpp" />
|
||||||
<ClCompile Include="source\PkiCertProcess.cpp" />
|
<ClCompile Include="source\PkiCertProcess.cpp" />
|
||||||
<ClCompile Include="source\PkiValidator.cpp" />
|
<ClCompile Include="source\PkiValidator.cpp" />
|
||||||
|
|
|
@ -19,27 +19,21 @@
|
||||||
<None Include="README.md" />
|
<None Include="README.md" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="source\AesCtrWrappedIFile.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\AssetProcess.h">
|
<ClInclude Include="source\AssetProcess.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="source\CnmtProcess.h">
|
<ClInclude Include="source\CnmtProcess.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="source\common.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="source\ElfSymbolParser.h">
|
<ClInclude Include="source\ElfSymbolParser.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="source\EsTikProcess.h">
|
<ClInclude Include="source\EsTikProcess.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="source\HashTreeMeta.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\HashTreeWrappedIFile.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\KeyConfiguration.h">
|
<ClInclude Include="source\KeyConfiguration.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -58,12 +52,6 @@
|
||||||
<ClInclude Include="source\NsoProcess.h">
|
<ClInclude Include="source\NsoProcess.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="source\nstool.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\OffsetAdjustedIFile.h">
|
|
||||||
<Filter>Header Files</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="source\PfsProcess.h">
|
<ClInclude Include="source\PfsProcess.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -93,9 +81,6 @@
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="source\AesCtrWrappedIFile.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\AssetProcess.cpp">
|
<ClCompile Include="source\AssetProcess.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -108,12 +93,6 @@
|
||||||
<ClCompile Include="source\EsTikProcess.cpp">
|
<ClCompile Include="source\EsTikProcess.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="source\HashTreeMeta.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\HashTreeWrappedIFile.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\KeyConfiguration.cpp">
|
<ClCompile Include="source\KeyConfiguration.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -135,9 +114,6 @@
|
||||||
<ClCompile Include="source\NsoProcess.cpp">
|
<ClCompile Include="source\NsoProcess.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="source\OffsetAdjustedIFile.cpp">
|
|
||||||
<Filter>Source Files</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="source\PfsProcess.cpp">
|
<ClCompile Include="source\PfsProcess.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
|
@ -1,114 +0,0 @@
|
||||||
#include "AesCtrWrappedIFile.h"
|
|
||||||
|
|
||||||
AesCtrWrappedIFile::AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr) :
|
|
||||||
mOwnIFile(ownIfile),
|
|
||||||
mFile(file),
|
|
||||||
mKey(key),
|
|
||||||
mBaseCtr(ctr),
|
|
||||||
mFileOffset(0)
|
|
||||||
{
|
|
||||||
mCache.alloc(kCacheSizeAllocSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
AesCtrWrappedIFile::~AesCtrWrappedIFile()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t AesCtrWrappedIFile::size()
|
|
||||||
{
|
|
||||||
return mFile->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AesCtrWrappedIFile::seek(size_t offset)
|
|
||||||
{
|
|
||||||
mFileOffset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AesCtrWrappedIFile::read(byte_t* out, size_t len)
|
|
||||||
{
|
|
||||||
//printf("[%x] AesCtrWrappedIFile::read(offset=0x%" PRIx64 ", size=0x%" PRIx64 ")\n", this, mFileOffset, len);
|
|
||||||
|
|
||||||
size_t read_len;
|
|
||||||
size_t read_pos;
|
|
||||||
|
|
||||||
size_t cache_reads = (len / kCacheSize) + ((len % kCacheSize) != 0);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < cache_reads; i++)
|
|
||||||
{
|
|
||||||
read_len = _MIN(len - (i * kCacheSize), kCacheSize);
|
|
||||||
read_pos = ((mFileOffset >> 4) << 4) + (i * kCacheSize);
|
|
||||||
|
|
||||||
//printf("[%x] AesCtrWrappedIFile::read() CACHE READ: readlen=%" PRIx64 "\n", this, read_len);
|
|
||||||
|
|
||||||
mFile->seek(read_pos);
|
|
||||||
mFile->read(mCache.data(), kCacheSizeAllocSize);
|
|
||||||
|
|
||||||
fnd::aes::AesIncrementCounter(mBaseCtr.iv, read_pos>>4, mCurrentCtr.iv);
|
|
||||||
fnd::aes::AesCtr(mCache.data(), kCacheSizeAllocSize, mKey.key, mCurrentCtr.iv, mCache.data());
|
|
||||||
|
|
||||||
memcpy(out + (i * kCacheSize), mCache.data() + (mFileOffset & 0xf), read_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
seek(mFileOffset + len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AesCtrWrappedIFile::read(byte_t* out, size_t offset, size_t len)
|
|
||||||
{
|
|
||||||
seek(offset);
|
|
||||||
read(out, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AesCtrWrappedIFile::write(const byte_t* in, size_t len)
|
|
||||||
{
|
|
||||||
size_t write_len;
|
|
||||||
size_t write_pos;
|
|
||||||
|
|
||||||
size_t cache_writes = (len / kCacheSize) + ((len % kCacheSize) != 0);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < cache_writes; i++)
|
|
||||||
{
|
|
||||||
write_len = _MIN(len - (i * kCacheSize), kCacheSize);
|
|
||||||
write_pos = ((mFileOffset >> 4) << 4) + (i * kCacheSize);
|
|
||||||
|
|
||||||
//printf("[%x] AesCtrWrappedIFile::read() CACHE READ: readlen=%" PRIx64 "\n", this, read_len);
|
|
||||||
|
|
||||||
memcpy(mCache.data() + (mFileOffset & 0xf), in + (i * kCacheSize), write_len);
|
|
||||||
|
|
||||||
fnd::aes::AesIncrementCounter(mBaseCtr.iv, write_pos>>4, mCurrentCtr.iv);
|
|
||||||
fnd::aes::AesCtr(mCache.data(), kCacheSizeAllocSize, mKey.key, mCurrentCtr.iv, mCache.data());
|
|
||||||
|
|
||||||
mFile->seek(write_pos);
|
|
||||||
mFile->write(mCache.data(), kCacheSizeAllocSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
seek(mFileOffset + len);
|
|
||||||
|
|
||||||
/*
|
|
||||||
for (size_t i = 0; i < (len / kAesCtrScratchSize); i++)
|
|
||||||
{
|
|
||||||
memcpy(mScratch.data() + mBlockOffset, out + (i * kAesCtrScratchSize), kAesCtrScratchSize);
|
|
||||||
fnd::aes::AesCtr(mScratch.data(), kAesCtrScratchAllocSize, mKey.key, mCurrentCtr.iv, mScratch.data());
|
|
||||||
mFile->write(mScratch.data() + mBlockOffset, kAesCtrScratchSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len % kAesCtrScratchSize)
|
|
||||||
{
|
|
||||||
size_t write_len = len % kAesCtrScratchSize;
|
|
||||||
size_t write_pos = ((len / kAesCtrScratchSize) * kAesCtrScratchSize);
|
|
||||||
memcpy(mScratch.data() + mBlockOffset, out + write_pos, write_len);
|
|
||||||
fnd::aes::AesCtr(mScratch.data(), kAesCtrScratchAllocSize, mKey.key, mCurrentCtr.iv, mScratch.data());
|
|
||||||
mFile->write(mScratch.data() + mBlockOffset, write_len);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
seek(mFileOffset + len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AesCtrWrappedIFile::write(const byte_t* in, size_t offset, size_t len)
|
|
||||||
{
|
|
||||||
seek(offset);
|
|
||||||
write(in, len);
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
#include <fnd/IFile.h>
|
|
||||||
#include <fnd/Vec.h>
|
|
||||||
#include <fnd/aes.h>
|
|
||||||
|
|
||||||
class AesCtrWrappedIFile : public fnd::IFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr);
|
|
||||||
~AesCtrWrappedIFile();
|
|
||||||
|
|
||||||
size_t size();
|
|
||||||
void seek(size_t offset);
|
|
||||||
void read(byte_t* out, size_t len);
|
|
||||||
void read(byte_t* out, size_t offset, size_t len);
|
|
||||||
void write(const byte_t* out, size_t len);
|
|
||||||
void write(const byte_t* out, size_t offset, size_t len);
|
|
||||||
private:
|
|
||||||
const std::string kModuleName = "AesCtrWrappedIFile";
|
|
||||||
static const size_t kCacheSize = 0x10000;
|
|
||||||
static const size_t kCacheSizeAllocSize = kCacheSize + fnd::aes::kAesBlockSize;
|
|
||||||
|
|
||||||
bool mOwnIFile;
|
|
||||||
fnd::IFile* mFile;
|
|
||||||
fnd::aes::sAes128Key mKey;
|
|
||||||
fnd::aes::sAesIvCtr mBaseCtr, mCurrentCtr;
|
|
||||||
size_t mFileOffset;
|
|
||||||
|
|
||||||
fnd::Vec<byte_t> mCache;
|
|
||||||
};
|
|
|
@ -1,26 +1,16 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fnd/SimpleFile.h>
|
#include <fnd/SimpleFile.h>
|
||||||
|
#include <fnd/OffsetAdjustedIFile.h>
|
||||||
#include <fnd/Vec.h>
|
#include <fnd/Vec.h>
|
||||||
#include "AssetProcess.h"
|
#include "AssetProcess.h"
|
||||||
#include "OffsetAdjustedIFile.h"
|
|
||||||
|
|
||||||
|
|
||||||
AssetProcess::AssetProcess() :
|
AssetProcess::AssetProcess() :
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false)
|
mVerify(false)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetProcess::~AssetProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetProcess::process()
|
void AssetProcess::process()
|
||||||
|
@ -31,10 +21,9 @@ void AssetProcess::process()
|
||||||
processSections();
|
processSections();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void AssetProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetProcess::setCliOutputMode(CliOutputMode type)
|
void AssetProcess::setCliOutputMode(CliOutputMode type)
|
||||||
|
@ -72,18 +61,18 @@ void AssetProcess::importHeader()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mFile->size() < sizeof(nn::hac::sAssetHeader))
|
if ((*mFile)->size() < sizeof(nn::hac::sAssetHeader))
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "Corrupt ASET: file too small");
|
throw fnd::Exception(kModuleName, "Corrupt ASET: file too small");
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.alloc(sizeof(nn::hac::sAssetHeader));
|
scratch.alloc(sizeof(nn::hac::sAssetHeader));
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||||
|
|
||||||
mHdr.fromBytes(scratch.data(), scratch.size());
|
mHdr.fromBytes(scratch.data(), scratch.size());
|
||||||
}
|
}
|
||||||
|
@ -92,21 +81,21 @@ void AssetProcess::processSections()
|
||||||
{
|
{
|
||||||
if (mHdr.getIconInfo().size > 0 && mIconExtractPath.isSet)
|
if (mHdr.getIconInfo().size > 0 && mIconExtractPath.isSet)
|
||||||
{
|
{
|
||||||
if ((mHdr.getIconInfo().size + mHdr.getIconInfo().offset) > mFile->size())
|
if ((mHdr.getIconInfo().size + mHdr.getIconInfo().offset) > (*mFile)->size())
|
||||||
throw fnd::Exception(kModuleName, "ASET geometry for icon beyond file size");
|
throw fnd::Exception(kModuleName, "ASET geometry for icon beyond file size");
|
||||||
|
|
||||||
fnd::SimpleFile outfile(mIconExtractPath.var, fnd::SimpleFile::Create);
|
fnd::SimpleFile outfile(mIconExtractPath.var, fnd::SimpleFile::Create);
|
||||||
fnd::Vec<byte_t> cache;
|
fnd::Vec<byte_t> cache;
|
||||||
|
|
||||||
cache.alloc(mHdr.getIconInfo().size);
|
cache.alloc(mHdr.getIconInfo().size);
|
||||||
mFile->read(cache.data(), mHdr.getIconInfo().offset, cache.size());
|
(*mFile)->read(cache.data(), mHdr.getIconInfo().offset, cache.size());
|
||||||
outfile.write(cache.data(), cache.size());
|
outfile.write(cache.data(), cache.size());
|
||||||
outfile.close();
|
outfile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mHdr.getNacpInfo().size > 0)
|
if (mHdr.getNacpInfo().size > 0)
|
||||||
{
|
{
|
||||||
if ((mHdr.getNacpInfo().size + mHdr.getNacpInfo().offset) > mFile->size())
|
if ((mHdr.getNacpInfo().size + mHdr.getNacpInfo().offset) > (*mFile)->size())
|
||||||
throw fnd::Exception(kModuleName, "ASET geometry for nacp beyond file size");
|
throw fnd::Exception(kModuleName, "ASET geometry for nacp beyond file size");
|
||||||
|
|
||||||
if (mNacpExtractPath.isSet)
|
if (mNacpExtractPath.isSet)
|
||||||
|
@ -115,12 +104,12 @@ void AssetProcess::processSections()
|
||||||
fnd::Vec<byte_t> cache;
|
fnd::Vec<byte_t> cache;
|
||||||
|
|
||||||
cache.alloc(mHdr.getNacpInfo().size);
|
cache.alloc(mHdr.getNacpInfo().size);
|
||||||
mFile->read(cache.data(), mHdr.getNacpInfo().offset, cache.size());
|
(*mFile)->read(cache.data(), mHdr.getNacpInfo().offset, cache.size());
|
||||||
outfile.write(cache.data(), cache.size());
|
outfile.write(cache.data(), cache.size());
|
||||||
outfile.close();
|
outfile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
mNacp.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size), true);
|
mNacp.setInputFile(new fnd::OffsetAdjustedIFile(mFile, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size));
|
||||||
mNacp.setCliOutputMode(mCliOutputMode);
|
mNacp.setCliOutputMode(mCliOutputMode);
|
||||||
mNacp.setVerifyMode(mVerify);
|
mNacp.setVerifyMode(mVerify);
|
||||||
|
|
||||||
|
@ -129,10 +118,10 @@ void AssetProcess::processSections()
|
||||||
|
|
||||||
if (mHdr.getRomfsInfo().size > 0)
|
if (mHdr.getRomfsInfo().size > 0)
|
||||||
{
|
{
|
||||||
if ((mHdr.getRomfsInfo().size + mHdr.getRomfsInfo().offset) > mFile->size())
|
if ((mHdr.getRomfsInfo().size + mHdr.getRomfsInfo().offset) > (*mFile)->size())
|
||||||
throw fnd::Exception(kModuleName, "ASET geometry for romfs beyond file size");
|
throw fnd::Exception(kModuleName, "ASET geometry for romfs beyond file size");
|
||||||
|
|
||||||
mRomfs.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getRomfsInfo().offset, mHdr.getRomfsInfo().size), true);
|
mRomfs.setInputFile(new fnd::OffsetAdjustedIFile(mFile, mHdr.getRomfsInfo().offset, mHdr.getRomfsInfo().size));
|
||||||
mRomfs.setCliOutputMode(mCliOutputMode);
|
mRomfs.setCliOutputMode(mCliOutputMode);
|
||||||
mRomfs.setVerifyMode(mVerify);
|
mRomfs.setVerifyMode(mVerify);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/IFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <nn/hac/AssetHeader.h>
|
#include <nn/hac/AssetHeader.h>
|
||||||
#include "NacpProcess.h"
|
#include "NacpProcess.h"
|
||||||
#include "RomfsProcess.h"
|
#include "RomfsProcess.h"
|
||||||
|
@ -12,11 +13,10 @@ class AssetProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AssetProcess();
|
AssetProcess();
|
||||||
~AssetProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setCliOutputMode(CliOutputMode type);
|
void setCliOutputMode(CliOutputMode type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
@ -30,8 +30,7 @@ public:
|
||||||
private:
|
private:
|
||||||
const std::string kModuleName = "AssetProcess";
|
const std::string kModuleName = "AssetProcess";
|
||||||
|
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,16 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
#include <fnd/OffsetAdjustedIFile.h>
|
||||||
#include "CnmtProcess.h"
|
#include "CnmtProcess.h"
|
||||||
|
|
||||||
CnmtProcess::CnmtProcess() :
|
CnmtProcess::CnmtProcess() :
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false)
|
mVerify(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CnmtProcess::~CnmtProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CnmtProcess::process()
|
void CnmtProcess::process()
|
||||||
{
|
{
|
||||||
importCnmt();
|
importCnmt();
|
||||||
|
@ -28,10 +19,9 @@ void CnmtProcess::process()
|
||||||
displayCnmt();
|
displayCnmt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void CnmtProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CnmtProcess::setCliOutputMode(CliOutputMode type)
|
void CnmtProcess::setCliOutputMode(CliOutputMode type)
|
||||||
|
@ -53,13 +43,13 @@ void CnmtProcess::importCnmt()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.alloc(mFile->size());
|
scratch.alloc((*mFile)->size());
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||||
|
|
||||||
mCnmt.fromBytes(scratch.data(), scratch.size());
|
mCnmt.fromBytes(scratch.data(), scratch.size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/IFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <nn/hac/ContentMetaBinary.h>
|
#include <nn/hac/ContentMetaBinary.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
@ -10,11 +11,10 @@ class CnmtProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CnmtProcess();
|
CnmtProcess();
|
||||||
~CnmtProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setCliOutputMode(CliOutputMode type);
|
void setCliOutputMode(CliOutputMode type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@ public:
|
||||||
private:
|
private:
|
||||||
const std::string kModuleName = "CnmtProcess";
|
const std::string kModuleName = "CnmtProcess";
|
||||||
|
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
||||||
|
|
|
@ -1,29 +1,20 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
|
#include <fnd/OffsetAdjustedIFile.h>
|
||||||
#include <nn/pki/SignUtils.h>
|
#include <nn/pki/SignUtils.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
|
||||||
#include "EsTikProcess.h"
|
#include "EsTikProcess.h"
|
||||||
#include "PkiValidator.h"
|
#include "PkiValidator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EsTikProcess::EsTikProcess() :
|
EsTikProcess::EsTikProcess() :
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false)
|
mVerify(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
EsTikProcess::~EsTikProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EsTikProcess::process()
|
void EsTikProcess::process()
|
||||||
{
|
{
|
||||||
importTicket();
|
importTicket();
|
||||||
|
@ -35,10 +26,9 @@ void EsTikProcess::process()
|
||||||
displayTicket();
|
displayTicket();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EsTikProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void EsTikProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EsTikProcess::setKeyCfg(const KeyConfiguration& keycfg)
|
void EsTikProcess::setKeyCfg(const KeyConfiguration& keycfg)
|
||||||
|
@ -66,13 +56,13 @@ void EsTikProcess::importTicket()
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
|
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.alloc(mFile->size());
|
scratch.alloc((*mFile)->size());
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||||
mTik.fromBytes(scratch.data(), scratch.size());
|
mTik.fromBytes(scratch.data(), scratch.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/IFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <fnd/Vec.h>
|
#include <fnd/Vec.h>
|
||||||
#include <nn/pki/SignedData.h>
|
#include <nn/pki/SignedData.h>
|
||||||
#include <nn/pki/CertificateBody.h>
|
#include <nn/pki/CertificateBody.h>
|
||||||
|
@ -13,11 +14,10 @@ class EsTikProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EsTikProcess();
|
EsTikProcess();
|
||||||
~EsTikProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setKeyCfg(const KeyConfiguration& keycfg);
|
void setKeyCfg(const KeyConfiguration& keycfg);
|
||||||
void setCertificateChain(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs);
|
void setCertificateChain(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs);
|
||||||
void setCliOutputMode(CliOutputMode mode);
|
void setCliOutputMode(CliOutputMode mode);
|
||||||
|
@ -26,8 +26,7 @@ public:
|
||||||
private:
|
private:
|
||||||
const std::string kModuleName = "EsTikProcess";
|
const std::string kModuleName = "EsTikProcess";
|
||||||
|
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
KeyConfiguration mKeyCfg;
|
KeyConfiguration mKeyCfg;
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
|
@ -1,135 +0,0 @@
|
||||||
#include "HashTreeMeta.h"
|
|
||||||
|
|
||||||
HashTreeMeta::HashTreeMeta() :
|
|
||||||
mLayerInfo(),
|
|
||||||
mDataLayer(),
|
|
||||||
mMasterHashList(),
|
|
||||||
mDoAlignHashToBlock(false)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
HashTreeMeta::HashTreeMeta(const byte_t* data, size_t len, HashTreeType type) :
|
|
||||||
HashTreeMeta()
|
|
||||||
{
|
|
||||||
importData(data, len, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HashTreeMeta::operator=(const HashTreeMeta& other)
|
|
||||||
{
|
|
||||||
mLayerInfo = other.mLayerInfo;
|
|
||||||
mDataLayer = other.mDataLayer;
|
|
||||||
mMasterHashList = other.mMasterHashList;
|
|
||||||
mDoAlignHashToBlock = other.mDoAlignHashToBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HashTreeMeta::operator==(const HashTreeMeta& other) const
|
|
||||||
{
|
|
||||||
return (mLayerInfo == other.mLayerInfo) \
|
|
||||||
&& (mDataLayer == other.mDataLayer) \
|
|
||||||
&& (mMasterHashList == other.mMasterHashList) \
|
|
||||||
&& (mDoAlignHashToBlock == other.mDoAlignHashToBlock);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HashTreeMeta::operator!=(const HashTreeMeta& other) const
|
|
||||||
{
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HashTreeMeta::importData(const byte_t* data, size_t len, HashTreeType type)
|
|
||||||
{
|
|
||||||
if (type == HASH_TYPE_INTEGRITY)
|
|
||||||
{
|
|
||||||
nn::hac::HierarchicalIntegrityHeader hdr;
|
|
||||||
hdr.fromBytes(data, len);
|
|
||||||
importHierarchicalIntergityHeader(hdr);
|
|
||||||
}
|
|
||||||
else if (type == HASH_TYPE_SHA256)
|
|
||||||
{
|
|
||||||
nn::hac::HierarchicalSha256Header hdr;
|
|
||||||
hdr.fromBytes(data, len);
|
|
||||||
importHierarchicalSha256Header(hdr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const fnd::List<HashTreeMeta::sLayer>& HashTreeMeta::getHashLayerInfo() const
|
|
||||||
{
|
|
||||||
return mLayerInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HashTreeMeta::setHashLayerInfo(const fnd::List<sLayer>& layer_info)
|
|
||||||
{
|
|
||||||
mLayerInfo = layer_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
const HashTreeMeta::sLayer& HashTreeMeta::getDataLayer() const
|
|
||||||
{
|
|
||||||
return mDataLayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HashTreeMeta::setDataLayer(const sLayer& data_info)
|
|
||||||
{
|
|
||||||
mDataLayer = data_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fnd::List<fnd::sha::sSha256Hash>& HashTreeMeta::getMasterHashList() const
|
|
||||||
{
|
|
||||||
return mMasterHashList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HashTreeMeta::setMasterHashList(const fnd::List<fnd::sha::sSha256Hash>& master_hash_list)
|
|
||||||
{
|
|
||||||
mMasterHashList = master_hash_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HashTreeMeta::getAlignHashToBlock() const
|
|
||||||
{
|
|
||||||
return mDoAlignHashToBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HashTreeMeta::setAlignHashToBlock(bool doAlign)
|
|
||||||
{
|
|
||||||
mDoAlignHashToBlock = doAlign;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HashTreeMeta::importHierarchicalIntergityHeader(const nn::hac::HierarchicalIntegrityHeader& hdr)
|
|
||||||
{
|
|
||||||
mDoAlignHashToBlock = true;
|
|
||||||
for (size_t i = 0; i < hdr.getLayerInfo().size(); i++)
|
|
||||||
{
|
|
||||||
sLayer layer;
|
|
||||||
layer.offset = hdr.getLayerInfo()[i].offset;
|
|
||||||
layer.size = hdr.getLayerInfo()[i].size;
|
|
||||||
layer.block_size = _BIT(hdr.getLayerInfo()[i].block_size);
|
|
||||||
if (i+1 == hdr.getLayerInfo().size())
|
|
||||||
{
|
|
||||||
mDataLayer = layer;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mLayerInfo.addElement(layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mMasterHashList = hdr.getMasterHashList();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HashTreeMeta::importHierarchicalSha256Header(const nn::hac::HierarchicalSha256Header& hdr)
|
|
||||||
{
|
|
||||||
mDoAlignHashToBlock = false;
|
|
||||||
for (size_t i = 0; i < hdr.getLayerInfo().size(); i++)
|
|
||||||
{
|
|
||||||
sLayer layer;
|
|
||||||
layer.offset = hdr.getLayerInfo()[i].offset;
|
|
||||||
layer.size = hdr.getLayerInfo()[i].size;
|
|
||||||
layer.block_size = hdr.getHashBlockSize();
|
|
||||||
if (i+1 == hdr.getLayerInfo().size())
|
|
||||||
{
|
|
||||||
mDataLayer = layer;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mLayerInfo.addElement(layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mMasterHashList.addElement(hdr.getMasterHash());
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <nn/hac/HierarchicalIntegrityHeader.h>
|
|
||||||
#include <nn/hac/HierarchicalSha256Header.h>
|
|
||||||
|
|
||||||
class HashTreeMeta
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum HashTreeType
|
|
||||||
{
|
|
||||||
HASH_TYPE_INTEGRITY,
|
|
||||||
HASH_TYPE_SHA256
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sLayer
|
|
||||||
{
|
|
||||||
size_t offset;
|
|
||||||
size_t size;
|
|
||||||
size_t block_size;
|
|
||||||
|
|
||||||
void operator=(const sLayer& other)
|
|
||||||
{
|
|
||||||
offset = other.offset;
|
|
||||||
size = other.size;
|
|
||||||
block_size = other.block_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const sLayer& other) const
|
|
||||||
{
|
|
||||||
return (offset == other.offset && size == other.size && block_size == other.block_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const sLayer& other) const
|
|
||||||
{
|
|
||||||
return !(*this == other);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
HashTreeMeta();
|
|
||||||
HashTreeMeta(const byte_t* data, size_t len, HashTreeType type);
|
|
||||||
|
|
||||||
void operator=(const HashTreeMeta& other);
|
|
||||||
bool operator==(const HashTreeMeta& other) const;
|
|
||||||
bool operator!=(const HashTreeMeta& other) const;
|
|
||||||
|
|
||||||
void importData(const byte_t* data, size_t len, HashTreeType type);
|
|
||||||
|
|
||||||
const fnd::List<sLayer>& getHashLayerInfo() const;
|
|
||||||
void setHashLayerInfo(const fnd::List<sLayer>& layer_info);
|
|
||||||
|
|
||||||
const sLayer& getDataLayer() const;
|
|
||||||
void setDataLayer(const sLayer& data_info);
|
|
||||||
|
|
||||||
const fnd::List<fnd::sha::sSha256Hash>& getMasterHashList() const;
|
|
||||||
void setMasterHashList(const fnd::List<fnd::sha::sSha256Hash>& master_hash_list);
|
|
||||||
|
|
||||||
bool getAlignHashToBlock() const;
|
|
||||||
void setAlignHashToBlock(bool doAlign);
|
|
||||||
private:
|
|
||||||
|
|
||||||
// data
|
|
||||||
fnd::List<sLayer> mLayerInfo;
|
|
||||||
sLayer mDataLayer;
|
|
||||||
fnd::List<fnd::sha::sSha256Hash> mMasterHashList;
|
|
||||||
bool mDoAlignHashToBlock;
|
|
||||||
|
|
||||||
void importHierarchicalIntergityHeader(const nn::hac::HierarchicalIntegrityHeader& hdr);
|
|
||||||
void importHierarchicalSha256Header(const nn::hac::HierarchicalSha256Header& hdr);
|
|
||||||
};
|
|
|
@ -1,46 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <sstream>
|
|
||||||
#include <fnd/IFile.h>
|
|
||||||
#include <fnd/Vec.h>
|
|
||||||
#include <fnd/sha.h>
|
|
||||||
#include "HashTreeMeta.h"
|
|
||||||
|
|
||||||
|
|
||||||
class HashTreeWrappedIFile : public fnd::IFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, const HashTreeMeta& hdr);
|
|
||||||
~HashTreeWrappedIFile();
|
|
||||||
|
|
||||||
size_t size();
|
|
||||||
void seek(size_t offset);
|
|
||||||
void read(byte_t* out, size_t len);
|
|
||||||
void read(byte_t* out, size_t offset, size_t len);
|
|
||||||
void write(const byte_t* out, size_t len);
|
|
||||||
void write(const byte_t* out, size_t offset, size_t len);
|
|
||||||
private:
|
|
||||||
const std::string kModuleName = "HashTreeWrappedIFile";
|
|
||||||
static const size_t kDefaultCacheSize = 0x10000;
|
|
||||||
std::stringstream mErrorSs;
|
|
||||||
|
|
||||||
bool mOwnIFile;
|
|
||||||
fnd::IFile* mFile;
|
|
||||||
|
|
||||||
// data file
|
|
||||||
fnd::IFile* mData;
|
|
||||||
size_t mDataOffset;
|
|
||||||
size_t mDataBlockSize;
|
|
||||||
fnd::List<fnd::sha::sSha256Hash> mDataHashLayer;
|
|
||||||
bool mAlignHashCalcToBlock;
|
|
||||||
|
|
||||||
fnd::Vec<byte_t> mCache;
|
|
||||||
size_t mCacheBlockNum;
|
|
||||||
|
|
||||||
inline size_t getOffsetBlock(size_t offset) const { return offset / mDataBlockSize; }
|
|
||||||
inline size_t getOffsetInBlock(size_t offset) const { return offset % mDataBlockSize; }
|
|
||||||
inline size_t getRemanderBlockReadSize(size_t total_size) const { return total_size % mDataBlockSize; }
|
|
||||||
inline size_t getBlockNum(size_t total_size) const { return (total_size / mDataBlockSize) + (getRemanderBlockReadSize(total_size) > 0); }
|
|
||||||
|
|
||||||
void initialiseDataLayer(const HashTreeMeta& hdr);
|
|
||||||
void readData(size_t block_offset, size_t block_num);
|
|
||||||
};
|
|
|
@ -2,25 +2,16 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
#include <fnd/OffsetAdjustedIFile.h>
|
||||||
#include "NacpProcess.h"
|
#include "NacpProcess.h"
|
||||||
|
|
||||||
NacpProcess::NacpProcess() :
|
NacpProcess::NacpProcess() :
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false)
|
mVerify(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NacpProcess::~NacpProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NacpProcess::process()
|
void NacpProcess::process()
|
||||||
{
|
{
|
||||||
importNacp();
|
importNacp();
|
||||||
|
@ -29,10 +20,9 @@ void NacpProcess::process()
|
||||||
displayNacp();
|
displayNacp();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void NacpProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NacpProcess::setCliOutputMode(CliOutputMode type)
|
void NacpProcess::setCliOutputMode(CliOutputMode type)
|
||||||
|
@ -54,13 +44,13 @@ void NacpProcess::importNacp()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.alloc(mFile->size());
|
scratch.alloc((*mFile)->size());
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||||
|
|
||||||
mNacp.fromBytes(scratch.data(), scratch.size());
|
mNacp.fromBytes(scratch.data(), scratch.size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/IFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <nn/hac/ApplicationControlPropertyBinary.h>
|
#include <nn/hac/ApplicationControlPropertyBinary.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
@ -10,11 +11,10 @@ class NacpProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NacpProcess();
|
NacpProcess();
|
||||||
~NacpProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setCliOutputMode(CliOutputMode type);
|
void setCliOutputMode(CliOutputMode type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@ public:
|
||||||
private:
|
private:
|
||||||
const std::string kModuleName = "NacpProcess";
|
const std::string kModuleName = "NacpProcess";
|
||||||
|
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
||||||
|
|
|
@ -2,19 +2,21 @@
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
|
#include <fnd/OffsetAdjustedIFile.h>
|
||||||
|
#include <fnd/AesCtrWrappedIFile.h>
|
||||||
|
#include <fnd/LayeredIntegrityWrappedIFile.h>
|
||||||
#include <nn/hac/NcaUtils.h>
|
#include <nn/hac/NcaUtils.h>
|
||||||
#include <nn/hac/AesKeygen.h>
|
#include <nn/hac/AesKeygen.h>
|
||||||
|
#include <nn/hac/HierarchicalSha256Header.h>
|
||||||
|
#include <nn/hac/HierarchicalIntegrityHeader.h>
|
||||||
#include "NcaProcess.h"
|
#include "NcaProcess.h"
|
||||||
#include "PfsProcess.h"
|
#include "PfsProcess.h"
|
||||||
#include "RomfsProcess.h"
|
#include "RomfsProcess.h"
|
||||||
#include "NpdmProcess.h"
|
#include "NpdmProcess.h"
|
||||||
#include "OffsetAdjustedIFile.h"
|
|
||||||
#include "AesCtrWrappedIFile.h"
|
|
||||||
#include "HashTreeWrappedIFile.h"
|
|
||||||
|
|
||||||
NcaProcess::NcaProcess() :
|
NcaProcess::NcaProcess() :
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false),
|
mVerify(false),
|
||||||
mListFs(false)
|
mListFs(false)
|
||||||
|
@ -22,23 +24,6 @@ NcaProcess::NcaProcess() :
|
||||||
for (size_t i = 0; i < nn::hac::nca::kPartitionNum; i++)
|
for (size_t i = 0; i < nn::hac::nca::kPartitionNum; i++)
|
||||||
{
|
{
|
||||||
mPartitionPath[i].doExtract = false;
|
mPartitionPath[i].doExtract = false;
|
||||||
mPartitions[i].reader = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NcaProcess::~NcaProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < nn::hac::nca::kPartitionNum; i++)
|
|
||||||
{
|
|
||||||
if (mPartitions[i].reader != nullptr)
|
|
||||||
{
|
|
||||||
delete mPartitions[i].reader;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,10 +50,9 @@ void NcaProcess::process()
|
||||||
processPartitions();
|
processPartitions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcaProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void NcaProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NcaProcess::setKeyCfg(const KeyConfiguration& keycfg)
|
void NcaProcess::setKeyCfg(const KeyConfiguration& keycfg)
|
||||||
|
@ -117,13 +101,13 @@ void NcaProcess::setListFs(bool list_fs)
|
||||||
|
|
||||||
void NcaProcess::importHeader()
|
void NcaProcess::importHeader()
|
||||||
{
|
{
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// read header block
|
// read header block
|
||||||
mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock));
|
(*mFile)->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock));
|
||||||
|
|
||||||
// decrypt header block
|
// decrypt header block
|
||||||
fnd::aes::sAesXts128Key header_key;
|
fnd::aes::sAesXts128Key header_key;
|
||||||
|
@ -277,9 +261,69 @@ void NcaProcess::generatePartitionConfiguration()
|
||||||
info.hash_type = (nn::hac::nca::HashType)fs_header.hash_type;
|
info.hash_type = (nn::hac::nca::HashType)fs_header.hash_type;
|
||||||
info.enc_type = (nn::hac::nca::EncryptionType)fs_header.encryption_type;
|
info.enc_type = (nn::hac::nca::EncryptionType)fs_header.encryption_type;
|
||||||
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256)
|
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256)
|
||||||
info.hash_tree_meta.importData(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen, HashTreeMeta::HASH_TYPE_SHA256);
|
{
|
||||||
|
// info.hash_tree_meta.importData(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen, LayeredIntegrityMetadata::HASH_TYPE_SHA256);
|
||||||
|
nn::hac::HierarchicalSha256Header hdr;
|
||||||
|
fnd::List<fnd::LayeredIntegrityMetadata::sLayer> hash_layers;
|
||||||
|
fnd::LayeredIntegrityMetadata::sLayer data_layer;
|
||||||
|
fnd::List<fnd::sha::sSha256Hash> master_hash_list;
|
||||||
|
|
||||||
|
// import raw data
|
||||||
|
hdr.fromBytes(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen);
|
||||||
|
for (size_t i = 0; i < hdr.getLayerInfo().size(); i++)
|
||||||
|
{
|
||||||
|
fnd::LayeredIntegrityMetadata::sLayer layer;
|
||||||
|
layer.offset = hdr.getLayerInfo()[i].offset;
|
||||||
|
layer.size = hdr.getLayerInfo()[i].size;
|
||||||
|
layer.block_size = hdr.getHashBlockSize();
|
||||||
|
if (i + 1 == hdr.getLayerInfo().size())
|
||||||
|
{
|
||||||
|
data_layer = layer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hash_layers.addElement(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
master_hash_list.addElement(hdr.getMasterHash());
|
||||||
|
|
||||||
|
// write data into metadata
|
||||||
|
info.layered_intergrity_metadata.setAlignHashToBlock(false);
|
||||||
|
info.layered_intergrity_metadata.setHashLayerInfo(hash_layers);
|
||||||
|
info.layered_intergrity_metadata.setDataLayerInfo(data_layer);
|
||||||
|
info.layered_intergrity_metadata.setMasterHashList(master_hash_list);
|
||||||
|
}
|
||||||
else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
|
else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
|
||||||
info.hash_tree_meta.importData(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen, HashTreeMeta::HASH_TYPE_INTEGRITY);
|
{
|
||||||
|
// info.hash_tree_meta.importData(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen, LayeredIntegrityMetadata::HASH_TYPE_INTEGRITY);
|
||||||
|
nn::hac::HierarchicalIntegrityHeader hdr;
|
||||||
|
fnd::List<fnd::LayeredIntegrityMetadata::sLayer> hash_layers;
|
||||||
|
fnd::LayeredIntegrityMetadata::sLayer data_layer;
|
||||||
|
fnd::List<fnd::sha::sSha256Hash> master_hash_list;
|
||||||
|
|
||||||
|
hdr.fromBytes(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen);
|
||||||
|
for (size_t i = 0; i < hdr.getLayerInfo().size(); i++)
|
||||||
|
{
|
||||||
|
fnd::LayeredIntegrityMetadata::sLayer layer;
|
||||||
|
layer.offset = hdr.getLayerInfo()[i].offset;
|
||||||
|
layer.size = hdr.getLayerInfo()[i].size;
|
||||||
|
layer.block_size = _BIT(hdr.getLayerInfo()[i].block_size);
|
||||||
|
if (i + 1 == hdr.getLayerInfo().size())
|
||||||
|
{
|
||||||
|
data_layer = layer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hash_layers.addElement(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write data into metadata
|
||||||
|
info.layered_intergrity_metadata.setAlignHashToBlock(true);
|
||||||
|
info.layered_intergrity_metadata.setHashLayerInfo(hash_layers);
|
||||||
|
info.layered_intergrity_metadata.setDataLayerInfo(data_layer);
|
||||||
|
info.layered_intergrity_metadata.setMasterHashList(hdr.getMasterHashList());
|
||||||
|
}
|
||||||
|
|
||||||
// create reader
|
// create reader
|
||||||
try
|
try
|
||||||
|
@ -299,13 +343,13 @@ void NcaProcess::generatePartitionConfiguration()
|
||||||
// create reader based on encryption type0
|
// create reader based on encryption type0
|
||||||
if (info.enc_type == nn::hac::nca::CRYPT_NONE)
|
if (info.enc_type == nn::hac::nca::CRYPT_NONE)
|
||||||
{
|
{
|
||||||
info.reader = new OffsetAdjustedIFile(mFile, SHARED_IFILE, info.offset, info.size);
|
info.reader = new fnd::OffsetAdjustedIFile(mFile, info.offset, info.size);
|
||||||
}
|
}
|
||||||
else if (info.enc_type == nn::hac::nca::CRYPT_AESCTR)
|
else if (info.enc_type == nn::hac::nca::CRYPT_AESCTR)
|
||||||
{
|
{
|
||||||
if (mContentKey.aes_ctr.isSet == false)
|
if (mContentKey.aes_ctr.isSet == false)
|
||||||
throw fnd::Exception(kModuleName, "AES-CTR Key was not determined");
|
throw fnd::Exception(kModuleName, "AES-CTR Key was not determined");
|
||||||
info.reader = new OffsetAdjustedIFile(new AesCtrWrappedIFile(mFile, SHARED_IFILE, mContentKey.aes_ctr.var, info.aes_ctr), OWN_IFILE, info.offset, info.size);
|
info.reader = new fnd::OffsetAdjustedIFile(new fnd::AesCtrWrappedIFile(mFile, mContentKey.aes_ctr.var, info.aes_ctr), info.offset, info.size);
|
||||||
}
|
}
|
||||||
else if (info.enc_type == nn::hac::nca::CRYPT_AESXTS || info.enc_type == nn::hac::nca::CRYPT_AESCTREX)
|
else if (info.enc_type == nn::hac::nca::CRYPT_AESXTS || info.enc_type == nn::hac::nca::CRYPT_AESCTREX)
|
||||||
{
|
{
|
||||||
|
@ -323,9 +367,7 @@ void NcaProcess::generatePartitionConfiguration()
|
||||||
// filter out unrecognised hash types, and hash based readers
|
// filter out unrecognised hash types, and hash based readers
|
||||||
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256 || info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
|
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256 || info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
|
||||||
{
|
{
|
||||||
fnd::IFile* tmp = info.reader;
|
info.reader = new fnd::LayeredIntegrityWrappedIFile(info.reader, info.layered_intergrity_metadata);
|
||||||
info.reader = nullptr;
|
|
||||||
info.reader = new HashTreeWrappedIFile(tmp, OWN_IFILE, info.hash_tree_meta);
|
|
||||||
}
|
}
|
||||||
else if (info.hash_type != nn::hac::nca::HASH_NONE)
|
else if (info.hash_type != nn::hac::nca::HASH_NONE)
|
||||||
{
|
{
|
||||||
|
@ -337,9 +379,6 @@ void NcaProcess::generatePartitionConfiguration()
|
||||||
catch (const fnd::Exception& e)
|
catch (const fnd::Exception& e)
|
||||||
{
|
{
|
||||||
info.fail_reason = std::string(e.error());
|
info.fail_reason = std::string(e.error());
|
||||||
if (info.reader != nullptr)
|
|
||||||
delete info.reader;
|
|
||||||
info.reader = nullptr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -359,10 +398,10 @@ void NcaProcess::validateNcaSignatures()
|
||||||
{
|
{
|
||||||
if (mPartitions[nn::hac::nca::PARTITION_CODE].format_type == nn::hac::nca::FORMAT_PFS0)
|
if (mPartitions[nn::hac::nca::PARTITION_CODE].format_type == nn::hac::nca::FORMAT_PFS0)
|
||||||
{
|
{
|
||||||
if (mPartitions[nn::hac::nca::PARTITION_CODE].reader != nullptr)
|
if (*mPartitions[nn::hac::nca::PARTITION_CODE].reader != nullptr)
|
||||||
{
|
{
|
||||||
PfsProcess exefs;
|
PfsProcess exefs;
|
||||||
exefs.setInputFile(mPartitions[nn::hac::nca::PARTITION_CODE].reader, SHARED_IFILE);
|
exefs.setInputFile(mPartitions[nn::hac::nca::PARTITION_CODE].reader);
|
||||||
exefs.setCliOutputMode(0);
|
exefs.setCliOutputMode(0);
|
||||||
exefs.process();
|
exefs.process();
|
||||||
|
|
||||||
|
@ -372,7 +411,7 @@ void NcaProcess::validateNcaSignatures()
|
||||||
const nn::hac::PfsHeader::sFile& file = exefs.getPfsHeader().getFileList().getElement(kNpdmExefsPath);
|
const nn::hac::PfsHeader::sFile& file = exefs.getPfsHeader().getFileList().getElement(kNpdmExefsPath);
|
||||||
|
|
||||||
NpdmProcess npdm;
|
NpdmProcess npdm;
|
||||||
npdm.setInputFile(new OffsetAdjustedIFile(mPartitions[nn::hac::nca::PARTITION_CODE].reader, SHARED_IFILE, file.offset, file.size), OWN_IFILE);
|
npdm.setInputFile(new fnd::OffsetAdjustedIFile(mPartitions[nn::hac::nca::PARTITION_CODE].reader, file.offset, file.size));
|
||||||
npdm.setCliOutputMode(0);
|
npdm.setCliOutputMode(0);
|
||||||
npdm.process();
|
npdm.process();
|
||||||
|
|
||||||
|
@ -464,7 +503,7 @@ void NcaProcess::displayHeader()
|
||||||
}
|
}
|
||||||
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
|
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
|
||||||
{
|
{
|
||||||
HashTreeMeta& hash_hdr = info.hash_tree_meta;
|
fnd::LayeredIntegrityMetadata& hash_hdr = info.layered_intergrity_metadata;
|
||||||
std::cout << " HierarchicalIntegrity Header:" << std::endl;
|
std::cout << " HierarchicalIntegrity Header:" << std::endl;
|
||||||
for (size_t j = 0; j < hash_hdr.getHashLayerInfo().size(); j++)
|
for (size_t j = 0; j < hash_hdr.getHashLayerInfo().size(); j++)
|
||||||
{
|
{
|
||||||
|
@ -487,7 +526,7 @@ void NcaProcess::displayHeader()
|
||||||
}
|
}
|
||||||
else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256)
|
else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256)
|
||||||
{
|
{
|
||||||
HashTreeMeta& hash_hdr = info.hash_tree_meta;
|
fnd::LayeredIntegrityMetadata& hash_hdr = info.layered_intergrity_metadata;
|
||||||
std::cout << " HierarchicalSha256 Header:" << std::endl;
|
std::cout << " HierarchicalSha256 Header:" << std::endl;
|
||||||
std::cout << " Master Hash:" << std::endl;
|
std::cout << " Master Hash:" << std::endl;
|
||||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[0].bytes, 0x10, true, ":") << std::endl;
|
std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[0].bytes, 0x10, true, ":") << std::endl;
|
||||||
|
@ -513,7 +552,7 @@ void NcaProcess::processPartitions()
|
||||||
struct sPartitionInfo& partition = mPartitions[index];
|
struct sPartitionInfo& partition = mPartitions[index];
|
||||||
|
|
||||||
// if the reader is null, skip
|
// if the reader is null, skip
|
||||||
if (partition.reader == nullptr)
|
if (*partition.reader == nullptr)
|
||||||
{
|
{
|
||||||
std::cout << "[WARNING] NCA Partition " << std::dec << index << " not readable.";
|
std::cout << "[WARNING] NCA Partition " << std::dec << index << " not readable.";
|
||||||
if (partition.fail_reason.empty() == false)
|
if (partition.fail_reason.empty() == false)
|
||||||
|
@ -527,7 +566,7 @@ void NcaProcess::processPartitions()
|
||||||
if (partition.format_type == nn::hac::nca::FORMAT_PFS0)
|
if (partition.format_type == nn::hac::nca::FORMAT_PFS0)
|
||||||
{
|
{
|
||||||
PfsProcess pfs;
|
PfsProcess pfs;
|
||||||
pfs.setInputFile(partition.reader, SHARED_IFILE);
|
pfs.setInputFile(partition.reader);
|
||||||
pfs.setCliOutputMode(mCliOutputMode);
|
pfs.setCliOutputMode(mCliOutputMode);
|
||||||
pfs.setListFs(mListFs);
|
pfs.setListFs(mListFs);
|
||||||
if (mHdr.getContentType() == nn::hac::nca::TYPE_PROGRAM)
|
if (mHdr.getContentType() == nn::hac::nca::TYPE_PROGRAM)
|
||||||
|
@ -546,7 +585,7 @@ void NcaProcess::processPartitions()
|
||||||
else if (partition.format_type == nn::hac::nca::FORMAT_ROMFS)
|
else if (partition.format_type == nn::hac::nca::FORMAT_ROMFS)
|
||||||
{
|
{
|
||||||
RomfsProcess romfs;
|
RomfsProcess romfs;
|
||||||
romfs.setInputFile(partition.reader, SHARED_IFILE);
|
romfs.setInputFile(partition.reader);
|
||||||
romfs.setCliOutputMode(mCliOutputMode);
|
romfs.setCliOutputMode(mCliOutputMode);
|
||||||
romfs.setListFs(mListFs);
|
romfs.setListFs(mListFs);
|
||||||
if (mHdr.getContentType() == nn::hac::nca::TYPE_PROGRAM)
|
if (mHdr.getContentType() == nn::hac::nca::TYPE_PROGRAM)
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/SimpleFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
|
#include <fnd/LayeredIntegrityMetadata.h>
|
||||||
#include <nn/hac/NcaHeader.h>
|
#include <nn/hac/NcaHeader.h>
|
||||||
#include "HashTreeMeta.h"
|
|
||||||
#include "KeyConfiguration.h"
|
#include "KeyConfiguration.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,12 +14,11 @@ class NcaProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NcaProcess();
|
NcaProcess();
|
||||||
~NcaProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setKeyCfg(const KeyConfiguration& keycfg);
|
void setKeyCfg(const KeyConfiguration& keycfg);
|
||||||
void setCliOutputMode(CliOutputMode type);
|
void setCliOutputMode(CliOutputMode type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
@ -35,8 +35,7 @@ private:
|
||||||
const std::string kNpdmExefsPath = "main.npdm";
|
const std::string kNpdmExefsPath = "main.npdm";
|
||||||
|
|
||||||
// user options
|
// user options
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
KeyConfiguration mKeyCfg;
|
KeyConfiguration mKeyCfg;
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
@ -92,7 +91,7 @@ private:
|
||||||
|
|
||||||
struct sPartitionInfo
|
struct sPartitionInfo
|
||||||
{
|
{
|
||||||
fnd::IFile* reader;
|
fnd::SharedPtr<fnd::IFile> reader;
|
||||||
std::string fail_reason;
|
std::string fail_reason;
|
||||||
size_t offset;
|
size_t offset;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -101,7 +100,7 @@ private:
|
||||||
nn::hac::nca::FormatType format_type;
|
nn::hac::nca::FormatType format_type;
|
||||||
nn::hac::nca::HashType hash_type;
|
nn::hac::nca::HashType hash_type;
|
||||||
nn::hac::nca::EncryptionType enc_type;
|
nn::hac::nca::EncryptionType enc_type;
|
||||||
HashTreeMeta hash_tree_meta;
|
fnd::LayeredIntegrityMetadata layered_intergrity_metadata;
|
||||||
fnd::aes::sAesIvCtr aes_ctr;
|
fnd::aes::sAesIvCtr aes_ctr;
|
||||||
} mPartitions[nn::hac::nca::kPartitionNum];
|
} mPartitions[nn::hac::nca::kPartitionNum];
|
||||||
|
|
||||||
|
|
|
@ -3,21 +3,12 @@
|
||||||
#include "NpdmProcess.h"
|
#include "NpdmProcess.h"
|
||||||
|
|
||||||
NpdmProcess::NpdmProcess() :
|
NpdmProcess::NpdmProcess() :
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false)
|
mVerify(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NpdmProcess::~NpdmProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NpdmProcess::process()
|
void NpdmProcess::process()
|
||||||
{
|
{
|
||||||
importNpdm();
|
importNpdm();
|
||||||
|
@ -50,10 +41,9 @@ void NpdmProcess::process()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpdmProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void NpdmProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NpdmProcess::setKeyCfg(const KeyConfiguration& keycfg)
|
void NpdmProcess::setKeyCfg(const KeyConfiguration& keycfg)
|
||||||
|
@ -80,13 +70,13 @@ void NpdmProcess::importNpdm()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.alloc(mFile->size());
|
scratch.alloc((*mFile)->size());
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||||
|
|
||||||
mNpdm.fromBytes(scratch.data(), scratch.size());
|
mNpdm.fromBytes(scratch.data(), scratch.size());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/IFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <nn/hac/NpdmBinary.h>
|
#include <nn/hac/NpdmBinary.h>
|
||||||
#include "KeyConfiguration.h"
|
#include "KeyConfiguration.h"
|
||||||
|
|
||||||
|
@ -11,11 +12,10 @@ class NpdmProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NpdmProcess();
|
NpdmProcess();
|
||||||
~NpdmProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setKeyCfg(const KeyConfiguration& keycfg);
|
void setKeyCfg(const KeyConfiguration& keycfg);
|
||||||
void setCliOutputMode(CliOutputMode type);
|
void setCliOutputMode(CliOutputMode type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
@ -25,8 +25,7 @@ public:
|
||||||
private:
|
private:
|
||||||
const std::string kModuleName = "NpdmProcess";
|
const std::string kModuleName = "NpdmProcess";
|
||||||
|
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
KeyConfiguration mKeyCfg;
|
KeyConfiguration mKeyCfg;
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
|
@ -1,28 +1,19 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
|
#include <fnd/OffsetAdjustedIFile.h>
|
||||||
#include <fnd/Vec.h>
|
#include <fnd/Vec.h>
|
||||||
#include <fnd/lz4.h>
|
#include <fnd/lz4.h>
|
||||||
#include <nn/hac/nro-hb.h>
|
#include <nn/hac/nro-hb.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
|
||||||
#include "NroProcess.h"
|
#include "NroProcess.h"
|
||||||
|
|
||||||
NroProcess::NroProcess():
|
NroProcess::NroProcess():
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false)
|
mVerify(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NroProcess::~NroProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NroProcess::process()
|
void NroProcess::process()
|
||||||
{
|
{
|
||||||
importHeader();
|
importHeader();
|
||||||
|
@ -37,10 +28,9 @@ void NroProcess::process()
|
||||||
mAssetProc.process();
|
mAssetProc.process();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NroProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void NroProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NroProcess::setCliOutputMode(CliOutputMode type)
|
void NroProcess::setCliOutputMode(CliOutputMode type)
|
||||||
|
@ -97,27 +87,27 @@ void NroProcess::importHeader()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mFile->size() < sizeof(nn::hac::sNroHeader))
|
if ((*mFile)->size() < sizeof(nn::hac::sNroHeader))
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "Corrupt NRO: file too small");
|
throw fnd::Exception(kModuleName, "Corrupt NRO: file too small");
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.alloc(sizeof(nn::hac::sNroHeader));
|
scratch.alloc(sizeof(nn::hac::sNroHeader));
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||||
|
|
||||||
mHdr.fromBytes(scratch.data(), scratch.size());
|
mHdr.fromBytes(scratch.data(), scratch.size());
|
||||||
|
|
||||||
// setup homebrew extension
|
// setup homebrew extension
|
||||||
nn::hac::sNroHeader* raw_hdr = (nn::hac::sNroHeader*)scratch.data();
|
nn::hac::sNroHeader* raw_hdr = (nn::hac::sNroHeader*)scratch.data();
|
||||||
if (((le_uint64_t*)raw_hdr->reserved_0)->get() == nn::hac::nro::kNroHomebrewStructMagic && mFile->size() > mHdr.getNroSize())
|
if (((le_uint64_t*)raw_hdr->reserved_0)->get() == nn::hac::nro::kNroHomebrewStructMagic && (*mFile)->size() > mHdr.getNroSize())
|
||||||
{
|
{
|
||||||
mIsHomebrewNro = true;
|
mIsHomebrewNro = true;
|
||||||
mAssetProc.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNroSize(), mFile->size() - mHdr.getNroSize()), true);
|
mAssetProc.setInputFile(new fnd::OffsetAdjustedIFile(mFile, mHdr.getNroSize(), (*mFile)->size() - mHdr.getNroSize()));
|
||||||
mAssetProc.setCliOutputMode(mCliOutputMode);
|
mAssetProc.setCliOutputMode(mCliOutputMode);
|
||||||
mAssetProc.setVerifyMode(mVerify);
|
mAssetProc.setVerifyMode(mVerify);
|
||||||
}
|
}
|
||||||
|
@ -128,11 +118,11 @@ void NroProcess::importHeader()
|
||||||
void NroProcess::importCodeSegments()
|
void NroProcess::importCodeSegments()
|
||||||
{
|
{
|
||||||
mTextBlob.alloc(mHdr.getTextInfo().size);
|
mTextBlob.alloc(mHdr.getTextInfo().size);
|
||||||
mFile->read(mTextBlob.data(), mHdr.getTextInfo().memory_offset, mTextBlob.size());
|
(*mFile)->read(mTextBlob.data(), mHdr.getTextInfo().memory_offset, mTextBlob.size());
|
||||||
mRoBlob.alloc(mHdr.getRoInfo().size);
|
mRoBlob.alloc(mHdr.getRoInfo().size);
|
||||||
mFile->read(mRoBlob.data(), mHdr.getRoInfo().memory_offset, mRoBlob.size());
|
(*mFile)->read(mRoBlob.data(), mHdr.getRoInfo().memory_offset, mRoBlob.size());
|
||||||
mDataBlob.alloc(mHdr.getDataInfo().size);
|
mDataBlob.alloc(mHdr.getDataInfo().size);
|
||||||
mFile->read(mDataBlob.data(), mHdr.getDataInfo().memory_offset, mDataBlob.size());
|
(*mFile)->read(mDataBlob.data(), mHdr.getDataInfo().memory_offset, mDataBlob.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NroProcess::displayHeader()
|
void NroProcess::displayHeader()
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/IFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <nn/hac/npdm.h>
|
#include <nn/hac/npdm.h>
|
||||||
#include <nn/hac/NroHeader.h>
|
#include <nn/hac/NroHeader.h>
|
||||||
#include "AssetProcess.h"
|
#include "AssetProcess.h"
|
||||||
|
@ -14,11 +15,10 @@ class NroProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NroProcess();
|
NroProcess();
|
||||||
~NroProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setCliOutputMode(CliOutputMode type);
|
void setCliOutputMode(CliOutputMode type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
@ -36,9 +36,7 @@ public:
|
||||||
private:
|
private:
|
||||||
const std::string kModuleName = "NroProcess";
|
const std::string kModuleName = "NroProcess";
|
||||||
|
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
|
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,18 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
|
#include <fnd/OffsetAdjustedIFile.h>
|
||||||
#include <fnd/Vec.h>
|
#include <fnd/Vec.h>
|
||||||
#include <fnd/lz4.h>
|
#include <fnd/lz4.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
|
||||||
#include "NsoProcess.h"
|
#include "NsoProcess.h"
|
||||||
|
|
||||||
NsoProcess::NsoProcess():
|
NsoProcess::NsoProcess():
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false)
|
mVerify(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
NsoProcess::~NsoProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NsoProcess::process()
|
void NsoProcess::process()
|
||||||
{
|
{
|
||||||
importHeader();
|
importHeader();
|
||||||
|
@ -32,10 +23,9 @@ void NsoProcess::process()
|
||||||
processRoMeta();
|
processRoMeta();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void NsoProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NsoProcess::setCliOutputMode(CliOutputMode type)
|
void NsoProcess::setCliOutputMode(CliOutputMode type)
|
||||||
|
@ -72,18 +62,18 @@ void NsoProcess::importHeader()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mFile->size() < sizeof(nn::hac::sNsoHeader))
|
if ((*mFile)->size() < sizeof(nn::hac::sNsoHeader))
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "Corrupt NSO: file too small");
|
throw fnd::Exception(kModuleName, "Corrupt NSO: file too small");
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.alloc(sizeof(nn::hac::sNsoHeader));
|
scratch.alloc(sizeof(nn::hac::sNsoHeader));
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||||
|
|
||||||
mHdr.fromBytes(scratch.data(), scratch.size());
|
mHdr.fromBytes(scratch.data(), scratch.size());
|
||||||
}
|
}
|
||||||
|
@ -98,7 +88,7 @@ void NsoProcess::importCodeSegments()
|
||||||
if (mHdr.getTextSegmentInfo().is_compressed)
|
if (mHdr.getTextSegmentInfo().is_compressed)
|
||||||
{
|
{
|
||||||
scratch.alloc(mHdr.getTextSegmentInfo().file_layout.size);
|
scratch.alloc(mHdr.getTextSegmentInfo().file_layout.size);
|
||||||
mFile->read(scratch.data(), mHdr.getTextSegmentInfo().file_layout.offset, scratch.size());
|
(*mFile)->read(scratch.data(), mHdr.getTextSegmentInfo().file_layout.offset, scratch.size());
|
||||||
mTextBlob.alloc(mHdr.getTextSegmentInfo().memory_layout.size);
|
mTextBlob.alloc(mHdr.getTextSegmentInfo().memory_layout.size);
|
||||||
fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mTextBlob.data(), (uint32_t)mTextBlob.size(), decompressed_len);
|
fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mTextBlob.data(), (uint32_t)mTextBlob.size(), decompressed_len);
|
||||||
if (decompressed_len != mTextBlob.size())
|
if (decompressed_len != mTextBlob.size())
|
||||||
|
@ -109,7 +99,7 @@ void NsoProcess::importCodeSegments()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mTextBlob.alloc(mHdr.getTextSegmentInfo().file_layout.size);
|
mTextBlob.alloc(mHdr.getTextSegmentInfo().file_layout.size);
|
||||||
mFile->read(mTextBlob.data(), mHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.size());
|
(*mFile)->read(mTextBlob.data(), mHdr.getTextSegmentInfo().file_layout.offset, mTextBlob.size());
|
||||||
}
|
}
|
||||||
if (mHdr.getTextSegmentInfo().is_hashed)
|
if (mHdr.getTextSegmentInfo().is_hashed)
|
||||||
{
|
{
|
||||||
|
@ -124,7 +114,7 @@ void NsoProcess::importCodeSegments()
|
||||||
if (mHdr.getRoSegmentInfo().is_compressed)
|
if (mHdr.getRoSegmentInfo().is_compressed)
|
||||||
{
|
{
|
||||||
scratch.alloc(mHdr.getRoSegmentInfo().file_layout.size);
|
scratch.alloc(mHdr.getRoSegmentInfo().file_layout.size);
|
||||||
mFile->read(scratch.data(), mHdr.getRoSegmentInfo().file_layout.offset, scratch.size());
|
(*mFile)->read(scratch.data(), mHdr.getRoSegmentInfo().file_layout.offset, scratch.size());
|
||||||
mRoBlob.alloc(mHdr.getRoSegmentInfo().memory_layout.size);
|
mRoBlob.alloc(mHdr.getRoSegmentInfo().memory_layout.size);
|
||||||
fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mRoBlob.data(), (uint32_t)mRoBlob.size(), decompressed_len);
|
fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mRoBlob.data(), (uint32_t)mRoBlob.size(), decompressed_len);
|
||||||
if (decompressed_len != mRoBlob.size())
|
if (decompressed_len != mRoBlob.size())
|
||||||
|
@ -135,7 +125,7 @@ void NsoProcess::importCodeSegments()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mRoBlob.alloc(mHdr.getRoSegmentInfo().file_layout.size);
|
mRoBlob.alloc(mHdr.getRoSegmentInfo().file_layout.size);
|
||||||
mFile->read(mRoBlob.data(), mHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.size());
|
(*mFile)->read(mRoBlob.data(), mHdr.getRoSegmentInfo().file_layout.offset, mRoBlob.size());
|
||||||
}
|
}
|
||||||
if (mHdr.getRoSegmentInfo().is_hashed)
|
if (mHdr.getRoSegmentInfo().is_hashed)
|
||||||
{
|
{
|
||||||
|
@ -150,7 +140,7 @@ void NsoProcess::importCodeSegments()
|
||||||
if (mHdr.getDataSegmentInfo().is_compressed)
|
if (mHdr.getDataSegmentInfo().is_compressed)
|
||||||
{
|
{
|
||||||
scratch.alloc(mHdr.getDataSegmentInfo().file_layout.size);
|
scratch.alloc(mHdr.getDataSegmentInfo().file_layout.size);
|
||||||
mFile->read(scratch.data(), mHdr.getDataSegmentInfo().file_layout.offset, scratch.size());
|
(*mFile)->read(scratch.data(), mHdr.getDataSegmentInfo().file_layout.offset, scratch.size());
|
||||||
mDataBlob.alloc(mHdr.getDataSegmentInfo().memory_layout.size);
|
mDataBlob.alloc(mHdr.getDataSegmentInfo().memory_layout.size);
|
||||||
fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mDataBlob.data(), (uint32_t)mDataBlob.size(), decompressed_len);
|
fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mDataBlob.data(), (uint32_t)mDataBlob.size(), decompressed_len);
|
||||||
if (decompressed_len != mDataBlob.size())
|
if (decompressed_len != mDataBlob.size())
|
||||||
|
@ -161,7 +151,7 @@ void NsoProcess::importCodeSegments()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mDataBlob.alloc(mHdr.getDataSegmentInfo().file_layout.size);
|
mDataBlob.alloc(mHdr.getDataSegmentInfo().file_layout.size);
|
||||||
mFile->read(mDataBlob.data(), mHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.size());
|
(*mFile)->read(mDataBlob.data(), mHdr.getDataSegmentInfo().file_layout.offset, mDataBlob.size());
|
||||||
}
|
}
|
||||||
if (mHdr.getDataSegmentInfo().is_hashed)
|
if (mHdr.getDataSegmentInfo().is_hashed)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/IFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <nn/hac/npdm.h>
|
#include <nn/hac/npdm.h>
|
||||||
#include <nn/hac/NsoHeader.h>
|
#include <nn/hac/NsoHeader.h>
|
||||||
|
|
||||||
|
@ -13,11 +14,10 @@ class NsoProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NsoProcess();
|
NsoProcess();
|
||||||
~NsoProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setCliOutputMode(CliOutputMode type);
|
void setCliOutputMode(CliOutputMode type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
@ -29,9 +29,7 @@ public:
|
||||||
private:
|
private:
|
||||||
const std::string kModuleName = "NsoProcess";
|
const std::string kModuleName = "NsoProcess";
|
||||||
|
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
|
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
nn::hac::npdm::InstructionType mInstructionType;
|
nn::hac::npdm::InstructionType mInstructionType;
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
#include "OffsetAdjustedIFile.h"
|
|
||||||
|
|
||||||
OffsetAdjustedIFile::OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size) :
|
|
||||||
mOwnIFile(ownIFile),
|
|
||||||
mFile(file),
|
|
||||||
mBaseOffset(offset),
|
|
||||||
mCurrentOffset(0),
|
|
||||||
mSize(size)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
OffsetAdjustedIFile::~OffsetAdjustedIFile()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t OffsetAdjustedIFile::size()
|
|
||||||
{
|
|
||||||
return mSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OffsetAdjustedIFile::seek(size_t offset)
|
|
||||||
{
|
|
||||||
mCurrentOffset = _MIN(offset, mSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OffsetAdjustedIFile::read(byte_t* out, size_t len)
|
|
||||||
{
|
|
||||||
// assert proper position in file
|
|
||||||
mFile->seek(mCurrentOffset + mBaseOffset);
|
|
||||||
mFile->read(out, len);
|
|
||||||
seek(mCurrentOffset + len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OffsetAdjustedIFile::read(byte_t* out, size_t offset, size_t len)
|
|
||||||
{
|
|
||||||
seek(offset);
|
|
||||||
read(out, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OffsetAdjustedIFile::write(const byte_t* out, size_t len)
|
|
||||||
{
|
|
||||||
// assert proper position in file
|
|
||||||
mFile->seek(mCurrentOffset + mBaseOffset);
|
|
||||||
mFile->write(out, len);
|
|
||||||
seek(mCurrentOffset + len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OffsetAdjustedIFile::write(const byte_t* out, size_t offset, size_t len)
|
|
||||||
{
|
|
||||||
seek(offset);
|
|
||||||
write(out, len);
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
#include <fnd/IFile.h>
|
|
||||||
|
|
||||||
class OffsetAdjustedIFile : public fnd::IFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size);
|
|
||||||
~OffsetAdjustedIFile();
|
|
||||||
|
|
||||||
size_t size();
|
|
||||||
void seek(size_t offset);
|
|
||||||
void read(byte_t* out, size_t len);
|
|
||||||
void read(byte_t* out, size_t offset, size_t len);
|
|
||||||
void write(const byte_t* out, size_t len);
|
|
||||||
void write(const byte_t* out, size_t offset, size_t len);
|
|
||||||
private:
|
|
||||||
bool mOwnIFile;
|
|
||||||
fnd::IFile* mFile;
|
|
||||||
size_t mBaseOffset, mCurrentOffset;
|
|
||||||
size_t mSize;
|
|
||||||
};
|
|
|
@ -5,8 +5,7 @@
|
||||||
#include "PfsProcess.h"
|
#include "PfsProcess.h"
|
||||||
|
|
||||||
PfsProcess::PfsProcess() :
|
PfsProcess::PfsProcess() :
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false),
|
mVerify(false),
|
||||||
mExtractPath(),
|
mExtractPath(),
|
||||||
|
@ -17,14 +16,6 @@ PfsProcess::PfsProcess() :
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PfsProcess::~PfsProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PfsProcess::process()
|
void PfsProcess::process()
|
||||||
{
|
{
|
||||||
importHeader();
|
importHeader();
|
||||||
|
@ -41,10 +32,9 @@ void PfsProcess::process()
|
||||||
extractFs();
|
extractFs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PfsProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void PfsProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PfsProcess::setCliOutputMode(CliOutputMode type)
|
void PfsProcess::setCliOutputMode(CliOutputMode type)
|
||||||
|
@ -82,14 +72,14 @@ void PfsProcess::importHeader()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// open minimum header to get full header size
|
// open minimum header to get full header size
|
||||||
scratch.alloc(sizeof(nn::hac::sPfsHeader));
|
scratch.alloc(sizeof(nn::hac::sPfsHeader));
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||||
if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false)
|
if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "Corrupt Header");
|
throw fnd::Exception(kModuleName, "Corrupt Header");
|
||||||
|
@ -98,7 +88,7 @@ void PfsProcess::importHeader()
|
||||||
|
|
||||||
// open minimum header to get full header size
|
// open minimum header to get full header size
|
||||||
scratch.alloc(pfsHeaderSize);
|
scratch.alloc(pfsHeaderSize);
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||||
mPfs.fromBytes(scratch.data(), scratch.size());
|
mPfs.fromBytes(scratch.data(), scratch.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +152,7 @@ void PfsProcess::validateHfs()
|
||||||
for (size_t i = 0; i < file.size(); i++)
|
for (size_t i = 0; i < file.size(); i++)
|
||||||
{
|
{
|
||||||
mCache.alloc(file[i].hash_protected_size);
|
mCache.alloc(file[i].hash_protected_size);
|
||||||
mFile->read(mCache.data(), file[i].offset, file[i].hash_protected_size);
|
(*mFile)->read(mCache.data(), file[i].offset, file[i].hash_protected_size);
|
||||||
fnd::sha::Sha256(mCache.data(), file[i].hash_protected_size, hash.bytes);
|
fnd::sha::Sha256(mCache.data(), file[i].hash_protected_size, hash.bytes);
|
||||||
if (hash != file[i].hash)
|
if (hash != file[i].hash)
|
||||||
{
|
{
|
||||||
|
@ -193,10 +183,10 @@ void PfsProcess::extractFs()
|
||||||
printf("extract=[%s]\n", file_path.c_str());
|
printf("extract=[%s]\n", file_path.c_str());
|
||||||
|
|
||||||
outFile.open(file_path, outFile.Create);
|
outFile.open(file_path, outFile.Create);
|
||||||
mFile->seek(file[i].offset);
|
(*mFile)->seek(file[i].offset);
|
||||||
for (size_t j = 0; j < ((file[i].size / kCacheSize) + ((file[i].size % kCacheSize) != 0)); j++)
|
for (size_t j = 0; j < ((file[i].size / kCacheSize) + ((file[i].size % kCacheSize) != 0)); j++)
|
||||||
{
|
{
|
||||||
mFile->read(mCache.data(), _MIN(file[i].size - (kCacheSize * j),kCacheSize));
|
(*mFile)->read(mCache.data(), _MIN(file[i].size - (kCacheSize * j),kCacheSize));
|
||||||
outFile.write(mCache.data(), _MIN(file[i].size - (kCacheSize * j),kCacheSize));
|
outFile.write(mCache.data(), _MIN(file[i].size - (kCacheSize * j),kCacheSize));
|
||||||
}
|
}
|
||||||
outFile.close();
|
outFile.close();
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/IFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <nn/hac/PfsHeader.h>
|
#include <nn/hac/PfsHeader.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
@ -10,12 +11,11 @@ class PfsProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PfsProcess();
|
PfsProcess();
|
||||||
~PfsProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setCliOutputMode(CliOutputMode type);
|
void setCliOutputMode(CliOutputMode type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
@ -30,8 +30,7 @@ private:
|
||||||
const std::string kModuleName = "PfsProcess";
|
const std::string kModuleName = "PfsProcess";
|
||||||
static const size_t kCacheSize = 0x10000;
|
static const size_t kCacheSize = 0x10000;
|
||||||
|
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,18 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
|
#include <fnd/OffsetAdjustedIFile.h>
|
||||||
#include <nn/pki/SignUtils.h>
|
#include <nn/pki/SignUtils.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
|
||||||
#include "PkiCertProcess.h"
|
#include "PkiCertProcess.h"
|
||||||
#include "PkiValidator.h"
|
#include "PkiValidator.h"
|
||||||
|
|
||||||
PkiCertProcess::PkiCertProcess() :
|
PkiCertProcess::PkiCertProcess() :
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false)
|
mVerify(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PkiCertProcess::~PkiCertProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PkiCertProcess::process()
|
void PkiCertProcess::process()
|
||||||
{
|
{
|
||||||
importCerts();
|
importCerts();
|
||||||
|
@ -33,10 +24,9 @@ void PkiCertProcess::process()
|
||||||
displayCerts();
|
displayCerts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PkiCertProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void PkiCertProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PkiCertProcess::setKeyCfg(const KeyConfiguration& keycfg)
|
void PkiCertProcess::setKeyCfg(const KeyConfiguration& keycfg)
|
||||||
|
@ -58,13 +48,13 @@ void PkiCertProcess::importCerts()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch.alloc(mFile->size());
|
scratch.alloc((*mFile)->size());
|
||||||
mFile->read(scratch.data(), 0, scratch.size());
|
(*mFile)->read(scratch.data(), 0, scratch.size());
|
||||||
|
|
||||||
nn::pki::SignedData<nn::pki::CertificateBody> cert;
|
nn::pki::SignedData<nn::pki::CertificateBody> cert;
|
||||||
for (size_t f_pos = 0; f_pos < scratch.size(); f_pos += cert.getBytes().size())
|
for (size_t f_pos = 0; f_pos < scratch.size(); f_pos += cert.getBytes().size())
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/IFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <fnd/List.h>
|
#include <fnd/List.h>
|
||||||
#include <fnd/Vec.h>
|
#include <fnd/Vec.h>
|
||||||
#include <nn/pki/SignedData.h>
|
#include <nn/pki/SignedData.h>
|
||||||
|
@ -13,11 +14,10 @@ class PkiCertProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PkiCertProcess();
|
PkiCertProcess();
|
||||||
~PkiCertProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setKeyCfg(const KeyConfiguration& keycfg);
|
void setKeyCfg(const KeyConfiguration& keycfg);
|
||||||
void setCliOutputMode(CliOutputMode type);
|
void setCliOutputMode(CliOutputMode type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
@ -26,8 +26,7 @@ private:
|
||||||
const std::string kModuleName = "PkiCertProcess";
|
const std::string kModuleName = "PkiCertProcess";
|
||||||
static const size_t kSmallHexDumpLen = 0x10;
|
static const size_t kSmallHexDumpLen = 0x10;
|
||||||
|
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
KeyConfiguration mKeyCfg;
|
KeyConfiguration mKeyCfg;
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
#include "RomfsProcess.h"
|
#include "RomfsProcess.h"
|
||||||
|
|
||||||
RomfsProcess::RomfsProcess() :
|
RomfsProcess::RomfsProcess() :
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false),
|
mVerify(false),
|
||||||
mExtractPath(),
|
mExtractPath(),
|
||||||
|
@ -22,14 +21,6 @@ RomfsProcess::RomfsProcess() :
|
||||||
mRootDir.file_list.clear();
|
mRootDir.file_list.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
RomfsProcess::~RomfsProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RomfsProcess::process()
|
void RomfsProcess::process()
|
||||||
{
|
{
|
||||||
resolveRomfs();
|
resolveRomfs();
|
||||||
|
@ -45,10 +36,9 @@ void RomfsProcess::process()
|
||||||
extractFs();
|
extractFs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RomfsProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void RomfsProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RomfsProcess::setCliOutputMode(CliOutputMode type)
|
void RomfsProcess::setCliOutputMode(CliOutputMode type)
|
||||||
|
@ -163,10 +153,10 @@ void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir)
|
||||||
std::cout << "extract=[" << file_path << "]" << std::endl;
|
std::cout << "extract=[" << file_path << "]" << std::endl;
|
||||||
|
|
||||||
outFile.open(file_path, outFile.Create);
|
outFile.open(file_path, outFile.Create);
|
||||||
mFile->seek(dir.file_list[i].offset);
|
(*mFile)->seek(dir.file_list[i].offset);
|
||||||
for (size_t j = 0; j < ((dir.file_list[i].size / kCacheSize) + ((dir.file_list[i].size % kCacheSize) != 0)); j++)
|
for (size_t j = 0; j < ((dir.file_list[i].size / kCacheSize) + ((dir.file_list[i].size % kCacheSize) != 0)); j++)
|
||||||
{
|
{
|
||||||
mFile->read(mCache.data(), _MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize));
|
(*mFile)->read(mCache.data(), _MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize));
|
||||||
outFile.write(mCache.data(), _MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize));
|
outFile.write(mCache.data(), _MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize));
|
||||||
}
|
}
|
||||||
outFile.close();
|
outFile.close();
|
||||||
|
@ -258,13 +248,13 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir)
|
||||||
|
|
||||||
void RomfsProcess::resolveRomfs()
|
void RomfsProcess::resolveRomfs()
|
||||||
{
|
{
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// read header
|
// read header
|
||||||
mFile->read((byte_t*)&mHdr, 0, sizeof(nn::hac::sRomfsHeader));
|
(*mFile)->read((byte_t*)&mHdr, 0, sizeof(nn::hac::sRomfsHeader));
|
||||||
|
|
||||||
// logic check on the header layout
|
// logic check on the header layout
|
||||||
if (validateHeaderLayout(&mHdr) == false)
|
if (validateHeaderLayout(&mHdr) == false)
|
||||||
|
@ -274,13 +264,13 @@ void RomfsProcess::resolveRomfs()
|
||||||
|
|
||||||
// read directory nodes
|
// read directory nodes
|
||||||
mDirNodes.alloc(mHdr.sections[nn::hac::romfs::DIR_NODE_TABLE].size.get());
|
mDirNodes.alloc(mHdr.sections[nn::hac::romfs::DIR_NODE_TABLE].size.get());
|
||||||
mFile->read(mDirNodes.data(), mHdr.sections[nn::hac::romfs::DIR_NODE_TABLE].offset.get(), mDirNodes.size());
|
(*mFile)->read(mDirNodes.data(), mHdr.sections[nn::hac::romfs::DIR_NODE_TABLE].offset.get(), mDirNodes.size());
|
||||||
//printf("[RAW DIR NODES]\n");
|
//printf("[RAW DIR NODES]\n");
|
||||||
//fnd::SimpleTextOutput::hxdStyleDump(mDirNodes.data(), mDirNodes.size());
|
//fnd::SimpleTextOutput::hxdStyleDump(mDirNodes.data(), mDirNodes.size());
|
||||||
|
|
||||||
// read file nodes
|
// read file nodes
|
||||||
mFileNodes.alloc(mHdr.sections[nn::hac::romfs::FILE_NODE_TABLE].size.get());
|
mFileNodes.alloc(mHdr.sections[nn::hac::romfs::FILE_NODE_TABLE].size.get());
|
||||||
mFile->read(mFileNodes.data(), mHdr.sections[nn::hac::romfs::FILE_NODE_TABLE].offset.get(), mFileNodes.size());
|
(*mFile)->read(mFileNodes.data(), mHdr.sections[nn::hac::romfs::FILE_NODE_TABLE].offset.get(), mFileNodes.size());
|
||||||
//printf("[RAW FILE NODES]\n");
|
//printf("[RAW FILE NODES]\n");
|
||||||
//fnd::SimpleTextOutput::hxdStyleDump(mFileNodes.data(), mFileNodes.size());
|
//fnd::SimpleTextOutput::hxdStyleDump(mFileNodes.data(), mFileNodes.size());
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/IFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <fnd/Vec.h>
|
#include <fnd/Vec.h>
|
||||||
#include <fnd/List.h>
|
#include <fnd/List.h>
|
||||||
#include <nn/hac/romfs.h>
|
#include <nn/hac/romfs.h>
|
||||||
|
@ -77,12 +78,11 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
RomfsProcess();
|
RomfsProcess();
|
||||||
~RomfsProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setCliOutputMode(CliOutputMode type);
|
void setCliOutputMode(CliOutputMode type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
|
||||||
|
@ -96,8 +96,7 @@ private:
|
||||||
const std::string kModuleName = "RomfsProcess";
|
const std::string kModuleName = "RomfsProcess";
|
||||||
static const size_t kCacheSize = 0x10000;
|
static const size_t kCacheSize = 0x10000;
|
||||||
|
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <fnd/SimpleTextOutput.h>
|
#include <fnd/SimpleTextOutput.h>
|
||||||
|
#include <fnd/OffsetAdjustedIFile.h>
|
||||||
#include <nn/hac/XciUtils.h>
|
#include <nn/hac/XciUtils.h>
|
||||||
#include "OffsetAdjustedIFile.h"
|
|
||||||
#include "XciProcess.h"
|
#include "XciProcess.h"
|
||||||
|
|
||||||
XciProcess::XciProcess() :
|
XciProcess::XciProcess() :
|
||||||
mFile(nullptr),
|
mFile(),
|
||||||
mOwnIFile(false),
|
|
||||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||||
mVerify(false),
|
mVerify(false),
|
||||||
mListFs(false),
|
mListFs(false),
|
||||||
|
@ -16,14 +15,6 @@ XciProcess::XciProcess() :
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
XciProcess::~XciProcess()
|
|
||||||
{
|
|
||||||
if (mOwnIFile)
|
|
||||||
{
|
|
||||||
delete mFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void XciProcess::process()
|
void XciProcess::process()
|
||||||
{
|
{
|
||||||
importHeader();
|
importHeader();
|
||||||
|
@ -43,10 +34,9 @@ void XciProcess::process()
|
||||||
processPartitionPfs();
|
processPartitionPfs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XciProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
void XciProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||||
{
|
{
|
||||||
mFile = file;
|
mFile = file;
|
||||||
mOwnIFile = ownIFile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XciProcess::setKeyCfg(const KeyConfiguration& keycfg)
|
void XciProcess::setKeyCfg(const KeyConfiguration& keycfg)
|
||||||
|
@ -78,13 +68,13 @@ void XciProcess::importHeader()
|
||||||
{
|
{
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
|
|
||||||
if (mFile == nullptr)
|
if (*mFile == nullptr)
|
||||||
{
|
{
|
||||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// read header page
|
// read header page
|
||||||
mFile->read((byte_t*)&mHdrPage, 0, sizeof(nn::hac::sXciHeaderPage));
|
(*mFile)->read((byte_t*)&mHdrPage, 0, sizeof(nn::hac::sXciHeaderPage));
|
||||||
|
|
||||||
// allocate memory for and decrypt sXciHeader
|
// allocate memory for and decrypt sXciHeader
|
||||||
scratch.alloc(sizeof(nn::hac::sXciHeader));
|
scratch.alloc(sizeof(nn::hac::sXciHeader));
|
||||||
|
@ -193,7 +183,7 @@ bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* t
|
||||||
fnd::Vec<byte_t> scratch;
|
fnd::Vec<byte_t> scratch;
|
||||||
fnd::sha::sSha256Hash calc_hash;
|
fnd::sha::sSha256Hash calc_hash;
|
||||||
scratch.alloc(len);
|
scratch.alloc(len);
|
||||||
mFile->read(scratch.data(), offset, scratch.size());
|
(*mFile)->read(scratch.data(), offset, scratch.size());
|
||||||
fnd::sha::Sha256(scratch.data(), scratch.size(), calc_hash.bytes);
|
fnd::sha::Sha256(scratch.data(), scratch.size(), calc_hash.bytes);
|
||||||
return calc_hash.compare(test_hash);
|
return calc_hash.compare(test_hash);
|
||||||
}
|
}
|
||||||
|
@ -216,7 +206,7 @@ void XciProcess::processRootPfs()
|
||||||
{
|
{
|
||||||
std::cout << "[WARNING] XCI Root HFS0: FAIL (bad hash)" << std::endl;
|
std::cout << "[WARNING] XCI Root HFS0: FAIL (bad hash)" << std::endl;
|
||||||
}
|
}
|
||||||
mRootPfs.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()), OWN_IFILE);
|
mRootPfs.setInputFile(new fnd::OffsetAdjustedIFile(mFile, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()));
|
||||||
mRootPfs.setListFs(mListFs);
|
mRootPfs.setListFs(mListFs);
|
||||||
mRootPfs.setVerifyMode(false);
|
mRootPfs.setVerifyMode(false);
|
||||||
mRootPfs.setCliOutputMode(mCliOutputMode);
|
mRootPfs.setCliOutputMode(mCliOutputMode);
|
||||||
|
@ -236,7 +226,7 @@ void XciProcess::processPartitionPfs()
|
||||||
}
|
}
|
||||||
|
|
||||||
PfsProcess tmp;
|
PfsProcess tmp;
|
||||||
tmp.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size), OWN_IFILE);
|
tmp.setInputFile(new fnd::OffsetAdjustedIFile(mFile, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size));
|
||||||
tmp.setListFs(mListFs);
|
tmp.setListFs(mListFs);
|
||||||
tmp.setVerifyMode(mVerify);
|
tmp.setVerifyMode(mVerify);
|
||||||
tmp.setCliOutputMode(mCliOutputMode);
|
tmp.setCliOutputMode(mCliOutputMode);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fnd/types.h>
|
#include <fnd/types.h>
|
||||||
#include <fnd/IFile.h>
|
#include <fnd/IFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <fnd/List.h>
|
#include <fnd/List.h>
|
||||||
#include <nn/hac/XciHeader.h>
|
#include <nn/hac/XciHeader.h>
|
||||||
#include "KeyConfiguration.h"
|
#include "KeyConfiguration.h"
|
||||||
|
@ -13,12 +14,11 @@ class XciProcess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
XciProcess();
|
XciProcess();
|
||||||
~XciProcess();
|
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
// generic
|
// generic
|
||||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||||
void setKeyCfg(const KeyConfiguration& keycfg);
|
void setKeyCfg(const KeyConfiguration& keycfg);
|
||||||
void setCliOutputMode(CliOutputMode type);
|
void setCliOutputMode(CliOutputMode type);
|
||||||
void setVerifyMode(bool verify);
|
void setVerifyMode(bool verify);
|
||||||
|
@ -31,8 +31,7 @@ private:
|
||||||
const std::string kModuleName = "XciProcess";
|
const std::string kModuleName = "XciProcess";
|
||||||
const std::string kXciMountPointName = "gamecard:/";
|
const std::string kXciMountPointName = "gamecard:/";
|
||||||
|
|
||||||
fnd::IFile* mFile;
|
fnd::SharedPtr<fnd::IFile> mFile;
|
||||||
bool mOwnIFile;
|
|
||||||
KeyConfiguration mKeyCfg;
|
KeyConfiguration mKeyCfg;
|
||||||
CliOutputMode mCliOutputMode;
|
CliOutputMode mCliOutputMode;
|
||||||
bool mVerify;
|
bool mVerify;
|
||||||
|
|
|
@ -8,12 +8,6 @@
|
||||||
static const size_t kMasterKeyNum = 0x20;
|
static const size_t kMasterKeyNum = 0x20;
|
||||||
static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum;
|
static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum;
|
||||||
|
|
||||||
enum IFileOwnershipMode
|
|
||||||
{
|
|
||||||
SHARED_IFILE = false,
|
|
||||||
OWN_IFILE = true
|
|
||||||
};
|
|
||||||
|
|
||||||
enum FileType
|
enum FileType
|
||||||
{
|
{
|
||||||
FILE_XCI,
|
FILE_XCI,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <fnd/SimpleFile.h>
|
#include <fnd/SimpleFile.h>
|
||||||
|
#include <fnd/SharedPtr.h>
|
||||||
#include <fnd/StringConv.h>
|
#include <fnd/StringConv.h>
|
||||||
#include "UserSettings.h"
|
#include "UserSettings.h"
|
||||||
#include "XciProcess.h"
|
#include "XciProcess.h"
|
||||||
|
@ -35,11 +36,13 @@ int main(int argc, char** argv)
|
||||||
try {
|
try {
|
||||||
user_set.parseCmdArgs(args);
|
user_set.parseCmdArgs(args);
|
||||||
|
|
||||||
|
fnd::SharedPtr<fnd::IFile> inputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read));
|
||||||
|
|
||||||
if (user_set.getFileType() == FILE_XCI)
|
if (user_set.getFileType() == FILE_XCI)
|
||||||
{
|
{
|
||||||
XciProcess xci;
|
XciProcess xci;
|
||||||
|
|
||||||
xci.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
xci.setInputFile(inputFile);
|
||||||
|
|
||||||
xci.setKeyCfg(user_set.getKeyCfg());
|
xci.setKeyCfg(user_set.getKeyCfg());
|
||||||
xci.setCliOutputMode(user_set.getCliOutputMode());
|
xci.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
|
@ -61,7 +64,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
PfsProcess pfs;
|
PfsProcess pfs;
|
||||||
|
|
||||||
pfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
pfs.setInputFile(inputFile);
|
||||||
pfs.setCliOutputMode(user_set.getCliOutputMode());
|
pfs.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
pfs.setVerifyMode(user_set.isVerifyFile());
|
pfs.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
@ -75,7 +78,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
RomfsProcess romfs;
|
RomfsProcess romfs;
|
||||||
|
|
||||||
romfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
romfs.setInputFile(inputFile);
|
||||||
romfs.setCliOutputMode(user_set.getCliOutputMode());
|
romfs.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
romfs.setVerifyMode(user_set.isVerifyFile());
|
romfs.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
@ -89,7 +92,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
NcaProcess nca;
|
NcaProcess nca;
|
||||||
|
|
||||||
nca.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
nca.setInputFile(inputFile);
|
||||||
nca.setKeyCfg(user_set.getKeyCfg());
|
nca.setKeyCfg(user_set.getKeyCfg());
|
||||||
nca.setCliOutputMode(user_set.getCliOutputMode());
|
nca.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
nca.setVerifyMode(user_set.isVerifyFile());
|
nca.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
@ -111,7 +114,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
NpdmProcess npdm;
|
NpdmProcess npdm;
|
||||||
|
|
||||||
npdm.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
npdm.setInputFile(inputFile);
|
||||||
npdm.setKeyCfg(user_set.getKeyCfg());
|
npdm.setKeyCfg(user_set.getKeyCfg());
|
||||||
npdm.setCliOutputMode(user_set.getCliOutputMode());
|
npdm.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
npdm.setVerifyMode(user_set.isVerifyFile());
|
npdm.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
@ -122,7 +125,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
CnmtProcess cnmt;
|
CnmtProcess cnmt;
|
||||||
|
|
||||||
cnmt.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
cnmt.setInputFile(inputFile);
|
||||||
cnmt.setCliOutputMode(user_set.getCliOutputMode());
|
cnmt.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
cnmt.setVerifyMode(user_set.isVerifyFile());
|
cnmt.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
@ -132,7 +135,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
NsoProcess obj;
|
NsoProcess obj;
|
||||||
|
|
||||||
obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
obj.setInputFile(inputFile);
|
||||||
obj.setCliOutputMode(user_set.getCliOutputMode());
|
obj.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
obj.setVerifyMode(user_set.isVerifyFile());
|
obj.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
@ -146,7 +149,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
NroProcess obj;
|
NroProcess obj;
|
||||||
|
|
||||||
obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
obj.setInputFile(inputFile);
|
||||||
obj.setCliOutputMode(user_set.getCliOutputMode());
|
obj.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
obj.setVerifyMode(user_set.isVerifyFile());
|
obj.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
@ -169,7 +172,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
NacpProcess nacp;
|
NacpProcess nacp;
|
||||||
|
|
||||||
nacp.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
nacp.setInputFile(inputFile);
|
||||||
nacp.setCliOutputMode(user_set.getCliOutputMode());
|
nacp.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
nacp.setVerifyMode(user_set.isVerifyFile());
|
nacp.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
@ -179,7 +182,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
PkiCertProcess cert;
|
PkiCertProcess cert;
|
||||||
|
|
||||||
cert.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
cert.setInputFile(inputFile);
|
||||||
cert.setKeyCfg(user_set.getKeyCfg());
|
cert.setKeyCfg(user_set.getKeyCfg());
|
||||||
cert.setCliOutputMode(user_set.getCliOutputMode());
|
cert.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
cert.setVerifyMode(user_set.isVerifyFile());
|
cert.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
@ -190,7 +193,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
EsTikProcess tik;
|
EsTikProcess tik;
|
||||||
|
|
||||||
tik.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
tik.setInputFile(inputFile);
|
||||||
tik.setKeyCfg(user_set.getKeyCfg());
|
tik.setKeyCfg(user_set.getKeyCfg());
|
||||||
tik.setCertificateChain(user_set.getCertificateChain());
|
tik.setCertificateChain(user_set.getCertificateChain());
|
||||||
tik.setCliOutputMode(user_set.getCliOutputMode());
|
tik.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
|
@ -202,7 +205,7 @@ int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
AssetProcess obj;
|
AssetProcess obj;
|
||||||
|
|
||||||
obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
obj.setInputFile(inputFile);
|
||||||
obj.setCliOutputMode(user_set.getCliOutputMode());
|
obj.setCliOutputMode(user_set.getCliOutputMode());
|
||||||
obj.setVerifyMode(user_set.isVerifyFile());
|
obj.setVerifyMode(user_set.isVerifyFile());
|
||||||
|
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
#define BIN_NAME "nstool"
|
#define BIN_NAME "nstool"
|
||||||
#define VER_MAJOR 1
|
#define VER_MAJOR 1
|
||||||
#define VER_MINOR 0
|
#define VER_MINOR 0
|
||||||
#define VER_PATCH 3
|
#define VER_PATCH 5
|
||||||
#define AUTHORS "jakcron"
|
#define AUTHORS "jakcron"
|
Loading…
Reference in a new issue