diff --git a/lib/libes/libes.vcxproj b/lib/libes/libes.vcxproj
index 9c25a22..b1fe783 100644
--- a/lib/libes/libes.vcxproj
+++ b/lib/libes/libes.vcxproj
@@ -20,7 +20,7 @@
{7BE99936-0D40-410D-944B-4513C2EFF8DC}
- 8.1
+ 10.0.16299.0
diff --git a/lib/libfnd/include/fnd/BitMath.h b/lib/libfnd/include/fnd/BitMath.h
index f3a4ceb..722036a 100644
--- a/lib/libfnd/include/fnd/BitMath.h
+++ b/lib/libfnd/include/fnd/BitMath.h
@@ -1,8 +1,6 @@
/*
BitMath.h
(c) 2018 Jakcron
-
-This is a 0x40 byte header to prepend to raw EXEFS .code binaries that provide enough data to be equivalent to an ELF.
*/
#pragma once
@@ -12,3 +10,5 @@ This is a 0x40 byte header to prepend to raw EXEFS .code binaries that provide e
// Bit math macros
#define _BIT(n) BIT(n)
#define _HAS_BIT(val, bit) (((val) & _BIT(bit)) != 0)
+#define _SET_BIT(val, bit) ((val) |= _BIT(bit))
+#define _BITMASK(width) (_BIT(width)-1)
\ No newline at end of file
diff --git a/lib/libfnd/include/fnd/SharedPtr.h b/lib/libfnd/include/fnd/SharedPtr.h
new file mode 100644
index 0000000..e976d4e
--- /dev/null
+++ b/lib/libfnd/include/fnd/SharedPtr.h
@@ -0,0 +1,141 @@
+#pragma once
+#include
+#include
+
+namespace fnd
+{
+ template
+ class SharedPtr
+ {
+ public:
+ SharedPtr();
+
+ // constructor for creating owner object
+ SharedPtr(T* ptr);
+
+ // copy constructor
+ SharedPtr(const SharedPtr& other);
+
+ // destructor
+ ~SharedPtr();
+
+ // own operator
+ void operator=(T* ptr);
+
+ // copy operator
+ void operator=(const SharedPtr& other);
+
+ // access ptr
+ const T* operator*() const;
+ T* operator*();
+
+ private:
+ T* mPtr;
+ size_t* mRefCnt;
+
+ void deletePtr();
+ };
+
+ template
+ inline SharedPtr::SharedPtr() :
+ mPtr(nullptr),
+ mRefCnt(new size_t)
+ {
+ *mRefCnt = 0;
+ }
+
+ template
+ inline SharedPtr::SharedPtr(T* ptr) :
+ SharedPtr()
+ {
+ *this = ptr;
+ }
+
+ template
+ inline SharedPtr::SharedPtr(const SharedPtr& other) :
+ SharedPtr()
+ {
+ *this = other;
+ }
+
+ template
+ inline SharedPtr::~SharedPtr()
+ {
+ deletePtr();
+ }
+
+ template
+ inline void SharedPtr::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
+ inline void SharedPtr::operator=(const SharedPtr& other)
+ {
+ deletePtr();
+
+ mPtr = other.mPtr;
+ mRefCnt = other.mRefCnt;
+ *mRefCnt += 1;
+ }
+
+ template
+ inline const T* SharedPtr::operator*() const
+ {
+ return mPtr;
+ }
+
+ template
+ inline T* SharedPtr::operator*()
+ {
+ return mPtr;
+ }
+
+ template
+ inline void SharedPtr::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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/libfnd/include/fnd/SimpleTextOutput.h b/lib/libfnd/include/fnd/SimpleTextOutput.h
index bbf8e73..15c3c8e 100644
--- a/lib/libfnd/include/fnd/SimpleTextOutput.h
+++ b/lib/libfnd/include/fnd/SimpleTextOutput.h
@@ -1,5 +1,7 @@
#pragma once
+#include
#include
+#include
namespace fnd
{
@@ -10,6 +12,9 @@ namespace fnd
static void hxdStyleDump(const byte_t* data, size_t len);
static void hexDump(const byte_t* data, size_t len, size_t row_len, size_t indent_len);
static void hexDump(const byte_t* data, size_t len);
+ static std::string arrayToString(const byte_t* data, size_t len, bool upper_case, const std::string& separator);
+ static void stringToArray(const std::string& str, fnd::Vec& array);
+
private:
static const size_t kDefaultRowLen = 0x10;
static const size_t kDefaultByteGroupingSize = 1;
diff --git a/lib/libfnd/include/fnd/ecdsa.h b/lib/libfnd/include/fnd/ecdsa.h
index e06880e..aa9e48b 100644
--- a/lib/libfnd/include/fnd/ecdsa.h
+++ b/lib/libfnd/include/fnd/ecdsa.h
@@ -21,8 +21,8 @@ namespace fnd
void operator=(const sEcdsa240Point& other)
{
- memcpy(this->r, r, kEcdsa240Size);
- memcpy(this->s, s, kEcdsa240Size);
+ memcpy(this->r, other.r, kEcdsa240Size);
+ memcpy(this->s, other.s, kEcdsa240Size);
}
bool operator==(const sEcdsa240Point& other) const
@@ -43,7 +43,7 @@ namespace fnd
void operator=(const sEcdsa240PrivateKey& other)
{
- memcpy(this->k, k, kEcdsa240Size);
+ memcpy(this->k, other.k, kEcdsa240Size);
}
bool operator==(const sEcdsa240PrivateKey& other) const
@@ -56,6 +56,28 @@ namespace fnd
return !operator==(other);
}
};
+
+ struct sEcdsa240Key
+ {
+ sEcdsa240Point pub;
+ sEcdsa240PrivateKey pvt;
+
+ void operator=(const sEcdsa240Key& other)
+ {
+ this->pub = other.pub;
+ this->pvt = other.pvt;
+ }
+
+ bool operator==(const sEcdsa240Key& other) const
+ {
+ return this->pub == other.pub && this->pvt == other.pvt;
+ }
+
+ bool operator!=(const sEcdsa240Key& other) const
+ {
+ return !operator==(other);
+ }
+ };
#pragma pack (pop)
}
}
diff --git a/lib/libfnd/include/fnd/elf.h b/lib/libfnd/include/fnd/elf.h
index d46d20d..0f32ccd 100644
--- a/lib/libfnd/include/fnd/elf.h
+++ b/lib/libfnd/include/fnd/elf.h
@@ -1,216 +1,458 @@
#pragma once
#include "types.h"
-typedef byte_t Elf_Byte;
-typedef word_t Elf32_Addr;
-typedef word_t Elf32_Off;
-typedef long_t Elf32_Sword; // lol "sword"
-typedef word_t Elf32_Word;
-typedef hword_t Elf32_Half;
-
-enum
+namespace fnd
{
- EI_MAG0 = 0, // 0x7F
- EI_MAG1 = 1, // 'E'
- EI_MAG2 = 2, // 'L'
- EI_MAG3 = 3, // 'F'
- EI_CLASS = 4, // File class
- EI_DATA = 5, // Data encoding
- EI_VERSION = 6, // File version
- EI_PAD = 7, // Start of padding bytes
- EI_NIDENT = 16 // Size of e_ident[]
-};
+ namespace elf
+ {
+ /* These constants are for the segment types stored in the image headers */
+ enum SegmentType
+ {
+ PT_NULL = 0,
+ PT_LOAD = 1,
+ PT_DYNAMIC = 2,
+ PT_INTERP = 3,
+ PT_NOTE = 4,
+ PT_SHLIB = 5,
+ PT_PHDR = 6,
+ PT_TLS = 7, /* Thread local storage segment */
+ PT_LOOS = 0x60000000, /* OS-specific */
+ PT_HIOS = 0x6fffffff, /* OS-specific */
+ PT_LOPROC = 0x70000000,
+ PT_HIPROC = 0x7fffffff
+ };
-typedef struct
-{
- unsigned char e_ident[EI_NIDENT]; // Identification bytes
- Elf32_Half e_type; // Object file type
- Elf32_Half e_machine; // Object architecture
- Elf32_Word e_version; // Object file version
- Elf32_Addr e_entry; // Object entry point
- Elf32_Off e_phoff; // Program header file offset
- Elf32_Off e_shoff; // Section header file offset
- Elf32_Word e_flags; // Processor-specific flags
- Elf32_Half e_ehsize; // ELF header size
- Elf32_Half e_phentsize; // Program header entry size
- Elf32_Half e_phnum; // Program header entries
- Elf32_Half e_shentsize; // Section header entry size
- Elf32_Half e_shnum; // Section header entries
- Elf32_Half e_shstrndx; // String table index
-} Elf32_Ehdr;
+ /* These constants define the different elf file types */
+ enum ElfType
+ {
+ ET_NONE = 0,
+ ET_REL = 1,
+ ET_EXEC = 2,
+ ET_DYN = 3,
+ ET_CORE = 4,
+ ET_LOPROC = 0xff00,
+ ET_HIPROC = 0xffff
+ };
-typedef struct
-{
- Elf32_Word p_type; // Segment type
- Elf32_Off p_offset; // File offset
- Elf32_Addr p_vaddr; // Virtual address
- Elf32_Addr p_paddr; // Physical address
- Elf32_Word p_filesz; // File image size
- Elf32_Word p_memsz; // Memory image size
- Elf32_Word p_flags; // Segment flags
- Elf32_Word p_align; // Alignment value
-} Elf32_Phdr;
+ /* This is the info that is needed to parse the dynamic section of the file */
+ enum DynamicSectionType
+ {
+ DT_NULL = 0,
+ DT_NEEDED = 1,
+ DT_PLTRELSZ = 2,
+ DT_PLTGOT = 3,
+ DT_HASH = 4,
+ DT_STRTAB = 5,
+ DT_SYMTAB = 6,
+ DT_RELA = 7,
+ DT_RELASZ = 8,
+ DT_RELAENT = 9,
+ DT_STRSZ = 10,
+ DT_SYMENT = 11,
+ DT_INIT = 12,
+ DT_FINI = 13,
+ DT_SONAME = 14,
+ DT_RPATH = 15,
+ DT_SYMBOLIC = 16,
+ DT_REL = 17,
+ DT_RELSZ = 18,
+ DT_RELENT = 19,
+ DT_PLTREL = 20,
+ DT_DEBUG = 21,
+ DT_TEXTREL = 22,
+ DT_JMPREL = 23,
+ DT_ENCODING = 32,
+ OLD_DT_LOOS = 0x60000000,
+ DT_LOOS = 0x6000000d,
+ DT_HIOS = 0x6ffff000,
+ DT_VALRNGLO = 0x6ffffd00,
+ DT_VALRNGHI = 0x6ffffdff,
+ DT_ADDRRNGLO = 0x6ffffe00,
+ DT_ADDRRNGHI = 0x6ffffeff,
+ DT_VERSYM = 0x6ffffff0,
+ DT_RELACOUNT = 0x6ffffff9,
+ DT_RELCOUNT = 0x6ffffffa,
+ DT_FLAGS_1 = 0x6ffffffb,
+ DT_VERDEF = 0x6ffffffc,
+ DT_VERDEFNUM = 0x6ffffffd,
+ DT_VERNEED = 0x6ffffffe,
+ DT_VERNEEDNUM = 0x6fffffff,
+ OLD_DT_HIOS = 0x6fffffff,
+ DT_LOPROC = 0x70000000,
+ DT_HIPROC = 0x7fffffff
+ };
-typedef struct
-{
- Elf32_Word sh_name; // Name (index into section header string table section)
- Elf32_Word sh_type; // Type
- Elf32_Word sh_flags; // Flags
- Elf32_Addr sh_addr; // Address
- Elf32_Off sh_offset; // File offset
- Elf32_Word sh_size; // Section size
- Elf32_Word sh_link; // Section header table index link
- Elf32_Word sh_info; // Extra information
- Elf32_Word sh_addralign; // Address alignment
- Elf32_Word sh_entsize; // Section entry size
-} Elf32_Shdr;
+ /* This info is needed when parsing the symbol table */
+ enum SymbolBinding
+ {
+ STB_LOCAL = 0,
+ STB_GLOBAL = 1,
+ STB_WEAK = 2,
+ STB_LOOS = 10,
+ STB_HIOS = 12,
+ STB_LOPROC,
+ STB_HIPROC = 0xf
+ };
-typedef struct
-{
- Elf32_Addr r_offset; // Offset of relocation
- Elf32_Word r_info; // Symbol table index and type
-} Elf32_Rel;
+ enum SymbolType
+ {
+ STT_NOTYPE = 0,
+ STT_OBJECT = 1,
+ STT_FUNC = 2,
+ STT_SECTION = 3,
+ STT_FILE = 4,
+ STT_COMMON = 5,
+ STT_TLS = 6,
+ STT_LOOS = 10,
+ STT_HIOS = 12,
+ STT_LOPROC,
+ STT_HIPROC = 0xf
+ };
-typedef struct
-{
- Elf32_Word st_name; // Name - index into string table
- Elf32_Addr st_value; // Symbol value
- Elf32_Word st_size; // Symbol size
- unsigned char st_info; // Type and binding
- unsigned char st_other; // Visibility
- Elf32_Half st_shndx; // Section header index
-} Elf32_Sym;
+ /* These constants define the permissions on sections in the program
+ header, p_flags. */
+ enum PermissionFlag
+ {
+ PF_R = 0x4,
+ PF_W = 0x2,
+ PF_X = 0x1
+ };
-enum
-{
- ET_NONE = 0, // No file type
- ET_REL = 1, // Relocatable file
- ET_EXEC = 2, // Executable file
- ET_DYN = 3, // Shared object file
- ET_CORE = 4, // Core file
-};
+ /* sh_type */
+ enum SectionHeaderType
+ {
+ SHT_NULL = 0,
+ SHT_PROGBITS = 1,
+ SHT_SYMTAB = 2,
+ SHT_STRTAB = 3,
+ SHT_RELA = 4,
+ SHT_HASH = 5,
+ SHT_DYNAMIC = 6,
+ SHT_NOTE = 7,
+ SHT_NOBITS = 8,
+ SHT_REL = 9,
+ SHT_SHLIB = 10,
+ SHT_DYNSYM = 11,
+ SHT_NUM = 12,
+ SHT_LOPROC = 0x70000000,
+ SHT_HIPROC = 0x7fffffff,
+ SHT_LOUSER = 0x80000000,
+ SHT_HIUSER = 0xffffffff
+ };
+
+ /* sh_flags */
+ enum SectionHeaderFlag
+ {
+ SHF_WRITE = 0x1,
+ SHF_ALLOC = 0x2,
+ SHF_EXECINSTR = 0x4,
+ SHF_RELA_LIVEPATCH = 0x00100000,
+ SHF_RO_AFTER_INIT = 0x00200000,
+ SHF_MASKPROC = 0xf0000000
+ };
+
+ /* special section indexes */
+ enum SpecialSectionIndex
+ {
+ SHN_UNDEF = 0,
+ SHN_LORESERVE = 0xff00,
+ SHN_LOPROC = 0xff00,
+ SHN_HIPROC = 0xff1f,
+ SHN_LOOS = 0xff20,
+ SHN_HIOS = 0xff3f,
+ SHN_ABS = 0xfff1,
+ SHN_COMMON = 0xfff2,
+ SHN_HIRESERVE = 0xffff
+ };
-enum
-{
- ET_ARM = 40 // ARM architecture
-};
+ enum ElfIdentIndex
+ {
+ EI_MAG0 = 0, /* e_ident[] indexes */
+ EI_MAG1 = 1,
+ EI_MAG2 = 2,
+ EI_MAG3 = 3,
+ EI_CLASS = 4,
+ EI_DATA = 5,
+ EI_VERSION = 6,
+ EI_OSABI = 7,
+ EI_PAD = 8
+ };
-enum
-{
- EV_NONE = 0, // Invalid version
- EV_CURRENT = 1 // Current version
-};
+ enum ElfClass
+ {
+ ELFCLASSNONE = 0, /* EI_CLASS */
+ ELFCLASS32 = 1,
+ ELFCLASS64 = 2,
+ ELFCLASSNUM = 3
+ };
+
+ enum ElfData
+ {
+ ELFDATANONE = 0, /* e_ident[EI_DATA] */
+ ELFDATA2LSB = 1,
+ ELFDATA2MSB = 2
+ };
+
+ enum ElfVersion
+ {
+ EV_NONE = 0, /* e_version, EI_VERSION */
+ EV_CURRENT = 1,
+ EV_NUM = 2,
+ };
+
+ enum ElfOsAbi
+ {
+ ELFOSABI_NONE = 0,
+ ELFOSABI_LINUX =3
+ };
+
-#define ELF_MAGIC "\177ELF"
+ /*
+ * Notes used in ET_CORE. Architectures export some of the arch register sets
+ * using the corresponding note types via the PTRACE_GETREGSET and
+ * PTRACE_SETREGSET requests.
+ */
+ enum NoteType
+ {
+ NT_PRSTATUS = 1,
+ NT_PRFPREG = 2,
+ NT_PRPSINFO = 3,
+ NT_TASKSTRUCT = 4,
+ NT_AUXV = 6,
+ /*
+ * Note to userspace developers: size of NT_SIGINFO note may increase
+ * in the future to accomodate more fields, don't assume it is fixed!
+ */
+ NT_SIGINFO = 0x53494749,
+ NT_FILE = 0x46494c45,
+ NT_PRXFPREG = 0x46e62b7f, /* copied from gdb5.1/include/elf/common.h */
+ NT_PPC_VMX = 0x100, /* PowerPC Altivec/VMX registers */
+ NT_PPC_SPE = 0x101, /* PowerPC SPE/EVR registers */
+ NT_PPC_VSX = 0x102, /* PowerPC VSX registers */
+ NT_PPC_TAR = 0x103, /* Target Address Register */
+ NT_PPC_PPR = 0x104, /* Program Priority Register */
+ NT_PPC_DSCR = 0x105, /* Data Stream Control Register */
+ NT_PPC_EBB = 0x106, /* Event Based Branch Registers */
+ NT_PPC_PMU = 0x107, /* Performance Monitor Registers */
+ NT_PPC_TM_CGPR = 0x108, /* TM checkpointed GPR Registers */
+ NT_PPC_TM_CFPR = 0x109, /* TM checkpointed FPR Registers */
+ NT_PPC_TM_CVMX = 0x10a, /* TM checkpointed VMX Registers */
+ NT_PPC_TM_CVSX = 0x10b, /* TM checkpointed VSX Registers */
+ NT_PPC_TM_SPR = 0x10c, /* TM Special Purpose Registers */
+ NT_PPC_TM_CTAR = 0x10d, /* TM checkpointed Target Address Register */
+ NT_PPC_TM_CPPR = 0x10e, /* TM checkpointed Program Priority Register */
+ NT_PPC_TM_CDSCR = 0x10f, /* TM checkpointed Data Stream Control Register */
+ NT_PPC_PKEY = 0x110, /* Memory Protection Keys registers */
+ NT_386_TLS = 0x200, /* i386 TLS slots (struct user_desc) */
+ NT_386_IOPERM = 0x201, /* x86 io permission bitmap (1=deny) */
+ NT_X86_XSTATE = 0x202, /* x86 extended state using xsave */
+ NT_S390_HIGH_GPRS = 0x300, /* s390 upper register halves */
+ NT_S390_TIMER = 0x301, /* s390 timer register */
+ NT_S390_TODCMP = 0x302, /* s390 TOD clock comparator register */
+ NT_S390_TODPREG = 0x303, /* s390 TOD programmable register */
+ NT_S390_CTRS = 0x304, /* s390 control registers */
+ NT_S390_PREFIX = 0x305, /* s390 prefix register */
+ NT_S390_LAST_BREAK = 0x306, /* s390 breaking event address */
+ NT_S390_SYSTEM_CALL = 0x307, /* s390 system call restart data */
+ NT_S390_TDB = 0x308, /* s390 transaction diagnostic block */
+ NT_S390_VXRS_LOW = 0x309, /* s390 vector registers 0-15 upper half */
+ NT_S390_VXRS_HIGH = 0x30a, /* s390 vector registers 16-31 */
+ NT_S390_GS_CB = 0x30b, /* s390 guarded storage registers */
+ NT_S390_GS_BC = 0x30c, /* s390 guarded storage broadcast control block */
+ NT_S390_RI_CB = 0x30d, /* s390 runtime instrumentation */
+ NT_ARM_VFP = 0x400, /* ARM VFP/NEON registers */
+ NT_ARM_TLS = 0x401, /* ARM TLS register */
+ NT_ARM_HW_BREAK = 0x402, /* ARM hardware breakpoint registers */
+ NT_ARM_HW_WATCH = 0x403, /* ARM hardware watchpoint registers */
+ NT_ARM_SYSTEM_CALL = 0x404, /* ARM system call number */
+ NT_ARM_SVE = 0x405, /* ARM Scalable Vector Extension registers */
+ NT_ARC_V2 = 0x600, /* ARCv2 accumulator/extra registers */
+ NT_VMCOREDD = 0x700, /* Vmcore Device Dump Note */
+ NT_MIPS_DSP = 0x800, /* MIPS DSP ASE registers */
+ NT_MIPS_FP_MODE = 0x801, /* MIPS floating-point mode */
+ };
+
+ static const size_t kEIdentSize = 0x10;
+ static const byte_t kElfMagic[sizeof(uint32_t)] = {0x7f, 'E', 'L', 'F'};
-enum
-{
- ELFDATANONE = 0, // Invalid data encoding
- ELFDATA2LSB = 1, // Little endian
- ELFDATA2MSB = 2, // Big endian
-};
-enum
-{
- PT_NULL = 0, // Unused
- PT_LOAD = 1, // Loadable segment
- PT_DYNAMIC = 2, // Dynamic linking information
- PT_INTERP = 3, // Interpreter
- PT_NOTE = 4, // Auxiliary information
- PT_SHLIB = 5, // Reserved
- PT_PHDR = 6 // Program header table
-};
+ inline byte_t get_elf_st_bind(byte_t st_info) { return st_info >> 4; }
+ inline byte_t get_elf_st_type(byte_t st_info) { return st_info & 0xf; }
+ inline byte_t get_elf_st_info(byte_t st_bind, byte_t st_type) { return (st_type & 0xf) | ((st_bind & 0xf) << 4);}
-enum
-{
- PF_R = 4, // Read flag
- PF_W = 2, // Write flag
- PF_X = 1, // Execute flag
- PF_OS_SHARED = 0x100000, // OS-specific
- PF_CTRSDK = 0x80000000, // Set in CTRSDK ELF Text segments
-};
+ /* The following are used with relocations */
+ #define ELF32_R_SYM(x) ((x) >> 8)
+ #define ELF32_R_TYPE(x) ((x) & 0xff)
-enum
-{
- SHN_LORESERVE = 0xFF00,
- SHN_HIRESERVE = 0xFFFF
-};
+ #define ELF64_R_SYM(i) ((i) >> 32)
+ #define ELF64_R_TYPE(i) ((i) & 0xffffffff)
+ }
-enum
-{
- SHT_NULL = 0, // Inactive
- SHT_PROGBITS = 1, // Program defined information
- SHT_SYMTAB = 2, // Symbol table section
- SHT_STRTAB = 3, // String table section
- SHT_RELA = 4, // Relocation section with addends
- SHT_HASH = 5, // Symbol hash table section
- SHT_DYNAMIC = 6, // Dynamic section
- SHT_NOTE = 7, // Note section
- SHT_NOBITS = 8, // No space section
- SHT_REL = 9, // Relation section without addends
- SHT_SHLIB = 10, // Reserved
- SHT_DYNSYM = 11, // Dynamic symbol table section
- SHT_NUM = 12, // Number of section types
- SHT_LOPROC = 0x70000000, // Reserved range for processor
- SHT_ARM_EXIDX = 0x70000001, // ARM exception index table
- SHT_HIPROC = 0x7fffffff, // Specific section header types
- SHT_LOUSER = 0x80000000, // Reserved range for application
- SHT_HIUSER = 0xffffffff // Specific indexes
-};
+ struct Elf32_Dyn
+ {
+ int32_t d_tag;
+ union{
+ int32_t d_val;
+ uint32_t d_ptr;
+ } d_un;
+ };
-enum
-{
- SHF_WRITE = 1, // Writable section
- SHF_ALLOC = 2, // Loadable section
- SHF_EXECINSTR = 4, // Executable section
- SHF_MASKPROC = 0xf0000000, // Processor-specific
-};
+ struct Elf64_Dyn
+ {
+ int64_t d_tag; /* entry tag value */
+ union {
+ uint64_t d_val;
+ uint64_t d_ptr;
+ } d_un;
+ };
-#define ELF32_R_SYM(i) ((i) >> 8)
-#define ELF32_R_TYPE(i) ((unsigned char)(i))
-#define ELF32_R_INFO(s,t) (((s) << 8) + (unsigned char)(t))
+ struct Elf32_Rel
+ {
+ uint32_t r_offset;
+ uint32_t r_info;
+ };
-enum
-{
- R_ARM_NONE = 0,
- R_ARM_PC24 = 1,
- R_ARM_ABS32 = 2,
- R_ARM_REL32 = 3,
- R_ARM_THM_CALL = 10,
- R_ARM_PLT32 = 27,
- R_ARM_CALL = 28,
- R_ARM_JUMP24 = 29,
- R_ARM_TARGET1 = 38,
- R_ARM_TARGET2 = 41,
- R_ARM_PREL31 = 42,
- R_ARM_THM_JUMP11 = 102,
- R_ARM_THM_JUMP8 = 103
-};
+ struct Elf64_Rel
+ {
+ uint64_t r_offset; /* Location at which to apply the action */
+ uint64_t r_info; /* index and type of relocation */
+ };
-// Symbol scope
-enum
-{
- STB_LOCAL = 0,
- STB_GLOBAL = 1,
- STB_WEAK = 2
-};
+ struct Elf32_Rela
+ {
+ uint32_t r_offset;
+ uint32_t r_info;
+ int32_t r_addend;
+ };
-#define ELF32_ST_BIND(i) (((unsigned char)(i)) >> 4)
-#define ELF32_ST_TYPE(val) ((val) & 0xf)
+ struct Elf64_Rela
+ {
+ uint64_t r_offset; /* Location at which to apply the action */
+ uint64_t r_info; /* index and type of relocation */
+ int64_t r_addend; /* Constant addend used to compute value */
+ };
-// Symbol type
-enum
-{
- STT_NOTYPE = 0,
- STT_OBJECT = 1,
- STT_FUNC = 2
-};
+ struct Elf32_Sym
+ {
+ uint32_t st_name;
+ uint32_t st_value;
+ uint32_t st_size;
+ byte_t st_info;
+ byte_t st_other;
+ uint16_t st_shndx;
+ };
-// Symbol visibility
-enum
-{
- STV_DEFAULT = 0,
- STV_INTERNAL = 1,
- STV_HIDDEN = 2,
- STV_PROTECTED = 3
-};
+ struct Elf64_Sym
+ {
+ uint32_t st_name; /* Symbol name, index in string tbl */
+ byte_t st_info; /* Type and binding attributes */
+ byte_t st_other; /* No defined meaning, 0 */
+ uint16_t st_shndx; /* Associated section index */
+ uint64_t st_value; /* Value of the symbol */
+ uint64_t st_size; /* Associated symbol size */
+ };
+
+ struct Elf32_Ehdr
+ {
+ byte_t e_ident[elf::kEIdentSize];
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint32_t e_entry; /* Entry point */
+ uint32_t e_phoff;
+ uint32_t e_shoff;
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+ };
+
+ struct Elf64_Ehdr
+ {
+ byte_t e_ident[elf::kEIdentSize]; /* ELF "magic number" */
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint64_t e_entry; /* Entry point virtual address */
+ uint64_t e_phoff; /* Program header table file offset */
+ uint64_t e_shoff; /* Section header table file offset */
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+ };
+
+ struct Elf32_Phdr
+ {
+ uint32_t p_type;
+ uint32_t p_offset;
+ uint32_t p_vaddr;
+ uint32_t p_paddr;
+ uint32_t p_filesz;
+ uint32_t p_memsz;
+ uint32_t p_flags;
+ uint32_t p_align;
+ };
+
+ struct Elf64_Phdr
+ {
+ uint32_t p_type;
+ uint32_t p_flags;
+ uint64_t p_offset; /* Segment file offset */
+ uint64_t p_vaddr; /* Segment virtual address */
+ uint64_t p_paddr; /* Segment physical address */
+ uint64_t p_filesz; /* Segment size in file */
+ uint64_t p_memsz; /* Segment size in memory */
+ uint64_t p_align; /* Segment alignment, file & memory */
+ };
+
+ struct Elf32_Shdr
+ {
+ uint32_t sh_name;
+ uint32_t sh_type;
+ uint32_t sh_flags;
+ uint32_t sh_addr;
+ uint32_t sh_offset;
+ uint32_t sh_size;
+ uint32_t sh_link;
+ uint32_t sh_info;
+ uint32_t sh_addralign;
+ uint32_t sh_entsize;
+ };
+
+ struct Elf64_Shdr
+ {
+ uint32_t sh_name; /* Section name, index in string tbl */
+ uint32_t sh_type; /* Type of section */
+ uint64_t sh_flags; /* Miscellaneous section attributes */
+ uint64_t sh_addr; /* Section virtual addr at execution */
+ uint64_t sh_offset; /* Section file offset */
+ uint64_t sh_size; /* Size of section in bytes */
+ uint32_t sh_link; /* Index of another section */
+ uint32_t sh_info; /* Additional section information */
+ uint64_t sh_addralign; /* Section alignment */
+ uint64_t sh_entsize; /* Entry size if section holds table */
+ };
+
+ /* Note header in a PT_NOTE section */
+ struct Elf32_Nhdr
+ {
+ uint32_t n_namesz; /* Name size */
+ uint32_t n_descsz; /* Content size */
+ uint32_t n_type; /* Content type */
+ };
+
+ /* Note header in a PT_NOTE section */
+ struct Elf64_Nhdr
+ {
+ uint32_t n_namesz; /* Name size */
+ uint32_t n_descsz; /* Content size */
+ uint32_t n_type; /* Content type */
+ };
+}
\ No newline at end of file
diff --git a/lib/libfnd/include/fnd/rsa.h b/lib/libfnd/include/fnd/rsa.h
index 455fd21..fd05987 100644
--- a/lib/libfnd/include/fnd/rsa.h
+++ b/lib/libfnd/include/fnd/rsa.h
@@ -114,7 +114,7 @@ namespace fnd
//int rsaSign(const sRsa1024Key& key, sha::HashType hash_type, const uint8_t* hash, uint8_t signature[kRsa1024Size]);
//int rsaVerify(const sRsa1024Key& key, sha::HashType hash_type, const uint8_t* hash, const uint8_t signature[kRsa1024Size]);
// rsa2048
- //int rsaSign(const sRsa2048Key& key, sha::HashType hash_type, const uint8_t* hash, uint8_t signature[kRsa2048Size]);
+ int rsaSign(const sRsa2048Key& key, sha::HashType hash_type, const uint8_t* hash, uint8_t signature[kRsa2048Size]);
int rsaVerify(const sRsa2048Key& key, sha::HashType hash_type, const uint8_t* hash, const uint8_t signature[kRsa2048Size]);
// rsa4096
//int rsaSign(const sRsa4096Key& key, sha::HashType hash_type, const uint8_t* hash, uint8_t signature[kRsa4096Size]);
diff --git a/lib/libfnd/libfnd.vcxproj b/lib/libfnd/libfnd.vcxproj
index b7d30e7..8be0a87 100644
--- a/lib/libfnd/libfnd.vcxproj
+++ b/lib/libfnd/libfnd.vcxproj
@@ -21,7 +21,7 @@
15.0
{4D27EDB9-5110-44FE-8CE2-D46C5AD3C55B}
- 10.0.15063.0
+ 10.0.16299.0
@@ -136,6 +136,7 @@
+
diff --git a/lib/libfnd/libfnd.vcxproj.filters b/lib/libfnd/libfnd.vcxproj.filters
index d13edab..1619016 100644
--- a/lib/libfnd/libfnd.vcxproj.filters
+++ b/lib/libfnd/libfnd.vcxproj.filters
@@ -63,6 +63,9 @@
Header Files
+
+ Header Files
+
Header Files
diff --git a/lib/libfnd/source/SimpleTextOutput.cpp b/lib/libfnd/source/SimpleTextOutput.cpp
index 7dbc17d..1ee71ce 100644
--- a/lib/libfnd/source/SimpleTextOutput.cpp
+++ b/lib/libfnd/source/SimpleTextOutput.cpp
@@ -1,5 +1,8 @@
-#include
+#include
+#include
+#include
#include
+#include
void fnd::SimpleTextOutput::hxdStyleDump(const byte_t* data, size_t len, size_t row_len, size_t byte_grouping_size)
{
@@ -58,31 +61,57 @@ void fnd::SimpleTextOutput::hxdStyleDump(const byte_t* data, size_t len)
void fnd::SimpleTextOutput::hexDump(const byte_t* data, size_t len, size_t row_len, size_t indent_len)
{
- for (size_t i = 0; i < len; i++)
+ for (size_t i = 0; i < len; i += row_len)
{
- if ((i % row_len) == 0)
- {
- if (i > 0)
- putchar('\n');
- for (size_t j = 0; j < indent_len; j++)
- {
- putchar(' ');
- }
- }
- printf("%02X", data[i]);
- if ((i+1) >= len)
- {
- putchar('\n');
- }
-
+ for (size_t j = 0; j < indent_len; j++)
+ std::cout << " ";
+ std::cout << arrayToString(data+i, _MIN(len-i, row_len), true, "") << std::endl;
}
}
void fnd::SimpleTextOutput::hexDump(const byte_t* data, size_t len)
{
+ std::cout << arrayToString(data, len, true, "") << std::endl;
+}
+
+std::string fnd::SimpleTextOutput::arrayToString(const byte_t* data, size_t len, bool upper_case, const std::string& separator)
+{
+ std::stringstream ss;
+
+ if (upper_case)
+ ss << std::uppercase;
for (size_t i = 0; i < len; i++)
{
- printf("%02X", data[i]);
+ ss << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)data[i];
+ if (i+1 < len)
+ ss << separator;
+ }
+ return ss.str();
+}
+
+inline byte_t charToByte(char chr)
+{
+ if (chr >= 'a' && chr <= 'f')
+ return (chr - 'a') + 0xa;
+ else if (chr >= 'A' && chr <= 'F')
+ return (chr - 'A') + 0xa;
+ else if (chr >= '0' && chr <= '9')
+ return chr - '0';
+ return 0;
+}
+
+void fnd::SimpleTextOutput::stringToArray(const std::string& str, fnd::Vec& array)
+{
+ size_t size = str.size();
+ if ((size % 2))
+ {
+ return;
+ }
+
+ array.alloc(size/2);
+
+ for (size_t i = 0; i < array.size(); i++)
+ {
+ array[i] = (charToByte(str[i * 2]) << 4) | charToByte(str[(i * 2) + 1]);
}
- putchar('\n');
}
\ No newline at end of file
diff --git a/lib/libfnd/source/rsa_wrapper.cpp b/lib/libfnd/source/rsa_wrapper.cpp
index 197a813..c6aee2a 100644
--- a/lib/libfnd/source/rsa_wrapper.cpp
+++ b/lib/libfnd/source/rsa_wrapper.cpp
@@ -1,6 +1,8 @@
#include
#include
#include
+#include
+#include
using namespace fnd::rsa;
using namespace fnd::sha;
@@ -165,6 +167,33 @@ int fnd::rsa::pkcs::rsaVerify(const sRsa4096Key & key, HashType hash_type, const
return ret;
}
+int fnd::rsa::pss::rsaSign(const sRsa2048Key & key, HashType hash_type, const uint8_t * hash, uint8_t signature[kRsa2048Size])
+{
+ int ret;
+ const char* pers = "fnd::rsa::pss::rsaSign";
+
+ // rsa
+ rsa_context rsa;
+ rsa_init(&rsa, RSA_PKCS_V21, getMdWrappedHashType(hash_type));
+ rsa.len = kRsa2048Size;
+ mpi_read_binary(&rsa.D, key.priv_exponent, rsa.len);
+ mpi_read_binary(&rsa.N, key.modulus, rsa.len);
+
+ entropy_context entropy;
+ entropy_init(&entropy);
+
+ ctr_drbg_context ctr_drbg;
+ ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, (const uint8_t*)pers, strlen(pers));
+
+ ret = rsa_rsassa_pss_sign(&rsa, ctr_drbg_random, &ctr_drbg, RSA_PRIVATE, getWrappedHashType(hash_type), getWrappedHashSize(hash_type), hash, signature);
+
+ rsa_free(&rsa);
+
+
+ return ret;
+}
+
+
int fnd::rsa::pss::rsaVerify(const sRsa2048Key & key, HashType hash_type, const uint8_t * hash, const uint8_t signature[kRsa2048Size])
{
static const uint8_t public_exponent[3] = { 0x01, 0x00, 0x01 };
diff --git a/lib/libhac/include/nn/hac/ContentMetaBinary.h b/lib/libhac/include/nn/hac/ContentMetaBinary.h
index 84f5d9c..8c57644 100644
--- a/lib/libhac/include/nn/hac/ContentMetaBinary.h
+++ b/lib/libhac/include/nn/hac/ContentMetaBinary.h
@@ -120,18 +120,18 @@ namespace hac
struct AddOnContentMetaExtendedHeader
{
uint64_t application_id;
- uint32_t required_system_version;
+ uint32_t required_application_version;
void operator=(const AddOnContentMetaExtendedHeader& other)
{
application_id = other.application_id;
- required_system_version = other.required_system_version;
+ required_application_version = other.required_application_version;
}
bool operator==(const AddOnContentMetaExtendedHeader& other) const
{
return (application_id == other.application_id) \
- && (required_system_version == other.required_system_version);
+ && (required_application_version == other.required_application_version);
}
bool operator!=(const AddOnContentMetaExtendedHeader& other) const
diff --git a/lib/libhac/include/nn/hac/IdConverter.h b/lib/libhac/include/nn/hac/IdConverter.h
new file mode 100644
index 0000000..40702ea
--- /dev/null
+++ b/lib/libhac/include/nn/hac/IdConverter.h
@@ -0,0 +1,21 @@
+#pragma once
+#include
+
+namespace nn
+{
+namespace hac
+{
+ class IdConverter
+ {
+ public:
+ static uint64_t convertToAocBaseId(uint64_t application_id);
+ static uint64_t convertToDeltaId(uint64_t application_id);
+ static uint64_t convertToPatchId(uint64_t application_id);
+
+ private:
+ static const uint64_t kAocBaseId = 0x1000;
+ static const uint64_t kDeltaId = 0xc00;
+ static const uint64_t kPatchId = 0x800;
+ };
+}
+}
\ No newline at end of file
diff --git a/lib/libhac/include/nn/hac/Result.h b/lib/libhac/include/nn/hac/Result.h
new file mode 100644
index 0000000..f13587a
--- /dev/null
+++ b/lib/libhac/include/nn/hac/Result.h
@@ -0,0 +1,39 @@
+#pragma once
+#include
+
+namespace nn
+{
+namespace hac
+{
+ class Result
+ {
+ public:
+ Result();
+ Result(uint32_t result);
+ Result(uint32_t module_num, uint32_t desc, uint32_t sub_desc);
+
+ void operator=(const Result& other);
+ bool operator==(const Result& other) const;
+ bool operator!=(const Result& other) const;
+
+ bool isSuccess() const;
+ bool isFailure() const;
+
+ uint32_t getInnerValue() const;
+ uint32_t getModuleNum() const;
+ uint32_t getDescription() const;
+ uint32_t getSubDescription() const;
+
+ private:
+ static const uint32_t kModuleNumBitWidth = 9;
+ static const uint32_t kModuleNumBitPos = 0;
+ static const uint32_t kDescriptionBitWidth = 13;
+ static const uint32_t kDescriptionBitPos = 9;
+ static const uint32_t kSubDescriptionBitWidth = 10;
+ static const uint32_t kSubDescriptionBitPos = 22;
+ inline uint32_t bitWidthToMask(uint32_t bit_width) const { return _BIT(bit_width) - 1; }
+
+ uint32_t mResult;
+ };
+}
+}
\ No newline at end of file
diff --git a/lib/libhac/include/nn/hac/cnmt.h b/lib/libhac/include/nn/hac/cnmt.h
index f7c8eb3..81871c0 100644
--- a/lib/libhac/include/nn/hac/cnmt.h
+++ b/lib/libhac/include/nn/hac/cnmt.h
@@ -118,7 +118,7 @@ namespace hac
struct sAddOnContentMetaExtendedHeader
{
le_uint64_t application_id;
- le_uint32_t required_system_version;
+ le_uint32_t required_application_version;
byte_t reserved[4];
};
diff --git a/lib/libhac/include/nn/hac/elf.h b/lib/libhac/include/nn/hac/elf.h
deleted file mode 100644
index 2083238..0000000
--- a/lib/libhac/include/nn/hac/elf.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#pragma once
-#include
-
-namespace nn
-{
-namespace hac
-{
- namespace elf
- {
- enum SpecialSectionIndex
- {
- SHN_UNDEF,
- SHN_LORESERVE = 0xFF00,
- SHN_LOPROC = 0xFF00,
- SHN_HIPROC = 0xFF1F,
- SHN_LOOS,
- SHN_HIOS = 0xFF3F,
- SHN_ABS = 0xFFF1,
- SHN_COMMON,
- SHN_HIRESERVE = 0xFFFF
- };
-
- enum SymbolType
- {
- STT_NOTYPE,
- STT_OBJECT,
- STT_FUNC,
- STT_SECTION,
- STT_FILE,
- STT_LOOS = 10,
- STT_HIOS = 12,
- STT_LOPROC,
- STT_HIPROC = 0xF
- };
-
- enum SymbolBinding
- {
- STB_LOCAL,
- STB_GLOBAL,
- STB_WEAK,
- STB_LOOS = 10,
- STB_HIOS = 12,
- STB_LOPROC,
- STB_HIPROC = 0xF
- };
- }
-
-#pragma pack(push,1)
- struct sElfSymbol32Bit
- {
- le_uint32_t name;
- le_uint32_t value;
- le_uint32_t size;
- le_uint32_t info;
- le_uint32_t other;
- le_uint32_t special_section_index;
- };
-
- struct sElfSymbol64Bit
- {
- le_uint32_t name;
- byte_t info;
- byte_t other;
- le_uint16_t special_section_index;
- le_uint64_t value;
- le_uint64_t size;
- };
-#pragma pack(pop)
-}
-}
\ No newline at end of file
diff --git a/lib/libhac/libhac.vcxproj b/lib/libhac/libhac.vcxproj
index 3ff63ae..db66da1 100644
--- a/lib/libhac/libhac.vcxproj
+++ b/lib/libhac/libhac.vcxproj
@@ -39,6 +39,7 @@
+
@@ -67,6 +68,7 @@
+
@@ -90,6 +92,7 @@
+
@@ -108,6 +111,7 @@
+
@@ -121,7 +125,7 @@
15.0
{91BA9E79-8242-4F7D-B997-0DFEC95EA22B}
hac
- 10.0.15063.0
+ 10.0.16299.0
libhac
diff --git a/lib/libhac/libhac.vcxproj.filters b/lib/libhac/libhac.vcxproj.filters
index 3c44384..2099435 100644
--- a/lib/libhac/libhac.vcxproj.filters
+++ b/lib/libhac/libhac.vcxproj.filters
@@ -183,6 +183,12 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
@@ -296,5 +302,11 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
\ No newline at end of file
diff --git a/lib/libhac/source/AccessControlInfoBinary.cpp b/lib/libhac/source/AccessControlInfoBinary.cpp
index cdf5a50..5a22449 100644
--- a/lib/libhac/source/AccessControlInfoBinary.cpp
+++ b/lib/libhac/source/AccessControlInfoBinary.cpp
@@ -34,14 +34,10 @@ bool nn::hac::AccessControlInfoBinary::operator!=(const AccessControlInfoBinary
void nn::hac::AccessControlInfoBinary::toBytes()
{
- if (mFileSystemAccessControl.getBytes().size() == 0)
- mFileSystemAccessControl.toBytes();
-
- if (mServiceAccessControl.getBytes().size() == 0)
- mServiceAccessControl.toBytes();
-
- if (mKernelCapabilities.getBytes().size() == 0)
- mKernelCapabilities.toBytes();
+ // serialise the sections
+ mFileSystemAccessControl.toBytes();
+ mServiceAccessControl.toBytes();
+ mKernelCapabilities.toBytes();
// determine section layout
struct sLayout {
@@ -74,6 +70,11 @@ void nn::hac::AccessControlInfoBinary::toBytes()
hdr->sac.size = sac.size;
hdr->kc.offset = kc.offset;
hdr->kc.size = kc.size;
+
+ // write data
+ memcpy(mRawBinary.data() + fac.offset, mFileSystemAccessControl.getBytes().data(), fac.size);
+ memcpy(mRawBinary.data() + sac.offset, mServiceAccessControl.getBytes().data(), sac.size);
+ memcpy(mRawBinary.data() + kc.offset, mKernelCapabilities.getBytes().data(), kc.size);
}
void nn::hac::AccessControlInfoBinary::fromBytes(const byte_t* data, size_t len)
diff --git a/lib/libhac/source/AccessControlInfoDescBinary.cpp b/lib/libhac/source/AccessControlInfoDescBinary.cpp
index 50ac86e..efd29c4 100644
--- a/lib/libhac/source/AccessControlInfoDescBinary.cpp
+++ b/lib/libhac/source/AccessControlInfoDescBinary.cpp
@@ -38,14 +38,10 @@ bool nn::hac::AccessControlInfoDescBinary::operator!=(const AccessControlInfoDes
void nn::hac::AccessControlInfoDescBinary::toBytes()
{
- if (mFileSystemAccessControl.getBytes().size() == 0)
- mFileSystemAccessControl.toBytes();
-
- if (mServiceAccessControl.getBytes().size() == 0)
- mServiceAccessControl.toBytes();
-
- if (mKernelCapabilities.getBytes().size() == 0)
- mKernelCapabilities.toBytes();
+ // serialise the sections
+ mFileSystemAccessControl.toBytes();
+ mServiceAccessControl.toBytes();
+ mKernelCapabilities.toBytes();
// determine section layout
struct sLayout {
@@ -91,6 +87,11 @@ void nn::hac::AccessControlInfoDescBinary::toBytes()
hdr->sac.size = sac.size;
hdr->kc.offset = kc.offset;
hdr->kc.size = kc.size;
+
+ // write data
+ memcpy(mRawBinary.data() + fac.offset, mFileSystemAccessControl.getBytes().data(), fac.size);
+ memcpy(mRawBinary.data() + sac.offset, mServiceAccessControl.getBytes().data(), sac.size);
+ memcpy(mRawBinary.data() + kc.offset, mKernelCapabilities.getBytes().data(), kc.size);
}
void nn::hac::AccessControlInfoDescBinary::fromBytes(const byte_t* data, size_t len)
@@ -157,7 +158,7 @@ void nn::hac::AccessControlInfoDescBinary::generateSignature(const fnd::rsa::sRs
byte_t hash[fnd::sha::kSha256HashLen];
fnd::sha::Sha256(mRawBinary.data() + fnd::rsa::kRsa2048Size, mRawBinary.size() - fnd::rsa::kRsa2048Size, hash);
- if (fnd::rsa::pkcs::rsaSign(key, fnd::sha::HASH_SHA256, hash, mRawBinary.data()) != 0)
+ if (fnd::rsa::pss::rsaSign(key, fnd::sha::HASH_SHA256, hash, mRawBinary.data()) != 0)
{
throw fnd::Exception(kModuleName, "Failed to sign Access Control Info Desc");
}
diff --git a/lib/libhac/source/ContentMetaBinary.cpp b/lib/libhac/source/ContentMetaBinary.cpp
index 22c5ab7..7ebd628 100644
--- a/lib/libhac/source/ContentMetaBinary.cpp
+++ b/lib/libhac/source/ContentMetaBinary.cpp
@@ -100,7 +100,7 @@ void nn::hac::ContentMetaBinary::fromBytes(const byte_t* data, size_t len)
break;
case (cnmt::METATYPE_ADD_ON_CONTENT):
mAddOnContentMetaExtendedHeader.application_id = ((sAddOnContentMetaExtendedHeader*)mExtendedHeader.data())->application_id.get();
- mAddOnContentMetaExtendedHeader.required_system_version = ((sAddOnContentMetaExtendedHeader*)mExtendedHeader.data())->required_system_version.get();
+ mAddOnContentMetaExtendedHeader.required_application_version = ((sAddOnContentMetaExtendedHeader*)mExtendedHeader.data())->required_application_version.get();
break;
case (cnmt::METATYPE_DELTA):
mDeltaMetaExtendedHeader.application_id = ((sDeltaMetaExtendedHeader*)mExtendedHeader.data())->application_id.get();
diff --git a/lib/libhac/source/FileSystemAccessControlBinary.cpp b/lib/libhac/source/FileSystemAccessControlBinary.cpp
index c8c7e94..18f08af 100644
--- a/lib/libhac/source/FileSystemAccessControlBinary.cpp
+++ b/lib/libhac/source/FileSystemAccessControlBinary.cpp
@@ -41,9 +41,17 @@ void nn::hac::FileSystemAccessControlBinary::toBytes()
} content, savedata;
content.offset = (uint32_t)align(sizeof(sFacHeader), fac::kSectionAlignSize);
- content.size = (uint32_t)(sizeof(uint32_t) + mContentOwnerIdList.size() * sizeof(uint64_t));
+ if (mContentOwnerIdList.size() > 0)
+ content.size = (uint32_t)(sizeof(uint32_t) + mContentOwnerIdList.size() * sizeof(uint64_t));
+ else
+ content.size = 0;
+
savedata.offset = (uint32_t)(content.offset + (content.size > 0 ? align(content.size, fac::kSectionAlignSize) : 0));
- savedata.size = (uint32_t)(sizeof(uint32_t) + align(mSaveDataOwnerIdList.size(), fac::kSectionAlignSize) + mSaveDataOwnerIdList.size() * sizeof(uint64_t));
+ if (mSaveDataOwnerIdList.size() > 0)
+ savedata.size = (uint32_t)(sizeof(uint32_t) + align(mSaveDataOwnerIdList.size(), fac::kSectionAlignSize) + mSaveDataOwnerIdList.size() * sizeof(uint64_t));
+ else
+ savedata.size = 0;
+
// get total size
size_t total_size = _MAX(_MAX(content.offset + content.size, savedata.offset + savedata.size), align(sizeof(sFacHeader), fac::kSectionAlignSize));
diff --git a/lib/libhac/source/IdConverter.cpp b/lib/libhac/source/IdConverter.cpp
new file mode 100644
index 0000000..5455263
--- /dev/null
+++ b/lib/libhac/source/IdConverter.cpp
@@ -0,0 +1,16 @@
+#include
+
+uint64_t nn::hac::IdConverter::convertToAocBaseId(uint64_t application_id)
+{
+ return application_id + kAocBaseId;
+}
+
+uint64_t nn::hac::IdConverter::convertToDeltaId(uint64_t application_id)
+{
+ return application_id + kDeltaId;
+}
+
+uint64_t nn::hac::IdConverter::convertToPatchId(uint64_t application_id)
+{
+ return application_id + kPatchId;
+}
\ No newline at end of file
diff --git a/lib/libhac/source/KernelCapabilityBinary.cpp b/lib/libhac/source/KernelCapabilityBinary.cpp
index 71d5eed..096c7b3 100644
--- a/lib/libhac/source/KernelCapabilityBinary.cpp
+++ b/lib/libhac/source/KernelCapabilityBinary.cpp
@@ -11,6 +11,7 @@ nn::hac::KernelCapabilityBinary::KernelCapabilityBinary(const KernelCapabilityBi
void nn::hac::KernelCapabilityBinary::operator=(const KernelCapabilityBinary & other)
{
clear();
+ mRawBinary = other.mRawBinary;
mThreadInfo = other.mThreadInfo;
mSystemCalls = other.mSystemCalls;
mMemoryMap = other.mMemoryMap;
diff --git a/lib/libhac/source/NpdmBinary.cpp b/lib/libhac/source/NpdmBinary.cpp
index 716cc08..fe26c3a 100644
--- a/lib/libhac/source/NpdmBinary.cpp
+++ b/lib/libhac/source/NpdmBinary.cpp
@@ -132,16 +132,8 @@ void nn::hac::NpdmBinary::fromBytes(const byte_t* data, size_t len)
mMainThreadCpuId = hdr.main_thread_cpu_id;
mVersion = hdr.version.get();
mMainThreadStackSize = hdr.main_thread_stack_size.get();
- mName = std::string(hdr.name, npdm::kNameMaxLen);
- if (mName[0] == '\0')
- {
- mName.clear();
- }
- mProductCode = std::string(hdr.product_code, npdm::kProductCodeMaxLen);
- if (mProductCode[0] == '\0')
- {
- mProductCode.clear();
- }
+ mName = std::string(hdr.name, _MIN(strlen(hdr.name), npdm::kNameMaxLen));
+ mProductCode = std::string(hdr.product_code, _MIN(strlen(hdr.product_code), npdm::kProductCodeMaxLen));
// 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));
diff --git a/lib/libhac/source/Result.cpp b/lib/libhac/source/Result.cpp
new file mode 100644
index 0000000..da06c05
--- /dev/null
+++ b/lib/libhac/source/Result.cpp
@@ -0,0 +1,62 @@
+#include
+
+nn::hac::Result::Result() :
+ mResult(0)
+{}
+
+nn::hac::Result::Result(uint32_t result) :
+ mResult(result)
+{}
+
+nn::hac::Result::Result(uint32_t module_num, uint32_t desc, uint32_t sub_desc) :
+ mResult(0)
+{
+ mResult |= (module_num & bitWidthToMask(kModuleNumBitWidth)) << kModuleNumBitPos;
+ mResult |= (desc & bitWidthToMask(kDescriptionBitWidth)) << kDescriptionBitPos;
+ mResult |= (sub_desc & bitWidthToMask(kSubDescriptionBitWidth)) << kSubDescriptionBitPos;
+}
+
+void nn::hac::Result::operator=(const Result & other)
+{
+ mResult = other.mResult;
+}
+
+bool nn::hac::Result::operator==(const Result & other) const
+{
+ return mResult == other.mResult;
+}
+
+bool nn::hac::Result::operator!=(const Result & other) const
+{
+ return !(*this == other);
+}
+
+bool nn::hac::Result::isSuccess() const
+{
+ return mResult == 0;
+}
+
+bool nn::hac::Result::isFailure() const
+{
+ return !isSuccess();
+}
+
+uint32_t nn::hac::Result::getInnerValue() const
+{
+ return mResult;
+}
+
+uint32_t nn::hac::Result::getModuleNum() const
+{
+ return (mResult >> kModuleNumBitPos) & bitWidthToMask(kModuleNumBitWidth);
+}
+
+uint32_t nn::hac::Result::getDescription() const
+{
+ return (mResult >> kDescriptionBitPos) & bitWidthToMask(kDescriptionBitWidth);
+}
+
+uint32_t nn::hac::Result::getSubDescription() const
+{
+ return (mResult >> kSubDescriptionBitPos) & bitWidthToMask(kSubDescriptionBitWidth);
+}
diff --git a/lib/libhac/source/SystemCallHandler.cpp b/lib/libhac/source/SystemCallHandler.cpp
index c2e58b5..da03380 100644
--- a/lib/libhac/source/SystemCallHandler.cpp
+++ b/lib/libhac/source/SystemCallHandler.cpp
@@ -54,7 +54,7 @@ void nn::hac::SystemCallHandler::exportKernelCapabilityList(fnd::List entries;
+ SystemCallEntry entries[kSyscallTotalEntryNum];
for (size_t i = 0; i < kSyscallTotalEntryNum; i++)
{
entries[i].setSystemCallUpperBits((uint32_t)i);
@@ -71,7 +71,7 @@ void nn::hac::SystemCallHandler::exportKernelCapabilityList(fnd::List
-
- Source Files
+
+ Header Files
diff --git a/lib/libpolarssl/include/polarssl/config.h b/lib/libpolarssl/include/polarssl/config.h
index ae0d486..035238b 100644
--- a/lib/libpolarssl/include/polarssl/config.h
+++ b/lib/libpolarssl/include/polarssl/config.h
@@ -506,7 +506,7 @@
*
* This module provides the CTR_DRBG AES-256 random number generator.
*/
-//#define POLARSSL_CTR_DRBG_C
+#define POLARSSL_CTR_DRBG_C
/**
* \def POLARSSL_DEBUG_C
@@ -578,7 +578,7 @@
*
* This module provides a generic entropy pool
*/
-//#define POLARSSL_ENTROPY_C
+#define POLARSSL_ENTROPY_C
/**
* \def POLARSSL_ERROR_C
@@ -838,7 +838,7 @@
*
* This module adds support for SHA-384 and SHA-512.
*/
-//#define POLARSSL_SHA4_C
+#define POLARSSL_SHA4_C
/**
* \def POLARSSL_SSL_CACHE_C
diff --git a/lib/libpolarssl/include/polarssl/ctr_drbg.h b/lib/libpolarssl/include/polarssl/ctr_drbg.h
new file mode 100644
index 0000000..6f81af8
--- /dev/null
+++ b/lib/libpolarssl/include/polarssl/ctr_drbg.h
@@ -0,0 +1,234 @@
+/**
+ * \file ctr_drbg.h
+ *
+ * \brief CTR_DRBG based on AES-256 (NIST SP 800-90)
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *
+ * This file is part of mbed TLS (https://polarssl.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_CTR_DRBG_H
+#define POLARSSL_CTR_DRBG_H
+
+#include
+
+#include "aes.h"
+
+#define POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED -0x0034 /**< The entropy source failed. */
+#define POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 /**< Too many random requested in single call. */
+#define POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /**< Input too large (Entropy + additional). */
+#define POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read/write error in file. */
+
+#define CTR_DRBG_BLOCKSIZE 16 /**< Block size used by the cipher */
+#define CTR_DRBG_KEYSIZE 32 /**< Key size used by the cipher */
+#define CTR_DRBG_KEYBITS ( CTR_DRBG_KEYSIZE * 8 )
+#define CTR_DRBG_SEEDLEN ( CTR_DRBG_KEYSIZE + CTR_DRBG_BLOCKSIZE )
+ /**< The seed length (counter + AES key) */
+
+#if !defined(POLARSSL_CONFIG_OPTIONS)
+#define CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default */
+#define CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */
+#define CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */
+#define CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */
+#define CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */
+#endif /* !POLARSSL_CONFIG_OPTIONS */
+
+#define CTR_DRBG_PR_OFF 0 /**< No prediction resistance */
+#define CTR_DRBG_PR_ON 1 /**< Prediction resistance enabled */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief CTR_DRBG context structure
+ */
+typedef struct
+{
+ unsigned char counter[16]; /*!< counter (V) */
+ int reseed_counter; /*!< reseed counter */
+ int prediction_resistance; /*!< enable prediction resistance (Automatic
+ reseed before every random generation) */
+ size_t entropy_len; /*!< amount of entropy grabbed on each (re)seed */
+ int reseed_interval; /*!< reseed interval */
+
+ aes_context aes_ctx; /*!< AES context */
+
+ /*
+ * Callbacks (Entropy)
+ */
+ int (*f_entropy)(void *, unsigned char *, size_t);
+
+ void *p_entropy; /*!< context for the entropy function */
+}
+ctr_drbg_context;
+
+/**
+ * \brief CTR_DRBG initialization
+ *
+ * Note: Personalization data can be provided in addition to the more generic
+ * entropy source to make this instantiation as unique as possible.
+ *
+ * \param ctx CTR_DRBG context to be initialized
+ * \param f_entropy Entropy callback (p_entropy, buffer to fill, buffer
+ * length)
+ * \param p_entropy Entropy context
+ * \param custom Personalization data (Device specific identifiers)
+ * (Can be NULL)
+ * \param len Length of personalization data
+ *
+ * \return 0 if successful, or
+ * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED
+ */
+int ctr_drbg_init( ctr_drbg_context *ctx,
+ int (*f_entropy)(void *, unsigned char *, size_t),
+ void *p_entropy,
+ const unsigned char *custom,
+ size_t len );
+
+/**
+ * \brief Enable / disable prediction resistance (Default: Off)
+ *
+ * Note: If enabled, entropy is used for ctx->entropy_len before each call!
+ * Only use this if you have ample supply of good entropy!
+ *
+ * \param ctx CTR_DRBG context
+ * \param resistance CTR_DRBG_PR_ON or CTR_DRBG_PR_OFF
+ */
+void ctr_drbg_set_prediction_resistance( ctr_drbg_context *ctx,
+ int resistance );
+
+/**
+ * \brief Set the amount of entropy grabbed on each (re)seed
+ * (Default: CTR_DRBG_ENTROPY_LEN)
+ *
+ * \param ctx CTR_DRBG context
+ * \param len Amount of entropy to grab
+ */
+void ctr_drbg_set_entropy_len( ctr_drbg_context *ctx,
+ size_t len );
+
+/**
+ * \brief Set the reseed interval
+ * (Default: CTR_DRBG_RESEED_INTERVAL)
+ *
+ * \param ctx CTR_DRBG context
+ * \param interval Reseed interval
+ */
+void ctr_drbg_set_reseed_interval( ctr_drbg_context *ctx,
+ int interval );
+
+/**
+ * \brief CTR_DRBG reseeding (extracts data from entropy source)
+ *
+ * \param ctx CTR_DRBG context
+ * \param additional Additional data to add to state (Can be NULL)
+ * \param len Length of additional data
+ *
+ * \return 0 if successful, or
+ * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED
+ */
+int ctr_drbg_reseed( ctr_drbg_context *ctx,
+ const unsigned char *additional, size_t len );
+
+/**
+ * \brief CTR_DRBG update state
+ *
+ * \param ctx CTR_DRBG context
+ * \param additional Additional data to update state with
+ * \param add_len Length of additional data
+ *
+ * \note If add_len is greater than CTR_DRBG_MAX_SEED_INPUT,
+ * only the first CTR_DRBG_MAX_SEED_INPUT bytes are used,
+ * the remaining ones are silently discarded.
+ */
+void ctr_drbg_update( ctr_drbg_context *ctx,
+ const unsigned char *additional, size_t add_len );
+
+/**
+ * \brief CTR_DRBG generate random with additional update input
+ *
+ * Note: Automatically reseeds if reseed_counter is reached.
+ *
+ * \param p_rng CTR_DRBG context
+ * \param output Buffer to fill
+ * \param output_len Length of the buffer
+ * \param additional Additional data to update with (Can be NULL)
+ * \param add_len Length of additional data
+ *
+ * \return 0 if successful, or
+ * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or
+ * POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG
+ */
+int ctr_drbg_random_with_add( void *p_rng,
+ unsigned char *output, size_t output_len,
+ const unsigned char *additional, size_t add_len );
+
+/**
+ * \brief CTR_DRBG generate random
+ *
+ * Note: Automatically reseeds if reseed_counter is reached.
+ *
+ * \param p_rng CTR_DRBG context
+ * \param output Buffer to fill
+ * \param output_len Length of the buffer
+ *
+ * \return 0 if successful, or
+ * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or
+ * POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG
+ */
+int ctr_drbg_random( void *p_rng,
+ unsigned char *output, size_t output_len );
+
+#if defined(POLARSSL_FS_IO)
+/**
+ * \brief Write a seed file
+ *
+ * \param path Name of the file
+ *
+ * \return 0 if successful,
+ * POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR on file error, or
+ * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED
+ */
+int ctr_drbg_write_seed_file( ctr_drbg_context *ctx, const char *path );
+
+/**
+ * \brief Read and update a seed file. Seed is added to this
+ * instance
+ *
+ * \param path Name of the file
+ *
+ * \return 0 if successful,
+ * POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR on file error,
+ * POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or
+ * POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG
+ */
+int ctr_drbg_update_seed_file( ctr_drbg_context *ctx, const char *path );
+#endif
+
+/**
+ * \brief Checkup routine
+ *
+ * \return 0 if successful, or 1 if the test failed
+ */
+int ctr_drbg_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ctr_drbg.h */
diff --git a/lib/libpolarssl/include/polarssl/entropy.h b/lib/libpolarssl/include/polarssl/entropy.h
new file mode 100644
index 0000000..7ce7a5a
--- /dev/null
+++ b/lib/libpolarssl/include/polarssl/entropy.h
@@ -0,0 +1,180 @@
+/**
+ * \file entropy.h
+ *
+ * \brief Entropy accumulator implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *
+ * This file is part of mbed TLS (https://polarssl.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_ENTROPY_H
+#define POLARSSL_ENTROPY_H
+
+#include
+
+#include "config.h"
+
+#include "sha4.h"
+#if defined(POLARSSL_HAVEGE_C)
+#include "havege.h"
+#endif
+
+#define POLARSSL_ERR_ENTROPY_SOURCE_FAILED -0x003C /**< Critical entropy source failure. */
+#define POLARSSL_ERR_ENTROPY_MAX_SOURCES -0x003E /**< No more sources can be added. */
+#define POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED -0x0040 /**< No sources have been added to poll. */
+#define POLARSSL_ERR_ENTROPY_FILE_IO_ERROR -0x0058 /**< Read/write error in file. */
+
+#if !defined(POLARSSL_CONFIG_OPTIONS)
+#define ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */
+#define ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */
+#endif /* !POLARSSL_CONFIG_OPTIONS */
+
+#define ENTROPY_BLOCK_SIZE 64 /**< Block size of entropy accumulator (SHA-512) */
+
+#define ENTROPY_MAX_SEED_SIZE 1024 /**< Maximum size of seed we read from seed file */
+#define ENTROPY_SOURCE_MANUAL ENTROPY_MAX_SOURCES
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Entropy poll callback pointer
+ *
+ * \param data Callback-specific data pointer
+ * \param output Data to fill
+ * \param len Maximum size to provide
+ * \param olen The actual amount of bytes put into the buffer (Can be 0)
+ *
+ * \return 0 if no critical failures occurred,
+ * POLARSSL_ERR_ENTROPY_SOURCE_FAILED otherwise
+ */
+typedef int (*f_source_ptr)(void *data, unsigned char *output, size_t len, size_t *olen);
+
+/**
+ * \brief Entropy source state
+ */
+typedef struct
+{
+ f_source_ptr f_source; /**< The entropy source callback */
+ void * p_source; /**< The callback data pointer */
+ size_t size; /**< Amount received */
+ size_t threshold; /**< Minimum level required before release */
+}
+source_state;
+
+/**
+ * \brief Entropy context structure
+ */
+typedef struct
+{
+ sha4_context accumulator;
+ int source_count;
+ source_state source[ENTROPY_MAX_SOURCES];
+#if defined(POLARSSL_HAVEGE_C)
+ havege_state havege_data;
+#endif
+}
+entropy_context;
+
+/**
+ * \brief Initialize the context
+ *
+ * \param ctx Entropy context to initialize
+ */
+void entropy_init( entropy_context *ctx );
+
+/**
+ * \brief Adds an entropy source to poll
+ *
+ * \param ctx Entropy context
+ * \param f_source Entropy function
+ * \param p_source Function data
+ * \param threshold Minimum required from source before entropy is released
+ * ( with entropy_func() )
+ *
+ * \return 0 if successful or POLARSSL_ERR_ENTROPY_MAX_SOURCES
+ */
+int entropy_add_source( entropy_context *ctx,
+ f_source_ptr f_source, void *p_source,
+ size_t threshold );
+
+/**
+ * \brief Trigger an extra gather poll for the accumulator
+ *
+ * \param ctx Entropy context
+ *
+ * \return 0 if successful, or POLARSSL_ERR_ENTROPY_SOURCE_FAILED
+ */
+int entropy_gather( entropy_context *ctx );
+
+/**
+ * \brief Retrieve entropy from the accumulator (Max ENTROPY_BLOCK_SIZE)
+ *
+ * \param data Entropy context
+ * \param output Buffer to fill
+ * \param len Length of buffer
+ *
+ * \return 0 if successful, or POLARSSL_ERR_ENTROPY_SOURCE_FAILED
+ */
+int entropy_func( void *data, unsigned char *output, size_t len );
+
+/**
+ * \brief Add data to the accumulator manually
+ *
+ * \param ctx Entropy context
+ * \param data Data to add
+ * \param len Length of data
+ *
+ * \return 0 if successful
+ */
+int entropy_update_manual( entropy_context *ctx,
+ const unsigned char *data, size_t len );
+
+#if defined(POLARSSL_FS_IO)
+/**
+ * \brief Write a seed file
+ *
+ * \param ctx Entropy context
+ * \param path Name of the file
+ *
+ * \return 0 if successful,
+ * POLARSSL_ERR_ENTROPY_FILE_IO_ERROR on file error, or
+ * POLARSSL_ERR_ENTROPY_SOURCE_FAILED
+ */
+int entropy_write_seed_file( entropy_context *ctx, const char *path );
+
+/**
+ * \brief Read and update a seed file. Seed is added to this
+ * instance. No more than ENTROPY_MAX_SEED_SIZE bytes are
+ * read from the seed file. The rest is ignored.
+ *
+ * \param ctx Entropy context
+ * \param path Name of the file
+ *
+ * \return 0 if successful,
+ * POLARSSL_ERR_ENTROPY_FILE_IO_ERROR on file error,
+ * POLARSSL_ERR_ENTROPY_SOURCE_FAILED
+ */
+int entropy_update_seed_file( entropy_context *ctx, const char *path );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* entropy.h */
diff --git a/lib/libpolarssl/include/polarssl/entropy_poll.h b/lib/libpolarssl/include/polarssl/entropy_poll.h
new file mode 100644
index 0000000..82842ce
--- /dev/null
+++ b/lib/libpolarssl/include/polarssl/entropy_poll.h
@@ -0,0 +1,72 @@
+/**
+ * \file entropy_poll.h
+ *
+ * \brief Platform-specific and custom entropy polling functions
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *
+ * This file is part of mbed TLS (https://polarssl.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_ENTROPY_POLL_H
+#define POLARSSL_ENTROPY_POLL_H
+
+#include
+
+#include "config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Default thresholds for built-in sources
+ */
+#define ENTROPY_MIN_PLATFORM 128 /**< Minimum for platform source */
+#define ENTROPY_MIN_HAVEGE 128 /**< Minimum for HAVEGE */
+#define ENTROPY_MIN_HARDCLOCK 32 /**< Minimum for hardclock() */
+
+#if !defined(POLARSSL_NO_PLATFORM_ENTROPY)
+/**
+ * \brief Platform-specific entropy poll callback
+ */
+int platform_entropy_poll( void *data,
+ unsigned char *output, size_t len, size_t *olen );
+#endif
+
+#if defined(POLARSSL_HAVEGE_C)
+/**
+ * \brief HAVEGE based entropy poll callback
+ *
+ * Requires an HAVEGE state as its data pointer.
+ */
+int havege_poll( void *data,
+ unsigned char *output, size_t len, size_t *olen );
+#endif
+
+#if defined(POLARSSL_TIMING_C)
+/**
+ * \brief hardclock-based entropy poll callback
+ */
+int hardclock_poll( void *data,
+ unsigned char *output, size_t len, size_t *olen );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* entropy_poll.h */
diff --git a/lib/libpolarssl/include/polarssl/sha4.h b/lib/libpolarssl/include/polarssl/sha4.h
new file mode 100644
index 0000000..fa57d4d
--- /dev/null
+++ b/lib/libpolarssl/include/polarssl/sha4.h
@@ -0,0 +1,183 @@
+/**
+ * \file sha4.h
+ *
+ * \brief SHA-384 and SHA-512 cryptographic hash function
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *
+ * This file is part of mbed TLS (https://polarssl.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef POLARSSL_SHA4_H
+#define POLARSSL_SHA4_H
+
+#include "config.h"
+
+#include
+
+#if defined(_MSC_VER) || defined(__WATCOMC__)
+ #define UL64(x) x##ui64
+ typedef unsigned __int64 uint64_t;
+#else
+ #include
+ #define UL64(x) x##ULL
+#endif
+
+#define POLARSSL_ERR_SHA4_FILE_IO_ERROR -0x007A /**< Read/write error in file. */
+
+#if !defined(POLARSSL_SHA1_ALT)
+// Regular implementation
+//
+
+/**
+ * \brief SHA-512 context structure
+ */
+typedef struct
+{
+ uint64_t total[2]; /*!< number of bytes processed */
+ uint64_t state[8]; /*!< intermediate digest state */
+ unsigned char buffer[128]; /*!< data block being processed */
+
+ unsigned char ipad[128]; /*!< HMAC: inner padding */
+ unsigned char opad[128]; /*!< HMAC: outer padding */
+ int is384; /*!< 0 => SHA-512, else SHA-384 */
+}
+sha4_context;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief SHA-512 context setup
+ *
+ * \param ctx context to be initialized
+ * \param is384 0 = use SHA512, 1 = use SHA384
+ */
+void sha4_starts( sha4_context *ctx, int is384 );
+
+/**
+ * \brief SHA-512 process buffer
+ *
+ * \param ctx SHA-512 context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ */
+void sha4_update( sha4_context *ctx, const unsigned char *input, size_t ilen );
+
+/**
+ * \brief SHA-512 final digest
+ *
+ * \param ctx SHA-512 context
+ * \param output SHA-384/512 checksum result
+ */
+void sha4_finish( sha4_context *ctx, unsigned char output[64] );
+
+#ifdef __cplusplus
+}
+#endif
+
+#else /* POLARSSL_SHA4_ALT */
+#include "sha4_alt.h"
+#endif /* POLARSSL_SHA4_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Output = SHA-512( input buffer )
+ *
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output SHA-384/512 checksum result
+ * \param is384 0 = use SHA512, 1 = use SHA384
+ */
+void sha4( const unsigned char *input, size_t ilen,
+ unsigned char output[64], int is384 );
+
+/**
+ * \brief Output = SHA-512( file contents )
+ *
+ * \param path input file name
+ * \param output SHA-384/512 checksum result
+ * \param is384 0 = use SHA512, 1 = use SHA384
+ *
+ * \return 0 if successful, or POLARSSL_ERR_SHA4_FILE_IO_ERROR
+ */
+int sha4_file( const char *path, unsigned char output[64], int is384 );
+
+/**
+ * \brief SHA-512 HMAC context setup
+ *
+ * \param ctx HMAC context to be initialized
+ * \param is384 0 = use SHA512, 1 = use SHA384
+ * \param key HMAC secret key
+ * \param keylen length of the HMAC key
+ */
+void sha4_hmac_starts( sha4_context *ctx, const unsigned char *key, size_t keylen,
+ int is384 );
+
+/**
+ * \brief SHA-512 HMAC process buffer
+ *
+ * \param ctx HMAC context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ */
+void sha4_hmac_update( sha4_context *ctx, const unsigned char *input, size_t ilen );
+
+/**
+ * \brief SHA-512 HMAC final digest
+ *
+ * \param ctx HMAC context
+ * \param output SHA-384/512 HMAC checksum result
+ */
+void sha4_hmac_finish( sha4_context *ctx, unsigned char output[64] );
+
+/**
+ * \brief SHA-512 HMAC context reset
+ *
+ * \param ctx HMAC context to be reset
+ */
+void sha4_hmac_reset( sha4_context *ctx );
+
+/**
+ * \brief Output = HMAC-SHA-512( hmac key, input buffer )
+ *
+ * \param key HMAC secret key
+ * \param keylen length of the HMAC key
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output HMAC-SHA-384/512 result
+ * \param is384 0 = use SHA512, 1 = use SHA384
+ */
+void sha4_hmac( const unsigned char *key, size_t keylen,
+ const unsigned char *input, size_t ilen,
+ unsigned char output[64], int is384 );
+
+/**
+ * \brief Checkup routine
+ *
+ * \return 0 if successful, or 1 if the test failed
+ */
+int sha4_self_test( int verbose );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* sha4.h */
diff --git a/lib/libpolarssl/libpolarssl.vcxproj b/lib/libpolarssl/libpolarssl.vcxproj
index 18336ba..e392881 100644
--- a/lib/libpolarssl/libpolarssl.vcxproj
+++ b/lib/libpolarssl/libpolarssl.vcxproj
@@ -21,7 +21,7 @@
15.0
{394EFC16-BD3A-4538-B33D-7BA1EDB8DAC1}
- 10.0.15063.0
+ 10.0.16299.0
@@ -117,30 +117,38 @@
true
+
+
+
+
+
+
+
+
+
+
-
-
-
+
diff --git a/lib/libpolarssl/libpolarssl.vcxproj.filters b/lib/libpolarssl/libpolarssl.vcxproj.filters
index 1b4bf96..035cf2a 100644
--- a/lib/libpolarssl/libpolarssl.vcxproj.filters
+++ b/lib/libpolarssl/libpolarssl.vcxproj.filters
@@ -14,6 +14,9 @@
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
Header Files
@@ -30,6 +33,21 @@
Header Files
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
Header Files
@@ -39,10 +57,7 @@
Header Files
-
- Header Files
-
-
+
Header Files
@@ -56,6 +71,15 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
Source Files
@@ -71,8 +95,8 @@
Source Files
-
-
-
+
+ Source Files
+
\ No newline at end of file
diff --git a/lib/libpolarssl/source/ctr_drbg.c b/lib/libpolarssl/source/ctr_drbg.c
new file mode 100644
index 0000000..989eb45
--- /dev/null
+++ b/lib/libpolarssl/source/ctr_drbg.c
@@ -0,0 +1,582 @@
+/*
+ * CTR_DRBG implementation based on AES-256 (NIST SP 800-90)
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *
+ * This file is part of mbed TLS (https://polarssl.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ * The NIST SP 800-90 DRBGs are described in the following publucation.
+ *
+ * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_CTR_DRBG_C)
+
+#include "polarssl/ctr_drbg.h"
+
+#if defined(POLARSSL_FS_IO)
+#include
+#endif
+
+/*
+ * Non-public function wrapped by ctr_crbg_init(). Necessary to allow NIST
+ * tests to succeed (which require known length fixed entropy)
+ */
+int ctr_drbg_init_entropy_len(
+ ctr_drbg_context *ctx,
+ int (*f_entropy)(void *, unsigned char *, size_t),
+ void *p_entropy,
+ const unsigned char *custom,
+ size_t len,
+ size_t entropy_len );
+
+int ctr_drbg_init_entropy_len(
+ ctr_drbg_context *ctx,
+ int (*f_entropy)(void *, unsigned char *, size_t),
+ void *p_entropy,
+ const unsigned char *custom,
+ size_t len,
+ size_t entropy_len )
+{
+ int ret;
+ unsigned char key[CTR_DRBG_KEYSIZE];
+
+ memset( ctx, 0, sizeof(ctr_drbg_context) );
+ memset( key, 0, CTR_DRBG_KEYSIZE );
+
+ ctx->f_entropy = f_entropy;
+ ctx->p_entropy = p_entropy;
+
+ ctx->entropy_len = entropy_len;
+ ctx->reseed_interval = CTR_DRBG_RESEED_INTERVAL;
+
+ /*
+ * Initialize with an empty key
+ */
+ aes_setkey_enc( &ctx->aes_ctx, key, CTR_DRBG_KEYBITS );
+
+ if( ( ret = ctr_drbg_reseed( ctx, custom, len ) ) != 0 )
+ return( ret );
+
+ return( 0 );
+}
+
+int ctr_drbg_init( ctr_drbg_context *ctx,
+ int (*f_entropy)(void *, unsigned char *, size_t),
+ void *p_entropy,
+ const unsigned char *custom,
+ size_t len )
+{
+ return( ctr_drbg_init_entropy_len( ctx, f_entropy, p_entropy, custom, len,
+ CTR_DRBG_ENTROPY_LEN ) );
+}
+
+void ctr_drbg_set_prediction_resistance( ctr_drbg_context *ctx, int resistance )
+{
+ ctx->prediction_resistance = resistance;
+}
+
+void ctr_drbg_set_entropy_len( ctr_drbg_context *ctx, size_t len )
+{
+ ctx->entropy_len = len;
+}
+
+void ctr_drbg_set_reseed_interval( ctr_drbg_context *ctx, int interval )
+{
+ ctx->reseed_interval = interval;
+}
+
+static int block_cipher_df( unsigned char *output,
+ const unsigned char *data, size_t data_len )
+{
+ unsigned char buf[CTR_DRBG_MAX_SEED_INPUT + CTR_DRBG_BLOCKSIZE + 16];
+ unsigned char tmp[CTR_DRBG_SEEDLEN];
+ unsigned char key[CTR_DRBG_KEYSIZE];
+ unsigned char chain[CTR_DRBG_BLOCKSIZE];
+ unsigned char *p, *iv;
+ aes_context aes_ctx;
+
+ int i, j, buf_len, use_len;
+
+ if( data_len > CTR_DRBG_MAX_SEED_INPUT )
+ return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG );
+
+ memset( buf, 0, CTR_DRBG_MAX_SEED_INPUT + CTR_DRBG_BLOCKSIZE + 16 );
+
+ /*
+ * Construct IV (16 bytes) and S in buffer
+ * IV = Counter (in 32-bits) padded to 16 with zeroes
+ * S = Length input string (in 32-bits) || Length of output (in 32-bits) ||
+ * data || 0x80
+ * (Total is padded to a multiple of 16-bytes with zeroes)
+ */
+ p = buf + CTR_DRBG_BLOCKSIZE;
+ *p++ = ( data_len >> 24 ) & 0xff;
+ *p++ = ( data_len >> 16 ) & 0xff;
+ *p++ = ( data_len >> 8 ) & 0xff;
+ *p++ = ( data_len ) & 0xff;
+ p += 3;
+ *p++ = CTR_DRBG_SEEDLEN;
+ memcpy( p, data, data_len );
+ p[data_len] = 0x80;
+
+ buf_len = CTR_DRBG_BLOCKSIZE + 8 + data_len + 1;
+
+ for( i = 0; i < CTR_DRBG_KEYSIZE; i++ )
+ key[i] = i;
+
+ aes_setkey_enc( &aes_ctx, key, CTR_DRBG_KEYBITS );
+
+ /*
+ * Reduce data to POLARSSL_CTR_DRBG_SEEDLEN bytes of data
+ */
+ for( j = 0; j < CTR_DRBG_SEEDLEN; j += CTR_DRBG_BLOCKSIZE )
+ {
+ p = buf;
+ memset( chain, 0, CTR_DRBG_BLOCKSIZE );
+ use_len = buf_len;
+
+ while( use_len > 0 )
+ {
+ for( i = 0; i < CTR_DRBG_BLOCKSIZE; i++ )
+ chain[i] ^= p[i];
+ p += CTR_DRBG_BLOCKSIZE;
+ use_len -= CTR_DRBG_BLOCKSIZE;
+
+ aes_crypt_ecb( &aes_ctx, AES_ENCRYPT, chain, chain );
+ }
+
+ memcpy( tmp + j, chain, CTR_DRBG_BLOCKSIZE );
+
+ /*
+ * Update IV
+ */
+ buf[3]++;
+ }
+
+ /*
+ * Do final encryption with reduced data
+ */
+ aes_setkey_enc( &aes_ctx, tmp, CTR_DRBG_KEYBITS );
+ iv = tmp + CTR_DRBG_KEYSIZE;
+ p = output;
+
+ for( j = 0; j < CTR_DRBG_SEEDLEN; j += CTR_DRBG_BLOCKSIZE )
+ {
+ aes_crypt_ecb( &aes_ctx, AES_ENCRYPT, iv, iv );
+ memcpy( p, iv, CTR_DRBG_BLOCKSIZE );
+ p += CTR_DRBG_BLOCKSIZE;
+ }
+
+ return( 0 );
+}
+
+static int ctr_drbg_update_internal( ctr_drbg_context *ctx,
+ const unsigned char data[CTR_DRBG_SEEDLEN] )
+{
+ unsigned char tmp[CTR_DRBG_SEEDLEN];
+ unsigned char *p = tmp;
+ int i, j;
+
+ memset( tmp, 0, CTR_DRBG_SEEDLEN );
+
+ for( j = 0; j < CTR_DRBG_SEEDLEN; j += CTR_DRBG_BLOCKSIZE )
+ {
+ /*
+ * Increase counter
+ */
+ for( i = CTR_DRBG_BLOCKSIZE; i > 0; i-- )
+ if( ++ctx->counter[i - 1] != 0 )
+ break;
+
+ /*
+ * Crypt counter block
+ */
+ aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, ctx->counter, p );
+
+ p += CTR_DRBG_BLOCKSIZE;
+ }
+
+ for( i = 0; i < CTR_DRBG_SEEDLEN; i++ )
+ tmp[i] ^= data[i];
+
+ /*
+ * Update key and counter
+ */
+ aes_setkey_enc( &ctx->aes_ctx, tmp, CTR_DRBG_KEYBITS );
+ memcpy( ctx->counter, tmp + CTR_DRBG_KEYSIZE, CTR_DRBG_BLOCKSIZE );
+
+ return( 0 );
+}
+
+void ctr_drbg_update( ctr_drbg_context *ctx,
+ const unsigned char *additional, size_t add_len )
+{
+ unsigned char add_input[CTR_DRBG_SEEDLEN];
+
+ if( add_len > 0 )
+ {
+ /* MAX_INPUT would be more logical here, but we have to match
+ * block_cipher_df()'s limits since we can't propagate errors */
+ if( add_len > CTR_DRBG_MAX_SEED_INPUT )
+ add_len = CTR_DRBG_MAX_SEED_INPUT;
+
+ block_cipher_df( add_input, additional, add_len );
+ ctr_drbg_update_internal( ctx, add_input );
+ }
+}
+
+int ctr_drbg_reseed( ctr_drbg_context *ctx,
+ const unsigned char *additional, size_t len )
+{
+ unsigned char seed[CTR_DRBG_MAX_SEED_INPUT];
+ size_t seedlen = 0;
+
+ if( ctx->entropy_len + len > CTR_DRBG_MAX_SEED_INPUT )
+ return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG );
+
+ memset( seed, 0, CTR_DRBG_MAX_SEED_INPUT );
+
+ /*
+ * Gather enropy_len bytes of entropy to seed state
+ */
+ if( 0 != ctx->f_entropy( ctx->p_entropy, seed,
+ ctx->entropy_len ) )
+ {
+ return( POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED );
+ }
+
+ seedlen += ctx->entropy_len;
+
+ /*
+ * Add additional data
+ */
+ if( additional && len )
+ {
+ memcpy( seed + seedlen, additional, len );
+ seedlen += len;
+ }
+
+ /*
+ * Reduce to 384 bits
+ */
+ block_cipher_df( seed, seed, seedlen );
+
+ /*
+ * Update state
+ */
+ ctr_drbg_update_internal( ctx, seed );
+ ctx->reseed_counter = 1;
+
+ return( 0 );
+}
+
+int ctr_drbg_random_with_add( void *p_rng,
+ unsigned char *output, size_t output_len,
+ const unsigned char *additional, size_t add_len )
+{
+ int ret = 0;
+ ctr_drbg_context *ctx = (ctr_drbg_context *) p_rng;
+ unsigned char add_input[CTR_DRBG_SEEDLEN];
+ unsigned char *p = output;
+ unsigned char tmp[CTR_DRBG_BLOCKSIZE];
+ int i;
+ size_t use_len;
+
+ if( output_len > CTR_DRBG_MAX_REQUEST )
+ return( POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG );
+
+ if( add_len > CTR_DRBG_MAX_INPUT )
+ return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG );
+
+ memset( add_input, 0, CTR_DRBG_SEEDLEN );
+
+ if( ctx->reseed_counter > ctx->reseed_interval ||
+ ctx->prediction_resistance )
+ {
+ if( ( ret = ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 )
+ return( ret );
+
+ add_len = 0;
+ }
+
+ if( add_len > 0 )
+ {
+ block_cipher_df( add_input, additional, add_len );
+ ctr_drbg_update_internal( ctx, add_input );
+ }
+
+ while( output_len > 0 )
+ {
+ /*
+ * Increase counter
+ */
+ for( i = CTR_DRBG_BLOCKSIZE; i > 0; i-- )
+ if( ++ctx->counter[i - 1] != 0 )
+ break;
+
+ /*
+ * Crypt counter block
+ */
+ aes_crypt_ecb( &ctx->aes_ctx, AES_ENCRYPT, ctx->counter, tmp );
+
+ use_len = (output_len > CTR_DRBG_BLOCKSIZE ) ? CTR_DRBG_BLOCKSIZE : output_len;
+ /*
+ * Copy random block to destination
+ */
+ memcpy( p, tmp, use_len );
+ p += use_len;
+ output_len -= use_len;
+ }
+
+ ctr_drbg_update_internal( ctx, add_input );
+
+ ctx->reseed_counter++;
+
+ return( 0 );
+}
+
+int ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len )
+{
+ return ctr_drbg_random_with_add( p_rng, output, output_len, NULL, 0 );
+}
+
+#if defined(POLARSSL_FS_IO)
+int ctr_drbg_write_seed_file( ctr_drbg_context *ctx, const char *path )
+{
+ int ret;
+ FILE *f;
+ unsigned char buf[ CTR_DRBG_MAX_INPUT ];
+
+ if( ( f = fopen( path, "wb" ) ) == NULL )
+ return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR );
+
+ if( ( ret = ctr_drbg_random( ctx, buf, CTR_DRBG_MAX_INPUT ) ) != 0 )
+ {
+ fclose( f );
+ return( ret );
+ }
+
+ if( fwrite( buf, 1, CTR_DRBG_MAX_INPUT, f ) != CTR_DRBG_MAX_INPUT )
+ {
+ fclose( f );
+ return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR );
+ }
+
+ fclose( f );
+ return( 0 );
+}
+
+int ctr_drbg_update_seed_file( ctr_drbg_context *ctx, const char *path )
+{
+ FILE *f;
+ size_t n;
+ unsigned char buf[ CTR_DRBG_MAX_INPUT ];
+
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR );
+
+ fseek( f, 0, SEEK_END );
+ n = (size_t) ftell( f );
+ fseek( f, 0, SEEK_SET );
+
+ if( n > CTR_DRBG_MAX_INPUT )
+ {
+ fclose( f );
+ return( POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG );
+ }
+
+ if( fread( buf, 1, n, f ) != n )
+ {
+ fclose( f );
+ return( POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR );
+ }
+
+ ctr_drbg_update( ctx, buf, n );
+
+ fclose( f );
+
+ return( ctr_drbg_write_seed_file( ctx, path ) );
+}
+#endif /* POLARSSL_FS_IO */
+
+#if defined(POLARSSL_SELF_TEST)
+
+#include
+
+unsigned char entropy_source_pr[96] =
+ { 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16,
+ 0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02,
+ 0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b,
+ 0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb,
+ 0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9,
+ 0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95,
+ 0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63,
+ 0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3,
+ 0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31,
+ 0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4,
+ 0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56,
+ 0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 };
+
+unsigned char entropy_source_nopr[64] =
+ { 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14,
+ 0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe,
+ 0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d,
+ 0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20,
+ 0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9,
+ 0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46,
+ 0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e,
+ 0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e };
+
+unsigned char nonce_pers_pr[16] =
+ { 0xd2, 0x54, 0xfc, 0xff, 0x02, 0x1e, 0x69, 0xd2,
+ 0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c };
+
+unsigned char nonce_pers_nopr[16] =
+ { 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5,
+ 0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f };
+
+unsigned char result_pr[16] =
+ { 0x34, 0x01, 0x16, 0x56, 0xb4, 0x29, 0x00, 0x8f,
+ 0x35, 0x63, 0xec, 0xb5, 0xf2, 0x59, 0x07, 0x23 };
+
+unsigned char result_nopr[16] =
+ { 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88,
+ 0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f };
+
+static size_t test_offset;
+static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf,
+ size_t len )
+{
+ unsigned char *p = data;
+ memcpy( buf, p + test_offset, len );
+ test_offset += 32;
+ return( 0 );
+}
+
+/*
+ * Checkup routine
+ */
+int ctr_drbg_self_test( int verbose )
+{
+ ctr_drbg_context ctx;
+ unsigned char buf[16];
+
+ /*
+ * Based on a NIST CTR_DRBG test vector (PR = True)
+ */
+ if( verbose != 0 )
+ printf( " CTR_DRBG (PR = TRUE) : " );
+
+ test_offset = 0;
+ if( ctr_drbg_init_entropy_len( &ctx, ctr_drbg_self_test_entropy, entropy_source_pr, nonce_pers_pr, 16, 32 ) != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( 1 );
+ }
+ ctr_drbg_set_prediction_resistance( &ctx, CTR_DRBG_PR_ON );
+
+ if( ctr_drbg_random( &ctx, buf, CTR_DRBG_BLOCKSIZE ) != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( ctr_drbg_random( &ctx, buf, CTR_DRBG_BLOCKSIZE ) != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( memcmp( buf, result_pr, CTR_DRBG_BLOCKSIZE ) != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ printf( "passed\n" );
+
+ /*
+ * Based on a NIST CTR_DRBG test vector (PR = FALSE)
+ */
+ if( verbose != 0 )
+ printf( " CTR_DRBG (PR = FALSE): " );
+
+ test_offset = 0;
+ if( ctr_drbg_init_entropy_len( &ctx, ctr_drbg_self_test_entropy, entropy_source_nopr, nonce_pers_nopr, 16, 32 ) != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( ctr_drbg_random( &ctx, buf, 16 ) != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( ctr_drbg_reseed( &ctx, NULL, 0 ) != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( ctr_drbg_random( &ctx, buf, 16 ) != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( memcmp( buf, result_nopr, 16 ) != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ printf( "passed\n" );
+
+ if( verbose != 0 )
+ printf( "\n" );
+
+ return( 0 );
+}
+#endif
+
+#endif
diff --git a/lib/libpolarssl/source/entropy.c b/lib/libpolarssl/source/entropy.c
new file mode 100644
index 0000000..a9d2f1b
--- /dev/null
+++ b/lib/libpolarssl/source/entropy.c
@@ -0,0 +1,261 @@
+/*
+ * Entropy accumulator implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *
+ * This file is part of mbed TLS (https://polarssl.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_ENTROPY_C)
+
+#include "polarssl/entropy.h"
+#include "polarssl/entropy_poll.h"
+
+#if defined(POLARSSL_FS_IO)
+#include
+#endif
+
+#if defined(POLARSSL_HAVEGE_C)
+#include "polarssl/havege.h"
+#endif
+
+#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */
+
+void entropy_init( entropy_context *ctx )
+{
+ memset( ctx, 0, sizeof(entropy_context) );
+
+ sha4_starts( &ctx->accumulator, 0 );
+#if defined(POLARSSL_HAVEGE_C)
+ havege_init( &ctx->havege_data );
+#endif
+
+#if !defined(POLARSSL_NO_DEFAULT_ENTROPY_SOURCES)
+#if !defined(POLARSSL_NO_PLATFORM_ENTROPY)
+ entropy_add_source( ctx, platform_entropy_poll, NULL,
+ ENTROPY_MIN_PLATFORM );
+#endif
+#if defined(POLARSSL_TIMING_C)
+ entropy_add_source( ctx, hardclock_poll, NULL, ENTROPY_MIN_HARDCLOCK );
+#endif
+#if defined(POLARSSL_HAVEGE_C)
+ entropy_add_source( ctx, havege_poll, &ctx->havege_data,
+ ENTROPY_MIN_HAVEGE );
+#endif
+#endif /* POLARSSL_NO_DEFAULT_ENTROPY_SOURCES */
+}
+
+int entropy_add_source( entropy_context *ctx,
+ f_source_ptr f_source, void *p_source,
+ size_t threshold )
+{
+ int index = ctx->source_count;
+
+ if( index >= ENTROPY_MAX_SOURCES )
+ return( POLARSSL_ERR_ENTROPY_MAX_SOURCES );
+
+ ctx->source[index].f_source = f_source;
+ ctx->source[index].p_source = p_source;
+ ctx->source[index].threshold = threshold;
+
+ ctx->source_count++;
+
+ return( 0 );
+}
+
+/*
+ * Entropy accumulator update
+ */
+static int entropy_update( entropy_context *ctx, unsigned char source_id,
+ const unsigned char *data, size_t len )
+{
+ unsigned char header[2];
+ unsigned char tmp[ENTROPY_BLOCK_SIZE];
+ size_t use_len = len;
+ const unsigned char *p = data;
+
+ if( use_len > ENTROPY_BLOCK_SIZE )
+ {
+ sha4( data, len, tmp, 0 );
+
+ p = tmp;
+ use_len = ENTROPY_BLOCK_SIZE;
+ }
+
+ header[0] = source_id;
+ header[1] = use_len & 0xFF;
+
+ sha4_update( &ctx->accumulator, header, 2 );
+ sha4_update( &ctx->accumulator, p, use_len );
+
+ return( 0 );
+}
+
+int entropy_update_manual( entropy_context *ctx,
+ const unsigned char *data, size_t len )
+{
+ return entropy_update( ctx, ENTROPY_SOURCE_MANUAL, data, len );
+}
+
+/*
+ * Run through the different sources to add entropy to our accumulator
+ */
+int entropy_gather( entropy_context *ctx )
+{
+ int ret, i;
+ unsigned char buf[ENTROPY_MAX_GATHER];
+ size_t olen;
+
+ if( ctx->source_count == 0 )
+ return( POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED );
+
+ /*
+ * Run through our entropy sources
+ */
+ for( i = 0; i < ctx->source_count; i++ )
+ {
+ olen = 0;
+ if ( ( ret = ctx->source[i].f_source( ctx->source[i].p_source,
+ buf, ENTROPY_MAX_GATHER, &olen ) ) != 0 )
+ {
+ return( ret );
+ }
+
+ /*
+ * Add if we actually gathered something
+ */
+ if( olen > 0 )
+ {
+ entropy_update( ctx, (unsigned char) i, buf, olen );
+ ctx->source[i].size += olen;
+ }
+ }
+
+ return( 0 );
+}
+
+int entropy_func( void *data, unsigned char *output, size_t len )
+{
+ int ret, count = 0, i, reached;
+ entropy_context *ctx = (entropy_context *) data;
+ unsigned char buf[ENTROPY_BLOCK_SIZE];
+
+ if( len > ENTROPY_BLOCK_SIZE )
+ return( POLARSSL_ERR_ENTROPY_SOURCE_FAILED );
+
+ /*
+ * Always gather extra entropy before a call
+ */
+ do
+ {
+ if( count++ > ENTROPY_MAX_LOOP )
+ return( POLARSSL_ERR_ENTROPY_SOURCE_FAILED );
+
+ if( ( ret = entropy_gather( ctx ) ) != 0 )
+ return( ret );
+
+ reached = 0;
+
+ for( i = 0; i < ctx->source_count; i++ )
+ if( ctx->source[i].size >= ctx->source[i].threshold )
+ reached++;
+ }
+ while( reached != ctx->source_count );
+
+ memset( buf, 0, ENTROPY_BLOCK_SIZE );
+
+ sha4_finish( &ctx->accumulator, buf );
+
+ /*
+ * Reset accumulator and counters and recycle existing entropy
+ */
+ memset( &ctx->accumulator, 0, sizeof( sha4_context ) );
+ sha4_starts( &ctx->accumulator, 0 );
+ sha4_update( &ctx->accumulator, buf, ENTROPY_BLOCK_SIZE );
+
+ /*
+ * Perform second SHA-512 on entropy
+ */
+ sha4( buf, ENTROPY_BLOCK_SIZE, buf, 0 );
+
+ for( i = 0; i < ctx->source_count; i++ )
+ ctx->source[i].size = 0;
+
+ memcpy( output, buf, len );
+
+ return( 0 );
+}
+
+#if defined(POLARSSL_FS_IO)
+int entropy_write_seed_file( entropy_context *ctx, const char *path )
+{
+ int ret = POLARSSL_ERR_ENTROPY_FILE_IO_ERROR;
+ FILE *f;
+ unsigned char buf[ENTROPY_BLOCK_SIZE];
+
+ if( ( f = fopen( path, "wb" ) ) == NULL )
+ return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR );
+
+ if( ( ret = entropy_func( ctx, buf, ENTROPY_BLOCK_SIZE ) ) != 0 )
+ goto exit;
+
+ if( fwrite( buf, 1, ENTROPY_BLOCK_SIZE, f ) != ENTROPY_BLOCK_SIZE )
+ {
+ ret = POLARSSL_ERR_ENTROPY_FILE_IO_ERROR;
+ goto exit;
+ }
+
+ ret = 0;
+
+exit:
+ fclose( f );
+ return( ret );
+}
+
+int entropy_update_seed_file( entropy_context *ctx, const char *path )
+{
+ FILE *f;
+ size_t n;
+ unsigned char buf[ ENTROPY_MAX_SEED_SIZE ];
+
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR );
+
+ fseek( f, 0, SEEK_END );
+ n = (size_t) ftell( f );
+ fseek( f, 0, SEEK_SET );
+
+ if( n > ENTROPY_MAX_SEED_SIZE )
+ n = ENTROPY_MAX_SEED_SIZE;
+
+ if( fread( buf, 1, n, f ) != n )
+ {
+ fclose( f );
+ return( POLARSSL_ERR_ENTROPY_FILE_IO_ERROR );
+ }
+
+ fclose( f );
+
+ entropy_update_manual( ctx, buf, n );
+
+ return( entropy_write_seed_file( ctx, path ) );
+}
+#endif /* POLARSSL_FS_IO */
+
+#endif
diff --git a/lib/libpolarssl/source/entropy_poll.c b/lib/libpolarssl/source/entropy_poll.c
new file mode 100644
index 0000000..17be637
--- /dev/null
+++ b/lib/libpolarssl/source/entropy_poll.c
@@ -0,0 +1,133 @@
+/*
+ * Platform-specific and custom entropy polling functions
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *
+ * This file is part of mbed TLS (https://polarssl.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_ENTROPY_C)
+
+#include "polarssl/entropy.h"
+#include "polarssl/entropy_poll.h"
+
+#if defined(POLARSSL_TIMING_C)
+#include "polarssl/timing.h"
+#endif
+#if defined(POLARSSL_HAVEGE_C)
+#include "polarssl/havege.h"
+#endif
+
+#if !defined(POLARSSL_NO_PLATFORM_ENTROPY)
+#if defined(_WIN32)
+
+#if !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x0400
+#endif
+#include
+#include
+
+int platform_entropy_poll( void *data, unsigned char *output, size_t len,
+ size_t *olen )
+{
+ HCRYPTPROV provider;
+ ((void) data);
+ *olen = 0;
+
+ if( CryptAcquireContext( &provider, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == FALSE )
+ {
+ return POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
+ }
+
+ if( CryptGenRandom( provider, len, output ) == FALSE )
+ return POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
+
+ CryptReleaseContext( provider, 0 );
+ *olen = len;
+
+ return( 0 );
+}
+#else
+
+#include
+
+int platform_entropy_poll( void *data,
+ unsigned char *output, size_t len, size_t *olen )
+{
+ FILE *file;
+ size_t ret;
+ ((void) data);
+
+ *olen = 0;
+
+ file = fopen( "/dev/urandom", "rb" );
+ if( file == NULL )
+ return POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
+
+ ret = fread( output, 1, len, file );
+ if( ret != len )
+ {
+ fclose( file );
+ return POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
+ }
+
+ fclose( file );
+ *olen = len;
+
+ return( 0 );
+}
+#endif
+#endif
+
+#if defined(POLARSSL_TIMING_C)
+int hardclock_poll( void *data,
+ unsigned char *output, size_t len, size_t *olen )
+{
+ unsigned long timer = hardclock();
+ ((void) data);
+ *olen = 0;
+
+ if( len < sizeof(unsigned long) )
+ return( 0 );
+
+ memcpy( output, &timer, sizeof(unsigned long) );
+ *olen = sizeof(unsigned long);
+
+ return( 0 );
+}
+#endif
+
+#if defined(POLARSSL_HAVEGE_C)
+int havege_poll( void *data,
+ unsigned char *output, size_t len, size_t *olen )
+{
+ havege_state *hs = (havege_state *) data;
+ *olen = 0;
+
+ if( havege_random( hs, output, len ) != 0 )
+ return POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
+
+ *olen = len;
+
+ return( 0 );
+}
+#endif
+
+#endif /* POLARSSL_ENTROPY_C */
diff --git a/lib/libpolarssl/source/sha4.c b/lib/libpolarssl/source/sha4.c
new file mode 100644
index 0000000..ebdc997
--- /dev/null
+++ b/lib/libpolarssl/source/sha4.c
@@ -0,0 +1,762 @@
+/*
+ * FIPS-180-2 compliant SHA-384/512 implementation
+ *
+ * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
+ *
+ * This file is part of mbed TLS (https://polarssl.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/*
+ * The SHA-512 Secure Hash Standard was published by NIST in 2002.
+ *
+ * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
+ */
+
+#include "polarssl/config.h"
+
+#if defined(POLARSSL_SHA4_C)
+
+#include "polarssl/sha4.h"
+
+#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST)
+#include
+#endif
+
+#if !defined(POLARSSL_SHA4_ALT)
+
+/* Implementation that should never be optimized out by the compiler */
+static void polarssl_zeroize( void *v, size_t n ) {
+ volatile unsigned char *p = v; while( n-- ) *p++ = 0;
+}
+
+/*
+ * 64-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT64_BE
+#define GET_UINT64_BE(n,b,i) \
+{ \
+ (n) = ( (uint64_t) (b)[(i) ] << 56 ) \
+ | ( (uint64_t) (b)[(i) + 1] << 48 ) \
+ | ( (uint64_t) (b)[(i) + 2] << 40 ) \
+ | ( (uint64_t) (b)[(i) + 3] << 32 ) \
+ | ( (uint64_t) (b)[(i) + 4] << 24 ) \
+ | ( (uint64_t) (b)[(i) + 5] << 16 ) \
+ | ( (uint64_t) (b)[(i) + 6] << 8 ) \
+ | ( (uint64_t) (b)[(i) + 7] ); \
+}
+#endif
+
+#ifndef PUT_UINT64_BE
+#define PUT_UINT64_BE(n,b,i) \
+{ \
+ (b)[(i) ] = (unsigned char) ( (n) >> 56 ); \
+ (b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \
+ (b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \
+ (b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \
+ (b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \
+ (b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \
+ (b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \
+ (b)[(i) + 7] = (unsigned char) ( (n) ); \
+}
+#endif
+
+/*
+ * Round constants
+ */
+static const uint64_t K[80] =
+{
+ UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD),
+ UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC),
+ UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019),
+ UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118),
+ UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE),
+ UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2),
+ UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1),
+ UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694),
+ UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3),
+ UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65),
+ UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483),
+ UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5),
+ UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210),
+ UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4),
+ UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725),
+ UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70),
+ UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926),
+ UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF),
+ UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8),
+ UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B),
+ UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001),
+ UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30),
+ UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910),
+ UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8),
+ UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53),
+ UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8),
+ UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB),
+ UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3),
+ UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60),
+ UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC),
+ UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9),
+ UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B),
+ UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207),
+ UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178),
+ UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6),
+ UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B),
+ UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493),
+ UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C),
+ UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A),
+ UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817)
+};
+
+/*
+ * SHA-512 context setup
+ */
+void sha4_starts( sha4_context *ctx, int is384 )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ if( is384 == 0 )
+ {
+ /* SHA-512 */
+ ctx->state[0] = UL64(0x6A09E667F3BCC908);
+ ctx->state[1] = UL64(0xBB67AE8584CAA73B);
+ ctx->state[2] = UL64(0x3C6EF372FE94F82B);
+ ctx->state[3] = UL64(0xA54FF53A5F1D36F1);
+ ctx->state[4] = UL64(0x510E527FADE682D1);
+ ctx->state[5] = UL64(0x9B05688C2B3E6C1F);
+ ctx->state[6] = UL64(0x1F83D9ABFB41BD6B);
+ ctx->state[7] = UL64(0x5BE0CD19137E2179);
+ }
+ else
+ {
+ /* SHA-384 */
+ ctx->state[0] = UL64(0xCBBB9D5DC1059ED8);
+ ctx->state[1] = UL64(0x629A292A367CD507);
+ ctx->state[2] = UL64(0x9159015A3070DD17);
+ ctx->state[3] = UL64(0x152FECD8F70E5939);
+ ctx->state[4] = UL64(0x67332667FFC00B31);
+ ctx->state[5] = UL64(0x8EB44A8768581511);
+ ctx->state[6] = UL64(0xDB0C2E0D64F98FA7);
+ ctx->state[7] = UL64(0x47B5481DBEFA4FA4);
+ }
+
+ ctx->is384 = is384;
+}
+
+static void sha4_process( sha4_context *ctx, const unsigned char data[128] )
+{
+ int i;
+ uint64_t temp1, temp2, W[80];
+ uint64_t A, B, C, D, E, F, G, H;
+
+#define SHR(x,n) (x >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (64 - n)))
+
+#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7))
+#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6))
+
+#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39))
+#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define P(a,b,c,d,e,f,g,h,x,K) \
+{ \
+ temp1 = h + S3(e) + F1(e,f,g) + K + x; \
+ temp2 = S2(a) + F0(a,b,c); \
+ d += temp1; h = temp1 + temp2; \
+}
+
+ for( i = 0; i < 16; i++ )
+ {
+ GET_UINT64_BE( W[i], data, i << 3 );
+ }
+
+ for( ; i < 80; i++ )
+ {
+ W[i] = S1(W[i - 2]) + W[i - 7] +
+ S0(W[i - 15]) + W[i - 16];
+ }
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+ F = ctx->state[5];
+ G = ctx->state[6];
+ H = ctx->state[7];
+ i = 0;
+
+ do
+ {
+ P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++;
+ P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++;
+ P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++;
+ P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++;
+ P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++;
+ P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++;
+ P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++;
+ P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++;
+ }
+ while( i < 80 );
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+ ctx->state[5] += F;
+ ctx->state[6] += G;
+ ctx->state[7] += H;
+}
+
+/*
+ * SHA-512 process buffer
+ */
+void sha4_update( sha4_context *ctx, const unsigned char *input, size_t ilen )
+{
+ size_t fill;
+ unsigned int left;
+
+ if( ilen <= 0 )
+ return;
+
+ left = (unsigned int) (ctx->total[0] & 0x7F);
+ fill = 128 - left;
+
+ ctx->total[0] += (uint64_t) ilen;
+
+ if( ctx->total[0] < (uint64_t) ilen )
+ ctx->total[1]++;
+
+ if( left && ilen >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left), input, fill );
+ sha4_process( ctx, ctx->buffer );
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while( ilen >= 128 )
+ {
+ sha4_process( ctx, input );
+ input += 128;
+ ilen -= 128;
+ }
+
+ if( ilen > 0 )
+ memcpy( (void *) (ctx->buffer + left), input, ilen );
+}
+
+static const unsigned char sha4_padding[128] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-512 final digest
+ */
+void sha4_finish( sha4_context *ctx, unsigned char output[64] )
+{
+ size_t last, padn;
+ uint64_t high, low;
+ unsigned char msglen[16];
+
+ high = ( ctx->total[0] >> 61 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT64_BE( high, msglen, 0 );
+ PUT_UINT64_BE( low, msglen, 8 );
+
+ last = (size_t)( ctx->total[0] & 0x7F );
+ padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last );
+
+ sha4_update( ctx, sha4_padding, padn );
+ sha4_update( ctx, msglen, 16 );
+
+ PUT_UINT64_BE( ctx->state[0], output, 0 );
+ PUT_UINT64_BE( ctx->state[1], output, 8 );
+ PUT_UINT64_BE( ctx->state[2], output, 16 );
+ PUT_UINT64_BE( ctx->state[3], output, 24 );
+ PUT_UINT64_BE( ctx->state[4], output, 32 );
+ PUT_UINT64_BE( ctx->state[5], output, 40 );
+
+ if( ctx->is384 == 0 )
+ {
+ PUT_UINT64_BE( ctx->state[6], output, 48 );
+ PUT_UINT64_BE( ctx->state[7], output, 56 );
+ }
+}
+
+#endif /* !POLARSSL_SHA4_ALT */
+
+/*
+ * output = SHA-512( input buffer )
+ */
+void sha4( const unsigned char *input, size_t ilen,
+ unsigned char output[64], int is384 )
+{
+ sha4_context ctx;
+
+ sha4_starts( &ctx, is384 );
+ sha4_update( &ctx, input, ilen );
+ sha4_finish( &ctx, output );
+
+ polarssl_zeroize( &ctx, sizeof( sha4_context ) );
+}
+
+#if defined(POLARSSL_FS_IO)
+/*
+ * output = SHA-512( file contents )
+ */
+int sha4_file( const char *path, unsigned char output[64], int is384 )
+{
+ FILE *f;
+ size_t n;
+ sha4_context ctx;
+ unsigned char buf[1024];
+
+ if( ( f = fopen( path, "rb" ) ) == NULL )
+ return( POLARSSL_ERR_SHA4_FILE_IO_ERROR );
+
+ sha4_starts( &ctx, is384 );
+
+ while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 )
+ sha4_update( &ctx, buf, n );
+
+ sha4_finish( &ctx, output );
+
+ polarssl_zeroize( &ctx, sizeof( sha4_context ) );
+
+ if( ferror( f ) != 0 )
+ {
+ fclose( f );
+ return( POLARSSL_ERR_SHA4_FILE_IO_ERROR );
+ }
+
+ fclose( f );
+ return( 0 );
+}
+#endif /* POLARSSL_FS_IO */
+
+/*
+ * SHA-512 HMAC context setup
+ */
+void sha4_hmac_starts( sha4_context *ctx, const unsigned char *key, size_t keylen,
+ int is384 )
+{
+ size_t i;
+ unsigned char sum[64];
+
+ if( keylen > 128 )
+ {
+ sha4( key, keylen, sum, is384 );
+ keylen = ( is384 ) ? 48 : 64;
+ key = sum;
+ }
+
+ memset( ctx->ipad, 0x36, 128 );
+ memset( ctx->opad, 0x5C, 128 );
+
+ for( i = 0; i < keylen; i++ )
+ {
+ ctx->ipad[i] = (unsigned char)( ctx->ipad[i] ^ key[i] );
+ ctx->opad[i] = (unsigned char)( ctx->opad[i] ^ key[i] );
+ }
+
+ sha4_starts( ctx, is384 );
+ sha4_update( ctx, ctx->ipad, 128 );
+
+ polarssl_zeroize( sum, sizeof( sum ) );
+}
+
+/*
+ * SHA-512 HMAC process buffer
+ */
+void sha4_hmac_update( sha4_context *ctx,
+ const unsigned char *input, size_t ilen )
+{
+ sha4_update( ctx, input, ilen );
+}
+
+/*
+ * SHA-512 HMAC final digest
+ */
+void sha4_hmac_finish( sha4_context *ctx, unsigned char output[64] )
+{
+ int is384, hlen;
+ unsigned char tmpbuf[64];
+
+ is384 = ctx->is384;
+ hlen = ( is384 == 0 ) ? 64 : 48;
+
+ sha4_finish( ctx, tmpbuf );
+ sha4_starts( ctx, is384 );
+ sha4_update( ctx, ctx->opad, 128 );
+ sha4_update( ctx, tmpbuf, hlen );
+ sha4_finish( ctx, output );
+
+ polarssl_zeroize( tmpbuf, sizeof( tmpbuf ) );
+}
+
+/*
+ * SHA-512 HMAC context reset
+ */
+void sha4_hmac_reset( sha4_context *ctx )
+{
+ sha4_starts( ctx, ctx->is384 );
+ sha4_update( ctx, ctx->ipad, 128 );
+}
+
+/*
+ * output = HMAC-SHA-512( hmac key, input buffer )
+ */
+void sha4_hmac( const unsigned char *key, size_t keylen,
+ const unsigned char *input, size_t ilen,
+ unsigned char output[64], int is384 )
+{
+ sha4_context ctx;
+
+ sha4_hmac_starts( &ctx, key, keylen, is384 );
+ sha4_hmac_update( &ctx, input, ilen );
+ sha4_hmac_finish( &ctx, output );
+
+ polarssl_zeroize( &ctx, sizeof( sha4_context ) );
+}
+
+#if defined(POLARSSL_SELF_TEST)
+
+/*
+ * FIPS-180-2 test vectors
+ */
+static unsigned char sha4_test_buf[3][113] =
+{
+ { "abc" },
+ { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" },
+ { "" }
+};
+
+static const int sha4_test_buflen[3] =
+{
+ 3, 112, 1000
+};
+
+static const unsigned char sha4_test_sum[6][64] =
+{
+ /*
+ * SHA-384 test vectors
+ */
+ { 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B,
+ 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07,
+ 0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63,
+ 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED,
+ 0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23,
+ 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 },
+ { 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8,
+ 0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47,
+ 0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2,
+ 0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12,
+ 0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9,
+ 0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 },
+ { 0x9D, 0x0E, 0x18, 0x09, 0x71, 0x64, 0x74, 0xCB,
+ 0x08, 0x6E, 0x83, 0x4E, 0x31, 0x0A, 0x4A, 0x1C,
+ 0xED, 0x14, 0x9E, 0x9C, 0x00, 0xF2, 0x48, 0x52,
+ 0x79, 0x72, 0xCE, 0xC5, 0x70, 0x4C, 0x2A, 0x5B,
+ 0x07, 0xB8, 0xB3, 0xDC, 0x38, 0xEC, 0xC4, 0xEB,
+ 0xAE, 0x97, 0xDD, 0xD8, 0x7F, 0x3D, 0x89, 0x85 },
+
+ /*
+ * SHA-512 test vectors
+ */
+ { 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA,
+ 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31,
+ 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2,
+ 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A,
+ 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8,
+ 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD,
+ 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E,
+ 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F },
+ { 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA,
+ 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F,
+ 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1,
+ 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18,
+ 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4,
+ 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A,
+ 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54,
+ 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 },
+ { 0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64,
+ 0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63,
+ 0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28,
+ 0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB,
+ 0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A,
+ 0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B,
+ 0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E,
+ 0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B }
+};
+
+/*
+ * RFC 4231 test vectors
+ */
+static unsigned char sha4_hmac_test_key[7][26] =
+{
+ { "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
+ "\x0B\x0B\x0B\x0B" },
+ { "Jefe" },
+ { "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
+ "\xAA\xAA\xAA\xAA" },
+ { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
+ "\x11\x12\x13\x14\x15\x16\x17\x18\x19" },
+ { "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
+ "\x0C\x0C\x0C\x0C" },
+ { "" }, /* 0xAA 131 times */
+ { "" }
+};
+
+static const int sha4_hmac_test_keylen[7] =
+{
+ 20, 4, 20, 25, 20, 131, 131
+};
+
+static unsigned char sha4_hmac_test_buf[7][153] =
+{
+ { "Hi There" },
+ { "what do ya want for nothing?" },
+ { "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
+ "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" },
+ { "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+ "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+ "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+ "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
+ "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" },
+ { "Test With Truncation" },
+ { "Test Using Larger Than Block-Size Key - Hash Key First" },
+ { "This is a test using a larger than block-size key "
+ "and a larger than block-size data. The key needs to "
+ "be hashed before being used by the HMAC algorithm." }
+};
+
+static const int sha4_hmac_test_buflen[7] =
+{
+ 8, 28, 50, 50, 20, 54, 152
+};
+
+static const unsigned char sha4_hmac_test_sum[14][64] =
+{
+ /*
+ * HMAC-SHA-384 test vectors
+ */
+ { 0xAF, 0xD0, 0x39, 0x44, 0xD8, 0x48, 0x95, 0x62,
+ 0x6B, 0x08, 0x25, 0xF4, 0xAB, 0x46, 0x90, 0x7F,
+ 0x15, 0xF9, 0xDA, 0xDB, 0xE4, 0x10, 0x1E, 0xC6,
+ 0x82, 0xAA, 0x03, 0x4C, 0x7C, 0xEB, 0xC5, 0x9C,
+ 0xFA, 0xEA, 0x9E, 0xA9, 0x07, 0x6E, 0xDE, 0x7F,
+ 0x4A, 0xF1, 0x52, 0xE8, 0xB2, 0xFA, 0x9C, 0xB6 },
+ { 0xAF, 0x45, 0xD2, 0xE3, 0x76, 0x48, 0x40, 0x31,
+ 0x61, 0x7F, 0x78, 0xD2, 0xB5, 0x8A, 0x6B, 0x1B,
+ 0x9C, 0x7E, 0xF4, 0x64, 0xF5, 0xA0, 0x1B, 0x47,
+ 0xE4, 0x2E, 0xC3, 0x73, 0x63, 0x22, 0x44, 0x5E,
+ 0x8E, 0x22, 0x40, 0xCA, 0x5E, 0x69, 0xE2, 0xC7,
+ 0x8B, 0x32, 0x39, 0xEC, 0xFA, 0xB2, 0x16, 0x49 },
+ { 0x88, 0x06, 0x26, 0x08, 0xD3, 0xE6, 0xAD, 0x8A,
+ 0x0A, 0xA2, 0xAC, 0xE0, 0x14, 0xC8, 0xA8, 0x6F,
+ 0x0A, 0xA6, 0x35, 0xD9, 0x47, 0xAC, 0x9F, 0xEB,
+ 0xE8, 0x3E, 0xF4, 0xE5, 0x59, 0x66, 0x14, 0x4B,
+ 0x2A, 0x5A, 0xB3, 0x9D, 0xC1, 0x38, 0x14, 0xB9,
+ 0x4E, 0x3A, 0xB6, 0xE1, 0x01, 0xA3, 0x4F, 0x27 },
+ { 0x3E, 0x8A, 0x69, 0xB7, 0x78, 0x3C, 0x25, 0x85,
+ 0x19, 0x33, 0xAB, 0x62, 0x90, 0xAF, 0x6C, 0xA7,
+ 0x7A, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9C,
+ 0xC5, 0x57, 0x7C, 0x6E, 0x1F, 0x57, 0x3B, 0x4E,
+ 0x68, 0x01, 0xDD, 0x23, 0xC4, 0xA7, 0xD6, 0x79,
+ 0xCC, 0xF8, 0xA3, 0x86, 0xC6, 0x74, 0xCF, 0xFB },
+ { 0x3A, 0xBF, 0x34, 0xC3, 0x50, 0x3B, 0x2A, 0x23,
+ 0xA4, 0x6E, 0xFC, 0x61, 0x9B, 0xAE, 0xF8, 0x97 },
+ { 0x4E, 0xCE, 0x08, 0x44, 0x85, 0x81, 0x3E, 0x90,
+ 0x88, 0xD2, 0xC6, 0x3A, 0x04, 0x1B, 0xC5, 0xB4,
+ 0x4F, 0x9E, 0xF1, 0x01, 0x2A, 0x2B, 0x58, 0x8F,
+ 0x3C, 0xD1, 0x1F, 0x05, 0x03, 0x3A, 0xC4, 0xC6,
+ 0x0C, 0x2E, 0xF6, 0xAB, 0x40, 0x30, 0xFE, 0x82,
+ 0x96, 0x24, 0x8D, 0xF1, 0x63, 0xF4, 0x49, 0x52 },
+ { 0x66, 0x17, 0x17, 0x8E, 0x94, 0x1F, 0x02, 0x0D,
+ 0x35, 0x1E, 0x2F, 0x25, 0x4E, 0x8F, 0xD3, 0x2C,
+ 0x60, 0x24, 0x20, 0xFE, 0xB0, 0xB8, 0xFB, 0x9A,
+ 0xDC, 0xCE, 0xBB, 0x82, 0x46, 0x1E, 0x99, 0xC5,
+ 0xA6, 0x78, 0xCC, 0x31, 0xE7, 0x99, 0x17, 0x6D,
+ 0x38, 0x60, 0xE6, 0x11, 0x0C, 0x46, 0x52, 0x3E },
+
+ /*
+ * HMAC-SHA-512 test vectors
+ */
+ { 0x87, 0xAA, 0x7C, 0xDE, 0xA5, 0xEF, 0x61, 0x9D,
+ 0x4F, 0xF0, 0xB4, 0x24, 0x1A, 0x1D, 0x6C, 0xB0,
+ 0x23, 0x79, 0xF4, 0xE2, 0xCE, 0x4E, 0xC2, 0x78,
+ 0x7A, 0xD0, 0xB3, 0x05, 0x45, 0xE1, 0x7C, 0xDE,
+ 0xDA, 0xA8, 0x33, 0xB7, 0xD6, 0xB8, 0xA7, 0x02,
+ 0x03, 0x8B, 0x27, 0x4E, 0xAE, 0xA3, 0xF4, 0xE4,
+ 0xBE, 0x9D, 0x91, 0x4E, 0xEB, 0x61, 0xF1, 0x70,
+ 0x2E, 0x69, 0x6C, 0x20, 0x3A, 0x12, 0x68, 0x54 },
+ { 0x16, 0x4B, 0x7A, 0x7B, 0xFC, 0xF8, 0x19, 0xE2,
+ 0xE3, 0x95, 0xFB, 0xE7, 0x3B, 0x56, 0xE0, 0xA3,
+ 0x87, 0xBD, 0x64, 0x22, 0x2E, 0x83, 0x1F, 0xD6,
+ 0x10, 0x27, 0x0C, 0xD7, 0xEA, 0x25, 0x05, 0x54,
+ 0x97, 0x58, 0xBF, 0x75, 0xC0, 0x5A, 0x99, 0x4A,
+ 0x6D, 0x03, 0x4F, 0x65, 0xF8, 0xF0, 0xE6, 0xFD,
+ 0xCA, 0xEA, 0xB1, 0xA3, 0x4D, 0x4A, 0x6B, 0x4B,
+ 0x63, 0x6E, 0x07, 0x0A, 0x38, 0xBC, 0xE7, 0x37 },
+ { 0xFA, 0x73, 0xB0, 0x08, 0x9D, 0x56, 0xA2, 0x84,
+ 0xEF, 0xB0, 0xF0, 0x75, 0x6C, 0x89, 0x0B, 0xE9,
+ 0xB1, 0xB5, 0xDB, 0xDD, 0x8E, 0xE8, 0x1A, 0x36,
+ 0x55, 0xF8, 0x3E, 0x33, 0xB2, 0x27, 0x9D, 0x39,
+ 0xBF, 0x3E, 0x84, 0x82, 0x79, 0xA7, 0x22, 0xC8,
+ 0x06, 0xB4, 0x85, 0xA4, 0x7E, 0x67, 0xC8, 0x07,
+ 0xB9, 0x46, 0xA3, 0x37, 0xBE, 0xE8, 0x94, 0x26,
+ 0x74, 0x27, 0x88, 0x59, 0xE1, 0x32, 0x92, 0xFB },
+ { 0xB0, 0xBA, 0x46, 0x56, 0x37, 0x45, 0x8C, 0x69,
+ 0x90, 0xE5, 0xA8, 0xC5, 0xF6, 0x1D, 0x4A, 0xF7,
+ 0xE5, 0x76, 0xD9, 0x7F, 0xF9, 0x4B, 0x87, 0x2D,
+ 0xE7, 0x6F, 0x80, 0x50, 0x36, 0x1E, 0xE3, 0xDB,
+ 0xA9, 0x1C, 0xA5, 0xC1, 0x1A, 0xA2, 0x5E, 0xB4,
+ 0xD6, 0x79, 0x27, 0x5C, 0xC5, 0x78, 0x80, 0x63,
+ 0xA5, 0xF1, 0x97, 0x41, 0x12, 0x0C, 0x4F, 0x2D,
+ 0xE2, 0xAD, 0xEB, 0xEB, 0x10, 0xA2, 0x98, 0xDD },
+ { 0x41, 0x5F, 0xAD, 0x62, 0x71, 0x58, 0x0A, 0x53,
+ 0x1D, 0x41, 0x79, 0xBC, 0x89, 0x1D, 0x87, 0xA6 },
+ { 0x80, 0xB2, 0x42, 0x63, 0xC7, 0xC1, 0xA3, 0xEB,
+ 0xB7, 0x14, 0x93, 0xC1, 0xDD, 0x7B, 0xE8, 0xB4,
+ 0x9B, 0x46, 0xD1, 0xF4, 0x1B, 0x4A, 0xEE, 0xC1,
+ 0x12, 0x1B, 0x01, 0x37, 0x83, 0xF8, 0xF3, 0x52,
+ 0x6B, 0x56, 0xD0, 0x37, 0xE0, 0x5F, 0x25, 0x98,
+ 0xBD, 0x0F, 0xD2, 0x21, 0x5D, 0x6A, 0x1E, 0x52,
+ 0x95, 0xE6, 0x4F, 0x73, 0xF6, 0x3F, 0x0A, 0xEC,
+ 0x8B, 0x91, 0x5A, 0x98, 0x5D, 0x78, 0x65, 0x98 },
+ { 0xE3, 0x7B, 0x6A, 0x77, 0x5D, 0xC8, 0x7D, 0xBA,
+ 0xA4, 0xDF, 0xA9, 0xF9, 0x6E, 0x5E, 0x3F, 0xFD,
+ 0xDE, 0xBD, 0x71, 0xF8, 0x86, 0x72, 0x89, 0x86,
+ 0x5D, 0xF5, 0xA3, 0x2D, 0x20, 0xCD, 0xC9, 0x44,
+ 0xB6, 0x02, 0x2C, 0xAC, 0x3C, 0x49, 0x82, 0xB1,
+ 0x0D, 0x5E, 0xEB, 0x55, 0xC3, 0xE4, 0xDE, 0x15,
+ 0x13, 0x46, 0x76, 0xFB, 0x6D, 0xE0, 0x44, 0x60,
+ 0x65, 0xC9, 0x74, 0x40, 0xFA, 0x8C, 0x6A, 0x58 }
+};
+
+/*
+ * Checkup routine
+ */
+int sha4_self_test( int verbose )
+{
+ int i, j, k, buflen;
+ unsigned char buf[1024];
+ unsigned char sha4sum[64];
+ sha4_context ctx;
+
+ for( i = 0; i < 6; i++ )
+ {
+ j = i % 3;
+ k = i < 3;
+
+ if( verbose != 0 )
+ printf( " SHA-%d test #%d: ", 512 - k * 128, j + 1 );
+
+ sha4_starts( &ctx, k );
+
+ if( j == 2 )
+ {
+ memset( buf, 'a', buflen = 1000 );
+
+ for( j = 0; j < 1000; j++ )
+ sha4_update( &ctx, buf, buflen );
+ }
+ else
+ sha4_update( &ctx, sha4_test_buf[j],
+ sha4_test_buflen[j] );
+
+ sha4_finish( &ctx, sha4sum );
+
+ if( memcmp( sha4sum, sha4_test_sum[i], 64 - k * 16 ) != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ printf( "\n" );
+
+ for( i = 0; i < 14; i++ )
+ {
+ j = i % 7;
+ k = i < 7;
+
+ if( verbose != 0 )
+ printf( " HMAC-SHA-%d test #%d: ", 512 - k * 128, j + 1 );
+
+ if( j == 5 || j == 6 )
+ {
+ memset( buf, '\xAA', buflen = 131 );
+ sha4_hmac_starts( &ctx, buf, buflen, k );
+ }
+ else
+ sha4_hmac_starts( &ctx, sha4_hmac_test_key[j],
+ sha4_hmac_test_keylen[j], k );
+
+ sha4_hmac_update( &ctx, sha4_hmac_test_buf[j],
+ sha4_hmac_test_buflen[j] );
+
+ sha4_hmac_finish( &ctx, sha4sum );
+
+ buflen = ( j == 4 ) ? 16 : 64 - k * 16;
+
+ if( memcmp( sha4sum, sha4_hmac_test_sum[i], buflen ) != 0 )
+ {
+ if( verbose != 0 )
+ printf( "failed\n" );
+
+ return( 1 );
+ }
+
+ if( verbose != 0 )
+ printf( "passed\n" );
+ }
+
+ if( verbose != 0 )
+ printf( "\n" );
+
+ return( 0 );
+}
+
+#endif
+
+#endif
diff --git a/programs/nstool/nstool.vcxproj b/programs/nstool/nstool.vcxproj
index 882f63e..d0605d4 100644
--- a/programs/nstool/nstool.vcxproj
+++ b/programs/nstool/nstool.vcxproj
@@ -181,16 +181,17 @@
+
+
-
@@ -210,6 +211,7 @@
+
diff --git a/programs/nstool/nstool.vcxproj.filters b/programs/nstool/nstool.vcxproj.filters
index 2227147..2cf288a 100644
--- a/programs/nstool/nstool.vcxproj.filters
+++ b/programs/nstool/nstool.vcxproj.filters
@@ -40,6 +40,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -55,9 +58,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -88,6 +88,9 @@
Header Files
+
+ Header Files
+
@@ -111,6 +114,9 @@
Source Files
+
+ Source Files
+
Source Files
diff --git a/programs/nstool/source/AesCtrWrappedIFile.cpp b/programs/nstool/source/AesCtrWrappedIFile.cpp
index 06ea584..3acebd7 100644
--- a/programs/nstool/source/AesCtrWrappedIFile.cpp
+++ b/programs/nstool/source/AesCtrWrappedIFile.cpp
@@ -1,7 +1,6 @@
#include "AesCtrWrappedIFile.h"
-AesCtrWrappedIFile::AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr) :
- mOwnIFile(ownIfile),
+AesCtrWrappedIFile::AesCtrWrappedIFile(const fnd::SharedPtr& file, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr) :
mFile(file),
mKey(key),
mBaseCtr(ctr),
@@ -10,17 +9,9 @@ AesCtrWrappedIFile::AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const fn
mCache.alloc(kCacheSizeAllocSize);
}
-AesCtrWrappedIFile::~AesCtrWrappedIFile()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
-}
-
size_t AesCtrWrappedIFile::size()
{
- return mFile->size();
+ return (*mFile)->size();
}
void AesCtrWrappedIFile::seek(size_t offset)
@@ -44,8 +35,8 @@ void AesCtrWrappedIFile::read(byte_t* out, size_t len)
//printf("[%x] AesCtrWrappedIFile::read() CACHE READ: readlen=%" PRIx64 "\n", this, read_len);
- mFile->seek(read_pos);
- mFile->read(mCache.data(), kCacheSizeAllocSize);
+ (*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());
@@ -81,8 +72,8 @@ void AesCtrWrappedIFile::write(const byte_t* in, size_t 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);
+ (*mFile)->seek(write_pos);
+ (*mFile)->write(mCache.data(), kCacheSizeAllocSize);
}
seek(mFileOffset + len);
@@ -92,7 +83,7 @@ void AesCtrWrappedIFile::write(const byte_t* in, size_t len)
{
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);
+ (*mFile)->write(mScratch.data() + mBlockOffset, kAesCtrScratchSize);
}
if (len % kAesCtrScratchSize)
@@ -101,7 +92,7 @@ void AesCtrWrappedIFile::write(const byte_t* in, size_t len)
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);
+ (*mFile)->write(mScratch.data() + mBlockOffset, write_len);
}
*/
seek(mFileOffset + len);
diff --git a/programs/nstool/source/AesCtrWrappedIFile.h b/programs/nstool/source/AesCtrWrappedIFile.h
index 1703bc8..0404cca 100644
--- a/programs/nstool/source/AesCtrWrappedIFile.h
+++ b/programs/nstool/source/AesCtrWrappedIFile.h
@@ -1,12 +1,12 @@
#include
+#include
#include
#include
class AesCtrWrappedIFile : public fnd::IFile
{
public:
- AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr);
- ~AesCtrWrappedIFile();
+ AesCtrWrappedIFile(const fnd::SharedPtr& file, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr);
size_t size();
void seek(size_t offset);
@@ -19,8 +19,7 @@ private:
static const size_t kCacheSize = 0x10000;
static const size_t kCacheSizeAllocSize = kCacheSize + fnd::aes::kAesBlockSize;
- bool mOwnIFile;
- fnd::IFile* mFile;
+ fnd::SharedPtr mFile;
fnd::aes::sAes128Key mKey;
fnd::aes::sAesIvCtr mBaseCtr, mCurrentCtr;
size_t mFileOffset;
diff --git a/programs/nstool/source/AssetProcess.cpp b/programs/nstool/source/AssetProcess.cpp
index ef48adf..a218f20 100644
--- a/programs/nstool/source/AssetProcess.cpp
+++ b/programs/nstool/source/AssetProcess.cpp
@@ -1,3 +1,5 @@
+#include
+#include
#include
#include
#include "AssetProcess.h"
@@ -5,39 +7,23 @@
AssetProcess::AssetProcess() :
- mFile(nullptr),
- mOwnIFile(false),
+ mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false)
{
-
-}
-
-AssetProcess::~AssetProcess()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
}
void AssetProcess::process()
{
- if (mFile == nullptr)
- {
- throw fnd::Exception(kModuleName, "No file reader set.");
- }
-
importHeader();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
displayHeader();
processSections();
}
-void AssetProcess::setInputFile(fnd::IFile* file, bool ownIFile)
+void AssetProcess::setInputFile(const fnd::SharedPtr& file)
{
mFile = file;
- mOwnIFile = ownIFile;
}
void AssetProcess::setCliOutputMode(CliOutputMode type)
@@ -74,13 +60,19 @@ void AssetProcess::setRomfsExtractPath(const std::string& path)
void AssetProcess::importHeader()
{
fnd::Vec scratch;
- if (mFile->size() < sizeof(nn::hac::sAssetHeader))
+
+ if (*mFile == nullptr)
+ {
+ throw fnd::Exception(kModuleName, "No file reader set.");
+ }
+
+ if ((*mFile)->size() < sizeof(nn::hac::sAssetHeader))
{
throw fnd::Exception(kModuleName, "Corrupt ASET: file too small");
}
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());
}
@@ -89,21 +81,21 @@ void AssetProcess::processSections()
{
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");
fnd::SimpleFile outfile(mIconExtractPath.var, fnd::SimpleFile::Create);
fnd::Vec cache;
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.close();
}
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");
if (mNacpExtractPath.isSet)
@@ -112,12 +104,12 @@ void AssetProcess::processSections()
fnd::Vec cache;
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.close();
}
- mNacp.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size), true);
+ mNacp.setInputFile(new OffsetAdjustedIFile(mFile, mHdr.getNacpInfo().offset, mHdr.getNacpInfo().size));
mNacp.setCliOutputMode(mCliOutputMode);
mNacp.setVerifyMode(mVerify);
@@ -126,10 +118,10 @@ void AssetProcess::processSections()
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");
- mRomfs.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getRomfsInfo().offset, mHdr.getRomfsInfo().size), true);
+ mRomfs.setInputFile(new OffsetAdjustedIFile(mFile, mHdr.getRomfsInfo().offset, mHdr.getRomfsInfo().size));
mRomfs.setCliOutputMode(mCliOutputMode);
mRomfs.setVerifyMode(mVerify);
@@ -141,16 +133,16 @@ void AssetProcess::displayHeader()
{
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
{
- printf("[ASET Header]\n");
- printf(" Icon:\n");
- printf(" Offset: 0x%" PRIx64 "\n", mHdr.getIconInfo().offset);
- printf(" Size: 0x%" PRIx64 "\n", mHdr.getIconInfo().size);
- printf(" NACP:\n");
- printf(" Offset: 0x%" PRIx64 "\n", mHdr.getNacpInfo().offset);
- printf(" Size: 0x%" PRIx64 "\n", mHdr.getNacpInfo().size);
- printf(" RomFS:\n");
- printf(" Offset: 0x%" PRIx64 "\n", mHdr.getRomfsInfo().offset);
- printf(" Size: 0x%" PRIx64 "\n", mHdr.getRomfsInfo().size);
+ std::cout << "[ASET Header]" << std::endl;
+ std::cout << " Icon:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << mHdr.getIconInfo().offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << mHdr.getIconInfo().size << std::endl;
+ std::cout << " NACP:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << mHdr.getNacpInfo().offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << mHdr.getNacpInfo().size << std::endl;
+ std::cout << " RomFS:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << mHdr.getRomfsInfo().offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << mHdr.getRomfsInfo().size << std::endl;
}
}
diff --git a/programs/nstool/source/AssetProcess.h b/programs/nstool/source/AssetProcess.h
index aae5177..7364d15 100644
--- a/programs/nstool/source/AssetProcess.h
+++ b/programs/nstool/source/AssetProcess.h
@@ -2,21 +2,21 @@
#include
#include
#include
+#include
#include
#include "NacpProcess.h"
#include "RomfsProcess.h"
-#include "nstool.h"
+#include "common.h"
class AssetProcess
{
public:
AssetProcess();
- ~AssetProcess();
void process();
- void setInputFile(fnd::IFile* file, bool ownIFile);
+ void setInputFile(const fnd::SharedPtr& file);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
@@ -30,8 +30,7 @@ public:
private:
const std::string kModuleName = "AssetProcess";
- fnd::IFile* mFile;
- bool mOwnIFile;
+ fnd::SharedPtr mFile;
CliOutputMode mCliOutputMode;
bool mVerify;
diff --git a/programs/nstool/source/CnmtProcess.cpp b/programs/nstool/source/CnmtProcess.cpp
index 1606a9d..8abc73d 100644
--- a/programs/nstool/source/CnmtProcess.cpp
+++ b/programs/nstool/source/CnmtProcess.cpp
@@ -1,184 +1,27 @@
+#include
+#include
#include
#include "OffsetAdjustedIFile.h"
#include "CnmtProcess.h"
-const std::string kContentTypeStr[7] =
-{
- "Meta",
- "Program",
- "Data",
- "Control",
- "HtmlDocument",
- "LegalInformation",
- "DeltaFragment"
-};
-
-const std::string kContentMetaTypeStr[2][0x80] =
-{
- {
- "",
- "SystemProgram",
- "SystemData",
- "SystemUpdate",
- "BootImagePackage",
- "BootImagePackageSafe"
- },
- {
- "Application",
- "Patch",
- "AddOnContent",
- "Delta"
- }
-};
-
-const std::string kUpdateTypeStr[3] =
-{
- "ApplyAsDelta",
- "Overwrite",
- "Create"
-};
-
-const std::string kContentMetaAttrStr[3] =
-{
- "IncludesExFatDriver",
- "Rebootless"
-};
-
-
-std::string kUnknownStr = "Unknown";
-
-inline const char* getBoolStr(bool isTrue)
-{
- return isTrue? "TRUE" : "FALSE";
-}
-
-inline const char* getContentTypeStr(byte_t i)
-{
- return i < 7 ? kContentTypeStr[i].c_str() : kUnknownStr.c_str();
-}
-
-inline const char* getContentMetaTypeStr(byte_t i)
-{
- return (i < 0x80) ? kContentMetaTypeStr[0][i].c_str() : kContentMetaTypeStr[1][i - 0x80].c_str();
-}
-
-void CnmtProcess::displayCmnt()
-{
-#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff)
-#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0)
-#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
-
- printf("[ContentMeta]\n");
- printf(" TitleId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getTitleId());
- printf(" Version: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getTitleVersion(), _SPLIT_VER(mCnmt.getTitleVersion()));
- printf(" Type: %s (%d)\n", getContentMetaTypeStr(mCnmt.getType()), mCnmt.getType());
- printf(" Attributes: %x\n", mCnmt.getAttributes());
- printf(" IncludesExFatDriver: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER)));
- printf(" Rebootless: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_REBOOTLESS)));
- printf(" RequiredDownloadSystemVersion: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getRequiredDownloadSystemVersion(), _SPLIT_VER(mCnmt.getRequiredDownloadSystemVersion()));
- switch(mCnmt.getType())
- {
- case (nn::hac::cnmt::METATYPE_APPLICATION):
- printf(" ApplicationExtendedHeader:\n");
- printf(" RequiredSystemVersion: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getApplicationMetaExtendedHeader().required_system_version, _SPLIT_VER(mCnmt.getApplicationMetaExtendedHeader().required_system_version));
- printf(" PatchId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getApplicationMetaExtendedHeader().patch_id);
- break;
- case (nn::hac::cnmt::METATYPE_PATCH):
- printf(" PatchMetaExtendedHeader:\n");
- printf(" RequiredSystemVersion: v%" PRId32 " (%d.%d.%d.%d))\n", (uint32_t)mCnmt.getPatchMetaExtendedHeader().required_system_version, _SPLIT_VER(mCnmt.getPatchMetaExtendedHeader().required_system_version));
- printf(" ApplicationId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getPatchMetaExtendedHeader().application_id);
- break;
- case (nn::hac::cnmt::METATYPE_ADD_ON_CONTENT):
- printf(" AddOnContentMetaExtendedHeader:\n");
- printf(" RequiredSystemVersion: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)mCnmt.getAddOnContentMetaExtendedHeader().required_system_version, _SPLIT_VER(mCnmt.getAddOnContentMetaExtendedHeader().required_system_version));
- printf(" ApplicationId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getAddOnContentMetaExtendedHeader().application_id);
- break;
- case (nn::hac::cnmt::METATYPE_DELTA):
- printf(" DeltaMetaExtendedHeader:\n");
- printf(" ApplicationId: 0x%016" PRIx64 "\n", (uint64_t)mCnmt.getDeltaMetaExtendedHeader().application_id);
- break;
- default:
- break;
- }
- if (mCnmt.getContentInfo().size() > 0)
- {
- printf(" ContentInfo:\n");
- for (size_t i = 0; i < mCnmt.getContentInfo().size(); i++)
- {
- const nn::hac::ContentMetaBinary::ContentInfo& info = mCnmt.getContentInfo()[i];
- printf(" %d\n", (int)i);
- printf(" Type: %s (%d)\n", getContentTypeStr(info.type), info.type);
- printf(" Id: ");
- _HEXDUMP_L(info.nca_id, nn::hac::cnmt::kContentIdLen);
- printf("\n");
- printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size);
- printf(" Hash: ");
- _HEXDUMP_L(info.hash.bytes, sizeof(info.hash));
- printf("\n");
- }
- }
- if (mCnmt.getContentMetaInfo().size() > 0)
- {
- printf(" ContentMetaInfo:\n");
- for (size_t i = 0; i < mCnmt.getContentMetaInfo().size(); i++)
- {
- const nn::hac::ContentMetaBinary::ContentMetaInfo& info = mCnmt.getContentMetaInfo()[i];
- printf(" %d\n", (int)i);
- printf(" Id: 0x%016" PRIx64 "\n", (uint64_t)info.id);
- printf(" Version: v%" PRId32 " (%d.%d.%d.%d)\n", (uint32_t)info.version, _SPLIT_VER(info.version));
- printf(" Type: %s (%d)\n", getContentMetaTypeStr(info.type), info.type);
- printf(" Attributes: %x\n", mCnmt.getAttributes());
- printf(" IncludesExFatDriver: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER)));
- printf(" Rebootless: %s\n", getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_REBOOTLESS)));
- }
- }
- printf(" Digest: ");
- _HEXDUMP_L(mCnmt.getDigest().data, nn::hac::cnmt::kDigestLen);
- printf("\n");
-
-#undef _HEXDUMP_L
-#undef _HEXDUMP_U
-#undef _SPLIT_VER
-}
-
CnmtProcess::CnmtProcess() :
- mFile(nullptr),
- mOwnIFile(false),
+ mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false)
{
}
-CnmtProcess::~CnmtProcess()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
-}
-
void CnmtProcess::process()
{
- fnd::Vec scratch;
-
- if (mFile == nullptr)
- {
- throw fnd::Exception(kModuleName, "No file reader set.");
- }
-
- scratch.alloc(mFile->size());
- mFile->read(scratch.data(), 0, scratch.size());
-
- mCnmt.fromBytes(scratch.data(), scratch.size());
+ importCnmt();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
- displayCmnt();
+ displayCnmt();
}
-void CnmtProcess::setInputFile(fnd::IFile* file, bool ownIFile)
+void CnmtProcess::setInputFile(const fnd::SharedPtr& file)
{
mFile = file;
- mOwnIFile = ownIFile;
}
void CnmtProcess::setCliOutputMode(CliOutputMode type)
@@ -195,3 +38,212 @@ const nn::hac::ContentMetaBinary& CnmtProcess::getContentMetaBinary() const
{
return mCnmt;
}
+
+void CnmtProcess::importCnmt()
+{
+ fnd::Vec scratch;
+
+ if (*mFile == nullptr)
+ {
+ throw fnd::Exception(kModuleName, "No file reader set.");
+ }
+
+ scratch.alloc((*mFile)->size());
+ (*mFile)->read(scratch.data(), 0, scratch.size());
+
+ mCnmt.fromBytes(scratch.data(), scratch.size());
+}
+
+void CnmtProcess::displayCnmt()
+{
+#define _SPLIT_VER(ver) (uint32_t)((ver>>26) & 0x3f) << "." << (uint32_t)((ver>>20) & 0x3f) << "." << (uint32_t)((ver>>16) & 0xf) << "." << (uint32_t)(ver & 0xffff)
+
+ std::cout << "[ContentMeta]" << std::endl;
+ std::cout << " TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getTitleId() << std::endl;
+ std::cout << " Version: v" << std::dec << mCnmt.getTitleVersion() << " (" << _SPLIT_VER(mCnmt.getTitleVersion()) << ")"<< std::endl;
+ std::cout << " Type: " << getContentMetaTypeStr(mCnmt.getType()) << " (" << std::dec << mCnmt.getType() << ")" << std::endl;
+ std::cout << " Attributes: 0x" << std::hex << (uint32_t)mCnmt.getAttributes() << std::endl;
+ std::cout << " IncludesExFatDriver: " << getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER)) << std::endl;
+ std::cout << " Rebootless: " << getBoolStr(_HAS_BIT(mCnmt.getAttributes(), nn::hac::cnmt::ATTRIBUTE_REBOOTLESS)) << std::endl;
+ std::cout << " RequiredDownloadSystemVersion: v" << mCnmt.getRequiredDownloadSystemVersion() << " (" << _SPLIT_VER(mCnmt.getRequiredDownloadSystemVersion()) << ")"<< std::endl;
+ switch(mCnmt.getType())
+ {
+ case (nn::hac::cnmt::METATYPE_APPLICATION):
+ std::cout << " ApplicationExtendedHeader:" << std::endl;
+ std::cout << " RequiredSystemVersion: v" << std::dec << mCnmt.getApplicationMetaExtendedHeader().required_system_version << " (" << _SPLIT_VER(mCnmt.getApplicationMetaExtendedHeader().required_system_version) << ")"<< std::endl;
+ std::cout << " PatchId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getApplicationMetaExtendedHeader().patch_id << std::endl;
+ break;
+ case (nn::hac::cnmt::METATYPE_PATCH):
+ std::cout << " PatchMetaExtendedHeader:" << std::endl;
+ std::cout << " RequiredSystemVersion: v" << std::dec << mCnmt.getPatchMetaExtendedHeader().required_system_version << " (" << _SPLIT_VER(mCnmt.getPatchMetaExtendedHeader().required_system_version) << ")"<< std::endl;
+ std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getPatchMetaExtendedHeader().application_id << std::endl;
+ break;
+ case (nn::hac::cnmt::METATYPE_ADD_ON_CONTENT):
+ std::cout << " AddOnContentMetaExtendedHeader:" << std::endl;
+ std::cout << " RequiredApplicationVersion: v" << std::dec << mCnmt.getAddOnContentMetaExtendedHeader().required_application_version << " (" << _SPLIT_VER(mCnmt.getAddOnContentMetaExtendedHeader().required_application_version) << ")" << std::endl;
+ std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getAddOnContentMetaExtendedHeader().application_id << std::endl;
+ break;
+ case (nn::hac::cnmt::METATYPE_DELTA):
+ std::cout << " DeltaMetaExtendedHeader:" << std::endl;
+ std::cout << " ApplicationId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mCnmt.getDeltaMetaExtendedHeader().application_id << std::endl;
+ break;
+ default:
+ break;
+ }
+ if (mCnmt.getContentInfo().size() > 0)
+ {
+ printf(" ContentInfo:\n");
+ for (size_t i = 0; i < mCnmt.getContentInfo().size(); i++)
+ {
+ const nn::hac::ContentMetaBinary::ContentInfo& info = mCnmt.getContentInfo()[i];
+ std::cout << " " << std::dec << i << std::endl;
+ std::cout << " Type: " << getContentTypeStr(info.type) << " (" << std::dec << info.type << ")" << std::endl;
+ std::cout << " Id: " << fnd::SimpleTextOutput::arrayToString(info.nca_id, nn::hac::cnmt::kContentIdLen, false, "") << std::endl;
+ std::cout << " Size: 0x" << std::hex << info.size << std::endl;
+ std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(info.hash.bytes, sizeof(info.hash), false, "") << std::endl;
+ }
+ }
+ if (mCnmt.getContentMetaInfo().size() > 0)
+ {
+ std::cout << " ContentMetaInfo:" << std::endl;
+ for (size_t i = 0; i < mCnmt.getContentMetaInfo().size(); i++)
+ {
+ const nn::hac::ContentMetaBinary::ContentMetaInfo& info = mCnmt.getContentMetaInfo()[i];
+ std::cout << " " << std::dec << i << std::endl;
+ std::cout << " Id: 0x" << std::hex << std::setw(16) << std::setfill('0') << info.id << std::endl;
+ std::cout << " Version: v" << std::dec << info.version << " (" << _SPLIT_VER(info.version) << ")"<< std::endl;
+ std::cout << " Type: " << getContentMetaTypeStr(info.type) << " (" << std::dec << info.type << ")" << std::endl;
+ std::cout << " Attributes: 0x" << std::hex << (uint32_t)info.attributes << std::endl;
+ std::cout << " IncludesExFatDriver: " << getBoolStr(_HAS_BIT(info.attributes, nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER)) << std::endl;
+ std::cout << " Rebootless: " << getBoolStr(_HAS_BIT(info.attributes, nn::hac::cnmt::ATTRIBUTE_REBOOTLESS)) << std::endl;
+ }
+ }
+
+ std::cout << " Digest: " << fnd::SimpleTextOutput::arrayToString(mCnmt.getDigest().data, nn::hac::cnmt::kDigestLen, false, "") << std::endl;
+
+#undef _SPLIT_VER
+}
+
+const char* CnmtProcess::getBoolStr(bool state) const
+{
+ return state? "TRUE" : "FALSE";
+}
+
+const char* CnmtProcess::getContentTypeStr(nn::hac::cnmt::ContentType type) const
+{
+ const char* str = nullptr;
+
+ switch (type)
+ {
+ case (nn::hac::cnmt::TYPE_META):
+ str = "Meta";
+ break;
+ case (nn::hac::cnmt::TYPE_PROGRAM):
+ str = "Program";
+ break;
+ case (nn::hac::cnmt::TYPE_DATA):
+ str = "Data";
+ break;
+ case (nn::hac::cnmt::TYPE_CONTROL):
+ str = "Control";
+ break;
+ case (nn::hac::cnmt::TYPE_HTML_DOCUMENT):
+ str = "HtmlDocument";
+ break;
+ case (nn::hac::cnmt::TYPE_LEGAL_INFORMATION):
+ str = "LegalInformation";
+ break;
+ case (nn::hac::cnmt::TYPE_DELTA_FRAGMENT):
+ str = "DeltaFragment";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* CnmtProcess::getContentMetaTypeStr(nn::hac::cnmt::ContentMetaType type) const
+{
+ const char* str = nullptr;
+
+ switch (type)
+ {
+ case (nn::hac::cnmt::METATYPE_SYSTEM_PROGRAM):
+ str = "SystemProgram";
+ break;
+ case (nn::hac::cnmt::METATYPE_SYSTEM_DATA):
+ str = "SystemData";
+ break;
+ case (nn::hac::cnmt::METATYPE_SYSTEM_UPDATE):
+ str = "SystemUpdate";
+ break;
+ case (nn::hac::cnmt::METATYPE_BOOT_IMAGE_PACKAGE):
+ str = "BootImagePackage";
+ break;
+ case (nn::hac::cnmt::METATYPE_BOOT_IMAGE_PACKAGE_SAFE):
+ str = "BootImagePackageSafe";
+ break;
+ case (nn::hac::cnmt::METATYPE_APPLICATION):
+ str = "Application";
+ break;
+ case (nn::hac::cnmt::METATYPE_PATCH):
+ str = "Patch";
+ break;
+ case (nn::hac::cnmt::METATYPE_ADD_ON_CONTENT):
+ str = "AddOnContent";
+ break;
+ case (nn::hac::cnmt::METATYPE_DELTA):
+ str = "Delta";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* CnmtProcess::getUpdateTypeStr(nn::hac::cnmt::UpdateType type) const
+{
+ const char* str = nullptr;
+
+ switch (type)
+ {
+ case (nn::hac::cnmt::UPDATETYPE_APPLY_AS_DELTA):
+ str = "ApplyAsDelta";
+ break;
+ case (nn::hac::cnmt::UPDATETYPE_OVERWRITE):
+ str = "Overwrite";
+ break;
+ case (nn::hac::cnmt::UPDATETYPE_CREATE):
+ str = "Create";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* CnmtProcess::getContentMetaAttrStr(nn::hac::cnmt::ContentMetaAttribute attr) const
+{
+ const char* str = nullptr;
+
+ switch (attr)
+ {
+ case (nn::hac::cnmt::ATTRIBUTE_INCLUDES_EX_FAT_DRIVER):
+ str = "IncludesExFatDriver";
+ break;
+ case (nn::hac::cnmt::ATTRIBUTE_REBOOTLESS):
+ str = "Rebootless";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
diff --git a/programs/nstool/source/CnmtProcess.h b/programs/nstool/source/CnmtProcess.h
index 1f4ca52..4fa561c 100644
--- a/programs/nstool/source/CnmtProcess.h
+++ b/programs/nstool/source/CnmtProcess.h
@@ -2,19 +2,19 @@
#include
#include
#include
+#include
#include
-#include "nstool.h"
+#include "common.h"
class CnmtProcess
{
public:
CnmtProcess();
- ~CnmtProcess();
void process();
- void setInputFile(fnd::IFile* file, bool ownIFile);
+ void setInputFile(const fnd::SharedPtr& file);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
@@ -23,12 +23,18 @@ public:
private:
const std::string kModuleName = "CnmtProcess";
- fnd::IFile* mFile;
- bool mOwnIFile;
+ fnd::SharedPtr mFile;
CliOutputMode mCliOutputMode;
bool mVerify;
nn::hac::ContentMetaBinary mCnmt;
- void displayCmnt();
+ void importCnmt();
+ void displayCnmt();
+
+ const char* getBoolStr(bool state) const;
+ const char* getContentTypeStr(nn::hac::cnmt::ContentType type) const;
+ const char* getContentMetaTypeStr(nn::hac::cnmt::ContentMetaType type) const;
+ const char* getUpdateTypeStr(nn::hac::cnmt::UpdateType type) const;
+ const char* getContentMetaAttrStr(nn::hac::cnmt::ContentMetaAttribute attr) const;
};
\ No newline at end of file
diff --git a/programs/nstool/source/ElfSymbolParser.cpp b/programs/nstool/source/ElfSymbolParser.cpp
index acac3d0..b57c9f2 100644
--- a/programs/nstool/source/ElfSymbolParser.cpp
+++ b/programs/nstool/source/ElfSymbolParser.cpp
@@ -22,38 +22,38 @@ bool ElfSymbolParser::operator!=(const ElfSymbolParser& other) const
void ElfSymbolParser::parseData(const byte_t *dyn_sym, size_t dyn_sym_size, const byte_t *dyn_str, size_t dyn_str_size, bool is64Bit)
{
- //printf("ElfSymbolParser::parseData()");
- size_t dynSymSize = is64Bit ? sizeof(nn::hac::sElfSymbol64Bit) : sizeof(nn::hac::sElfSymbol32Bit);
+ size_t dynSymSize = is64Bit ? sizeof(fnd::Elf64_Sym) : sizeof(fnd::Elf32_Sym);
sElfSymbol symbol;
for (size_t i = 0; i < dyn_sym_size; i += dynSymSize)
{
- //printf("pos %x\n", i);
-
uint32_t name_pos;
if (is64Bit)
{
- name_pos = ((nn::hac::sElfSymbol64Bit*)(dyn_sym + i))->name.get();
- symbol.shn_index = (nn::hac::elf::SpecialSectionIndex)((nn::hac::sElfSymbol64Bit*)(dyn_sym + i))->special_section_index.get();
- symbol.symbol_type = (nn::hac::elf::SymbolType)((((nn::hac::sElfSymbol64Bit*)(dyn_sym + i))->info) & nn::hac::elf::STT_HIPROC);
- symbol.symbol_binding = (nn::hac::elf::SymbolBinding)(((((nn::hac::sElfSymbol64Bit*)(dyn_sym + i))->info) >> 4) & nn::hac::elf::STB_HIPROC);
+ name_pos = le_word(((fnd::Elf64_Sym*)(dyn_sym + i))->st_name);
+ symbol.shn_index = le_hword(((fnd::Elf64_Sym*)(dyn_sym + i))->st_shndx);
+ symbol.symbol_type = fnd::elf::get_elf_st_type(((fnd::Elf64_Sym*)(dyn_sym + i))->st_info);
+ symbol.symbol_binding = fnd::elf::get_elf_st_bind(((fnd::Elf64_Sym*)(dyn_sym + i))->st_info);
}
else
{
- name_pos = ((nn::hac::sElfSymbol64Bit*)(dyn_sym + i))->name.get();
- symbol.shn_index = (nn::hac::elf::SpecialSectionIndex)((nn::hac::sElfSymbol32Bit*)(dyn_sym + i))->special_section_index.get();
- symbol.symbol_type = (nn::hac::elf::SymbolType)((((nn::hac::sElfSymbol32Bit*)(dyn_sym + i))->info.get()) & nn::hac::elf::STT_HIPROC);
- symbol.symbol_binding = (nn::hac::elf::SymbolBinding)(((((nn::hac::sElfSymbol32Bit*)(dyn_sym + i))->info.get()) >> 4) & nn::hac::elf::STB_HIPROC);
+ name_pos = le_word(((fnd::Elf32_Sym*)(dyn_sym + i))->st_name);
+ symbol.shn_index = le_hword(((fnd::Elf32_Sym*)(dyn_sym + i))->st_shndx);
+ symbol.symbol_type = fnd::elf::get_elf_st_type(((fnd::Elf32_Sym*)(dyn_sym + i))->st_info);
+ symbol.symbol_binding = fnd::elf::get_elf_st_bind(((fnd::Elf32_Sym*)(dyn_sym + i))->st_info);
}
- for (; dyn_str[name_pos] == 0x00 && name_pos < dyn_str_size; name_pos++);
+ if (name_pos >= dyn_str_size)
+ {
+ throw fnd::Exception(kModuleName, "Out of bounds symbol name offset");
+ }
+
+ //for (; dyn_str[name_pos] == 0x00 && name_pos < dyn_str_size; name_pos++);
- //printf("name_pos = 0x%x\n", name_pos);
symbol.name = std::string((char*)&dyn_str[name_pos]);
mSymbolList.addElement(symbol);
}
- //printf("ElfSymbolParser::parseData() end\n");
}
const fnd::List& ElfSymbolParser::getSymbolList() const
diff --git a/programs/nstool/source/ElfSymbolParser.h b/programs/nstool/source/ElfSymbolParser.h
index a4e4b5c..e06bdf3 100644
--- a/programs/nstool/source/ElfSymbolParser.h
+++ b/programs/nstool/source/ElfSymbolParser.h
@@ -1,16 +1,16 @@
#pragma once
#include
#include
-#include
+#include
class ElfSymbolParser
{
public:
struct sElfSymbol
{
- nn::hac::elf::SpecialSectionIndex shn_index;
- nn::hac::elf::SymbolType symbol_type;
- nn::hac::elf::SymbolBinding symbol_binding;
+ uint16_t shn_index;
+ byte_t symbol_type;
+ byte_t symbol_binding;
std::string name;
void operator=(const sElfSymbol& other)
@@ -42,6 +42,7 @@ public:
const fnd::List& getSymbolList() const;
private:
+ const std::string kModuleName = "ElfSymbolParser";
// data
fnd::List mSymbolList;
diff --git a/programs/nstool/source/EsTikProcess.cpp b/programs/nstool/source/EsTikProcess.cpp
index cec162a..b3d1c73 100644
--- a/programs/nstool/source/EsTikProcess.cpp
+++ b/programs/nstool/source/EsTikProcess.cpp
@@ -1,6 +1,5 @@
#include
#include
-
#include
#include
#include "OffsetAdjustedIFile.h"
@@ -10,21 +9,12 @@
EsTikProcess::EsTikProcess() :
- mFile(nullptr),
- mOwnIFile(false),
+ mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false)
{
}
-EsTikProcess::~EsTikProcess()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
-}
-
void EsTikProcess::process()
{
importTicket();
@@ -36,15 +26,14 @@ void EsTikProcess::process()
displayTicket();
}
-void EsTikProcess::setInputFile(fnd::IFile* file, bool ownIFile)
+void EsTikProcess::setInputFile(const fnd::SharedPtr& file)
{
mFile = file;
- mOwnIFile = ownIFile;
}
-void EsTikProcess::setKeyset(const sKeyset* keyset)
+void EsTikProcess::setKeyCfg(const KeyConfiguration& keycfg)
{
- mKeyset = keyset;
+ mKeyCfg = keycfg;
}
void EsTikProcess::setCertificateChain(const fnd::List>& certs)
@@ -64,14 +53,16 @@ void EsTikProcess::setVerifyMode(bool verify)
void EsTikProcess::importTicket()
{
- if (mFile == nullptr)
+ fnd::Vec scratch;
+
+
+ if (*mFile == nullptr)
{
throw fnd::Exception(kModuleName, "No file reader set.");
}
- fnd::Vec scratch;
- scratch.alloc(mFile->size());
- mFile->read(scratch.data(), 0, scratch.size());
+ scratch.alloc((*mFile)->size());
+ (*mFile)->read(scratch.data(), 0, scratch.size());
mTik.fromBytes(scratch.data(), scratch.size());
}
@@ -94,7 +85,7 @@ void EsTikProcess::verifyTicket()
try
{
- pki_validator.setRootKey(mKeyset->pki.root_sign_key);
+ pki_validator.setKeyCfg(mKeyCfg);
pki_validator.addCertificates(mCerts);
pki_validator.validateSignature(mTik.getBody().getIssuer(), mTik.getSignature().getSignType(), mTik.getSignature().getSignature(), tik_hash);
}
@@ -106,9 +97,7 @@ void EsTikProcess::verifyTicket()
void EsTikProcess::displayTicket()
{
-#define _SPLIT_VER(ver) ( (ver>>10) & 0x3f), ( (ver>>4) & 0x3f), ( (ver>>0) & 0xf)
-#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0)
-#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
+#define _SPLIT_VER(ver) (uint32_t)((ver>>10) & 0x3f) << "." << (uint32_t)((ver>>4) & 0x3f) << "." << (uint32_t)((ver>>0) & 0xf)
const nn::es::TicketBody_V2& body = mTik.getBody();
@@ -123,14 +112,26 @@ void EsTikProcess::displayTicket()
std::cout << " Title Key:" << std::endl;
std::cout << " EncMode: " << getTitleKeyPersonalisationStr(body.getTitleKeyEncType()) << std::endl;
std::cout << " KeyGeneration: " << std::dec << (uint32_t)body.getCommonKeyId() << std::endl;
- std::cout << " Data:" << std::endl;
- size_t size = body.getTitleKeyEncType() == nn::es::ticket::RSA2048 ? fnd::rsa::kRsa2048Size : fnd::aes::kAes128KeySize;
- fnd::SimpleTextOutput::hexDump(body.getEncTitleKey(), size, 0x10, 6);
+ if (body.getTitleKeyEncType() == nn::es::ticket::RSA2048)
+ {
+ std::cout << " Data:" << std::endl;
+ for (size_t i = 0; i < 0x10; i++)
+ std::cout << " " << fnd::SimpleTextOutput::arrayToString(body.getEncTitleKey() + 0x10*i, 0x10, true, ":") << std::endl;
+ }
+ else if (body.getTitleKeyEncType() == nn::es::ticket::AES128_CBC)
+ {
+ std::cout << " Data:" << std::endl;
+ std::cout << " " << fnd::SimpleTextOutput::arrayToString(body.getEncTitleKey(), 0x10, true, ":") << std::endl;
+ }
+ else
+ {
+ std::cout << " Data: " << std::endl;
+ }
- printf(" Version: v%d.%d.%d", _SPLIT_VER(body.getTicketVersion()));
+ std::cout << " Version: v" << _SPLIT_VER(body.getTicketVersion());
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- printf(" (%d)", body.getTicketVersion());
- printf("\n");
+ std::cout << " (" << (uint32_t)body.getTicketVersion() << ")";
+ std::cout << std::endl;
std::cout << " License Type: " << getLicenseTypeStr(body.getLicenseType()) << std::endl;
@@ -163,9 +164,6 @@ void EsTikProcess::displayTicket()
std::cout << " SectionNum: 0x" << std::hex << body.getSectionNum() << std::endl;
std::cout << " SectionEntrySize: 0x" << std::hex << body.getSectionEntrySize() << std::endl;
-
-#undef _HEXDUMP_L
-#undef _HEXDUMP_U
#undef _SPLIT_VER
}
diff --git a/programs/nstool/source/EsTikProcess.h b/programs/nstool/source/EsTikProcess.h
index 82d82d0..cf3e36e 100644
--- a/programs/nstool/source/EsTikProcess.h
+++ b/programs/nstool/source/EsTikProcess.h
@@ -2,22 +2,23 @@
#include
#include
#include
+#include
#include
#include
#include
#include
-#include "nstool.h"
+#include "KeyConfiguration.h"
+#include "common.h"
class EsTikProcess
{
public:
EsTikProcess();
- ~EsTikProcess();
void process();
- void setInputFile(fnd::IFile* file, bool ownIFile);
- void setKeyset(const sKeyset* keyset);
+ void setInputFile(const fnd::SharedPtr& file);
+ void setKeyCfg(const KeyConfiguration& keycfg);
void setCertificateChain(const fnd::List>& certs);
void setCliOutputMode(CliOutputMode mode);
void setVerifyMode(bool verify);
@@ -25,9 +26,8 @@ public:
private:
const std::string kModuleName = "EsTikProcess";
- fnd::IFile* mFile;
- bool mOwnIFile;
- const sKeyset* mKeyset;
+ fnd::SharedPtr mFile;
+ KeyConfiguration mKeyCfg;
CliOutputMode mCliOutputMode;
bool mVerify;
diff --git a/programs/nstool/source/HashTreeWrappedIFile.cpp b/programs/nstool/source/HashTreeWrappedIFile.cpp
index 3b147e9..a69acb2 100644
--- a/programs/nstool/source/HashTreeWrappedIFile.cpp
+++ b/programs/nstool/source/HashTreeWrappedIFile.cpp
@@ -1,9 +1,8 @@
-#include "nstool.h"
+#include "common.h"
#include "HashTreeWrappedIFile.h"
#include "OffsetAdjustedIFile.h"
-HashTreeWrappedIFile::HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, const HashTreeMeta& hdr) :
- mOwnIFile(ownIFile),
+HashTreeWrappedIFile::HashTreeWrappedIFile(const fnd::SharedPtr& file, const HashTreeMeta& hdr) :
mFile(file),
mData(nullptr),
mDataHashLayer(),
@@ -12,18 +11,9 @@ HashTreeWrappedIFile::HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, cons
initialiseDataLayer(hdr);
}
-HashTreeWrappedIFile::~HashTreeWrappedIFile()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
- delete mData;
-}
-
size_t HashTreeWrappedIFile::size()
{
- return mData->size();
+ return (*mData)->size();
}
void HashTreeWrappedIFile::seek(size_t offset)
@@ -118,7 +108,7 @@ void HashTreeWrappedIFile::initialiseDataLayer(const HashTreeMeta& hdr)
cur.alloc(align(layer.size, layer.block_size));
// read layer
- mFile->read(cur.data(), layer.offset, layer.size);
+ (*mFile)->read(cur.data(), layer.offset, layer.size);
// validate blocks
size_t validate_size;
@@ -145,7 +135,7 @@ void HashTreeWrappedIFile::initialiseDataLayer(const HashTreeMeta& hdr)
}
// generate reader for data layer
- mData = new OffsetAdjustedIFile(mFile, SHARED_IFILE, hdr.getDataLayer().offset, hdr.getDataLayer().size);
+ mData = new OffsetAdjustedIFile(mFile, hdr.getDataLayer().offset, hdr.getDataLayer().size);
mDataOffset = 0;
mDataBlockSize = hdr.getDataLayer().block_size;
@@ -160,17 +150,17 @@ void HashTreeWrappedIFile::initialiseDataLayer(const HashTreeMeta& hdr)
void HashTreeWrappedIFile::readData(size_t block_offset, size_t block_num)
{
- mData->seek(block_offset * mDataBlockSize);
+ (*mData)->seek(block_offset * mDataBlockSize);
fnd::sha::sSha256Hash hash;
// determine read size
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);
}
- else if ((block_offset + block_num) < getBlockNum(mData->size()))
+ else if ((block_offset + block_num) < getBlockNum((*mData)->size()))
{
read_len = block_num * mDataBlockSize;
}
@@ -180,7 +170,7 @@ void HashTreeWrappedIFile::readData(size_t block_offset, size_t block_num)
}
// read
- mData->read(mCache.data(), block_offset * mDataBlockSize, read_len);
+ (*mData)->read(mCache.data(), block_offset * mDataBlockSize, read_len);
if (block_num > mCacheBlockNum)
{
diff --git a/programs/nstool/source/HashTreeWrappedIFile.h b/programs/nstool/source/HashTreeWrappedIFile.h
index 6e97181..dd3f70c 100644
--- a/programs/nstool/source/HashTreeWrappedIFile.h
+++ b/programs/nstool/source/HashTreeWrappedIFile.h
@@ -1,6 +1,7 @@
#pragma once
#include
#include
+#include
#include
#include
#include "HashTreeMeta.h"
@@ -9,8 +10,7 @@
class HashTreeWrappedIFile : public fnd::IFile
{
public:
- HashTreeWrappedIFile(fnd::IFile* file, bool ownIFile, const HashTreeMeta& hdr);
- ~HashTreeWrappedIFile();
+ HashTreeWrappedIFile(const fnd::SharedPtr& file, const HashTreeMeta& hdr);
size_t size();
void seek(size_t offset);
@@ -23,11 +23,10 @@ private:
static const size_t kDefaultCacheSize = 0x10000;
std::stringstream mErrorSs;
- bool mOwnIFile;
- fnd::IFile* mFile;
+ fnd::SharedPtr mFile;
// data file
- fnd::IFile* mData;
+ fnd::SharedPtr mData;
size_t mDataOffset;
size_t mDataBlockSize;
fnd::List mDataHashLayer;
diff --git a/programs/nstool/source/KeyConfiguration.cpp b/programs/nstool/source/KeyConfiguration.cpp
new file mode 100644
index 0000000..91c1122
--- /dev/null
+++ b/programs/nstool/source/KeyConfiguration.cpp
@@ -0,0 +1,376 @@
+#include "KeyConfiguration.h"
+#include
+#include
+#include
+#include
+
+KeyConfiguration::KeyConfiguration()
+{
+ clearGeneralKeyConfiguration();
+ clearNcaExternalKeys();
+}
+
+KeyConfiguration::KeyConfiguration(const KeyConfiguration& other)
+{
+ *this = other;
+}
+
+void KeyConfiguration::operator=(const KeyConfiguration& other)
+{
+ mAcidSignKey = other.mAcidSignKey;
+ mPkg2SignKey = other.mPkg2SignKey;
+ mNcaHeader0SignKey = other.mNcaHeader0SignKey;
+ mXciHeaderSignKey = other.mXciHeaderSignKey;
+
+ mNcaHeaderKey = other.mNcaHeaderKey;
+ mXciHeaderKey = other.mXciHeaderKey;
+
+ for (size_t i = 0; i < kMasterKeyNum; i++)
+ {
+ mPkg2Key[i] = other.mPkg2Key[i];
+ mPkg1Key[i] = other.mPkg1Key[i];
+ mNcaKeyAreaEncryptionKey[0][i] = other.mNcaKeyAreaEncryptionKey[0][i];
+ mNcaKeyAreaEncryptionKey[1][i] = other.mNcaKeyAreaEncryptionKey[1][i];
+ mNcaKeyAreaEncryptionKey[2][i] = other.mNcaKeyAreaEncryptionKey[2][i];
+ mNcaKeyAreaEncryptionKeyHw[0][i] = other.mNcaKeyAreaEncryptionKeyHw[0][i];
+ mNcaKeyAreaEncryptionKeyHw[1][i] = other.mNcaKeyAreaEncryptionKeyHw[1][i];
+ mNcaKeyAreaEncryptionKeyHw[2][i] = other.mNcaKeyAreaEncryptionKeyHw[2][i];
+ mETicketCommonKey[i] = other.mETicketCommonKey[i];
+ }
+
+ mPkiRootKeyList = other.mPkiRootKeyList;
+
+ mNcaExternalContentKeyList = other.mNcaExternalContentKeyList;
+}
+
+void KeyConfiguration::importHactoolGenericKeyfile(const std::string& path)
+{
+ clearGeneralKeyConfiguration();
+
+ fnd::ResourceFileReader res;
+ try
+ {
+ res.processFile(path);
+ }
+ catch (const fnd::Exception&)
+ {
+ throw fnd::Exception(kModuleName, "Failed to open key file: " + path);
+ }
+
+ // internally used sources
+ fnd::aes::sAes128Key master_key[kMasterKeyNum] = { kNullAesKey };
+ fnd::aes::sAes128Key package2_key_source = kNullAesKey;
+ fnd::aes::sAes128Key ticket_titlekek_source = kNullAesKey;
+ fnd::aes::sAes128Key key_area_key_source[kNcaKeakNum] = { kNullAesKey, kNullAesKey, kNullAesKey };
+ fnd::aes::sAes128Key aes_kek_generation_source = kNullAesKey;
+ fnd::aes::sAes128Key aes_key_generation_source = kNullAesKey;
+ fnd::aes::sAes128Key nca_header_kek_source = kNullAesKey;
+ fnd::aes::sAesXts128Key nca_header_key_source = kNullAesXtsKey;
+ fnd::rsa::sRsa4096Key pki_root_sign_key = kNullRsa4096Key;
+
+#define _CONCAT_2_STRINGS(str1, str2) ((str1) + "_" + (str2))
+#define _CONCAT_3_STRINGS(str1, str2, str3) _CONCAT_2_STRINGS(_CONCAT_2_STRINGS(str1, str2), str3)
+
+ std::string key,val;
+ fnd::Vec dec_array;
+
+#define _SAVE_KEYDATA(key_name, array, len) \
+ key = (key_name); \
+ val = res[key]; \
+ if (val.empty() == false) { \
+ fnd::SimpleTextOutput::stringToArray(val, dec_array); \
+ if (dec_array.size() != len) \
+ throw fnd::Exception(kModuleName, "Key: \"" + key_name + "\" has incorrect length"); \
+ memcpy(array, dec_array.data(), len); \
+ }
+
+ for (size_t nameidx = 0; nameidx < kNameVariantNum; nameidx++)
+ {
+ // import sources
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kKeyStr, kSourceStr), package2_key_source.key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[nameidx], kSourceStr), ticket_titlekek_source.key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[0], kSourceStr), key_area_key_source[0].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[1], kSourceStr), key_area_key_source[1].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kSourceStr), key_area_key_source[2].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kKekGenBase[nameidx], kSourceStr), aes_kek_generation_source.key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kKeyGenBase[nameidx], kSourceStr), aes_key_generation_source.key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kKekStr, kSourceStr), nca_header_kek_source.key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kXciHeaderBase[nameidx], kKeyStr, kSourceStr), nca_header_key_source.key, 0x20);
+
+ // Store Key Variants/Derivatives
+ for (size_t mkeyidx = 0; mkeyidx < kMasterKeyNum; mkeyidx++)
+ {
+
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kMasterBase[nameidx], kKeyStr, kKeyIndex[mkeyidx]), master_key[mkeyidx].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg1Base[nameidx], kKeyStr, kKeyIndex[mkeyidx]), mPkg1Key[mkeyidx].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kPkg2Base[nameidx], kKeyStr, kKeyIndex[mkeyidx]), mPkg2Key[mkeyidx].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[nameidx], kKeyIndex[mkeyidx]), mETicketCommonKey[mkeyidx].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[0], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKey[0][mkeyidx].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[1], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKey[1][mkeyidx].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKey[2][mkeyidx].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[0], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[0][mkeyidx].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[1], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[1][mkeyidx].key, 0x10);
+ _SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaKeyAreaEncKeyHwBase[nameidx], kNcaKeyAreaKeyIndexStr[2], kKeyIndex[mkeyidx]), mNcaKeyAreaEncryptionKeyHw[2][mkeyidx].key, 0x10);
+ }
+
+ // store nca header key
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[nameidx], kKeyStr), mNcaHeaderKey.key[0], 0x20);
+
+ // store xci header key
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kKeyStr), mXciHeaderKey.key, 0x10);
+
+ // store rsa keys
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[nameidx], kRsaKeyPrivate), mNcaHeader0SignKey.priv_exponent, fnd::rsa::kRsa2048Size);
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[nameidx], kRsaKeyModulus), mNcaHeader0SignKey.modulus, fnd::rsa::kRsa2048Size);
+
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kRsaKeyPrivate), mXciHeaderSignKey.priv_exponent, fnd::rsa::kRsa2048Size);
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase[nameidx], kRsaKeyModulus), mXciHeaderSignKey.modulus, fnd::rsa::kRsa2048Size);
+
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase[nameidx], kRsaKeyPrivate), mAcidSignKey.priv_exponent, fnd::rsa::kRsa2048Size);
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase[nameidx], kRsaKeyModulus), mAcidSignKey.modulus, fnd::rsa::kRsa2048Size);
+
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkg2Base[nameidx], kRsaKeyPrivate), mPkg2SignKey.priv_exponent, fnd::rsa::kRsa2048Size);
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkg2Base[nameidx], kRsaKeyModulus), mPkg2SignKey.modulus, fnd::rsa::kRsa2048Size);
+
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase[nameidx], kRsaKeyPrivate), pki_root_sign_key.priv_exponent, fnd::rsa::kRsa4096Size);
+ _SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase[nameidx], kRsaKeyModulus), pki_root_sign_key.modulus, fnd::rsa::kRsa4096Size);
+ }
+
+#undef _SAVE_KEYDATA
+#undef _CONCAT_3_STRINGS
+#undef _CONCAT_2_STRINGS
+
+ // Derive keys
+ for (size_t i = 0; i < kMasterKeyNum; i++)
+ {
+ if (master_key[i] != kNullAesKey)
+ {
+ if (aes_kek_generation_source != kNullAesKey && aes_key_generation_source != kNullAesKey)
+ {
+ if (i == 0 && nca_header_kek_source != kNullAesKey && nca_header_key_source != kNullAesXtsKey)
+ {
+ if (mNcaHeaderKey == kNullAesXtsKey)
+ {
+ fnd::aes::sAes128Key nca_header_kek;
+ nn::hac::AesKeygen::generateKey(nca_header_kek.key, aes_kek_generation_source.key, nca_header_kek_source.key, aes_key_generation_source.key, master_key[i].key);
+ nn::hac::AesKeygen::generateKey(mNcaHeaderKey.key[0], nca_header_key_source.key[0], nca_header_kek.key);
+ nn::hac::AesKeygen::generateKey(mNcaHeaderKey.key[1], nca_header_key_source.key[1], nca_header_kek.key);
+ }
+ }
+
+ for (size_t j = 0; j < nn::hac::nca::kKeyAreaEncryptionKeyNum; j++)
+ {
+ if (key_area_key_source[j] != kNullAesKey && mNcaKeyAreaEncryptionKey[j][i] == kNullAesKey)
+ {
+ nn::hac::AesKeygen::generateKey(mNcaKeyAreaEncryptionKey[j][i].key, aes_kek_generation_source.key, key_area_key_source[j].key, aes_key_generation_source.key, master_key[i].key);
+ }
+ }
+ }
+
+ if (ticket_titlekek_source != kNullAesKey && mETicketCommonKey[i] == kNullAesKey)
+ {
+ nn::hac::AesKeygen::generateKey(mETicketCommonKey[i].key, ticket_titlekek_source.key, master_key[i].key);
+ }
+ if (package2_key_source != kNullAesKey && mPkg2Key[i] == kNullAesKey)
+ {
+ nn::hac::AesKeygen::generateKey(mPkg2Key[i].key, package2_key_source.key, master_key[i].key);
+ }
+ }
+ }
+
+ // populate pki root keys
+ if (pki_root_sign_key != kNullRsa4096Key)
+ {
+ sPkiRootKey tmp;
+
+ tmp.name = nn::pki::sign::kRootIssuerStr;
+ tmp.key_type = nn::pki::sign::SIGN_ALGO_RSA4096;
+ tmp.rsa4096_key = pki_root_sign_key;
+
+ mPkiRootKeyList.addElement(tmp);
+ }
+}
+
+
+void KeyConfiguration::clearGeneralKeyConfiguration()
+{
+ mAcidSignKey = kNullRsa2048Key;
+ mPkg2SignKey = kNullRsa2048Key;
+ mNcaHeader0SignKey = kNullRsa2048Key;
+ mXciHeaderSignKey = kNullRsa2048Key;
+ mPkiRootKeyList.clear();
+
+ mNcaHeaderKey = kNullAesXtsKey;
+ mXciHeaderKey = kNullAesKey;
+
+ for (size_t i = 0; i < kMasterKeyNum; i++)
+ {
+ mPkg1Key[i] = kNullAesKey;
+ mPkg2Key[i] = kNullAesKey;
+ mETicketCommonKey[i] = kNullAesKey;
+ for (size_t j = 0; j < kNcaKeakNum; j++)
+ {
+ mNcaKeyAreaEncryptionKey[j][i] = kNullAesKey;
+ mNcaKeyAreaEncryptionKey[j][i] = kNullAesKey;
+ }
+ }
+}
+
+void KeyConfiguration::clearNcaExternalKeys()
+{
+ mNcaExternalContentKeyList.clear();
+}
+
+bool KeyConfiguration::getNcaHeaderKey(fnd::aes::sAesXts128Key& key) const
+{
+ return copyOutKeyResourceIfExists(mNcaHeaderKey, key, kNullAesXtsKey);
+}
+
+bool KeyConfiguration::getNcaHeader0SignKey(fnd::rsa::sRsa2048Key& key) const
+{
+ return copyOutKeyResourceIfExists(mNcaHeader0SignKey, key, kNullRsa2048Key);
+}
+
+bool KeyConfiguration::getAcidSignKey(fnd::rsa::sRsa2048Key& key) const
+{
+ return copyOutKeyResourceIfExists(mAcidSignKey, key, kNullRsa2048Key);
+}
+
+bool KeyConfiguration::getNcaKeyAreaEncryptionKey(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const
+{
+ if (keak_type >= kNcaKeakNum || masterkey_index >= kMasterKeyNum)
+ {
+ return false;
+ }
+ return copyOutKeyResourceIfExists(mNcaKeyAreaEncryptionKey[keak_type][masterkey_index], key, kNullAesKey);
+}
+
+bool KeyConfiguration::getNcaKeyAreaEncryptionKeyHw(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const
+{
+ if (keak_type >= kNcaKeakNum || masterkey_index >= kMasterKeyNum)
+ {
+ return false;
+ }
+ return copyOutKeyResourceIfExists(mNcaKeyAreaEncryptionKeyHw[keak_type][masterkey_index], key, kNullAesKey);
+}
+
+void KeyConfiguration::addNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], const fnd::aes::sAes128Key& key)
+{
+ sNcaExternalContentKey tmp;
+ memcpy(tmp.rights_id.data, rights_id, nn::hac::nca::kRightsIdLen);
+ tmp.key = key;
+
+ if (mNcaExternalContentKeyList.hasElement(tmp))
+ return;
+
+ mNcaExternalContentKeyList.addElement(tmp);
+}
+
+bool KeyConfiguration::getNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], fnd::aes::sAes128Key& key) const
+{
+ sRightsId id;
+ bool res_exists = false;
+
+ memcpy(id.data, rights_id, nn::hac::nca::kRightsIdLen);
+ for (size_t i = 0; i < mNcaExternalContentKeyList.size(); i++)
+ {
+ if (mNcaExternalContentKeyList[i].rights_id == id)
+ {
+ res_exists = true;
+ key = mNcaExternalContentKeyList[i].key;
+ break;
+ }
+ }
+
+ return res_exists;
+}
+
+bool KeyConfiguration::getPkg1Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const
+{
+ if (masterkey_index >= kMasterKeyNum)
+ {
+ return false;
+ }
+ return copyOutKeyResourceIfExists(mPkg1Key[masterkey_index], key, kNullAesKey);
+}
+
+bool KeyConfiguration::getPkg2Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const
+{
+ if (masterkey_index >= kMasterKeyNum)
+ {
+ return false;
+ }
+ return copyOutKeyResourceIfExists(mPkg2Key[masterkey_index], key, kNullAesKey);
+}
+
+bool KeyConfiguration::getPkg2SignKey(fnd::rsa::sRsa2048Key& key) const
+{
+ return copyOutKeyResourceIfExists(mPkg2SignKey, key, kNullRsa2048Key);
+}
+
+bool KeyConfiguration::getXciHeaderSignKey(fnd::rsa::sRsa2048Key& key) const
+{
+ return copyOutKeyResourceIfExists(mXciHeaderSignKey, key, kNullRsa2048Key);
+}
+
+bool KeyConfiguration::getXciHeaderKey(fnd::aes::sAes128Key& key) const
+{
+ return copyOutKeyResourceIfExists(mXciHeaderKey, key, kNullAesKey);
+}
+
+bool KeyConfiguration::getETicketCommonKey(byte_t masterkey_index, fnd::aes::sAes128Key& key) const
+{
+ if (masterkey_index >= kMasterKeyNum)
+ {
+ return false;
+ }
+ return copyOutKeyResourceIfExists(mETicketCommonKey[masterkey_index], key, kNullAesKey);
+}
+
+bool KeyConfiguration::getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa4096Key& key) const
+{
+ bool res_exists = false;
+ for (size_t i = 0; i < mPkiRootKeyList.size(); i++)
+ {
+ if (root_name == mPkiRootKeyList[i].name && mPkiRootKeyList[i].key_type == nn::pki::sign::SIGN_ALGO_RSA4096)
+ {
+ res_exists = true;
+ key = mPkiRootKeyList[i].rsa4096_key;
+ break;
+ }
+ }
+
+ return res_exists;
+}
+
+bool KeyConfiguration::getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa2048Key& key) const
+{
+ bool res_exists = false;
+ for (size_t i = 0; i < mPkiRootKeyList.size(); i++)
+ {
+ if (root_name == mPkiRootKeyList[i].name && mPkiRootKeyList[i].key_type == nn::pki::sign::SIGN_ALGO_RSA2048)
+ {
+ res_exists = true;
+ key = mPkiRootKeyList[i].rsa2048_key;
+ break;
+ }
+ }
+
+ return res_exists;
+}
+
+bool KeyConfiguration::getPkiRootSignKey(const std::string& root_name, fnd::ecdsa::sEcdsa240Key& key) const
+{
+ bool res_exists = false;
+ for (size_t i = 0; i < mPkiRootKeyList.size(); i++)
+ {
+ if (root_name == mPkiRootKeyList[i].name && mPkiRootKeyList[i].key_type == nn::pki::sign::SIGN_ALGO_ECDSA240)
+ {
+ res_exists = true;
+ key = mPkiRootKeyList[i].ecdsa240_key;
+ break;
+ }
+ }
+
+ return res_exists;
+}
\ No newline at end of file
diff --git a/programs/nstool/source/KeyConfiguration.h b/programs/nstool/source/KeyConfiguration.h
new file mode 100644
index 0000000..8925708
--- /dev/null
+++ b/programs/nstool/source/KeyConfiguration.h
@@ -0,0 +1,209 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+class KeyConfiguration
+{
+public:
+ KeyConfiguration();
+ KeyConfiguration(const KeyConfiguration& other);
+
+ void operator=(const KeyConfiguration& other);
+
+ void importHactoolGenericKeyfile(const std::string& path);
+ //void importHactoolTitleKeyfile(const std::string& path);
+
+ void clearGeneralKeyConfiguration();
+ void clearNcaExternalKeys();
+
+ // nca keys
+ bool getNcaHeaderKey(fnd::aes::sAesXts128Key& key) const;
+ bool getNcaHeader0SignKey(fnd::rsa::sRsa2048Key& key) const;
+ bool getAcidSignKey(fnd::rsa::sRsa2048Key& key) const;
+ bool getNcaKeyAreaEncryptionKey(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const;
+ bool getNcaKeyAreaEncryptionKeyHw(byte_t masterkey_index, byte_t keak_type, fnd::aes::sAes128Key& key) const;
+
+ // external content keys
+ void addNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], const fnd::aes::sAes128Key& key);
+ bool getNcaExternalContentKey(const byte_t rights_id[nn::hac::nca::kRightsIdLen], fnd::aes::sAes128Key& key) const;
+
+ // pkg1/pkg2
+ bool getPkg1Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const;
+ bool getPkg2Key(byte_t masterkey_index, fnd::aes::sAes128Key& key) const;
+ bool getPkg2SignKey(fnd::rsa::sRsa2048Key& key) const;
+
+ // xci keys
+ bool getXciHeaderSignKey(fnd::rsa::sRsa2048Key& key) const;
+ bool getXciHeaderKey(fnd::aes::sAes128Key& key) const;
+
+ // ticket
+ bool getETicketCommonKey(byte_t masterkey_index, fnd::aes::sAes128Key& key) const;
+
+ // pki
+ bool getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa4096Key& key) const;
+ bool getPkiRootSignKey(const std::string& root_name, fnd::rsa::sRsa2048Key& key) const;
+ bool getPkiRootSignKey(const std::string& root_name, fnd::ecdsa::sEcdsa240Key& key) const;
+private:
+ const std::string kModuleName = "KeyConfiguration";
+ const fnd::aes::sAes128Key kNullAesKey = {{0}};
+ const fnd::aes::sAesXts128Key kNullAesXtsKey = {{{0}}};
+ const fnd::rsa::sRsa4096Key kNullRsa4096Key = {{0}, {0}, {0}};
+ const fnd::rsa::sRsa2048Key kNullRsa2048Key = {{0}, {0}, {0}};
+ static const size_t kMasterKeyNum = 0x20;
+ static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum;
+
+ // keynames
+ enum NameVariantIndex
+ {
+ NNTOOLS,
+ LEGACY_HACTOOL,
+ LEGACY_0
+ };
+ static const size_t kNameVariantNum = 3;
+ const std::string kMasterBase[kNameVariantNum] = { "master", "master", "master" };
+ const std::string kPkg1Base[kNameVariantNum] = { "package1", "package1", "package1" };
+ const std::string kPkg2Base[kNameVariantNum] = { "package2", "package2", "package2" };
+ const std::string kXciHeaderBase[kNameVariantNum] = { "xci_header", "xci_header", "xci_header" };
+ const std::string kNcaHeaderBase[kNameVariantNum] = { "nca_header", "header", "nca_header" };
+ const std::string kAcidBase[kNameVariantNum] = { "acid", "acid", "acid" };
+ const std::string kPkiRootBase[kNameVariantNum] = { "pki_root", "pki_root", "pki_root" };
+ const std::string kTicketCommonKeyBase[kNameVariantNum] = { "ticket_commonkey", "titlekek", "ticket_commonkey" };
+ const std::string kNcaKeyAreaEncKeyBase[kNameVariantNum] = { "nca_key_area_key", "key_area_key", "nca_body_keak" };
+ const std::string kNcaKeyAreaEncKeyHwBase[kNameVariantNum] = { "nca_key_area_key_hw", "key_area_hw_key", "nca_key_area_key_hw" };
+ const std::string kKekGenBase[kNameVariantNum] = { "aes_kek_generation", "aes_kek_generation", "aes_kek_generation" };
+ const std::string kKeyGenBase[kNameVariantNum] = { "aes_key_generation", "aes_key_generation", "aes_key_generation" };
+
+ // misc str
+ const std::string kKeyStr = "key";
+ const std::string kKekStr = "kek";
+ const std::string kSourceStr = "source";
+ const std::string kRsaKeyModulus = "sign_key_modulus";
+ const std::string kRsaKeyPrivate = "sign_key_private";
+ const std::string kNcaKeyAreaKeyIndexStr[kNcaKeakNum] = { "application", "ocean", "system" };
+ const std::string kKeyIndex[kMasterKeyNum] = {"00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f","10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f"};
+
+ struct sRightsId
+ {
+ byte_t data[nn::hac::nca::kRightsIdLen];
+
+ void operator=(const sRightsId& other)
+ {
+ memcpy(this->data, other.data, nn::hac::nca::kRightsIdLen);
+ }
+
+ bool operator==(const sRightsId& other) const
+ {
+ return memcmp(this->data, other.data, nn::hac::nca::kRightsIdLen) == 0;
+ }
+
+ bool operator!=(const sRightsId& other) const
+ {
+ return !(operator==(other));
+ }
+ };
+
+ struct sNcaExternalContentKey
+ {
+ sRightsId rights_id;
+ fnd::aes::sAes128Key key;
+
+ void operator=(const sNcaExternalContentKey& other)
+ {
+ rights_id = other.rights_id;
+ key = other.key;
+ }
+
+ bool operator==(const sNcaExternalContentKey& other) const
+ {
+ return (rights_id == other.rights_id) \
+ && (key == other.key);
+ }
+
+ bool operator!=(const sNcaExternalContentKey& other) const
+ {
+ return !(operator==(other));
+ }
+ };
+
+ struct sPkiRootKey
+ {
+ std::string name;
+ nn::pki::sign::SignatureAlgo key_type;
+ fnd::rsa::sRsa4096Key rsa4096_key;
+ fnd::rsa::sRsa2048Key rsa2048_key;
+ fnd::ecdsa::sEcdsa240Key ecdsa240_key;
+
+ void operator=(const sPkiRootKey& other)
+ {
+ name = other.name;
+ key_type = other.key_type;
+ rsa4096_key = other.rsa4096_key;
+ rsa2048_key = other.rsa2048_key;
+ ecdsa240_key = other.ecdsa240_key;
+ }
+
+ bool operator==(const sPkiRootKey& other) const
+ {
+ return (name == other.name) \
+ && (key_type == other.key_type) \
+ && (rsa4096_key == other.rsa4096_key) \
+ && (rsa2048_key == other.rsa2048_key) \
+ && (ecdsa240_key == other.ecdsa240_key);
+ }
+
+ bool operator!=(const sPkiRootKey& other) const
+ {
+ return !(operator==(other));
+ }
+ };
+
+
+ /* general key config */
+ // acid
+ fnd::rsa::sRsa2048Key mAcidSignKey;
+
+ // pkg1 and pkg2
+ fnd::aes::sAes128Key mPkg1Key[kMasterKeyNum];
+ fnd::rsa::sRsa2048Key mPkg2SignKey;
+ fnd::aes::sAes128Key mPkg2Key[kMasterKeyNum];
+
+ // nca
+ fnd::rsa::sRsa2048Key mNcaHeader0SignKey;
+ fnd::aes::sAesXts128Key mNcaHeaderKey;
+ fnd::aes::sAes128Key mNcaKeyAreaEncryptionKey[kNcaKeakNum][kMasterKeyNum];
+ fnd::aes::sAes128Key mNcaKeyAreaEncryptionKeyHw[kNcaKeakNum][kMasterKeyNum];
+
+ // xci
+ fnd::rsa::sRsa2048Key mXciHeaderSignKey;
+ fnd::aes::sAes128Key mXciHeaderKey;
+
+ // ticket
+ fnd::aes::sAes128Key mETicketCommonKey[kMasterKeyNum];
+
+ // pki
+ fnd::List mPkiRootKeyList;
+
+ /* Nca External Keys */
+ fnd::List mNcaExternalContentKeyList;
+
+ template
+ bool copyOutKeyResourceIfExists(const T& src, T& dst, const T& null_sample) const
+ {
+ bool resource_exists = false;
+
+ if (src != null_sample)
+ {
+ resource_exists = true;
+ dst = src;
+ }
+
+ return resource_exists;
+ }
+};
\ No newline at end of file
diff --git a/programs/nstool/source/NacpProcess.cpp b/programs/nstool/source/NacpProcess.cpp
index 52cb2f8..2d3b02f 100644
--- a/programs/nstool/source/NacpProcess.cpp
+++ b/programs/nstool/source/NacpProcess.cpp
@@ -1,11 +1,185 @@
#include
+#include
+#include
#include
#include "OffsetAdjustedIFile.h"
#include "NacpProcess.h"
-const char* getLanguageStr(nn::hac::nacp::Language var)
+NacpProcess::NacpProcess() :
+ mFile(),
+ mCliOutputMode(_BIT(OUTPUT_BASIC)),
+ mVerify(false)
+{
+}
+
+void NacpProcess::process()
+{
+ importNacp();
+
+ if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
+ displayNacp();
+}
+
+void NacpProcess::setInputFile(const fnd::SharedPtr& file)
+{
+ mFile = file;
+}
+
+void NacpProcess::setCliOutputMode(CliOutputMode type)
+{
+ mCliOutputMode = type;
+}
+
+void NacpProcess::setVerifyMode(bool verify)
+{
+ mVerify = verify;
+}
+
+const nn::hac::ApplicationControlPropertyBinary& NacpProcess::getApplicationControlPropertyBinary() const
+{
+ return mNacp;
+}
+
+void NacpProcess::importNacp()
+{
+ fnd::Vec scratch;
+
+ if (*mFile == nullptr)
+ {
+ throw fnd::Exception(kModuleName, "No file reader set.");
+ }
+
+ scratch.alloc((*mFile)->size());
+ (*mFile)->read(scratch.data(), 0, scratch.size());
+
+ mNacp.fromBytes(scratch.data(), scratch.size());
+}
+
+void NacpProcess::displayNacp()
+{
+ std::cout << "[ApplicationControlProperty]" << std::endl;
+ std::cout << " Menu Description:" << std::endl;
+ std::cout << " DisplayVersion: " << mNacp.getDisplayVersion() << std::endl;
+ if (mNacp.getIsbn().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ std::cout << " ISBN: " << mNacp.getIsbn() << std::endl;
+ for (size_t i = 0; i < mNacp.getTitle().size(); i++)
+ {
+ std::cout << " " << getLanguageStr(mNacp.getTitle()[i].language) << " Title:" << std::endl;
+ std::cout << " Name: " << mNacp.getTitle()[i].name << std::endl;
+ std::cout << " Publisher: " << mNacp.getTitle()[i].publisher << std::endl;
+ }
+ std::cout << " Logo:" << std::endl;
+ std::cout << " Type: " << getLogoTypeStr(mNacp.getLogoType()) << std::endl;
+ std::cout << " Handling: " << getLogoHandlingStr(mNacp.getLogoHandling()) << std::endl;
+ std::cout << " AddOnContent:" << std::endl;
+ std::cout << " BaseId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getAocBaseId() << std::endl;
+ std::cout << " RegistrationType: " << getAocRegistrationTypeStr(mNacp.getAocRegistrationType()) << std::endl;
+ std::cout << " RuntimeInstallMode: " << getRuntimeAocInstallModeStr(mNacp.getRuntimeAocInstallMode()) << std::endl;
+ std::cout << " Play Log:" << std::endl;
+ std::cout << " PlayLogPolicy: " << getPlayLogPolicyStr(mNacp.getPlayLogPolicy()) << std::endl;
+ std::cout << " PlayLogQueryCapability: " << getPlayLogQueryCapabilityStr(mNacp.getPlayLogQueryCapability()) << std::endl;
+ if (mNacp.getPlayLogQueryableApplicationId().size() > 0)
+ {
+ std::cout << " PlayLogQueryableApplicationId:" << std::endl;
+ for (size_t i = 0; i < mNacp.getPlayLogQueryableApplicationId().size(); i++)
+ {
+ std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getPlayLogQueryableApplicationId()[i] << std::endl;
+ }
+ }
+ std::cout << " Parental Controls:" << std::endl;
+ std::cout << " ParentalControlFlag: " << getParentalControlFlagStr(mNacp.getParentalControlFlag()) << std::endl;
+ for (size_t i = 0; i < mNacp.getRatingAge().size(); i++)
+ {
+ std::cout << " Age Restriction:" << std::endl;
+ std::cout << " Agency: " << getOrganisationStr(mNacp.getRatingAge()[i].organisation) << std::endl;
+ std::cout << " Age: " << std::dec << (uint32_t)mNacp.getRatingAge()[i].age << std::endl;
+ }
+
+ if (mNacp.getBcatPassphase().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ {
+ std::cout << " BCAT:" << std::endl;
+ std::cout << " BcatPassphase: " << mNacp.getBcatPassphase() << std::endl;
+ std::cout << " DeliveryCacheStorageSize: 0x" << std::hex << mNacp.getBcatDeliveryCacheStorageSize() << std::endl;
+ }
+ if (mNacp.getLocalCommunicationId().size() > 0)
+ {
+ std::cout << " Local Area Communication:" << std::endl;
+ std::cout << " LocalCommunicationId:" << std::endl;
+ for (size_t i = 0; i < mNacp.getLocalCommunicationId().size(); i++)
+ {
+ std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getLocalCommunicationId()[i] << std::endl;
+ }
+ }
+ std::cout << " SaveData:" << std::endl;
+ std::cout << " SaveDatawOwnerId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getSaveDatawOwnerId() << std::endl;
+ if (mNacp.getUserAccountSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ {
+ std::cout << " UserAccountSaveData:" << std::endl;
+ std::cout << " Size: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().size) << std::endl;
+ std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().journal_size) << std::endl;
+ }
+ if (mNacp.getDeviceSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ {
+ std::cout << " DeviceSaveData:" << std::endl;
+ std::cout << " Size: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().size) << std::endl;
+ std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().journal_size) << std::endl;
+ }
+ if (mNacp.getUserAccountSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ {
+ std::cout << " UserAccountSaveDataMax:" << std::endl;
+ std::cout << " Size: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().size) << std::endl;
+ std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().journal_size) << std::endl;
+ }
+ if (mNacp.getDeviceSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ {
+ std::cout << " DeviceSaveDataMax:" << std::endl;
+ std::cout << " Size: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().size) << std::endl;
+ std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().journal_size) << std::endl;
+ }
+ if (mNacp.getTemporaryStorageSize() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ {
+ std::cout << " TemporaryStorageSize: " << getSaveDataSizeStr(mNacp.getTemporaryStorageSize()) << std::endl;
+ }
+ if (mNacp.getCacheStorageSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ {
+ std::cout << " CacheStorage:" << std::endl;
+ std::cout << " Size: " << getSaveDataSizeStr(mNacp.getCacheStorageSize().size) << std::endl;
+ std::cout << " JournalSize: " << getSaveDataSizeStr(mNacp.getCacheStorageSize().journal_size) << std::endl;
+ std::cout << " MaxDataAndJournalSize: " << getSaveDataSizeStr(mNacp.getCacheStorageDataAndJournalSizeMax()) << std::endl;
+ std::cout << " StorageIndexMax: 0x" << std::hex << mNacp.getCacheStorageIndexMax() << std::endl;
+ }
+ std::cout << " Other Flags:" << std::endl;
+ std::cout << " StartupUserAccount: " << getStartupUserAccountStr(mNacp.getStartupUserAccount()) << std::endl;
+ if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ {
+ std::cout << " TouchScreenUsageMode: " << getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode()) << std::endl;
+ }
+ std::cout << " AttributeFlag: " << getAttributeFlagStr(mNacp.getAttributeFlag()) << std::endl;
+ std::cout << " CrashReportMode: " << getCrashReportModeStr(mNacp.getCrashReportMode()) << std::endl;
+ std::cout << " HDCP: " << getHdcpStr(mNacp.getHdcp()) << std::endl;
+ std::cout << " ScreenshotMode: " << getScreenshotModeStr(mNacp.getScreenshotMode()) << std::endl;
+ std::cout << " VideoCaptureMode: " << getVideoCaptureModeStr(mNacp.getVideoCaptureMode()) << std::endl;
+ std::cout << " DataLossConfirmation: " << getDataLossConfirmationStr(mNacp.getDataLossConfirmation()) << std::endl;
+ std::cout << " RepairFlag: " << getRepairFlagStr(mNacp.getRepairFlag()) << std::endl;
+ std::cout << " ProgramIndex: 0x" << std::hex << std::setw(2) << std::setfill('0') << (uint32_t)mNacp.getProgramIndex() << std::endl;
+ if (mNacp.getApplicationErrorCodeCategory().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ {
+ std::cout << " ApplicationErrorCodeCategory: " << mNacp.getApplicationErrorCodeCategory() << std::endl;
+ }
+ if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ {
+ std::cout << " Other Ids:" << std::endl;
+ if (mNacp.getSeedForPsuedoDeviceId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ std::cout << " SeedForPsuedoDeviceId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getSeedForPsuedoDeviceId() << std::endl;
+ if (mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
+ std::cout << " PresenceGroupId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mNacp.getPresenceGroupId() << std::endl;
+ }
+}
+
+const char* NacpProcess::getLanguageStr(nn::hac::nacp::Language var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::LANG_AmericanEnglish):
@@ -56,12 +230,14 @@ const char* getLanguageStr(nn::hac::nacp::Language var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var)
+const char* NacpProcess::getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::USER_None):
@@ -76,12 +252,14 @@ const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var)
+const char* NacpProcess::getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::TOUCH_None):
@@ -96,12 +274,14 @@ const char* getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var)
+const char* NacpProcess::getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::AOC_AllOnLaunch):
@@ -113,12 +293,14 @@ const char* getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getAttributeFlagStr(nn::hac::nacp::AttributeFlag var)
+const char* NacpProcess::getAttributeFlagStr(nn::hac::nacp::AttributeFlag var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::ATTR_None):
@@ -133,12 +315,14 @@ const char* getAttributeFlagStr(nn::hac::nacp::AttributeFlag var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var)
+const char* NacpProcess::getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::PC_None):
@@ -150,12 +334,14 @@ const char* getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var)
+const char* NacpProcess::getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::SCRN_Allow):
@@ -167,12 +353,14 @@ const char* getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var)
+const char* NacpProcess::getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::VCAP_Disable):
@@ -187,12 +375,14 @@ const char* getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var)
+const char* NacpProcess::getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::DLOSS_None):
@@ -204,12 +394,14 @@ const char* getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var)
+const char* NacpProcess::getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::PLP_All):
@@ -224,12 +416,14 @@ const char* getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getOrganisationStr(nn::hac::nacp::Organisation var)
+const char* NacpProcess::getOrganisationStr(nn::hac::nacp::Organisation var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::ORGN_CERO):
@@ -271,12 +465,14 @@ const char* getOrganisationStr(nn::hac::nacp::Organisation var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getLogoTypeStr(nn::hac::nacp::LogoType var)
+const char* NacpProcess::getLogoTypeStr(nn::hac::nacp::LogoType var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::LOGO_LicensedByNintendo):
@@ -291,12 +487,14 @@ const char* getLogoTypeStr(nn::hac::nacp::LogoType var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getLogoHandlingStr(nn::hac::nacp::LogoHandling var)
+const char* NacpProcess::getLogoHandlingStr(nn::hac::nacp::LogoHandling var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::LHND_Auto):
@@ -308,12 +506,14 @@ const char* getLogoHandlingStr(nn::hac::nacp::LogoHandling var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var)
+const char* NacpProcess::getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::RTAOC_Deny):
@@ -325,12 +525,14 @@ const char* getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var
default:
str = "Unknown";
}
+
return str;
}
-const char* getCrashReportModeStr(nn::hac::nacp::CrashReportMode var)
+const char* NacpProcess::getCrashReportModeStr(nn::hac::nacp::CrashReportMode var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::CREP_Deny):
@@ -342,12 +544,14 @@ const char* getCrashReportModeStr(nn::hac::nacp::CrashReportMode var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getHdcpStr(nn::hac::nacp::Hdcp var)
+const char* NacpProcess::getHdcpStr(nn::hac::nacp::Hdcp var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::HDCP_None):
@@ -359,12 +563,14 @@ const char* getHdcpStr(nn::hac::nacp::Hdcp var)
default:
str = "Unknown";
}
+
return str;
}
-const char* getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability var)
+const char* NacpProcess::getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::PLQC_None):
@@ -379,12 +585,14 @@ const char* getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability v
default:
str = "Unknown";
}
+
return str;
}
-const char* getRepairFlagStr(nn::hac::nacp::RepairFlag var)
+const char* NacpProcess::getRepairFlagStr(nn::hac::nacp::RepairFlag var) const
{
const char* str = nullptr;
+
switch(var)
{
case (nn::hac::nacp::REPF_None):
@@ -396,10 +604,11 @@ const char* getRepairFlagStr(nn::hac::nacp::RepairFlag var)
default:
str = "Unknown";
}
+
return str;
}
-std::string getSaveDataSizeStr(int64_t size)
+std::string NacpProcess::getSaveDataSizeStr(int64_t size) const
{
static const int64_t kKiloByte = 1024;
static const int64_t kMegaByte = 1024 * 1024;
@@ -421,180 +630,4 @@ std::string getSaveDataSizeStr(int64_t size)
}
return sstr.str();
-}
-
-NacpProcess::NacpProcess() :
- mFile(nullptr),
- mOwnIFile(false),
- mCliOutputMode(_BIT(OUTPUT_BASIC)),
- mVerify(false)
-{
-}
-
-NacpProcess::~NacpProcess()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
-}
-
-void NacpProcess::process()
-{
- fnd::Vec scratch;
-
- if (mFile == nullptr)
- {
- throw fnd::Exception(kModuleName, "No file reader set.");
- }
-
- scratch.alloc(mFile->size());
- mFile->read(scratch.data(), 0, scratch.size());
-
- mNacp.fromBytes(scratch.data(), scratch.size());
-
- if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
- displayNacp();
-}
-
-void NacpProcess::setInputFile(fnd::IFile* file, bool ownIFile)
-{
- mFile = file;
- mOwnIFile = ownIFile;
-}
-
-void NacpProcess::setCliOutputMode(CliOutputMode type)
-{
- mCliOutputMode = type;
-}
-
-void NacpProcess::setVerifyMode(bool verify)
-{
- mVerify = verify;
-}
-
-const nn::hac::ApplicationControlPropertyBinary& NacpProcess::getApplicationControlPropertyBinary() const
-{
- return mNacp;
-}
-
-void NacpProcess::displayNacp()
-{
- printf("[ApplicationControlProperty]\n");
- printf(" Menu Description:\n");
- printf(" DisplayVersion: %s\n", mNacp.getDisplayVersion().c_str());
- if (mNacp.getIsbn().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- printf(" ISBN: %s\n", mNacp.getIsbn().c_str());
- for (size_t i = 0; i < mNacp.getTitle().size(); i++)
- {
- printf(" %s Title:\n", getLanguageStr(mNacp.getTitle()[i].language));
- printf(" Name: %s\n", mNacp.getTitle()[i].name.c_str());
- printf(" Publisher: %s\n", mNacp.getTitle()[i].publisher.c_str());
- }
- printf(" Logo:\n");
- printf(" Type: %s\n", getLogoTypeStr(mNacp.getLogoType()));
- printf(" Handling: %s\n", getLogoHandlingStr(mNacp.getLogoHandling()));
- printf(" AddOnContent:\n");
- printf(" BaseId: 0x%016" PRIx64 "\n", mNacp.getAocBaseId());
- printf(" RegistrationType: %s\n", getAocRegistrationTypeStr(mNacp.getAocRegistrationType()));
- printf(" RuntimeInstallMode: %s\n", getRuntimeAocInstallModeStr(mNacp.getRuntimeAocInstallMode()));
- printf(" Play Log:\n");
- printf(" PlayLogPolicy: %s\n", getPlayLogPolicyStr(mNacp.getPlayLogPolicy()));
- printf(" PlayLogQueryCapability: %s\n", getPlayLogQueryCapabilityStr(mNacp.getPlayLogQueryCapability()));
- if (mNacp.getPlayLogQueryableApplicationId().size() > 0)
- {
- printf(" PlayLogQueryableApplicationId:\n");
- for (size_t i = 0; i < mNacp.getPlayLogQueryableApplicationId().size(); i++)
- {
- printf(" 0x%016" PRIx64 "\n", mNacp.getPlayLogQueryableApplicationId()[i]);
- }
- }
- printf(" Parental Controls:\n");
- printf(" ParentalControlFlag: %s\n", getParentalControlFlagStr(mNacp.getParentalControlFlag()));
- for (size_t i = 0; i < mNacp.getRatingAge().size(); i++)
- {
- printf(" Age Restriction:\n");
- printf(" Agency: %s\n", getOrganisationStr(mNacp.getRatingAge()[i].organisation));
- printf(" Age: %d\n", mNacp.getRatingAge()[i].age);
- }
-
- if (mNacp.getBcatPassphase().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- {
- printf(" BCAT:\n");
- printf(" BcatPassphase: %s\n", mNacp.getBcatPassphase().c_str());
- printf(" DeliveryCacheStorageSize: 0x%016" PRIx64 "\n", mNacp.getBcatDeliveryCacheStorageSize());
- }
- if (mNacp.getLocalCommunicationId().size() > 0)
- {
- printf(" Local Area Communication:\n");
- printf(" LocalCommunicationId:\n");
- for (size_t i = 0; i < mNacp.getLocalCommunicationId().size(); i++)
- {
- printf(" 0x%016" PRIx64 "\n", mNacp.getLocalCommunicationId()[i]);
- }
- }
- printf(" SaveData:\n");
- printf(" SaveDatawOwnerId: 0x%016" PRIx64 "\n", mNacp.getSaveDatawOwnerId());
- if (mNacp.getUserAccountSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- {
- printf(" UserAccountSaveData:\n");
- printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().size).c_str());
- printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataSize().journal_size).c_str());
- }
- if (mNacp.getDeviceSaveDataSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- {
- printf(" DeviceSaveData:\n");
- printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().size).c_str());
- printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataSize().journal_size).c_str());
- }
- if (mNacp.getUserAccountSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- {
- printf(" UserAccountSaveDataMax:\n");
- printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().size).c_str());
- printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getUserAccountSaveDataMax().journal_size).c_str());
- }
- if (mNacp.getDeviceSaveDataMax().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- {
- printf(" DeviceSaveDataMax:\n");
- printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().size).c_str());
- printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getDeviceSaveDataMax().journal_size).c_str());
- }
- if (mNacp.getTemporaryStorageSize() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- {
- printf(" TemporaryStorageSize: %s\n", getSaveDataSizeStr(mNacp.getTemporaryStorageSize()).c_str());
- }
- if (mNacp.getCacheStorageSize().journal_size > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- {
- printf(" CacheStorage:\n");
- printf(" Size: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().size).c_str());
- printf(" JournalSize: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageSize().journal_size).c_str());
- printf(" MaxDataAndJournalSize: %s\n", getSaveDataSizeStr(mNacp.getCacheStorageDataAndJournalSizeMax()).c_str());
- printf(" StorageIndexMax: 0x%" PRIx16 "\n", mNacp.getCacheStorageIndexMax());
- }
- printf(" Other Flags:\n");
- printf(" StartupUserAccount: %s\n", getStartupUserAccountStr(mNacp.getStartupUserAccount()));
- if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- {
- printf(" TouchScreenUsageMode: %s\n", getTouchScreenUsageModeStr(mNacp.getTouchScreenUsageMode()));
- }
- printf(" AttributeFlag: %s\n", getAttributeFlagStr(mNacp.getAttributeFlag()));
- printf(" CrashReportMode: %s\n", getCrashReportModeStr(mNacp.getCrashReportMode()));
- printf(" HDCP: %s\n", getHdcpStr(mNacp.getHdcp()));
- printf(" ScreenshotMode: %s\n", getScreenshotModeStr(mNacp.getScreenshotMode()));
- printf(" VideoCaptureMode: %s\n", getVideoCaptureModeStr(mNacp.getVideoCaptureMode()));
- printf(" DataLossConfirmation: %s\n", getDataLossConfirmationStr(mNacp.getDataLossConfirmation()));
- printf(" RepairFlag: %s\n", getRepairFlagStr(mNacp.getRepairFlag()));
- printf(" ProgramIndex: 0x%02x\n", mNacp.getProgramIndex());
- if (mNacp.getApplicationErrorCodeCategory().empty() == false || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- {
- printf(" ApplicationErrorCodeCategory: %s\n", mNacp.getApplicationErrorCodeCategory().c_str());
- }
- if (mNacp.getSeedForPsuedoDeviceId() > 0 || mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- {
- printf(" Other Ids:\n");
- if (mNacp.getSeedForPsuedoDeviceId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- printf(" SeedForPsuedoDeviceId: 0x%016" PRIx64 "\n", mNacp.getSeedForPsuedoDeviceId());
- if (mNacp.getPresenceGroupId() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- printf(" PresenceGroupId: 0x%016" PRIx64 "\n", mNacp.getPresenceGroupId());
- }
-}
+}
\ No newline at end of file
diff --git a/programs/nstool/source/NacpProcess.h b/programs/nstool/source/NacpProcess.h
index 7511d79..8a5064c 100644
--- a/programs/nstool/source/NacpProcess.h
+++ b/programs/nstool/source/NacpProcess.h
@@ -2,19 +2,19 @@
#include
#include
#include
+#include
#include
-#include "nstool.h"
+#include "common.h"
class NacpProcess
{
public:
NacpProcess();
- ~NacpProcess();
void process();
- void setInputFile(fnd::IFile* file, bool ownIFile);
+ void setInputFile(const fnd::SharedPtr& file);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
@@ -23,12 +23,31 @@ public:
private:
const std::string kModuleName = "NacpProcess";
- fnd::IFile* mFile;
- bool mOwnIFile;
+ fnd::SharedPtr mFile;
CliOutputMode mCliOutputMode;
bool mVerify;
nn::hac::ApplicationControlPropertyBinary mNacp;
+ void importNacp();
void displayNacp();
+ const char* getLanguageStr(nn::hac::nacp::Language var) const;
+ const char* getStartupUserAccountStr(nn::hac::nacp::StartupUserAccount var) const;
+ const char* getTouchScreenUsageModeStr(nn::hac::nacp::TouchScreenUsageMode var) const;
+ const char* getAocRegistrationTypeStr(nn::hac::nacp::AocRegistrationType var) const;
+ const char* getAttributeFlagStr(nn::hac::nacp::AttributeFlag var) const;
+ const char* getParentalControlFlagStr(nn::hac::nacp::ParentalControlFlag var) const;
+ const char* getScreenshotModeStr(nn::hac::nacp::ScreenshotMode var) const;
+ const char* getVideoCaptureModeStr(nn::hac::nacp::VideoCaptureMode var) const;
+ const char* getDataLossConfirmationStr(nn::hac::nacp::DataLossConfirmation var) const;
+ const char* getPlayLogPolicyStr(nn::hac::nacp::PlayLogPolicy var) const;
+ const char* getOrganisationStr(nn::hac::nacp::Organisation var) const;
+ const char* getLogoTypeStr(nn::hac::nacp::LogoType var) const;
+ const char* getLogoHandlingStr(nn::hac::nacp::LogoHandling var) const;
+ const char* getRuntimeAocInstallModeStr(nn::hac::nacp::RuntimeAocInstallMode var) const;
+ const char* getCrashReportModeStr(nn::hac::nacp::CrashReportMode var) const;
+ const char* getHdcpStr(nn::hac::nacp::Hdcp var) const;
+ const char* getPlayLogQueryCapabilityStr(nn::hac::nacp::PlayLogQueryCapability var) const;
+ const char* getRepairFlagStr(nn::hac::nacp::RepairFlag var) const;
+ std::string getSaveDataSizeStr(int64_t size) const;
};
\ No newline at end of file
diff --git a/programs/nstool/source/NcaProcess.cpp b/programs/nstool/source/NcaProcess.cpp
index bfc9f3f..aa4f504 100644
--- a/programs/nstool/source/NcaProcess.cpp
+++ b/programs/nstool/source/NcaProcess.cpp
@@ -1,4 +1,5 @@
#include
+#include
#include
#include
#include
@@ -11,219 +12,8 @@
#include "AesCtrWrappedIFile.h"
#include "HashTreeWrappedIFile.h"
-const char* getFormatVersionStr(nn::hac::NcaHeader::FormatVersion format_ver)
-{
- const char* str;
- switch (format_ver)
- {
- case (nn::hac::NcaHeader::NCA2_FORMAT):
- str = "NCA2";
- break;
- case (nn::hac::NcaHeader::NCA3_FORMAT):
- str = "NCA3";
- break;
- default:
- str = "Unknown";
- break;
- }
- return str;
-}
-
-const char* getDistributionTypeStr(nn::hac::nca::DistributionType dist_type)
-{
- const char* str;
- switch (dist_type)
- {
- case (nn::hac::nca::DIST_DOWNLOAD):
- str = "Download";
- break;
- case (nn::hac::nca::DIST_GAME_CARD):
- str = "Game Card";
- break;
- default:
- str = "Unknown";
- break;
- }
- return str;
-}
-
-
- const char* getContentTypeStr(nn::hac::nca::ContentType cont_type)
-{
- const char* str;
- switch (cont_type)
- {
- case (nn::hac::nca::TYPE_PROGRAM):
- str = "Program";
- break;
- case (nn::hac::nca::TYPE_META):
- str = "Meta";
- break;
- case (nn::hac::nca::TYPE_CONTROL):
- str = "Control";
- break;
- case (nn::hac::nca::TYPE_MANUAL):
- str = "Manual";
- break;
- case (nn::hac::nca::TYPE_DATA):
- str = "Data";
- break;
- case (nn::hac::nca::TYPE_PUBLIC_DATA):
- str = "PublicData";
- break;
- default:
- str = "Unknown";
- break;
- }
- return str;
-}
-
-const char* getEncryptionTypeStr(nn::hac::nca::EncryptionType enc_type)
-{
- const char* str;
- switch (enc_type)
- {
- case (nn::hac::nca::CRYPT_AUTO):
- str = "Auto";
- break;
- case (nn::hac::nca::CRYPT_NONE):
- str = "None";
- break;
- case (nn::hac::nca::CRYPT_AESXTS):
- str = "AesXts";
- break;
- case (nn::hac::nca::CRYPT_AESCTR):
- str = "AesCtr";
- break;
- case (nn::hac::nca::CRYPT_AESCTREX):
- str = "AesCtrEx";
- break;
- default:
- str = "Unknown";
- break;
- }
- return str;
-}
-
-inline const char* getHashTypeStr(nn::hac::nca::HashType hash_type)
-{
- const char* str;
- switch (hash_type)
- {
- case (nn::hac::nca::HASH_AUTO):
- str = "Auto";
- break;
- case (nn::hac::nca::HASH_NONE):
- str = "None";
- break;
- case (nn::hac::nca::HASH_HIERARCHICAL_SHA256):
- str = "HierarchicalSha256";
- break;
- case (nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY):
- str = "HierarchicalIntegrity";
- break;
- default:
- str = "Unknown";
- break;
- }
- return str;
-}
-
-inline const char* getFormatTypeStr(nn::hac::nca::FormatType format_type)
-{
- const char* str;
- switch (format_type)
- {
- case (nn::hac::nca::FORMAT_ROMFS):
- str = "RomFs";
- break;
- case (nn::hac::nca::FORMAT_PFS0):
- str = "PartitionFs";
- break;
- default:
- str = "Unknown";
- break;
- }
- return str;
-}
-
-inline const char* getKaekIndexStr(nn::hac::nca::KeyAreaEncryptionKeyIndex keak_index)
-{
- const char* str;
- switch (keak_index)
- {
- case (nn::hac::nca::KAEK_IDX_APPLICATION):
- str = "Application";
- break;
- case (nn::hac::nca::KAEK_IDX_OCEAN):
- str = "Ocean";
- break;
- case (nn::hac::nca::KAEK_IDX_SYSTEM):
- str = "System";
- break;
- default:
- str = "Unknown";
- break;
- }
- return str;
-}
-
-inline const char* getContentTypeForMountStr(nn::hac::nca::ContentType cont_type)
-{
- const char* str;
- switch (cont_type)
- {
- case (nn::hac::nca::TYPE_PROGRAM):
- str = "program";
- break;
- case (nn::hac::nca::TYPE_META):
- str = "meta";
- break;
- case (nn::hac::nca::TYPE_CONTROL):
- str = "control";
- break;
- case (nn::hac::nca::TYPE_MANUAL):
- str = "manual";
- break;
- case (nn::hac::nca::TYPE_DATA):
- str = "data";
- break;
- case (nn::hac::nca::TYPE_PUBLIC_DATA):
- str = "publicData";
- break;
- default:
- str = "";
- break;
- }
- return str;
-}
-
-const char* getProgramPartitionNameStr(size_t i)
-{
- const char* str;
- switch (i)
- {
- case (nn::hac::nca::PARTITION_CODE):
- str = "code";
- break;
- case (nn::hac::nca::PARTITION_DATA):
- str = "data";
- break;
- case (nn::hac::nca::PARTITION_LOGO):
- str = "logo";
- break;
- default:
- str = "";
- break;
- }
- return str;
-}
-
-
NcaProcess::NcaProcess() :
- mFile(nullptr),
- mOwnIFile(false),
- mKeyset(nullptr),
+ mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false),
mListFs(false)
@@ -231,44 +21,13 @@ NcaProcess::NcaProcess() :
for (size_t i = 0; i < nn::hac::nca::kPartitionNum; i++)
{
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;
- }
}
}
void NcaProcess::process()
{
- if (mFile == nullptr)
- {
- throw fnd::Exception(kModuleName, "No file reader set.");
- }
-
- // read header block
- mFile->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock));
-
- // decrypt header block
- nn::hac::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, mKeyset->nca.header_key);
-
- // generate header hash
- fnd::sha::Sha256((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader), mHdrHash.bytes);
-
- // proccess main header
- mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader));
+ // import header
+ importHeader();
// determine keys
generateNcaBodyEncryptionKeys();
@@ -288,15 +47,14 @@ void NcaProcess::process()
processPartitions();
}
-void NcaProcess::setInputFile(fnd::IFile* file, bool ownIFile)
+void NcaProcess::setInputFile(const fnd::SharedPtr& file)
{
mFile = file;
- mOwnIFile = ownIFile;
}
-void NcaProcess::setKeyset(const sKeyset* keyset)
+void NcaProcess::setKeyCfg(const KeyConfiguration& keycfg)
{
- mKeyset = keyset;
+ mKeyCfg = keycfg;
}
void NcaProcess::setCliOutputMode(CliOutputMode type)
@@ -338,120 +96,120 @@ void NcaProcess::setListFs(bool list_fs)
mListFs = list_fs;
}
+void NcaProcess::importHeader()
+{
+ if (*mFile == nullptr)
+ {
+ throw fnd::Exception(kModuleName, "No file reader set.");
+ }
+
+ // read header block
+ (*mFile)->read((byte_t*)&mHdrBlock, 0, sizeof(nn::hac::sNcaHeaderBlock));
+
+ // decrypt header block
+ fnd::aes::sAesXts128Key header_key;
+ mKeyCfg.getNcaHeaderKey(header_key);
+ nn::hac::NcaUtils::decryptNcaHeader((byte_t*)&mHdrBlock, (byte_t*)&mHdrBlock, header_key);
+
+ // generate header hash
+ fnd::sha::Sha256((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader), mHdrHash.bytes);
+
+ // proccess main header
+ mHdr.fromBytes((byte_t*)&mHdrBlock.header, sizeof(nn::hac::sNcaHeader));
+}
+
void NcaProcess::generateNcaBodyEncryptionKeys()
{
// create zeros key
fnd::aes::sAes128Key zero_aesctr_key;
memset(zero_aesctr_key.key, 0, sizeof(zero_aesctr_key));
- fnd::aes::sAesXts128Key zero_aesxts_key;
- memset(zero_aesxts_key.key, 0, sizeof(zero_aesxts_key));
// get key data from header
byte_t masterkey_rev = nn::hac::NcaUtils::getMasterKeyRevisionFromKeyGeneration(mHdr.getKeyGeneration());
byte_t keak_index = mHdr.getKaekIndex();
// process key area
- sKeys::sKeyAreaKey keak;
+ sKeys::sKeyAreaKey kak;
+ fnd::aes::sAes128Key key_area_enc_key;
for (size_t i = 0; i < nn::hac::nca::kAesKeyNum; i++)
{
if (mHdr.getEncAesKeys()[i] != zero_aesctr_key)
{
- keak.index = (byte_t)i;
- keak.enc = mHdr.getEncAesKeys()[i];
- if (i < 4 && mKeyset->nca.key_area_key[keak_index][masterkey_rev] != zero_aesctr_key)
+ kak.index = (byte_t)i;
+ kak.enc = mHdr.getEncAesKeys()[i];
+ // key[0-3]
+ if (i < 4 && mKeyCfg.getNcaKeyAreaEncryptionKey(masterkey_rev, keak_index, key_area_enc_key) == true)
{
- keak.decrypted = true;
- nn::hac::AesKeygen::generateKey(keak.dec.key, keak.enc.key, mKeyset->nca.key_area_key[keak_index][masterkey_rev].key);
+ kak.decrypted = true;
+ nn::hac::AesKeygen::generateKey(kak.dec.key, kak.enc.key, key_area_enc_key.key);
+ }
+ // key[4]
+ else if (i == 4 && mKeyCfg.getNcaKeyAreaEncryptionKeyHw(masterkey_rev, keak_index, key_area_enc_key) == true)
+ {
+ kak.decrypted = true;
+ nn::hac::AesKeygen::generateKey(kak.dec.key, kak.enc.key, key_area_enc_key.key);
}
else
{
- keak.decrypted = false;
+ kak.decrypted = false;
}
- mBodyKeys.keak_list.addElement(keak);
+ mContentKey.kak_list.addElement(kak);
}
}
// set flag to indicate that the keys are not available
- mBodyKeys.aes_ctr.isSet = false;
- mBodyKeys.aes_xts.isSet = false;
+ mContentKey.aes_ctr.isSet = false;
// if this has a rights id, the key needs to be sourced from a ticket
if (mHdr.hasRightsId() == true)
{
- // if the titlekey_kek is available
- if (mKeyset->ticket.titlekey_kek[masterkey_rev] != zero_aesctr_key)
+ fnd::aes::sAes128Key tmp_key;
+ if (mKeyCfg.getNcaExternalContentKey(mHdr.getRightsId(), tmp_key) == true)
{
- // the title key is provided (sourced from ticket)
- if (mKeyset->nca.manual_title_key_aesctr != zero_aesctr_key)
+ mContentKey.aes_ctr = tmp_key;
+ }
+ else if (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserTitleKey, tmp_key) == true)
+ {
+ fnd::aes::sAes128Key common_key;
+ if (mKeyCfg.getETicketCommonKey(masterkey_rev, common_key) == true)
{
- nn::hac::AesKeygen::generateKey(mBodyKeys.aes_ctr.var.key, mKeyset->nca.manual_title_key_aesctr.key, mKeyset->ticket.titlekey_kek[masterkey_rev].key);
- mBodyKeys.aes_ctr.isSet = true;
- }
- if (mKeyset->nca.manual_title_key_aesxts != zero_aesxts_key)
- {
- nn::hac::AesKeygen::generateKey(mBodyKeys.aes_xts.var.key[0], mKeyset->nca.manual_title_key_aesxts.key[0], mKeyset->ticket.titlekey_kek[masterkey_rev].key);
- nn::hac::AesKeygen::generateKey(mBodyKeys.aes_xts.var.key[1], mKeyset->nca.manual_title_key_aesxts.key[1], mKeyset->ticket.titlekey_kek[masterkey_rev].key);
- mBodyKeys.aes_xts.isSet = true;
+ nn::hac::AesKeygen::generateKey(tmp_key.key, tmp_key.key, common_key.key);
}
+ mContentKey.aes_ctr = tmp_key;
}
}
// otherwise decrypt key area
else
{
- fnd::aes::sAes128Key keak_aesctr_key = zero_aesctr_key;
- fnd::aes::sAesXts128Key keak_aesxts_key = zero_aesxts_key;
- for (size_t i = 0; i < mBodyKeys.keak_list.size(); i++)
+ fnd::aes::sAes128Key kak_aes_ctr = zero_aesctr_key;
+ for (size_t i = 0; i < mContentKey.kak_list.size(); i++)
{
- if (mBodyKeys.keak_list[i].index == nn::hac::nca::KEY_AESCTR && mBodyKeys.keak_list[i].decrypted)
+ if (mContentKey.kak_list[i].index == nn::hac::nca::KEY_AESCTR && mContentKey.kak_list[i].decrypted)
{
- keak_aesctr_key = mBodyKeys.keak_list[i].dec;
- }
- else if (mBodyKeys.keak_list[i].index == nn::hac::nca::KEY_AESXTS_0 && mBodyKeys.keak_list[i].decrypted)
- {
- memcpy(keak_aesxts_key.key[0], mBodyKeys.keak_list[i].dec.key, sizeof(fnd::aes::sAes128Key));
- }
- else if (mBodyKeys.keak_list[i].index == nn::hac::nca::KEY_AESXTS_1 && mBodyKeys.keak_list[i].decrypted)
- {
- memcpy(keak_aesxts_key.key[1], mBodyKeys.keak_list[i].dec.key, sizeof(fnd::aes::sAes128Key));
+ kak_aes_ctr = mContentKey.kak_list[i].dec;
}
}
- if (keak_aesctr_key != zero_aesctr_key)
+ if (kak_aes_ctr != zero_aesctr_key)
{
- mBodyKeys.aes_ctr = keak_aesctr_key;
- }
- if (keak_aesxts_key != zero_aesxts_key)
- {
- mBodyKeys.aes_xts = keak_aesxts_key;
+ mContentKey.aes_ctr = kak_aes_ctr;
}
}
// if the keys weren't generated, check if the keys were supplied by the user
- if (mBodyKeys.aes_ctr.isSet == false && mKeyset->nca.manual_body_key_aesctr != zero_aesctr_key)
+ if (mContentKey.aes_ctr.isSet == false)
{
- mBodyKeys.aes_ctr = mKeyset->nca.manual_body_key_aesctr;
- }
- if (mBodyKeys.aes_xts.isSet == false && mKeyset->nca.manual_body_key_aesxts != zero_aesxts_key)
- {
- mBodyKeys.aes_xts = mKeyset->nca.manual_body_key_aesxts;
+ if (mKeyCfg.getNcaExternalContentKey(kDummyRightsIdForUserBodyKey, mContentKey.aes_ctr.var) == true)
+ mContentKey.aes_ctr.isSet = true;
}
+
if (_HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA))
{
- if (mBodyKeys.aes_ctr.isSet)
+ if (mContentKey.aes_ctr.isSet)
{
- printf("[NCA Body Key]\n");
- printf(" AES-CTR Key: ");
- fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_ctr.var.key, sizeof(mBodyKeys.aes_ctr.var));
- }
-
- if (mBodyKeys.aes_xts.isSet)
- {
- printf("[NCA Body Key]\n");
- printf(" AES-XTS Key0: ");
- fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[0], sizeof(mBodyKeys.aes_ctr.var));
- printf(" AES-XTS Key1: ");
- fnd::SimpleTextOutput::hexDump(mBodyKeys.aes_xts.var.key[1], sizeof(mBodyKeys.aes_ctr.var));
+ std::cout << "[NCA Content Key]" << std::endl;
+ std::cout << " AES-CTR Key: " << fnd::SimpleTextOutput::arrayToString(mContentKey.aes_ctr.var.key, sizeof(mContentKey.aes_ctr.var), true, ":") << std::endl;
}
}
@@ -522,13 +280,13 @@ void NcaProcess::generatePartitionConfiguration()
// create reader based on encryption type0
if (info.enc_type == nn::hac::nca::CRYPT_NONE)
{
- info.reader = new OffsetAdjustedIFile(mFile, SHARED_IFILE, info.offset, info.size);
+ info.reader = new OffsetAdjustedIFile(mFile, info.offset, info.size);
}
else if (info.enc_type == nn::hac::nca::CRYPT_AESCTR)
{
- if (mBodyKeys.aes_ctr.isSet == false)
+ if (mContentKey.aes_ctr.isSet == false)
throw fnd::Exception(kModuleName, "AES-CTR Key was not determined");
- info.reader = new OffsetAdjustedIFile(new AesCtrWrappedIFile(mFile, SHARED_IFILE, mBodyKeys.aes_ctr.var, info.aes_ctr), OWN_IFILE, info.offset, info.size);
+ info.reader = new OffsetAdjustedIFile(new 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)
{
@@ -546,9 +304,7 @@ void NcaProcess::generatePartitionConfiguration()
// 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)
{
- fnd::IFile* tmp = info.reader;
- info.reader = nullptr;
- info.reader = new HashTreeWrappedIFile(tmp, OWN_IFILE, info.hash_tree_meta);
+ info.reader = new HashTreeWrappedIFile(info.reader, info.hash_tree_meta);
}
else if (info.hash_type != nn::hac::nca::HASH_NONE)
{
@@ -560,9 +316,6 @@ void NcaProcess::generatePartitionConfiguration()
catch (const fnd::Exception& e)
{
info.fail_reason = std::string(e.error());
- if (info.reader != nullptr)
- delete info.reader;
- info.reader = nullptr;
}
}
}
@@ -570,9 +323,11 @@ void NcaProcess::generatePartitionConfiguration()
void NcaProcess::validateNcaSignatures()
{
// validate signature[0]
- if (fnd::rsa::pss::rsaVerify(mKeyset->nca.header_sign_key, fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_main) != 0)
+ fnd::rsa::sRsa2048Key sign0_key;
+ mKeyCfg.getNcaHeader0SignKey(sign0_key);
+ if (fnd::rsa::pss::rsaVerify(sign0_key, fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_main) != 0)
{
- printf("[WARNING] NCA Header Main Signature: FAIL \n");
+ std::cout << "[WARNING] NCA Header Main Signature: FAIL" << std::endl;
}
// validate signature[1]
@@ -580,10 +335,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].reader != nullptr)
+ if (*mPartitions[nn::hac::nca::PARTITION_CODE].reader != nullptr)
{
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.process();
@@ -593,153 +348,136 @@ void NcaProcess::validateNcaSignatures()
const nn::hac::PfsHeader::sFile& file = exefs.getPfsHeader().getFileList().getElement(kNpdmExefsPath);
NpdmProcess npdm;
- npdm.setInputFile(new OffsetAdjustedIFile(mPartitions[nn::hac::nca::PARTITION_CODE].reader, SHARED_IFILE, file.offset, file.size), OWN_IFILE);
+ npdm.setInputFile(new OffsetAdjustedIFile(mPartitions[nn::hac::nca::PARTITION_CODE].reader, file.offset, file.size));
npdm.setCliOutputMode(0);
npdm.process();
if (fnd::rsa::pss::rsaVerify(npdm.getNpdmBinary().getAcid().getNcaHeaderSignature2Key(), fnd::sha::HASH_SHA256, mHdrHash.bytes, mHdrBlock.signature_acid) != 0)
{
- printf("[WARNING] NCA Header ACID Signature: FAIL \n");
+ std::cout << "[WARNING] NCA Header ACID Signature: FAIL" << std::endl;
}
}
else
{
- printf("[WARNING] NCA Header ACID Signature: FAIL (\"%s\" not present in ExeFs)\n", kNpdmExefsPath.c_str());
+ std::cout << "[WARNING] NCA Header ACID Signature: FAIL (\"" << kNpdmExefsPath << "\" not present in ExeFs)" << std::endl;
}
}
else
{
- printf("[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)\n");
+ std::cout << "[WARNING] NCA Header ACID Signature: FAIL (ExeFs unreadable)" << std::endl;
}
}
else
{
- printf("[WARNING] NCA Header ACID Signature: FAIL (No ExeFs partition)\n");
+ std::cout << "[WARNING] NCA Header ACID Signature: FAIL (No ExeFs partition)" << std::endl;
}
}
}
void NcaProcess::displayHeader()
{
-#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0)
-#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
-
- printf("[NCA Header]\n");
- printf(" Format Type: %s\n", getFormatVersionStr(mHdr.getFormatVersion()));
- printf(" Dist. Type: %s\n", getDistributionTypeStr(mHdr.getDistributionType()));
- printf(" Content Type: %s\n", getContentTypeStr(mHdr.getContentType()));
- printf(" Key Generation: %d\n", mHdr.getKeyGeneration());
- printf(" Kaek Index: %s (%d)\n", getKaekIndexStr((nn::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKaekIndex()), mHdr.getKaekIndex());
- printf(" Size: 0x%" PRIx64 "\n", mHdr.getContentSize());
- printf(" ProgID: 0x%016" PRIx64 "\n", mHdr.getProgramId());
- printf(" Content Index: %" PRIu32 "\n", mHdr.getContentIndex());
-#define _SPLIT_VER(ver) ( (ver>>24) & 0xff), ( (ver>>16) & 0xff), ( (ver>>8) & 0xff)
- printf(" SdkAddon Ver.: v%" PRIu32 " (%d.%d.%d)\n", mHdr.getSdkAddonVersion(), _SPLIT_VER(mHdr.getSdkAddonVersion()));
+ std::cout << "[NCA Header]" << std::endl;
+ std::cout << " Format Type: " << getFormatVersionStr(mHdr.getFormatVersion()) << std::endl;
+ std::cout << " Dist. Type: " << getDistributionTypeStr(mHdr.getDistributionType()) << std::endl;
+ std::cout << " Content Type: " << getContentTypeStr(mHdr.getContentType()) << std::endl;
+ std::cout << " Key Generation: " << std::dec << (uint32_t)mHdr.getKeyGeneration() << std::endl;
+ std::cout << " Kaek Index: " << getKaekIndexStr((nn::hac::nca::KeyAreaEncryptionKeyIndex)mHdr.getKaekIndex()) << " (" << std::dec << (uint32_t)mHdr.getKaekIndex() << ")" << std::endl;
+ std::cout << " Size: 0x" << std::hex << mHdr.getContentSize() << std::endl;
+ std::cout << " ProgID: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getProgramId() << std::endl;
+ std::cout << " Content Index: " << std::dec << mHdr.getContentIndex() << std::endl;
+#define _SPLIT_VER(ver) std::dec << (uint32_t)((ver>>24) & 0xff) << "." << (uint32_t)((ver>>16) & 0xff) << "." << (uint32_t)((ver>>8) & 0xff)
+ std::cout << " SdkAddon Ver.: v" << std::dec << mHdr.getSdkAddonVersion() << " (" << _SPLIT_VER(mHdr.getSdkAddonVersion()) << ")" << std::endl;
#undef _SPLIT_VER
if (mHdr.hasRightsId())
{
- printf(" RightsId: ");
- fnd::SimpleTextOutput::hexDump(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen);
+ std::cout << " RightsId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRightsId(), nn::hac::nca::kRightsIdLen, true, "") << std::endl;
}
-
- if (mBodyKeys.keak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA))
+ if (mContentKey.kak_list.size() > 0 && _HAS_BIT(mCliOutputMode, OUTPUT_KEY_DATA))
{
- printf(" Key Area: \n");
- printf(" <--------------------------------------------------------------------------->\n");
- printf(" | IDX | ENCRYPTED KEY | DECRYPTED KEY |\n");
- printf(" |-----|----------------------------------|----------------------------------|\n");
- for (size_t i = 0; i < mBodyKeys.keak_list.size(); i++)
+ std::cout << " Key Area:" << std::endl;
+ std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl;
+ std::cout << " | IDX | ENCRYPTED KEY | DECRYPTED KEY |" << std::endl;
+ std::cout << " |-----|-------------------------------------------------|-------------------------------------------------|" << std::endl;
+ for (size_t i = 0; i < mContentKey.kak_list.size(); i++)
{
- printf(" | %3d | ", mBodyKeys.keak_list[i].index);
+ std::cout << " | " << std::dec << std::setw(3) << std::setfill(' ') << (uint32_t)mContentKey.kak_list[i].index << " | ";
- _HEXDUMP_L(mBodyKeys.keak_list[i].enc.key, 16);
- //for (size_t j = 0; j < 16; j++) printf("%02x", mBodyKeys.keak_list[i].enc.key[j]);
+ std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].enc.key, 16, true, ":") << " | ";
- printf(" | ");
- if (mBodyKeys.keak_list[i].decrypted)
- _HEXDUMP_L(mBodyKeys.keak_list[i].dec.key, 16);
+ if (mContentKey.kak_list[i].decrypted)
+ std::cout << fnd::SimpleTextOutput::arrayToString(mContentKey.kak_list[i].dec.key, 16, true, ":");
else
- printf(" ");
+ std::cout << " ";
- printf(" |\n");
+ std::cout << " |" << std::endl;
}
- printf(" <--------------------------------------------------------------------------->\n");
+ std::cout << " <--------------------------------------------------------------------------------------------------------->" << std::endl;
}
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
{
- printf(" Partitions:\n");
+ std::cout << " Partitions:" << std::endl;
for (size_t i = 0; i < mHdr.getPartitions().size(); i++)
{
size_t index = mHdr.getPartitions()[i].index;
sPartitionInfo& info = mPartitions[index];
- printf(" %d:\n", (int)index);
- printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)info.offset);
- printf(" Size: 0x%" PRIx64 "\n", (uint64_t)info.size);
- printf(" Format Type: %s\n", getFormatTypeStr(info.format_type));
- printf(" Hash Type: %s\n", getHashTypeStr(info.hash_type));
- printf(" Enc. Type: %s\n", getEncryptionTypeStr(info.enc_type));
+ std::cout << " " << std::dec << index << ":" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << (uint64_t)info.offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << (uint64_t)info.size << std::endl;
+ std::cout << " Format Type: " << getFormatTypeStr(info.format_type) << std::endl;
+ std::cout << " Hash Type: " << getHashTypeStr(info.hash_type) << std::endl;
+ std::cout << " Enc. Type: " << getEncryptionTypeStr(info.enc_type) << std::endl;
if (info.enc_type == nn::hac::nca::CRYPT_AESCTR)
{
- printf(" AES-CTR: ");
fnd::aes::sAesIvCtr ctr;
fnd::aes::AesIncrementCounter(info.aes_ctr.iv, info.offset>>4, ctr.iv);
- fnd::SimpleTextOutput::hexDump(ctr.iv, sizeof(fnd::aes::sAesIvCtr));
+ std::cout << " AesCtr Counter:" << std::endl;
+ std::cout << " " << fnd::SimpleTextOutput::arrayToString(ctr.iv, sizeof(fnd::aes::sAesIvCtr), true, ":") << std::endl;
}
if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY)
{
HashTreeMeta& hash_hdr = info.hash_tree_meta;
- printf(" HierarchicalIntegrity Header:\n");
- //printf(" TypeId: 0x%x\n", hash_hdr.type_id.get());
- //printf(" MasterHashSize: 0x%x\n", hash_hdr.master_hash_size.get());
- //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().size());
+ std::cout << " HierarchicalIntegrity Header:" << std::endl;
for (size_t j = 0; j < hash_hdr.getHashLayerInfo().size(); j++)
{
- printf(" Hash Layer %d:\n", (int)j);
- printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].offset);
- printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[j].size);
- printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size);
+ std::cout << " Hash Layer " << std::dec << j << ":" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[j].offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[j].size << std::endl;
+ std::cout << " BlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getHashLayerInfo()[j].block_size << std::endl;
}
- printf(" Data Layer:\n");
- printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset);
- printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size);
- printf(" BlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size);
+ std::cout << " Data Layer:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().size << std::endl;
+ std::cout << " BlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl;
for (size_t j = 0; j < hash_hdr.getMasterHashList().size(); j++)
{
- printf(" Master Hash %d: ", (int)j);
- fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[j].bytes, sizeof(fnd::sha::sSha256Hash));
+ std::cout << " Master Hash " << std::dec << j << ":" << std::endl;
+ std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes, 0x10, true, ":") << std::endl;
+ std::cout << " " << fnd::SimpleTextOutput::arrayToString(hash_hdr.getMasterHashList()[j].bytes+0x10, 0x10, true, ":") << std::endl;
}
}
else if (info.hash_type == nn::hac::nca::HASH_HIERARCHICAL_SHA256)
{
HashTreeMeta& hash_hdr = info.hash_tree_meta;
- printf(" HierarchicalSha256 Header:\n");
- printf(" Master Hash: ");
- fnd::SimpleTextOutput::hexDump(hash_hdr.getMasterHashList()[0].bytes, sizeof(fnd::sha::sSha256Hash));
- printf(" HashBlockSize: 0x%" PRIx32 "\n", (uint32_t)hash_hdr.getDataLayer().block_size);
- //printf(" LayerNum: %d\n", hash_hdr.getLayerInfo().size());
- printf(" Hash Layer:\n");
- printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].offset);
- printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getHashLayerInfo()[0].size);
- printf(" Data Layer:\n");
- printf(" Offset: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().offset);
- printf(" Size: 0x%" PRIx64 "\n", (uint64_t)hash_hdr.getDataLayer().size);
+ std::cout << " HierarchicalSha256 Header:" << 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, 0x10, true, ":") << std::endl;
+ std::cout << " HashBlockSize: 0x" << std::hex << (uint32_t)hash_hdr.getDataLayer().block_size << std::endl;
+ std::cout << " Hash Layer:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getHashLayerInfo()[0].size << std::endl;
+ std::cout << " Data Layer:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << (uint64_t)hash_hdr.getDataLayer().size << std::endl;
}
- //else
- //{
- // printf(" Hash Superblock:\n");
- // fnd::SimpleTextOutput::hxdStyleDump(fs_header.hash_superblock, nn::hac::nca::kFsHeaderHashSuperblockLen);
- //}
}
}
-
-#undef _HEXDUMP_U
-#undef _HEXDUMP_L
}
@@ -751,21 +489,21 @@ void NcaProcess::processPartitions()
struct sPartitionInfo& partition = mPartitions[index];
// if the reader is null, skip
- if (partition.reader == nullptr)
+ if (*partition.reader == nullptr)
{
- printf("[WARNING] NCA Partition %d not readable.", (int)index);
+ std::cout << "[WARNING] NCA Partition " << std::dec << index << " not readable.";
if (partition.fail_reason.empty() == false)
{
- printf(" (%s)", partition.fail_reason.c_str());
+ std::cout << " (" << partition.fail_reason << ")";
}
- printf("\n");
+ std::cout << std::endl;
continue;
}
if (partition.format_type == nn::hac::nca::FORMAT_PFS0)
{
PfsProcess pfs;
- pfs.setInputFile(partition.reader, SHARED_IFILE);
+ pfs.setInputFile(partition.reader);
pfs.setCliOutputMode(mCliOutputMode);
pfs.setListFs(mListFs);
if (mHdr.getContentType() == nn::hac::nca::TYPE_PROGRAM)
@@ -779,14 +517,12 @@ void NcaProcess::processPartitions()
if (mPartitionPath[index].doExtract)
pfs.setExtractPath(mPartitionPath[index].path);
- //printf("pfs.process(%lx)\n",partition.data_offset);
pfs.process();
- //printf("pfs.process() end\n");
}
else if (partition.format_type == nn::hac::nca::FORMAT_ROMFS)
{
RomfsProcess romfs;
- romfs.setInputFile(partition.reader, SHARED_IFILE);
+ romfs.setInputFile(partition.reader);
romfs.setCliOutputMode(mCliOutputMode);
romfs.setListFs(mListFs);
if (mHdr.getContentType() == nn::hac::nca::TYPE_PROGRAM)
@@ -800,9 +536,233 @@ void NcaProcess::processPartitions()
if (mPartitionPath[index].doExtract)
romfs.setExtractPath(mPartitionPath[index].path);
- //printf("romfs.process(%lx)\n", partition.data_offset);
romfs.process();
- //printf("romfs.process() end\n");
}
}
}
+
+const char* NcaProcess::getFormatVersionStr(nn::hac::NcaHeader::FormatVersion format_ver) const
+{
+ const char* str = nullptr;
+
+ switch (format_ver)
+ {
+ case (nn::hac::NcaHeader::NCA2_FORMAT):
+ str = "NCA2";
+ break;
+ case (nn::hac::NcaHeader::NCA3_FORMAT):
+ str = "NCA3";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NcaProcess::getDistributionTypeStr(nn::hac::nca::DistributionType dist_type) const
+{
+ const char* str = nullptr;
+
+ switch (dist_type)
+ {
+ case (nn::hac::nca::DIST_DOWNLOAD):
+ str = "Download";
+ break;
+ case (nn::hac::nca::DIST_GAME_CARD):
+ str = "Game Card";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+
+const char* NcaProcess::getContentTypeStr(nn::hac::nca::ContentType cont_type) const
+{
+ const char* str = nullptr;
+
+ switch (cont_type)
+ {
+ case (nn::hac::nca::TYPE_PROGRAM):
+ str = "Program";
+ break;
+ case (nn::hac::nca::TYPE_META):
+ str = "Meta";
+ break;
+ case (nn::hac::nca::TYPE_CONTROL):
+ str = "Control";
+ break;
+ case (nn::hac::nca::TYPE_MANUAL):
+ str = "Manual";
+ break;
+ case (nn::hac::nca::TYPE_DATA):
+ str = "Data";
+ break;
+ case (nn::hac::nca::TYPE_PUBLIC_DATA):
+ str = "PublicData";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NcaProcess::getEncryptionTypeStr(nn::hac::nca::EncryptionType enc_type) const
+{
+ const char* str = nullptr;
+
+ switch (enc_type)
+ {
+ case (nn::hac::nca::CRYPT_AUTO):
+ str = "Auto";
+ break;
+ case (nn::hac::nca::CRYPT_NONE):
+ str = "None";
+ break;
+ case (nn::hac::nca::CRYPT_AESXTS):
+ str = "AesXts";
+ break;
+ case (nn::hac::nca::CRYPT_AESCTR):
+ str = "AesCtr";
+ break;
+ case (nn::hac::nca::CRYPT_AESCTREX):
+ str = "AesCtrEx";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NcaProcess::getHashTypeStr(nn::hac::nca::HashType hash_type) const
+{
+ const char* str = nullptr;
+
+ switch (hash_type)
+ {
+ case (nn::hac::nca::HASH_AUTO):
+ str = "Auto";
+ break;
+ case (nn::hac::nca::HASH_NONE):
+ str = "None";
+ break;
+ case (nn::hac::nca::HASH_HIERARCHICAL_SHA256):
+ str = "HierarchicalSha256";
+ break;
+ case (nn::hac::nca::HASH_HIERARCHICAL_INTERGRITY):
+ str = "HierarchicalIntegrity";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NcaProcess::getFormatTypeStr(nn::hac::nca::FormatType format_type) const
+{
+ const char* str = nullptr;
+
+ switch (format_type)
+ {
+ case (nn::hac::nca::FORMAT_ROMFS):
+ str = "RomFs";
+ break;
+ case (nn::hac::nca::FORMAT_PFS0):
+ str = "PartitionFs";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NcaProcess::getKaekIndexStr(nn::hac::nca::KeyAreaEncryptionKeyIndex keak_index) const
+{
+ const char* str = nullptr;
+
+ switch (keak_index)
+ {
+ case (nn::hac::nca::KAEK_IDX_APPLICATION):
+ str = "Application";
+ break;
+ case (nn::hac::nca::KAEK_IDX_OCEAN):
+ str = "Ocean";
+ break;
+ case (nn::hac::nca::KAEK_IDX_SYSTEM):
+ str = "System";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NcaProcess::getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const
+{
+ const char* str = nullptr;
+
+ switch (cont_type)
+ {
+ case (nn::hac::nca::TYPE_PROGRAM):
+ str = "program";
+ break;
+ case (nn::hac::nca::TYPE_META):
+ str = "meta";
+ break;
+ case (nn::hac::nca::TYPE_CONTROL):
+ str = "control";
+ break;
+ case (nn::hac::nca::TYPE_MANUAL):
+ str = "manual";
+ break;
+ case (nn::hac::nca::TYPE_DATA):
+ str = "data";
+ break;
+ case (nn::hac::nca::TYPE_PUBLIC_DATA):
+ str = "publicData";
+ break;
+ default:
+ str = "";
+ break;
+ }
+
+ return str;
+}
+
+const char* NcaProcess::getProgramPartitionNameStr(size_t i) const
+{
+ const char* str = nullptr;
+
+ switch (i)
+ {
+ case (nn::hac::nca::PARTITION_CODE):
+ str = "code";
+ break;
+ case (nn::hac::nca::PARTITION_DATA):
+ str = "data";
+ break;
+ case (nn::hac::nca::PARTITION_LOGO):
+ str = "logo";
+ break;
+ default:
+ str = "";
+ break;
+ }
+
+ return str;
+}
\ No newline at end of file
diff --git a/programs/nstool/source/NcaProcess.h b/programs/nstool/source/NcaProcess.h
index e21ded8..c5b0429 100644
--- a/programs/nstool/source/NcaProcess.h
+++ b/programs/nstool/source/NcaProcess.h
@@ -1,24 +1,25 @@
#pragma once
#include
#include
-#include
+#include
+#include
#include
#include "HashTreeMeta.h"
+#include "KeyConfiguration.h"
-#include "nstool.h"
+#include "common.h"
class NcaProcess
{
public:
NcaProcess();
- ~NcaProcess();
void process();
// generic
- void setInputFile(fnd::IFile* file, bool ownIFile);
- void setKeyset(const sKeyset* keyset);
+ void setInputFile(const fnd::SharedPtr& file);
+ void setKeyCfg(const KeyConfiguration& keycfg);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
@@ -34,9 +35,8 @@ private:
const std::string kNpdmExefsPath = "main.npdm";
// user options
- fnd::IFile* mFile;
- bool mOwnIFile;
- const sKeyset* mKeyset;
+ fnd::SharedPtr mFile;
+ KeyConfiguration mKeyCfg;
CliOutputMode mCliOutputMode;
bool mVerify;
@@ -84,15 +84,14 @@ private:
return !(*this == other);
}
};
- fnd::List keak_list;
+ fnd::List kak_list;
sOptional aes_ctr;
- sOptional aes_xts;
- } mBodyKeys;
+ } mContentKey;
struct sPartitionInfo
{
- fnd::IFile* reader;
+ fnd::SharedPtr reader;
std::string fail_reason;
size_t offset;
size_t size;
@@ -105,9 +104,20 @@ private:
fnd::aes::sAesIvCtr aes_ctr;
} mPartitions[nn::hac::nca::kPartitionNum];
+ void importHeader();
void generateNcaBodyEncryptionKeys();
void generatePartitionConfiguration();
void validateNcaSignatures();
void displayHeader();
void processPartitions();
+
+ const char* getFormatVersionStr(nn::hac::NcaHeader::FormatVersion format_ver) const;
+ const char* getDistributionTypeStr(nn::hac::nca::DistributionType dist_type) const;
+ const char* getContentTypeStr(nn::hac::nca::ContentType cont_type) const;
+ const char* getEncryptionTypeStr(nn::hac::nca::EncryptionType enc_type) const;
+ const char* getHashTypeStr(nn::hac::nca::HashType hash_type) const;
+ const char* getFormatTypeStr(nn::hac::nca::FormatType format_type) const;
+ const char* getKaekIndexStr(nn::hac::nca::KeyAreaEncryptionKeyIndex keak_index) const;
+ const char* getContentTypeForMountStr(nn::hac::nca::ContentType cont_type) const;
+ const char* getProgramPartitionNameStr(size_t i) const;
};
\ No newline at end of file
diff --git a/programs/nstool/source/NpdmProcess.cpp b/programs/nstool/source/NpdmProcess.cpp
index 6a7f977..c397b2e 100644
--- a/programs/nstool/source/NpdmProcess.cpp
+++ b/programs/nstool/source/NpdmProcess.cpp
@@ -1,35 +1,17 @@
+#include
+#include
#include "NpdmProcess.h"
NpdmProcess::NpdmProcess() :
- mFile(nullptr),
- mOwnIFile(false),
- mKeyset(nullptr),
+ mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false)
{
}
-NpdmProcess::~NpdmProcess()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
-}
-
void NpdmProcess::process()
{
- fnd::Vec scratch;
-
- if (mFile == nullptr)
- {
- throw fnd::Exception(kModuleName, "No file reader set.");
- }
-
- scratch.alloc(mFile->size());
- mFile->read(scratch.data(), 0, scratch.size());
-
- mNpdm.fromBytes(scratch.data(), scratch.size());
+ importNpdm();
if (mVerify)
{
@@ -59,15 +41,14 @@ void NpdmProcess::process()
}
}
-void NpdmProcess::setInputFile(fnd::IFile* file, bool ownIFile)
+void NpdmProcess::setInputFile(const fnd::SharedPtr& file)
{
mFile = file;
- mOwnIFile = ownIFile;
}
-void NpdmProcess::setKeyset(const sKeyset* keyset)
+void NpdmProcess::setKeyCfg(const KeyConfiguration& keycfg)
{
- mKeyset = keyset;
+ mKeyCfg = keycfg;
}
void NpdmProcess::setCliOutputMode(CliOutputMode type)
@@ -85,264 +66,32 @@ const nn::hac::NpdmBinary& NpdmProcess::getNpdmBinary() const
return mNpdm;
}
-const std::string kInstructionType[2] = { "32Bit", "64Bit" };
-const std::string kProcAddrSpace[4] = { "Unknown", "64Bit", "32Bit", "32Bit no reserved" };
-const std::string kAcidFlag[32] =
+void NpdmProcess::importNpdm()
{
- "Production",
- "UnqualifiedApproval",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown",
- "Unknown"
-};
-const std::string kMiscFlag[15] = { "EnableDebug", "ForceDebug", "bit2", "bit3", "bit4", "bit5", "bit6", "bit7", "bit8", "bit9", "bit10", "bit11", "bit12", "bit13", "bit14"};
-const std::string kFsaFlag[64] =
-{
- "ApplicationInfo",
- "BootModeControl",
- "Calibration",
- "SystemSaveData",
- "GameCard",
- "SaveDataBackUp",
- "SaveDataManagement",
- "BisAllRaw",
- "GameCardRaw",
- "GameCardPrivate",
- "SetTime",
- "ContentManager",
- "ImageManager",
- "CreateSaveData",
- "SystemSaveDataManagement",
- "BisFileSystem",
- "SystemUpdate",
- "SaveDataMeta",
- "DeviceSaveData",
- "SettingsControl",
- "Bit20",
- "Bit21",
- "Bit22",
- "Bit23",
- "Bit24",
- "Bit25",
- "Bit26",
- "Bit27",
- "Bit28",
- "Bit29",
- "Bit30",
- "Bit31",
- "Bit32",
- "Bit33",
- "Bit34",
- "Bit35",
- "Bit36",
- "Bit37",
- "Bit38",
- "Bit39",
- "Bit40",
- "Bit41",
- "Bit42",
- "Bit43",
- "Bit44",
- "Bit45",
- "Bit46",
- "Bit47",
- "Bit48",
- "Bit49",
- "Bit50",
- "Bit51",
- "Bit52",
- "Bit53",
- "Bit54",
- "Bit55",
- "Bit56",
- "Bit57",
- "Bit58",
- "Bit59",
- "Bit60",
- "Bit61",
- "Debug",
- "FullPermission"
-};
+ fnd::Vec scratch;
-const std::string kSaveDataOwnerAccessMode[4] =
-{
- "IllegalAccessCondition",
- "Read",
- "Write",
- "ReadWrite"
-};
+ if (*mFile == nullptr)
+ {
+ throw fnd::Exception(kModuleName, "No file reader set.");
+ }
-const std::string kSysCall[0x80] =
-{
- "svc00",
- "SetHeapSize",
- "SetMemoryPermission",
- "SetMemoryAttribute",
- "MapMemory",
- "UnmapMemory",
- "QueryMemory",
- "ExitProcess",
- "CreateThread",
- "StartThread",
- "ExitThread",
- "SleepThread",
- "GetThreadPriority",
- "SetThreadPriority",
- "GetThreadCoreMask",
- "SetThreadCoreMask",
- "GetCurrentProcessorNumber",
- "SignalEvent",
- "ClearEvent",
- "MapSharedMemory",
- "UnmapSharedMemory",
- "CreateTransferMemory",
- "CloseHandle",
- "ResetSignal",
- "WaitSynchronization",
- "CancelSynchronization",
- "ArbitrateLock",
- "ArbitrateUnlock",
- "WaitProcessWideKeyAtomic",
- "SignalProcessWideKey",
- "GetSystemTick",
- "ConnectToNamedPort",
- "SendSyncRequestLight",
- "SendSyncRequest",
- "SendSyncRequestWithUserBuffer",
- "SendAsyncRequestWithUserBuffer",
- "GetProcessId",
- "GetThreadId",
- "Break",
- "OutputDebugString",
- "ReturnFromException",
- "GetInfo",
- "FlushEntireDataCache",
- "FlushDataCache",
- "MapPhysicalMemory",
- "UnmapPhysicalMemory",
- "svc2E",
- "GetLastThreadInfo",
- "GetResourceLimitLimitValue",
- "GetResourceLimitCurrentValue",
- "SetThreadActivity",
- "GetThreadContext3",
- "svc34",
- "svc35",
- "svc36",
- "svc37",
- "svc38",
- "svc39",
- "svc3A",
- "svc3B",
- "DumpInfo",
- "svc3D",
- "svc3E",
- "svc3F",
- "CreateSession",
- "AcceptSession",
- "ReplyAndReceiveLight",
- "ReplyAndReceive",
- "ReplyAndReceiveWithUserBuffer",
- "CreateEvent",
- "svc46",
- "svc47",
- "svc48",
- "svc49",
- "svc4A",
- "svc4B",
- "svc4C",
- "SleepSystem",
- "ReadWriteRegister",
- "SetProcessActivity",
- "CreateSharedMemory",
- "MapTransferMemory",
- "UnmapTransferMemory",
- "CreateInterruptEvent",
- "QueryPhysicalAddress",
- "QueryIoMapping",
- "CreateDeviceAddressSpace",
- "AttachDeviceAddressSpace",
- "DetachDeviceAddressSpace",
- "MapDeviceAddressSpaceByForce",
- "MapDeviceAddressSpaceAligned",
- "MapDeviceAddressSpace",
- "UnmapDeviceAddressSpace",
- "InvalidateProcessDataCache",
- "StoreProcessDataCache",
- "FlushProcessDataCache",
- "DebugActiveProcess",
- "BreakDebugProcess",
- "TerminateDebugProcess",
- "GetDebugEvent",
- "ContinueDebugEvent",
- "GetProcessList",
- "GetThreadList",
- "GetDebugThreadContext",
- "SetDebugThreadContext",
- "QueryDebugProcessMemory",
- "ReadDebugProcessMemory",
- "WriteDebugProcessMemory",
- "SetHardwareBreakPoint",
- "GetDebugThreadParam",
- "svc6E",
- "svc6F",
- "CreatePort",
- "ManageNamedPort",
- "ConnectToPort",
- "SetProcessMemoryPermission",
- "MapProcessMemory",
- "UnmapProcessMemory",
- "QueryProcessMemory",
- "MapProcessCodeMemory",
- "UnmapProcessCodeMemory",
- "CreateProcess",
- "StartProcess",
- "TerminateProcess",
- "GetProcessInfo",
- "CreateResourceLimit",
- "SetResourceLimitLimitValue",
- "CallSecureMonitor"
-};
+ scratch.alloc((*mFile)->size());
+ (*mFile)->read(scratch.data(), 0, scratch.size());
-const std::string kMemMapPerm[2] = { "RW", "RO" };
-const std::string kMemMapType[2] = { "Io", "Static" };
-
-const std::string kAcidTarget[2] = { "Development", "Production" };
+ mNpdm.fromBytes(scratch.data(), scratch.size());
+}
void NpdmProcess::validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid)
{
try {
- acid.validateSignature(mKeyset->acid_sign_key);
+ fnd::rsa::sRsa2048Key acid_sign_key;
+ if (mKeyCfg.getAcidSignKey(acid_sign_key) != true)
+ throw fnd::Exception();
+
+ acid.validateSignature(acid_sign_key);
}
catch (...) {
- printf("[WARNING] ACID Signature: FAIL\n");
+ std::cout << "[WARNING] ACID Signature: FAIL" << std::endl;
}
}
@@ -352,11 +101,11 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
// check Program ID
if (acid.getProgramIdRestrict().min > 0 && aci.getProgramId() < acid.getProgramIdRestrict().min)
{
- printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n");
+ std::cout << "[WARNING] ACI ProgramId: FAIL (Outside Legal Range)" << std::endl;
}
else if (acid.getProgramIdRestrict().max > 0 && aci.getProgramId() > acid.getProgramIdRestrict().max)
{
- printf("[WARNING] ACI ProgramId: FAIL (Outside Legal Range)\n");
+ std::cout << "[WARNING] ACI ProgramId: FAIL (Outside Legal Range)" << std::endl;
}
for (size_t i = 0; i < aci.getFileSystemAccessControl().getFsaRightsList().size(); i++)
@@ -371,7 +120,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (fsaRightFound == false)
{
- printf("[WARNING] ACI/FAC FsaRights: FAIL (%s not permitted)\n", kFsaFlag[aci.getFileSystemAccessControl().getFsaRightsList()[i]].c_str());
+ std::cout << "[WARNING] ACI/FAC FsaRights: FAIL (" << getFsaRightStr(aci.getFileSystemAccessControl().getFsaRightsList()[i]) << " not permitted)" << std::endl;
}
}
@@ -387,7 +136,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false)
{
- printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%016" PRIx64 " not permitted)\n", aci.getFileSystemAccessControl().getContentOwnerIdList()[i]);
+ std::cout << "[WARNING] ACI/FAC ContentOwnerId: FAIL (" << std::hex << std::setw(16) << std::setfill('0') << aci.getFileSystemAccessControl().getContentOwnerIdList()[i] << " not permitted)" << std::endl;
}
}
@@ -403,7 +152,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false)
{
- printf("[WARNING] ACI/FAC ContentOwnerId: FAIL (%016" PRIx64 "(%d) not permitted)\n", aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id, aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type);
+ std::cout << "[WARNING] ACI/FAC SaveDataOwnerId: FAIL (" << std::hex << std::setw(16) << std::setfill('0') << aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].id << "(" << std::dec << (uint32_t)aci.getFileSystemAccessControl().getSaveDataOwnerIdList()[i].access_type << ") not permitted)" << std::endl;
}
}
@@ -419,7 +168,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false)
{
- printf("[WARNING] ACI/SAC ServiceList: FAIL (%s%s not permitted)\n", aci.getServiceAccessControl().getServiceList()[i].getName().c_str(), aci.getServiceAccessControl().getServiceList()[i].isServer()? " (Server)" : "");
+ std::cout << "[WARNING] ACI/SAC ServiceList: FAIL (" << aci.getServiceAccessControl().getServiceList()[i].getName() << (aci.getServiceAccessControl().getServiceList()[i].isServer()? " (Server)" : "") << " not permitted)" << std::endl;
}
}
@@ -427,19 +176,19 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
// check thread info
if (aci.getKernelCapabilities().getThreadInfo().getMaxCpuId() != acid.getKernelCapabilities().getThreadInfo().getMaxCpuId())
{
- printf("[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMaxCpuId());
+ std::cout << "[WARNING] ACI/KC ThreadInfo/MaxCpuId: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMaxCpuId() << " not permitted)" << std::endl;
}
if (aci.getKernelCapabilities().getThreadInfo().getMinCpuId() != acid.getKernelCapabilities().getThreadInfo().getMinCpuId())
{
- printf("[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMinCpuId());
+ std::cout << "[WARNING] ACI/KC ThreadInfo/MinCpuId: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMinCpuId() << " not permitted)" << std::endl;
}
if (aci.getKernelCapabilities().getThreadInfo().getMaxPriority() != acid.getKernelCapabilities().getThreadInfo().getMaxPriority())
{
- printf("[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMaxPriority());
+ std::cout << "[WARNING] ACI/KC ThreadInfo/MaxPriority: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMaxPriority() << " not permitted)" << std::endl;
}
if (aci.getKernelCapabilities().getThreadInfo().getMinPriority() != acid.getKernelCapabilities().getThreadInfo().getMinPriority())
{
- printf("[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getThreadInfo().getMinPriority());
+ std::cout << "[WARNING] ACI/KC ThreadInfo/MinPriority: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getThreadInfo().getMinPriority() << " not permitted)" << std::endl;
}
// check system calls
for (size_t i = 0; i < aci.getKernelCapabilities().getSystemCalls().getSystemCalls().size(); i++)
@@ -453,7 +202,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false)
{
- printf("[WARNING] ACI/KC SystemCallList: FAIL (%s not permitted)\n", kSysCall[aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i]].c_str());
+ std::cout << "[WARNING] ACI/KC SystemCallList: FAIL (" << getSystemCallStr(aci.getKernelCapabilities().getSystemCalls().getSystemCalls()[i]) << " not permitted)" << std::endl;
}
}
// check memory maps
@@ -470,7 +219,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
{
const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getMemoryMaps()[i];
- printf("[WARNING] ACI/KC MemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str());
+ std::cout << "[WARNING] ACI/KC MemoryMap: FAIL (0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)map.addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(map.addr + map.size) << 12) - 1) << " (perm=" << getMemMapPermStr(map.perm) << ") (type=" << getMemMapTypeStr(map.type) << ") not permitted)" << std::endl;
}
}
for (size_t i = 0; i < aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps().size(); i++)
@@ -486,7 +235,7 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
{
const nn::hac::MemoryMappingHandler::sMemoryMapping& map = aci.getKernelCapabilities().getMemoryMaps().getIoMemoryMaps()[i];
- printf("[WARNING] ACI/KC IoMemoryMap: FAIL (0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s) not permitted)\n", (uint64_t)map.addr << 12, ((uint64_t)(map.addr + map.size) << 12) - 1, kMemMapPerm[map.perm].c_str(), kMemMapType[map.type].c_str());
+ std::cout << "[WARNING] ACI/KC IoMemoryMap: FAIL (0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)map.addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(map.addr + map.size) << 12) - 1) << " (perm=" << getMemMapPermStr(map.perm) << ") (type=" << getMemMapTypeStr(map.type) << ") not permitted)" << std::endl;
}
}
// check interupts
@@ -501,25 +250,25 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false)
{
- printf("[WARNING] ACI/KC InteruptsList: FAIL (0x%0x not permitted)\n", aci.getKernelCapabilities().getInterupts().getInteruptList()[i]);
+ std::cout << "[WARNING] ACI/KC InteruptsList: FAIL (0x" << std::hex << (uint32_t)aci.getKernelCapabilities().getInterupts().getInteruptList()[i] << " not permitted)" << std::endl;
}
}
// check misc params
if (aci.getKernelCapabilities().getMiscParams().getProgramType() != acid.getKernelCapabilities().getMiscParams().getProgramType())
{
- printf("[WARNING] ACI/KC ProgramType: FAIL (%d not permitted)\n", aci.getKernelCapabilities().getMiscParams().getProgramType());
+ std::cout << "[WARNING] ACI/KC ProgramType: FAIL (" << std::dec << (uint32_t)aci.getKernelCapabilities().getMiscParams().getProgramType() << " not permitted)" << std::endl;
}
// check kernel version
uint32_t aciKernelVersion = (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)aci.getKernelCapabilities().getKernelVersion().getVerMinor();
uint32_t acidKernelVersion = (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMajor() << 16 | (uint32_t)acid.getKernelCapabilities().getKernelVersion().getVerMinor();
if (aciKernelVersion < acidKernelVersion)
{
- printf("[WARNING] ACI/KC RequiredKernelVersion: FAIL (%d.%d not permitted)\n", aci.getKernelCapabilities().getKernelVersion().getVerMajor(), aci.getKernelCapabilities().getKernelVersion().getVerMinor());
+ std::cout << "[WARNING] ACI/KC RequiredKernelVersion: FAIL (" << std::dec << aci.getKernelCapabilities().getKernelVersion().getVerMajor() << "." << aci.getKernelCapabilities().getKernelVersion().getVerMinor() << " not permitted)" << std::endl;
}
// check handle table size
if (aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize() > acid.getKernelCapabilities().getHandleTableSize().getHandleTableSize())
{
- printf("[WARNING] ACI/KC HandleTableSize: FAIL (0x%x too large)\n", aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize());
+ std::cout << "[WARNING] ACI/KC HandleTableSize: FAIL (0x" << std::hex << (uint32_t)aci.getKernelCapabilities().getHandleTableSize().getHandleTableSize() << " too large)" << std::endl;
}
// check misc flags
for (size_t i = 0; i < aci.getKernelCapabilities().getMiscFlags().getFlagList().size(); i++)
@@ -533,88 +282,92 @@ void NpdmProcess::validateAciFromAcid(const nn::hac::AccessControlInfoBinary& ac
if (rightFound == false)
{
- printf("[WARNING] ACI/KC MiscFlag: FAIL (%s not permitted)\n", kMiscFlag[aci.getKernelCapabilities().getMiscFlags().getFlagList()[i]].c_str());
+ std::cout << "[WARNING] ACI/KC MiscFlag: FAIL (" << getMiscFlagStr(aci.getKernelCapabilities().getMiscFlags().getFlagList()[i]) << " not permitted)" << std::endl;
}
}
}
void NpdmProcess::displayNpdmHeader(const nn::hac::NpdmBinary& hdr)
{
- printf("[NPDM HEADER]\n");
- printf(" Process Architecture Params:\n");
- printf(" Ins. Type: %s\n", kInstructionType[hdr.getInstructionType()].c_str());
- printf(" Addr Space: %s\n", kProcAddrSpace[hdr.getProcAddressSpaceType()].c_str());
- printf(" Main Thread Params:\n");
- printf(" Priority: %d\n", hdr.getMainThreadPriority());
- printf(" CpuId: %d\n", hdr.getMainThreadCpuId());
- printf(" StackSize: 0x%x\n", hdr.getMainThreadStackSize());
- printf(" TitleInfo:\n");
- printf(" Version: v%" PRIu32 "\n", hdr.getVersion());
- printf(" Name: %s\n", hdr.getName().c_str());
+ std::cout << "[NPDM HEADER]" << std::endl;
+ std::cout << " Process Architecture Params:" << std::endl;
+ std::cout << " Ins. Type: " << getInstructionTypeStr(hdr.getInstructionType()) << std::endl;
+ std::cout << " Addr Space: " << getProcAddressSpaceTypeStr(hdr.getProcAddressSpaceType()) << std::endl;
+ std::cout << " Main Thread Params:" << std::endl;
+ std::cout << " Priority: " << std::dec << (uint32_t)hdr.getMainThreadPriority() << std::endl;
+ std::cout << " CpuId: " << std::dec << (uint32_t)hdr.getMainThreadCpuId() << std::endl;
+ std::cout << " StackSize: 0x" << std::hex << hdr.getMainThreadStackSize() << std::endl;
+ std::cout << " TitleInfo:" << std::endl;
+ std::cout << " Version: v" << std::dec << hdr.getVersion() << std::endl;
+ std::cout << " Name: " << hdr.getName() << std::endl;
if (hdr.getProductCode().length())
{
- printf(" ProductCode: %s\n", hdr.getProductCode().c_str());
+ std::cout << " ProductCode: " << hdr.getProductCode() << std::endl;
}
}
void NpdmProcess::displayAciHdr(const nn::hac::AccessControlInfoBinary& aci)
{
- printf("[Access Control Info]\n");
- printf(" ProgramID: 0x%016" PRIx64 "\n", aci.getProgramId());
+ std::cout << "[Access Control Info]" << std::endl;
+ std::cout << " ProgramID: 0x" << std::hex << std::setw(16) << std::setfill('0') << aci.getProgramId() << std::endl;
}
void NpdmProcess::displayAciDescHdr(const nn::hac::AccessControlInfoDescBinary& acid)
{
- printf("[Access Control Info Desc]\n");
+ std::cout << "[Access Control Info Desc]" << std::endl;
if (acid.getFlagList().size() > 0 || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
- printf(" Flags: \n");
+ std::cout << " Flags: " << std::endl;
for (size_t i = 0; i < acid.getFlagList().size(); i++)
{
- printf(" %s (%d)\n", kAcidFlag[acid.getFlagList()[i]].c_str(), acid.getFlagList()[i]);
+ std::cout << " " << getAcidFlagStr(acid.getFlagList()[i]) << " (" << std::dec << (uint32_t)acid.getFlagList()[i] << ")" << std::endl;
}
}
- printf(" ProgramID Restriction\n");
- printf(" Min: 0x%016" PRIx64 "\n", acid.getProgramIdRestrict().min);
- printf(" Max: 0x%016" PRIx64 "\n", acid.getProgramIdRestrict().max);
+ std::cout << " ProgramID Restriction" << std::endl;
+ std::cout << " Min: 0x" << std::hex << std::setw(16) << std::setfill('0') << acid.getProgramIdRestrict().min << std::endl;
+ std::cout << " Max: 0x" << std::hex << std::setw(16) << std::setfill('0') << acid.getProgramIdRestrict().max << std::endl;
}
void NpdmProcess::displayFac(const nn::hac::FileSystemAccessControlBinary& fac)
{
- printf("[FS Access Control]\n");
- printf(" Format Version: %d\n", fac.getFormatVersion());
+ std::cout << "[FS Access Control]" << std::endl;
+ std::cout << " Format Version: " << std::dec << (uint32_t)fac.getFormatVersion() << std::endl;
if (fac.getFsaRightsList().size())
{
- printf(" FS Rights:\n");
+ std::cout << " FS Rights:" << std::endl;
for (size_t i = 0; i < fac.getFsaRightsList().size(); i++)
{
if (i % 10 == 0)
{
- printf("%s ", i != 0 ? "\n" : "");
+ if (i != 0)
+ std::cout << std::endl;
+ std::cout << " ";
}
- printf("%s", kFsaFlag[fac.getFsaRightsList()[i]].c_str());
+ std::cout << getFsaRightStr(fac.getFsaRightsList()[i]);
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- printf(" (bit %" PRId32 ")", fac.getFsaRightsList()[i]);
- printf("%s", fac.getFsaRightsList()[i] != fac.getFsaRightsList().atBack() ? ", " : "\n");
+ std::cout << " (bit " << std::dec << (uint32_t)fac.getFsaRightsList()[i] << ")";
+ if (fac.getFsaRightsList()[i] != fac.getFsaRightsList().atBack())
+ std::cout << ", ";
+ std::cout << std::endl;
}
}
if (fac.getContentOwnerIdList().size())
{
- printf(" Content Owner IDs:\n");
+ std::cout << " Content Owner IDs:" << std::endl;
for (size_t i = 0; i < fac.getContentOwnerIdList().size(); i++)
{
- printf(" 0x%016" PRIx64 "\n", fac.getContentOwnerIdList()[i]);
+ std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << fac.getContentOwnerIdList()[i] << std::endl;
}
}
if (fac.getSaveDataOwnerIdList().size())
{
- printf(" Save Data Owner IDs:\n");
+ std::cout << " Save Data Owner IDs:" << std::endl;
for (size_t i = 0; i < fac.getSaveDataOwnerIdList().size(); i++)
{
- printf(" 0x%016" PRIx64 " (%s)\n", fac.getSaveDataOwnerIdList()[i].id, kSaveDataOwnerAccessMode[fac.getSaveDataOwnerIdList()[i].access_type].c_str());
+ std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << fac.getSaveDataOwnerIdList()[i].id << " (" << getSaveDataOwnerAccessModeStr(fac.getSaveDataOwnerIdList()[i].access_type) << ")" << std::endl;
}
}
@@ -622,101 +375,744 @@ void NpdmProcess::displayFac(const nn::hac::FileSystemAccessControlBinary& fac)
void NpdmProcess::displaySac(const nn::hac::ServiceAccessControlBinary& sac)
{
- printf("[Service Access Control]\n");
- printf(" Service List:\n");
+ std::cout << "[Service Access Control]" << std::endl;
+ std::cout << " Service List:" << std::endl;
for (size_t i = 0; i < sac.getServiceList().size(); i++)
{
if (i % 10 == 0)
{
- printf("%s ", i != 0 ? "\n" : "");
+ if (i != 0)
+ std::cout << std::endl;
+ std::cout << " ";
}
- printf("%s%s%s", sac.getServiceList()[i].getName().c_str(), sac.getServiceList()[i].isServer() ? "(isSrv)" : "", sac.getServiceList()[i] != sac.getServiceList().atBack() ? ", " : "\n");
+ std::cout << sac.getServiceList()[i].getName();
+ if (sac.getServiceList()[i].isServer())
+ std::cout << "(isSrv)";
+ if (sac.getServiceList()[i] != sac.getServiceList().atBack())
+ std::cout << ", ";
}
+ std::cout << std::endl;
}
void NpdmProcess::displayKernelCap(const nn::hac::KernelCapabilityBinary& kern)
{
- printf("[Kernel Capabilities]\n");
+ std::cout << "[Kernel Capabilities]" << std::endl;
if (kern.getThreadInfo().isSet())
{
nn::hac::ThreadInfoHandler threadInfo = kern.getThreadInfo();
- printf(" Thread Priority:\n");
- printf(" Min: %d\n", threadInfo.getMinPriority());
- printf(" Max: %d\n", threadInfo.getMaxPriority());
- printf(" CpuId:\n");
- printf(" Min: %d\n", threadInfo.getMinCpuId());
- printf(" Max: %d\n", threadInfo.getMaxCpuId());
+ std::cout << " Thread Priority:" << std::endl;
+ std::cout << " Min: " << std::dec << (uint32_t)threadInfo.getMinPriority() << std::endl;
+ std::cout << " Max: " << std::dec << (uint32_t)threadInfo.getMaxPriority() << std::endl;
+ std::cout << " CpuId:" << std::endl;
+ std::cout << " Min: " << std::dec << (uint32_t)threadInfo.getMinCpuId() << std::endl;
+ std::cout << " Max: " << std::dec << (uint32_t)threadInfo.getMaxCpuId() << std::endl;
}
+
if (kern.getSystemCalls().isSet())
{
fnd::List syscalls = kern.getSystemCalls().getSystemCalls();
- printf(" SystemCalls:");
- printf("\n ");
+ std::cout << " SystemCalls:" << std::endl;
+ std::cout << " ";
size_t lineLen = 0;
for (size_t i = 0; i < syscalls.size(); i++)
{
if (lineLen > 60)
{
lineLen = 0;
- printf("\n ");
+ std::cout << std::endl;
+ std::cout << " ";
}
- printf("%s%s", kSysCall[syscalls[i]].c_str(), syscalls[i] != syscalls.atBack() ? ", " : "\n");
- lineLen += kSysCall[syscalls[i]].length();
+ std::cout << getSystemCallStr(syscalls[i]);
+ if (syscalls[i] != syscalls.atBack())
+ std::cout << ", ";
+ lineLen += strlen(getSystemCallStr(syscalls[i]));
}
+ std::cout << std::endl;
}
if (kern.getMemoryMaps().isSet())
{
fnd::List maps = kern.getMemoryMaps().getMemoryMaps();
fnd::List ioMaps = kern.getMemoryMaps().getIoMemoryMaps();
- printf(" MemoryMaps:\n");
+ std::cout << " MemoryMaps:" << std::endl;
for (size_t i = 0; i < maps.size(); i++)
{
- printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)maps[i].addr << 12, ((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1, kMemMapPerm[maps[i].perm].c_str(), kMemMapType[maps[i].type].c_str());
+ std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)maps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(maps[i].addr + maps[i].size) << 12) - 1) << " (perm=" << getMemMapPermStr(maps[i].perm) << ") (type=" << getMemMapTypeStr(maps[i].type) << ") not permitted)" << std::endl;
}
- //printf(" IoMaps:\n");
+ //std::cout << " IoMaps:" << std::endl;
for (size_t i = 0; i < ioMaps.size(); i++)
{
- printf(" 0x%016" PRIx64 " - 0x%016" PRIx64 " (perm=%s) (type=%s)\n", (uint64_t)ioMaps[i].addr << 12, ((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1, kMemMapPerm[ioMaps[i].perm].c_str(), kMemMapType[ioMaps[i].type].c_str());
+ std::cout << " 0x" << std::hex << std::setw(16) << std::setfill('0') << ((uint64_t)ioMaps[i].addr << 12) << " - 0x" << std::hex << std::setw(16) << std::setfill('0') << (((uint64_t)(ioMaps[i].addr + ioMaps[i].size) << 12) - 1) << " (perm=" << getMemMapPermStr(ioMaps[i].perm) << ") (type=" << getMemMapTypeStr(ioMaps[i].type) << ") not permitted)" << std::endl;
}
}
if (kern.getInterupts().isSet())
{
fnd::List interupts = kern.getInterupts().getInteruptList();
- printf(" Interupts Flags:\n");
+ std::cout << " Interupts Flags:" << std::endl;
for (uint32_t i = 0; i < interupts.size(); i++)
{
if (i % 10 == 0)
{
- printf("%s ", i != 0 ? "\n" : "");
+ if (i != 0)
+ std::cout << std::endl;
+ std::cout << " ";
}
- printf("0x%x%s", interupts[i], interupts[i] != interupts.atBack() ? ", " : "\n");
+ std::cout << "0x" << std::hex << (uint32_t)interupts[i];
+ if (interupts[i] != interupts.atBack())
+ std::cout << ", ";
+ std::cout << std::endl;
}
}
if (kern.getMiscParams().isSet())
{
- printf(" ProgramType: %d\n", kern.getMiscParams().getProgramType());
+ std::cout << " ProgramType: " << std::dec << (uint32_t)kern.getMiscParams().getProgramType() << std::endl;
}
if (kern.getKernelVersion().isSet())
{
- printf(" Kernel Version: %d.%d\n", kern.getKernelVersion().getVerMajor(), kern.getKernelVersion().getVerMinor());
+ std::cout << " Kernel Version: " << std::dec << (uint32_t)kern.getKernelVersion().getVerMajor() << "." << (uint32_t)kern.getKernelVersion().getVerMinor() << std::endl;
}
if (kern.getHandleTableSize().isSet())
{
- printf(" Handle Table Size: 0x%x\n", kern.getHandleTableSize().getHandleTableSize());
+ std::cout << " Handle Table Size: 0x" << std::hex << kern.getHandleTableSize().getHandleTableSize() << std::endl;
}
if (kern.getMiscFlags().isSet())
{
fnd::List flagList = kern.getMiscFlags().getFlagList();
- printf(" Misc Flags:\n");
+ std::cout << " Misc Flags:" << std::endl;
for (uint32_t i = 0; i < flagList.size(); i++)
{
if (i % 10 == 0)
{
- printf("%s ", i != 0 ? "\n" : "");
+ if (i != 0)
+ std::cout << std::endl;
+ std::cout << " ";
}
- printf("%s%s", kMiscFlag[flagList[i]].c_str(), flagList[i] != flagList.atBack() ? ", " : "\n");
+ std::cout << getMiscFlagStr(flagList[i]);
+ if (flagList[i] != flagList.atBack())
+ std::cout << ", ";
+ std::cout << std::endl;
}
}
}
+
+const char* NpdmProcess::getInstructionTypeStr(nn::hac::npdm::InstructionType type) const
+{
+ const char* str = nullptr;
+
+ switch(type)
+ {
+ case (nn::hac::npdm::INSTR_32BIT):
+ str = "32Bit";
+ break;
+ case (nn::hac::npdm::INSTR_64BIT):
+ str = "64Bit";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NpdmProcess::getProcAddressSpaceTypeStr(nn::hac::npdm::ProcAddrSpaceType type) const
+{
+ const char* str = nullptr;
+
+ switch(type)
+ {
+ case (nn::hac::npdm::ADDR_SPACE_64BIT):
+ str = "64Bit";
+ break;
+ case (nn::hac::npdm::ADDR_SPACE_32BIT):
+ str = "32Bit";
+ break;
+ case (nn::hac::npdm::ADDR_SPACE_32BIT_NO_RESERVED):
+ str = "32Bit no reserved";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NpdmProcess::getAcidFlagStr(nn::hac::aci::Flag flag) const
+{
+ const char* str = nullptr;
+
+ switch(flag)
+ {
+ case (nn::hac::aci::FLAG_PRODUCTION):
+ str = "Production";
+ break;
+ case (nn::hac::aci::FLAG_UNQUALIFIED_APPROVAL):
+ str = "UnqualifiedApproval";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NpdmProcess::getMiscFlagStr(nn::hac::MiscFlagsHandler::Flags flag) const
+{
+ const char* str = nullptr;
+
+ switch(flag)
+ {
+ case (nn::hac::MiscFlagsHandler::FLAG_ENABLE_DEBUG):
+ str = "EnableDebug";
+ break;
+ case (nn::hac::MiscFlagsHandler::FLAG_FORCE_DEBUG):
+ str = "ForceDebug";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NpdmProcess::getFsaRightStr(nn::hac::fac::FsAccessFlag flag) const
+{
+ const char* str = nullptr;
+
+ switch(flag)
+ {
+ case (nn::hac::fac::FSA_APPLICATION_INFO):
+ str = "ApplicationInfo";
+ break;
+ case (nn::hac::fac::FSA_BOOT_MODE_CONTROL):
+ str = "BootModeControl";
+ break;
+ case (nn::hac::fac::FSA_CALIBRATION):
+ str = "Calibration";
+ break;
+ case (nn::hac::fac::FSA_SYSTEM_SAVE_DATA):
+ str = "SystemSaveData";
+ break;
+ case (nn::hac::fac::FSA_GAME_CARD):
+ str = "GameCard";
+ break;
+ case (nn::hac::fac::FSA_SAVE_DATA_BACKUP):
+ str = "SaveDataBackUp";
+ break;
+ case (nn::hac::fac::FSA_SAVE_DATA_MANAGEMENT):
+ str = "SaveDataManagement";
+ break;
+ case (nn::hac::fac::FSA_BIS_ALL_RAW):
+ str = "BisAllRaw";
+ break;
+ case (nn::hac::fac::FSA_GAME_CARD_RAW):
+ str = "GameCardRaw";
+ break;
+ case (nn::hac::fac::FSA_GAME_CARD_PRIVATE):
+ str = "GameCardPrivate";
+ break;
+ case (nn::hac::fac::FSA_SET_TIME):
+ str = "SetTime";
+ break;
+ case (nn::hac::fac::FSA_CONTENT_MANAGER):
+ str = "ContentManager";
+ break;
+ case (nn::hac::fac::FSA_IMAGE_MANAGER):
+ str = "ImageManager";
+ break;
+ case (nn::hac::fac::FSA_CREATE_SAVE_DATA):
+ str = "CreateSaveData";
+ break;
+ case (nn::hac::fac::FSA_SYSTEM_SAVE_DATA_MANAGEMENT):
+ str = "SystemSaveDataManagement";
+ break;
+ case (nn::hac::fac::FSA_BIS_FILE_SYSTEM):
+ str = "BisFileSystem";
+ break;
+ case (nn::hac::fac::FSA_SYSTEM_UPDATE):
+ str = "SystemUpdate";
+ break;
+ case (nn::hac::fac::FSA_SAVE_DATA_META):
+ str = "SaveDataMeta";
+ break;
+ case (nn::hac::fac::FSA_DEVICE_SAVE_CONTROL):
+ str = "DeviceSaveData";
+ break;
+ case (nn::hac::fac::FSA_SETTINGS_CONTROL):
+ str = "SettingsControl";
+ break;
+ case (nn::hac::fac::FSA_DEBUG):
+ str = "Debug";
+ break;
+ case (nn::hac::fac::FSA_FULL_PERMISSION):
+ str = "FullPermission";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NpdmProcess::getSaveDataOwnerAccessModeStr(nn::hac::fac::SaveDataOwnerIdAccessType type) const
+{
+ const char* str = nullptr;
+
+ switch(type)
+ {
+ case (nn::hac::fac::SDO_READ):
+ str = "Read";
+ break;
+ case (nn::hac::fac::SDO_WRITE):
+ str = "Write";
+ break;
+ case (nn::hac::fac::SDO_READWRITE):
+ str = "ReadWrite";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NpdmProcess::getSystemCallStr(byte_t syscall_id) const
+{
+ const char* str = nullptr;
+
+ switch(syscall_id)
+ {
+ case (0x01):
+ str = "SetHeapSize";
+ break;
+ case (0x02):
+ str = "SetMemoryPermission";
+ break;
+ case (0x03):
+ str = "SetMemoryAttribute";
+ break;
+ case (0x04):
+ str = "MapMemory";
+ break;
+ case (0x05):
+ str = "UnmapMemory";
+ break;
+ case (0x06):
+ str = "QueryMemory";
+ break;
+ case (0x07):
+ str = "ExitProcess";
+ break;
+ case (0x08):
+ str = "CreateThread";
+ break;
+ case (0x09):
+ str = "StartThread";
+ break;
+ case (0x0a):
+ str = "ExitThread";
+ break;
+ case (0x0b):
+ str = "SleepThread";
+ break;
+ case (0x0c):
+ str = "GetThreadPriority";
+ break;
+ case (0x0d):
+ str = "SetThreadPriority";
+ break;
+ case (0x0e):
+ str = "GetThreadCoreMask";
+ break;
+ case (0x0f):
+ str = "SetThreadCoreMask";
+ break;
+ case (0x10):
+ str = "GetCurrentProcessorNumber";
+ break;
+ case (0x11):
+ str = "SignalEvent";
+ break;
+ case (0x12):
+ str = "ClearEvent";
+ break;
+ case (0x13):
+ str = "MapSharedMemory";
+ break;
+ case (0x14):
+ str = "UnmapSharedMemory";
+ break;
+ case (0x15):
+ str = "CreateTransferMemory";
+ break;
+ case (0x16):
+ str = "CloseHandle";
+ break;
+ case (0x17):
+ str = "ResetSignal";
+ break;
+ case (0x18):
+ str = "WaitSynchronization";
+ break;
+ case (0x19):
+ str = "CancelSynchronization";
+ break;
+ case (0x1a):
+ str = "ArbitrateLock";
+ break;
+ case (0x1b):
+ str = "ArbitrateUnlock";
+ break;
+ case (0x1c):
+ str = "WaitProcessWideKeyAtomic";
+ break;
+ case (0x1d):
+ str = "SignalProcessWideKey";
+ break;
+ case (0x1e):
+ str = "GetSystemTick";
+ break;
+ case (0x1f):
+ str = "ConnectToNamedPort";
+ break;
+ case (0x20):
+ str = "SendSyncRequestLight";
+ break;
+ case (0x21):
+ str = "SendSyncRequest";
+ break;
+ case (0x22):
+ str = "SendSyncRequestWithUserBuffer";
+ break;
+ case (0x23):
+ str = "SendAsyncRequestWithUserBuffer";
+ break;
+ case (0x24):
+ str = "GetProcessId";
+ break;
+ case (0x25):
+ str = "GetThreadId";
+ break;
+ case (0x26):
+ str = "Break";
+ break;
+ case (0x27):
+ str = "OutputDebugString";
+ break;
+ case (0x28):
+ str = "ReturnFromException";
+ break;
+ case (0x29):
+ str = "GetInfo";
+ break;
+ case (0x2a):
+ str = "FlushEntireDataCache";
+ break;
+ case (0x2b):
+ str = "FlushDataCache";
+ break;
+ case (0x2c):
+ str = "MapPhysicalMemory";
+ break;
+ case (0x2d):
+ str = "UnmapPhysicalMemory";
+ break;
+ case (0x2e):
+ str = "GetFutureThreadInfo";
+ break;
+ case (0x2f):
+ str = "GetLastThreadInfo";
+ break;
+ case (0x30):
+ str = "GetResourceLimitLimitValue";
+ break;
+ case (0x31):
+ str = "GetResourceLimitCurrentValue";
+ break;
+ case (0x32):
+ str = "SetThreadActivity";
+ break;
+ case (0x33):
+ str = "GetThreadContext3";
+ break;
+ case (0x34):
+ str = "WaitForAddress";
+ break;
+ case (0x35):
+ str = "SignalToAddress";
+ break;
+ case (0x36):
+ str = "svc36";
+ break;
+ case (0x37):
+ str = "svc37";
+ break;
+ case (0x38):
+ str = "svc38";
+ break;
+ case (0x39):
+ str = "svc39";
+ break;
+ case (0x3a):
+ str = "svc3A";
+ break;
+ case (0x3b):
+ str = "svc3B";
+ break;
+ case (0x3c):
+ str = "DumpInfo";
+ break;
+ case (0x3d):
+ str = "DumpInfoNew";
+ break;
+ case (0x3e):
+ str = "svc3E";
+ break;
+ case (0x3f):
+ str = "svc3F";
+ break;
+ case (0x40):
+ str = "CreateSession";
+ break;
+ case (0x41):
+ str = "AcceptSession";
+ break;
+ case (0x42):
+ str = "ReplyAndReceiveLight";
+ break;
+ case (0x43):
+ str = "ReplyAndReceive";
+ break;
+ case (0x44):
+ str = "ReplyAndReceiveWithUserBuffer";
+ break;
+ case (0x45):
+ str = "CreateEvent";
+ break;
+ case (0x46):
+ str = "svc46";
+ break;
+ case (0x47):
+ str = "svc47";
+ break;
+ case (0x48):
+ str = "MapPhysicalMemoryUnsafe";
+ break;
+ case (0x49):
+ str = "UnmapPhysicalMemoryUnsafe";
+ break;
+ case (0x4a):
+ str = "SetUnsafeLimit";
+ break;
+ case (0x4b):
+ str = "CreateCodeMemory";
+ break;
+ case (0x4c):
+ str = "ControlCodeMemory";
+ break;
+ case (0x4d):
+ str = "SleepSystem";
+ break;
+ case (0x4e):
+ str = "ReadWriteRegister";
+ break;
+ case (0x4f):
+ str = "SetProcessActivity";
+ break;
+ case (0x50):
+ str = "CreateSharedMemory";
+ break;
+ case (0x51):
+ str = "MapTransferMemory";
+ break;
+ case (0x52):
+ str = "UnmapTransferMemory";
+ break;
+ case (0x53):
+ str = "CreateInterruptEvent";
+ break;
+ case (0x54):
+ str = "QueryPhysicalAddress";
+ break;
+ case (0x55):
+ str = "QueryIoMapping";
+ break;
+ case (0x56):
+ str = "CreateDeviceAddressSpace";
+ break;
+ case (0x57):
+ str = "AttachDeviceAddressSpace";
+ break;
+ case (0x58):
+ str = "DetachDeviceAddressSpace";
+ break;
+ case (0x59):
+ str = "MapDeviceAddressSpaceByForce";
+ break;
+ case (0x5a):
+ str = "MapDeviceAddressSpaceAligned";
+ break;
+ case (0x5b):
+ str = "MapDeviceAddressSpace";
+ break;
+ case (0x5c):
+ str = "UnmapDeviceAddressSpace";
+ break;
+ case (0x5d):
+ str = "InvalidateProcessDataCache";
+ break;
+ case (0x5e):
+ str = "StoreProcessDataCache";
+ break;
+ case (0x5f):
+ str = "FlushProcessDataCache";
+ break;
+ case (0x60):
+ str = "DebugActiveProcess";
+ break;
+ case (0x61):
+ str = "BreakDebugProcess";
+ break;
+ case (0x62):
+ str = "TerminateDebugProcess";
+ break;
+ case (0x63):
+ str = "GetDebugEvent";
+ break;
+ case (0x64):
+ str = "ContinueDebugEvent";
+ break;
+ case (0x65):
+ str = "GetProcessList";
+ break;
+ case (0x66):
+ str = "GetThreadList";
+ break;
+ case (0x67):
+ str = "GetDebugThreadContext";
+ break;
+ case (0x68):
+ str = "SetDebugThreadContext";
+ break;
+ case (0x69):
+ str = "QueryDebugProcessMemory";
+ break;
+ case (0x6a):
+ str = "ReadDebugProcessMemory";
+ break;
+ case (0x6b):
+ str = "WriteDebugProcessMemory";
+ break;
+ case (0x6c):
+ str = "SetHardwareBreakPoint";
+ break;
+ case (0x6d):
+ str = "GetDebugThreadParam";
+ break;
+ case (0x6e):
+ str = "svc6E";
+ break;
+ case (0x6f):
+ str = "GetSystemInfo";
+ break;
+ case (0x70):
+ str = "CreatePort";
+ break;
+ case (0x71):
+ str = "ManageNamedPort";
+ break;
+ case (0x72):
+ str = "ConnectToPort";
+ break;
+ case (0x73):
+ str = "SetProcessMemoryPermission";
+ break;
+ case (0x74):
+ str = "MapProcessMemory";
+ break;
+ case (0x75):
+ str = "UnmapProcessMemory";
+ break;
+ case (0x76):
+ str = "QueryProcessMemory";
+ break;
+ case (0x77):
+ str = "MapProcessCodeMemory";
+ break;
+ case (0x78):
+ str = "UnmapProcessCodeMemory";
+ break;
+ case (0x79):
+ str = "CreateProcess";
+ break;
+ case (0x7a):
+ str = "StartProcess";
+ break;
+ case (0x7b):
+ str = "TerminateProcess";
+ break;
+ case (0x7c):
+ str = "GetProcessInfo";
+ break;
+ case (0x7d):
+ str = "CreateResourceLimit";
+ break;
+ case (0x7e):
+ str = "SetResourceLimitLimitValue";
+ break;
+ case (0x7f):
+ str = "CallSecureMonitor";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NpdmProcess::getMemMapPermStr(nn::hac::MemoryMappingHandler::MemoryPerm type) const
+{
+ const char* str = nullptr;
+
+ switch(type)
+ {
+ case (nn::hac::MemoryMappingHandler::MEM_RW):
+ str = "RW";
+ break;
+ case (nn::hac::MemoryMappingHandler::MEM_RO):
+ str = "RO";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
+
+const char* NpdmProcess::getMemMapTypeStr(nn::hac::MemoryMappingHandler::MappingType type) const
+{
+ const char* str = nullptr;
+
+ switch(type)
+ {
+ case (nn::hac::MemoryMappingHandler::MAP_IO):
+ str = "Io";
+ break;
+ case (nn::hac::MemoryMappingHandler::MAP_STATIC):
+ str = "Static";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
\ No newline at end of file
diff --git a/programs/nstool/source/NpdmProcess.h b/programs/nstool/source/NpdmProcess.h
index 6ed8959..b4868bd 100644
--- a/programs/nstool/source/NpdmProcess.h
+++ b/programs/nstool/source/NpdmProcess.h
@@ -2,20 +2,21 @@
#include
#include
#include
+#include
#include
+#include "KeyConfiguration.h"
-#include "nstool.h"
+#include "common.h"
class NpdmProcess
{
public:
NpdmProcess();
- ~NpdmProcess();
void process();
- void setInputFile(fnd::IFile* file, bool ownIFile);
- void setKeyset(const sKeyset* keyset);
+ void setInputFile(const fnd::SharedPtr& file);
+ void setKeyCfg(const KeyConfiguration& keycfg);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
@@ -24,14 +25,15 @@ public:
private:
const std::string kModuleName = "NpdmProcess";
- fnd::IFile* mFile;
- bool mOwnIFile;
- const sKeyset* mKeyset;
+ fnd::SharedPtr mFile;
+ KeyConfiguration mKeyCfg;
CliOutputMode mCliOutputMode;
bool mVerify;
nn::hac::NpdmBinary mNpdm;
+ void importNpdm();
+
void validateAcidSignature(const nn::hac::AccessControlInfoDescBinary& acid);
void validateAciFromAcid(const nn::hac::AccessControlInfoBinary& aci, const nn::hac::AccessControlInfoDescBinary& acid);
@@ -41,4 +43,14 @@ private:
void displayFac(const nn::hac::FileSystemAccessControlBinary& fac);
void displaySac(const nn::hac::ServiceAccessControlBinary& sac);
void displayKernelCap(const nn::hac::KernelCapabilityBinary& kern);
+
+ const char* getInstructionTypeStr(nn::hac::npdm::InstructionType type) const;
+ const char* getProcAddressSpaceTypeStr(nn::hac::npdm::ProcAddrSpaceType type) const;
+ const char* getAcidFlagStr(nn::hac::aci::Flag flag) const;
+ const char* getMiscFlagStr(nn::hac::MiscFlagsHandler::Flags flag) const;
+ const char* getFsaRightStr(nn::hac::fac::FsAccessFlag flag) const;
+ const char* getSaveDataOwnerAccessModeStr(nn::hac::fac::SaveDataOwnerIdAccessType type) const;
+ const char* getSystemCallStr(byte_t syscall_id) const;
+ const char* getMemMapPermStr(nn::hac::MemoryMappingHandler::MemoryPerm type) const;
+ const char* getMemMapTypeStr(nn::hac::MemoryMappingHandler::MappingType type) const;
};
\ No newline at end of file
diff --git a/programs/nstool/source/NroProcess.cpp b/programs/nstool/source/NroProcess.cpp
index 3beb776..83c1edb 100644
--- a/programs/nstool/source/NroProcess.cpp
+++ b/programs/nstool/source/NroProcess.cpp
@@ -1,3 +1,5 @@
+#include
+#include
#include
#include
#include
@@ -6,28 +8,14 @@
#include "NroProcess.h"
NroProcess::NroProcess():
- mFile(nullptr),
- mOwnIFile(false),
+ mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false)
{
}
-NroProcess::~NroProcess()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
-}
-
void NroProcess::process()
{
- if (mFile == nullptr)
- {
- throw fnd::Exception(kModuleName, "No file reader set.");
- }
-
importHeader();
importCodeSegments();
@@ -40,10 +28,9 @@ void NroProcess::process()
mAssetProc.process();
}
-void NroProcess::setInputFile(fnd::IFile* file, bool ownIFile)
+void NroProcess::setInputFile(const fnd::SharedPtr& file)
{
mFile = file;
- mOwnIFile = ownIFile;
}
void NroProcess::setCliOutputMode(CliOutputMode type)
@@ -99,22 +86,28 @@ const RoMetadataProcess& NroProcess::getRoMetadataProcess() const
void NroProcess::importHeader()
{
fnd::Vec scratch;
- if (mFile->size() < sizeof(nn::hac::sNroHeader))
+
+ if (*mFile == nullptr)
+ {
+ throw fnd::Exception(kModuleName, "No file reader set.");
+ }
+
+ if ((*mFile)->size() < sizeof(nn::hac::sNroHeader))
{
throw fnd::Exception(kModuleName, "Corrupt NRO: file too small");
}
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());
// setup homebrew extension
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;
- mAssetProc.setInputFile(new OffsetAdjustedIFile(mFile, false, mHdr.getNroSize(), mFile->size() - mHdr.getNroSize()), true);
+ mAssetProc.setInputFile(new OffsetAdjustedIFile(mFile, mHdr.getNroSize(), (*mFile)->size() - mHdr.getNroSize()));
mAssetProc.setCliOutputMode(mCliOutputMode);
mAssetProc.setVerifyMode(mVerify);
}
@@ -125,50 +118,43 @@ void NroProcess::importHeader()
void NroProcess::importCodeSegments()
{
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);
- 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);
- mFile->read(mDataBlob.data(), mHdr.getDataInfo().memory_offset, mDataBlob.size());
+ (*mFile)->read(mDataBlob.data(), mHdr.getDataInfo().memory_offset, mDataBlob.size());
}
void NroProcess::displayHeader()
{
-#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
- printf("[NRO Header]\n");
- printf(" RoCrt: ");
- _HEXDUMP_L(mHdr.getRoCrt().data, nn::hac::nro::kRoCrtSize);
- printf("\n");
- printf(" ModuleId: ");
- _HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nro::kModuleIdSize);
- printf("\n");
- printf(" NroSize: 0x%" PRIx32 "\n", mHdr.getNroSize());
- printf(" Program Sections:\n");
- printf(" .text:\n");
- printf(" Offset: 0x%" PRIx32 "\n", mHdr.getTextInfo().memory_offset);
- printf(" Size: 0x%" PRIx32 "\n", mHdr.getTextInfo().size);
- printf(" .ro:\n");
- printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoInfo().memory_offset);
- printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoInfo().size);
+ std::cout << "[NRO Header]" << std::endl;
+ std::cout << " RoCrt: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRoCrt().data, nn::hac::nro::kRoCrtSize, false, "") << std::endl;
+ std::cout << " ModuleId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getModuleId().data, nn::hac::nro::kModuleIdSize, false, "") << std::endl;
+ std::cout << " NroSize: 0x" << std::hex << mHdr.getNroSize() << std::endl;
+ std::cout << " Program Sections:" << std::endl;
+ std::cout << " .text:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << mHdr.getTextInfo().memory_offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << mHdr.getTextInfo().size << std::endl;
+ std::cout << " .ro:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << mHdr.getRoInfo().memory_offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << mHdr.getRoInfo().size << std::endl;
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
- printf(" .api_info:\n");
- printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().memory_offset);
- printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size);
- printf(" .dynstr:\n");
- printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().memory_offset);
- printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size);
- printf(" .dynsym:\n");
- printf(" Offset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().memory_offset);
- printf(" Size: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size);
+ std::cout << " .api_info:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().memory_offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << mHdr.getRoEmbeddedInfo().size << std::endl;
+ std::cout << " .dynstr:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << mHdr.getRoDynStrInfo().memory_offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << mHdr.getRoDynStrInfo().size << std::endl;
+ std::cout << " .dynsym:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << mHdr.getRoDynSymInfo().memory_offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << mHdr.getRoDynSymInfo().size << std::endl;
}
- printf(" .data:\n");
- printf(" Offset: 0x%" PRIx32 "\n", mHdr.getDataInfo().memory_offset);
- printf(" Size: 0x%" PRIx32 "\n", mHdr.getDataInfo().size);
- printf(" .bss:\n");
- printf(" Size: 0x%" PRIx32 "\n", mHdr.getBssSize());
-
-#undef _HEXDUMP_L
+ std::cout << " .data:" << std::endl;
+ std::cout << " Offset: 0x" << std::hex << mHdr.getDataInfo().memory_offset << std::endl;
+ std::cout << " Size: 0x" << std::hex << mHdr.getDataInfo().size << std::endl;
+ std::cout << " .bss:" << std::endl;
+ std::cout << " Size: 0x" << std::hex << mHdr.getBssSize() << std::endl;
}
void NroProcess::processRoMeta()
diff --git a/programs/nstool/source/NroProcess.h b/programs/nstool/source/NroProcess.h
index 12f1eb8..4ddd1eb 100644
--- a/programs/nstool/source/NroProcess.h
+++ b/programs/nstool/source/NroProcess.h
@@ -3,22 +3,22 @@
#include
#include
#include
+#include
#include
#include
#include "AssetProcess.h"
-#include "nstool.h"
+#include "common.h"
#include "RoMetadataProcess.h"
class NroProcess
{
public:
NroProcess();
- ~NroProcess();
void process();
- void setInputFile(fnd::IFile* file, bool ownIFile);
+ void setInputFile(const fnd::SharedPtr& file);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
@@ -36,9 +36,7 @@ public:
private:
const std::string kModuleName = "NroProcess";
- fnd::IFile* mFile;
- bool mOwnIFile;
-
+ fnd::SharedPtr mFile;
CliOutputMode mCliOutputMode;
bool mVerify;
diff --git a/programs/nstool/source/NsoProcess.cpp b/programs/nstool/source/NsoProcess.cpp
index 3113be5..11261c6 100644
--- a/programs/nstool/source/NsoProcess.cpp
+++ b/programs/nstool/source/NsoProcess.cpp
@@ -1,3 +1,5 @@
+#include
+#include
#include
#include
#include
@@ -5,28 +7,14 @@
#include "NsoProcess.h"
NsoProcess::NsoProcess():
- mFile(nullptr),
- mOwnIFile(false),
+ mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false)
{
}
-NsoProcess::~NsoProcess()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
-}
-
void NsoProcess::process()
{
- if (mFile == nullptr)
- {
- throw fnd::Exception(kModuleName, "No file reader set.");
- }
-
importHeader();
importCodeSegments();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
@@ -35,10 +23,9 @@ void NsoProcess::process()
processRoMeta();
}
-void NsoProcess::setInputFile(fnd::IFile* file, bool ownIFile)
+void NsoProcess::setInputFile(const fnd::SharedPtr& file)
{
mFile = file;
- mOwnIFile = ownIFile;
}
void NsoProcess::setCliOutputMode(CliOutputMode type)
@@ -74,13 +61,19 @@ const RoMetadataProcess& NsoProcess::getRoMetadataProcess() const
void NsoProcess::importHeader()
{
fnd::Vec scratch;
- if (mFile->size() < sizeof(nn::hac::sNsoHeader))
+
+ if (*mFile == nullptr)
+ {
+ throw fnd::Exception(kModuleName, "No file reader set.");
+ }
+
+ if ((*mFile)->size() < sizeof(nn::hac::sNsoHeader))
{
throw fnd::Exception(kModuleName, "Corrupt NSO: file too small");
}
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());
}
@@ -95,7 +88,7 @@ void NsoProcess::importCodeSegments()
if (mHdr.getTextSegmentInfo().is_compressed)
{
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);
fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mTextBlob.data(), (uint32_t)mTextBlob.size(), decompressed_len);
if (decompressed_len != mTextBlob.size())
@@ -106,7 +99,7 @@ void NsoProcess::importCodeSegments()
else
{
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)
{
@@ -121,7 +114,7 @@ void NsoProcess::importCodeSegments()
if (mHdr.getRoSegmentInfo().is_compressed)
{
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);
fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mRoBlob.data(), (uint32_t)mRoBlob.size(), decompressed_len);
if (decompressed_len != mRoBlob.size())
@@ -132,7 +125,7 @@ void NsoProcess::importCodeSegments()
else
{
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)
{
@@ -147,7 +140,7 @@ void NsoProcess::importCodeSegments()
if (mHdr.getDataSegmentInfo().is_compressed)
{
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);
fnd::lz4::decompressData(scratch.data(), (uint32_t)scratch.size(), mDataBlob.data(), (uint32_t)mDataBlob.size(), decompressed_len);
if (decompressed_len != mDataBlob.size())
@@ -158,7 +151,7 @@ void NsoProcess::importCodeSegments()
else
{
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)
{
@@ -172,72 +165,61 @@ void NsoProcess::importCodeSegments()
void NsoProcess::displayNsoHeader()
{
-#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
-
- printf("[NSO Header]\n");
- printf(" ModuleId: ");
- _HEXDUMP_L(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize);
- printf("\n");
+ std::cout << "[NSO Header]" << std::endl;
+ std::cout << " ModuleId: " << fnd::SimpleTextOutput::arrayToString(mHdr.getModuleId().data, nn::hac::nso::kModuleIdSize, false, "") << std::endl;
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
{
- printf(" Program Segments:\n");
- printf(" .module_name:\n");
- printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().offset);
- printf(" FileSize: 0x%" PRIx32 "\n", mHdr.getModuleNameInfo().size);
- printf(" .text:\n");
- printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().file_layout.offset);
- printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getTextSegmentInfo().file_layout.size, mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "");
- printf(" .ro:\n");
- printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().file_layout.offset);
- printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getRoSegmentInfo().file_layout.size, mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "");
- printf(" .data:\n");
- printf(" FileOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().file_layout.offset);
- printf(" FileSize: 0x%" PRIx32 "%s\n", mHdr.getDataSegmentInfo().file_layout.size, mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "");
+ std::cout << " Program Segments:" << std::endl;
+ std::cout << " .module_name:" << std::endl;
+ std::cout << " FileOffset: 0x" << std::hex << mHdr.getModuleNameInfo().offset << std::endl;
+ std::cout << " FileSize: 0x" << std::hex << mHdr.getModuleNameInfo().size << std::endl;
+ std::cout << " .text:" << std::endl;
+ std::cout << " FileOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.offset << std::endl;
+ std::cout << " FileSize: 0x" << std::hex << mHdr.getTextSegmentInfo().file_layout.size << (mHdr.getTextSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl;
+ std::cout << " .ro:" << std::endl;
+ std::cout << " FileOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.offset << std::endl;
+ std::cout << " FileSize: 0x" << std::hex << mHdr.getRoSegmentInfo().file_layout.size << (mHdr.getRoSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl;
+ std::cout << " .data:" << std::endl;
+ std::cout << " FileOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.offset << std::endl;
+ std::cout << " FileSize: 0x" << std::hex << mHdr.getDataSegmentInfo().file_layout.size << (mHdr.getDataSegmentInfo().is_compressed? " (COMPRESSED)" : "") << std::endl;
}
- printf(" Program Sections:\n");
- printf(" .text:\n");
- printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.offset);
- printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getTextSegmentInfo().memory_layout.size);
+ std::cout << " Program Sections:" << std::endl;
+ std::cout << " .text:" << std::endl;
+ std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.offset << std::endl;
+ std::cout << " MemorySize: 0x" << std::hex << mHdr.getTextSegmentInfo().memory_layout.size << std::endl;
if (mHdr.getTextSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
- printf(" Hash: ");
- _HEXDUMP_L(mHdr.getTextSegmentInfo().hash.bytes, 32);
- printf("\n");
+ std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getTextSegmentInfo().hash.bytes, 32, false, "") << std::endl;
}
- printf(" .ro:\n");
- printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.offset);
- printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoSegmentInfo().memory_layout.size);
+ std::cout << " .ro:" << std::endl;
+ std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.offset << std::endl;
+ std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoSegmentInfo().memory_layout.size << std::endl;
if (mHdr.getRoSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
- printf(" Hash: ");
- _HEXDUMP_L(mHdr.getRoSegmentInfo().hash.bytes, 32);
- printf("\n");
+ std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getRoSegmentInfo().hash.bytes, 32, false, "") << std::endl;
}
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
- printf(" .api_info:\n");
- printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().offset);
- printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoEmbeddedInfo().size);
- printf(" .dynstr:\n");
- printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().offset);
- printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynStrInfo().size);
- printf(" .dynsym:\n");
- printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().offset);
- printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getRoDynSymInfo().size);
+ std::cout << " .api_info:" << std::endl;
+ std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoEmbeddedInfo().offset << std::endl;
+ std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoEmbeddedInfo().size << std::endl;
+ std::cout << " .dynstr:" << std::endl;
+ std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoDynStrInfo().offset << std::endl;
+ std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoDynStrInfo().size << std::endl;
+ std::cout << " .dynsym:" << std::endl;
+ std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getRoDynSymInfo().offset << std::endl;
+ std::cout << " MemorySize: 0x" << std::hex << mHdr.getRoDynSymInfo().size << std::endl;
}
- printf(" .data:\n");
- printf(" MemoryOffset: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.offset);
- printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getDataSegmentInfo().memory_layout.size);
+ std::cout << " .data:" << std::endl;
+ std::cout << " MemoryOffset: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.offset << std::endl;
+ std::cout << " MemorySize: 0x" << std::hex << mHdr.getDataSegmentInfo().memory_layout.size << std::endl;
if (mHdr.getDataSegmentInfo().is_hashed && _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
{
- printf(" Hash: ");
- _HEXDUMP_L(mHdr.getDataSegmentInfo().hash.bytes, 32);
- printf("\n");
+ std::cout << " Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getDataSegmentInfo().hash.bytes, 32, false, "") << std::endl;
}
- printf(" .bss:\n");
- printf(" MemorySize: 0x%" PRIx32 "\n", mHdr.getBssSize());
-#undef _HEXDUMP_L
+ std::cout << " .bss:" << std::endl;
+ std::cout << " MemorySize: 0x" << std::hex << mHdr.getBssSize() << std::endl;
}
void NsoProcess::processRoMeta()
diff --git a/programs/nstool/source/NsoProcess.h b/programs/nstool/source/NsoProcess.h
index 0cf57c0..88170ae 100644
--- a/programs/nstool/source/NsoProcess.h
+++ b/programs/nstool/source/NsoProcess.h
@@ -3,21 +3,21 @@
#include
#include
#include
+#include
#include
#include
-#include "nstool.h"
+#include "common.h"
#include "RoMetadataProcess.h"
class NsoProcess
{
public:
NsoProcess();
- ~NsoProcess();
void process();
- void setInputFile(fnd::IFile* file, bool ownIFile);
+ void setInputFile(const fnd::SharedPtr& file);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
@@ -29,9 +29,7 @@ public:
private:
const std::string kModuleName = "NsoProcess";
- fnd::IFile* mFile;
- bool mOwnIFile;
-
+ fnd::SharedPtr mFile;
CliOutputMode mCliOutputMode;
bool mVerify;
nn::hac::npdm::InstructionType mInstructionType;
diff --git a/programs/nstool/source/OffsetAdjustedIFile.cpp b/programs/nstool/source/OffsetAdjustedIFile.cpp
index ad127f1..4891b39 100644
--- a/programs/nstool/source/OffsetAdjustedIFile.cpp
+++ b/programs/nstool/source/OffsetAdjustedIFile.cpp
@@ -1,21 +1,11 @@
#include "OffsetAdjustedIFile.h"
-OffsetAdjustedIFile::OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size) :
- mOwnIFile(ownIFile),
+OffsetAdjustedIFile::OffsetAdjustedIFile(const fnd::SharedPtr& file, size_t offset, size_t size) :
mFile(file),
mBaseOffset(offset),
mCurrentOffset(0),
mSize(size)
{
-
-}
-
-OffsetAdjustedIFile::~OffsetAdjustedIFile()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
}
size_t OffsetAdjustedIFile::size()
@@ -31,8 +21,8 @@ void OffsetAdjustedIFile::seek(size_t offset)
void OffsetAdjustedIFile::read(byte_t* out, size_t len)
{
// assert proper position in file
- mFile->seek(mCurrentOffset + mBaseOffset);
- mFile->read(out, len);
+ (*mFile)->seek(mCurrentOffset + mBaseOffset);
+ (*mFile)->read(out, len);
seek(mCurrentOffset + len);
}
@@ -45,8 +35,8 @@ void OffsetAdjustedIFile::read(byte_t* out, size_t offset, size_t len)
void OffsetAdjustedIFile::write(const byte_t* out, size_t len)
{
// assert proper position in file
- mFile->seek(mCurrentOffset + mBaseOffset);
- mFile->write(out, len);
+ (*mFile)->seek(mCurrentOffset + mBaseOffset);
+ (*mFile)->write(out, len);
seek(mCurrentOffset + len);
}
diff --git a/programs/nstool/source/OffsetAdjustedIFile.h b/programs/nstool/source/OffsetAdjustedIFile.h
index 4c68558..be3f582 100644
--- a/programs/nstool/source/OffsetAdjustedIFile.h
+++ b/programs/nstool/source/OffsetAdjustedIFile.h
@@ -1,10 +1,10 @@
#include
+#include
class OffsetAdjustedIFile : public fnd::IFile
{
public:
- OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size);
- ~OffsetAdjustedIFile();
+ OffsetAdjustedIFile(const fnd::SharedPtr& file, size_t offset, size_t size);
size_t size();
void seek(size_t offset);
@@ -13,8 +13,7 @@ public:
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;
+ fnd::SharedPtr mFile;
size_t mBaseOffset, mCurrentOffset;
size_t mSize;
};
\ No newline at end of file
diff --git a/programs/nstool/source/PfsProcess.cpp b/programs/nstool/source/PfsProcess.cpp
index c44fca0..999b487 100644
--- a/programs/nstool/source/PfsProcess.cpp
+++ b/programs/nstool/source/PfsProcess.cpp
@@ -1,10 +1,11 @@
+#include
+#include
#include
#include
#include "PfsProcess.h"
PfsProcess::PfsProcess() :
- mFile(nullptr),
- mOwnIFile(false),
+ mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false),
mExtractPath(),
@@ -15,36 +16,9 @@ PfsProcess::PfsProcess() :
{
}
-PfsProcess::~PfsProcess()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
-}
-
void PfsProcess::process()
{
- fnd::Vec scratch;
-
- if (mFile == nullptr)
- {
- throw fnd::Exception(kModuleName, "No file reader set.");
- }
-
- // open minimum header to get full header size
- scratch.alloc(sizeof(nn::hac::sPfsHeader));
- mFile->read(scratch.data(), 0, scratch.size());
- if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false)
- {
- throw fnd::Exception(kModuleName, "Corrupt Header");
- }
- size_t pfsHeaderSize = determineHeaderSize(((nn::hac::sPfsHeader*)scratch.data()));
-
- // open minimum header to get full header size
- scratch.alloc(pfsHeaderSize);
- mFile->read(scratch.data(), 0, scratch.size());
- mPfs.fromBytes(scratch.data(), scratch.size());
+ importHeader();
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
{
@@ -58,10 +32,9 @@ void PfsProcess::process()
extractFs();
}
-void PfsProcess::setInputFile(fnd::IFile* file, bool ownIFile)
+void PfsProcess::setInputFile(const fnd::SharedPtr& file)
{
mFile = file;
- mOwnIFile = ownIFile;
}
void PfsProcess::setCliOutputMode(CliOutputMode type)
@@ -95,32 +68,64 @@ const nn::hac::PfsHeader& PfsProcess::getPfsHeader() const
return mPfs;
}
+void PfsProcess::importHeader()
+{
+ fnd::Vec scratch;
+
+ if (*mFile == nullptr)
+ {
+ throw fnd::Exception(kModuleName, "No file reader set.");
+ }
+
+ // open minimum header to get full header size
+ scratch.alloc(sizeof(nn::hac::sPfsHeader));
+ (*mFile)->read(scratch.data(), 0, scratch.size());
+ if (validateHeaderMagic(((nn::hac::sPfsHeader*)scratch.data())) == false)
+ {
+ throw fnd::Exception(kModuleName, "Corrupt Header");
+ }
+ size_t pfsHeaderSize = determineHeaderSize(((nn::hac::sPfsHeader*)scratch.data()));
+
+ // open minimum header to get full header size
+ scratch.alloc(pfsHeaderSize);
+ (*mFile)->read(scratch.data(), 0, scratch.size());
+ mPfs.fromBytes(scratch.data(), scratch.size());
+}
+
void PfsProcess::displayHeader()
{
- printf("[PartitionFS]\n");
- printf(" Type: %s\n", mPfs.getFsType() == mPfs.TYPE_PFS0? "PFS0" : "HFS0");
- printf(" FileNum: %" PRId64 "\n", (uint64_t)mPfs.getFileList().size());
- if (mMountName.empty() == false)
- printf(" MountPoint: %s%s\n", mMountName.c_str(), mMountName.at(mMountName.length()-1) != '/' ? "/" : "");
+ std::cout << "[PartitionFS]" << std::endl;
+ std::cout << " Type: " << getFsTypeStr(mPfs.getFsType()) << std::endl;
+ std::cout << " FileNum: " << std::dec << mPfs.getFileList().size() << std::endl;
+ if (mMountName.empty() == false)
+ {
+ std::cout << " MountPoint: " << mMountName;
+ if (mMountName.at(mMountName.length()-1) != '/')
+ std::cout << "/";
+ std::cout << std::endl;
+ }
}
void PfsProcess::displayFs()
{
for (size_t i = 0; i < mPfs.getFileList().size(); i++)
{
- printf(" %s", mPfs.getFileList()[i].name.c_str());
+ const nn::hac::PfsHeader::sFile& file = mPfs.getFileList()[i];
+ std::cout << " " << file.name;
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
{
- if (mPfs.getFsType() == mPfs.TYPE_PFS0)
- printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")\n", (uint64_t)mPfs.getFileList()[i].offset, (uint64_t)mPfs.getFileList()[i].size);
- else
- printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ", hash_protected_size=0x%" PRIx64 ")\n", (uint64_t)mPfs.getFileList()[i].offset, (uint64_t)mPfs.getFileList()[i].size, (uint64_t)mPfs.getFileList()[i].hash_protected_size);
+ switch (mPfs.getFsType())
+ {
+ case (nn::hac::PfsHeader::TYPE_PFS0):
+ std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ")";
+ break;
+ case (nn::hac::PfsHeader::TYPE_HFS0):
+ std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ", hash_protected_size=0x" << file.hash_protected_size << ")";
+ break;
+ }
+
}
- else
- {
- printf("\n");
- }
-
+ std::cout << std::endl;
}
}
@@ -147,7 +152,7 @@ void PfsProcess::validateHfs()
for (size_t i = 0; i < file.size(); i++)
{
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);
if (hash != file[i].hash)
{
@@ -178,12 +183,32 @@ void PfsProcess::extractFs()
printf("extract=[%s]\n", file_path.c_str());
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++)
{
- 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.close();
}
}
+
+const char* PfsProcess::getFsTypeStr(nn::hac::PfsHeader::FsType type) const
+{
+ const char* str = nullptr;
+
+ switch (type)
+ {
+ case (nn::hac::PfsHeader::TYPE_PFS0):
+ str = "PFS0";
+ break;
+ case (nn::hac::PfsHeader::TYPE_HFS0):
+ str = "HFS0";
+ break;
+ default:
+ str = "Unknown";
+ break;
+ }
+
+ return str;
+}
\ No newline at end of file
diff --git a/programs/nstool/source/PfsProcess.h b/programs/nstool/source/PfsProcess.h
index 4b15c05..bf9d61c 100644
--- a/programs/nstool/source/PfsProcess.h
+++ b/programs/nstool/source/PfsProcess.h
@@ -2,20 +2,20 @@
#include
#include
#include
+#include
#include
-#include "nstool.h"
+#include "common.h"
class PfsProcess
{
public:
PfsProcess();
- ~PfsProcess();
void process();
// generic
- void setInputFile(fnd::IFile* file, bool ownIFile);
+ void setInputFile(const fnd::SharedPtr& file);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
@@ -30,8 +30,7 @@ private:
const std::string kModuleName = "PfsProcess";
static const size_t kCacheSize = 0x10000;
- fnd::IFile* mFile;
- bool mOwnIFile;
+ fnd::SharedPtr mFile;
CliOutputMode mCliOutputMode;
bool mVerify;
@@ -44,10 +43,13 @@ private:
nn::hac::PfsHeader mPfs;
+ void importHeader();
void displayHeader();
void displayFs();
size_t determineHeaderSize(const nn::hac::sPfsHeader* hdr);
bool validateHeaderMagic(const nn::hac::sPfsHeader* hdr);
void validateHfs();
void extractFs();
+
+ const char* getFsTypeStr(nn::hac::PfsHeader::FsType type) const;
};
\ No newline at end of file
diff --git a/programs/nstool/source/PkiCertProcess.cpp b/programs/nstool/source/PkiCertProcess.cpp
index db7c629..b3610f0 100644
--- a/programs/nstool/source/PkiCertProcess.cpp
+++ b/programs/nstool/source/PkiCertProcess.cpp
@@ -1,6 +1,5 @@
#include
#include
-
#include
#include
#include "OffsetAdjustedIFile.h"
@@ -8,29 +7,16 @@
#include "PkiValidator.h"
PkiCertProcess::PkiCertProcess() :
- mFile(nullptr),
- mOwnIFile(false),
+ mFile(),
mCliOutputMode(_BIT(OUTPUT_BASIC)),
mVerify(false)
{
}
-PkiCertProcess::~PkiCertProcess()
-{
- if (mOwnIFile)
- {
- delete mFile;
- }
-}
-
void PkiCertProcess::process()
{
- if (mFile == nullptr)
- {
- throw fnd::Exception(kModuleName, "No file reader set.");
- }
-
importCerts();
+
if (mVerify)
validateCerts();
@@ -38,15 +24,14 @@ void PkiCertProcess::process()
displayCerts();
}
-void PkiCertProcess::setInputFile(fnd::IFile* file, bool ownIFile)
+void PkiCertProcess::setInputFile(const fnd::SharedPtr& file)
{
mFile = file;
- mOwnIFile = ownIFile;
}
-void PkiCertProcess::setKeyset(const sKeyset* keyset)
+void PkiCertProcess::setKeyCfg(const KeyConfiguration& keycfg)
{
- mKeyset = keyset;
+ mKeyCfg = keycfg;
}
void PkiCertProcess::setCliOutputMode(CliOutputMode mode)
@@ -63,8 +48,13 @@ void PkiCertProcess::importCerts()
{
fnd::Vec scratch;
- scratch.alloc(mFile->size());
- mFile->read(scratch.data(), 0, scratch.size());
+ if (*mFile == nullptr)
+ {
+ throw fnd::Exception(kModuleName, "No file reader set.");
+ }
+
+ scratch.alloc((*mFile)->size());
+ (*mFile)->read(scratch.data(), 0, scratch.size());
nn::pki::SignedData cert;
for (size_t f_pos = 0; f_pos < scratch.size(); f_pos += cert.getBytes().size())
@@ -80,7 +70,7 @@ void PkiCertProcess::validateCerts()
try
{
- pki.setRootKey(mKeyset->pki.root_sign_key);
+ pki.setKeyCfg(mKeyCfg);
pki.addCertificates(mCert);
}
catch (const fnd::Exception& e)
@@ -100,15 +90,11 @@ void PkiCertProcess::displayCerts()
void PkiCertProcess::displayCert(const nn::pki::SignedData& cert)
{
-#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff)
-#define _HEXDUMP_U(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02X", var[a__a__A]); } while(0)
-#define _HEXDUMP_L(var, len) do { for (size_t a__a__A = 0; a__a__A < len; a__a__A++) printf("%02x", var[a__a__A]); } while(0)
-
std::cout << "[NNPKI Certificate]" << std::endl;
std::cout << " SignType " << getSignTypeStr(cert.getSignature().getSignType());
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
- std::cout << " (0x" << std::hex << cert.getSignature().getSignType() << ") (" << getEndiannessStr(cert.getSignature().isLittleEndian());
+ std::cout << " (0x" << std::hex << cert.getSignature().getSignType() << ") (" << getEndiannessStr(cert.getSignature().isLittleEndian()) << ")";
std::cout << std::endl;
std::cout << " Issuer: " << cert.getBody().getIssuer() << std::endl;
@@ -130,9 +116,9 @@ void PkiCertProcess::displayCert(const nn::pki::SignedData
#include
#include
+#include
#include
#include
#include
#include
-#include "nstool.h"
+#include "KeyConfiguration.h"
+#include "common.h"
class PkiCertProcess
{
public:
PkiCertProcess();
- ~PkiCertProcess();
void process();
- void setInputFile(fnd::IFile* file, bool ownIFile);
- void setKeyset(const sKeyset* keyset);
+ void setInputFile(const fnd::SharedPtr& file);
+ void setKeyCfg(const KeyConfiguration& keycfg);
void setCliOutputMode(CliOutputMode type);
void setVerifyMode(bool verify);
@@ -25,9 +26,8 @@ private:
const std::string kModuleName = "PkiCertProcess";
static const size_t kSmallHexDumpLen = 0x10;
- fnd::IFile* mFile;
- bool mOwnIFile;
- const sKeyset* mKeyset;
+ fnd::SharedPtr mFile;
+ KeyConfiguration mKeyCfg;
CliOutputMode mCliOutputMode;
bool mVerify;
diff --git a/programs/nstool/source/PkiValidator.cpp b/programs/nstool/source/PkiValidator.cpp
index 57531ea..37bb9b5 100644
--- a/programs/nstool/source/PkiValidator.cpp
+++ b/programs/nstool/source/PkiValidator.cpp
@@ -1,15 +1,15 @@
-#include "PkiValidator.h"
#include
#include
#include
#include