mirror of
https://github.com/jakcron/nstool.git
synced 2024-12-22 18:55:29 +00:00
Merge pull request #48 from jakcron/nstool-1.0
Update master to NSTool v1.0.4
This commit is contained in:
commit
f09c17ed51
|
@ -20,7 +20,7 @@
|
|||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{7BE99936-0D40-410D-944B-4513C2EFF8DC}</ProjectGuid>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
|
|
|
@ -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)
|
141
lib/libfnd/include/fnd/SharedPtr.h
Normal file
141
lib/libfnd/include/fnd/SharedPtr.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
#pragma once
|
||||
#include <fnd/types.h>
|
||||
#include <cstdio>
|
||||
|
||||
namespace fnd
|
||||
{
|
||||
template <class T>
|
||||
class SharedPtr
|
||||
{
|
||||
public:
|
||||
SharedPtr();
|
||||
|
||||
// constructor for creating owner object
|
||||
SharedPtr(T* ptr);
|
||||
|
||||
// copy constructor
|
||||
SharedPtr(const SharedPtr<T>& other);
|
||||
|
||||
// destructor
|
||||
~SharedPtr();
|
||||
|
||||
// own operator
|
||||
void operator=(T* ptr);
|
||||
|
||||
// copy operator
|
||||
void operator=(const SharedPtr<T>& other);
|
||||
|
||||
// access ptr
|
||||
const T* operator*() const;
|
||||
T* operator*();
|
||||
|
||||
private:
|
||||
T* mPtr;
|
||||
size_t* mRefCnt;
|
||||
|
||||
void deletePtr();
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline SharedPtr<T>::SharedPtr() :
|
||||
mPtr(nullptr),
|
||||
mRefCnt(new size_t)
|
||||
{
|
||||
*mRefCnt = 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline SharedPtr<T>::SharedPtr(T* ptr) :
|
||||
SharedPtr()
|
||||
{
|
||||
*this = ptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline SharedPtr<T>::SharedPtr(const SharedPtr<T>& other) :
|
||||
SharedPtr()
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline SharedPtr<T>::~SharedPtr()
|
||||
{
|
||||
deletePtr();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void SharedPtr<T>::operator=(T* ptr)
|
||||
{
|
||||
deletePtr();
|
||||
if (ptr != nullptr)
|
||||
{
|
||||
mPtr = ptr;
|
||||
mRefCnt = new size_t;
|
||||
*mRefCnt = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mPtr = nullptr;
|
||||
mRefCnt = new size_t;
|
||||
*mRefCnt = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void SharedPtr<T>::operator=(const SharedPtr<T>& other)
|
||||
{
|
||||
deletePtr();
|
||||
|
||||
mPtr = other.mPtr;
|
||||
mRefCnt = other.mRefCnt;
|
||||
*mRefCnt += 1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline const T* SharedPtr<T>::operator*() const
|
||||
{
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T* SharedPtr<T>::operator*()
|
||||
{
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void SharedPtr<T>::deletePtr()
|
||||
{
|
||||
// if this is not the last reference
|
||||
if (*mRefCnt > 1)
|
||||
{
|
||||
// decrement reference count
|
||||
*mRefCnt -= 1;
|
||||
|
||||
// make ptrs null
|
||||
mPtr = nullptr;
|
||||
mRefCnt = nullptr;
|
||||
}
|
||||
// if this is the last refeference
|
||||
else if (*mRefCnt == 1)
|
||||
{
|
||||
// delete memory
|
||||
delete mPtr;
|
||||
delete mRefCnt;
|
||||
|
||||
// make ptrs null
|
||||
mPtr = nullptr;
|
||||
mRefCnt = nullptr;
|
||||
}
|
||||
// else if this is an empty refernce
|
||||
else if (*mRefCnt == 0)
|
||||
{
|
||||
delete mRefCnt;
|
||||
|
||||
mPtr = nullptr;
|
||||
mRefCnt = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/Vec.h>
|
||||
|
||||
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<byte_t>& array);
|
||||
|
||||
private:
|
||||
static const size_t kDefaultRowLen = 0x10;
|
||||
static const size_t kDefaultByteGroupingSize = 1;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
}
|
|
@ -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]);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{4D27EDB9-5110-44FE-8CE2-D46C5AD3C55B}</ProjectGuid>
|
||||
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
|
@ -136,6 +136,7 @@
|
|||
<ClInclude Include="include\fnd\ResourceFileReader.h" />
|
||||
<ClInclude Include="include\fnd\rsa.h" />
|
||||
<ClInclude Include="include\fnd\sha.h" />
|
||||
<ClInclude Include="include\fnd\SharedPtr.h" />
|
||||
<ClInclude Include="include\fnd\SimpleFile.h" />
|
||||
<ClInclude Include="include\fnd\SimpleTextOutput.h" />
|
||||
<ClInclude Include="include\fnd\StringConv.h" />
|
||||
|
|
|
@ -63,6 +63,9 @@
|
|||
<ClInclude Include="include\fnd\sha.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\fnd\SharedPtr.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\fnd\SimpleFile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include <fnd/SimpleTextOutput.h>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
|
||||
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<byte_t>& 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');
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
#include <fnd/rsa.h>
|
||||
#include <polarssl/rsa.h>
|
||||
#include <polarssl/md.h>
|
||||
#include <polarssl/entropy.h>
|
||||
#include <polarssl/ctr_drbg.h>
|
||||
|
||||
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 };
|
||||
|
|
|
@ -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
|
||||
|
|
21
lib/libhac/include/nn/hac/IdConverter.h
Normal file
21
lib/libhac/include/nn/hac/IdConverter.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include <fnd/types.h>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
39
lib/libhac/include/nn/hac/Result.h
Normal file
39
lib/libhac/include/nn/hac/Result.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
#include <fnd/types.h>
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
};
|
||||
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
#pragma once
|
||||
#include <fnd/types.h>
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -39,6 +39,7 @@
|
|||
<ClInclude Include="include\nn\hac\HierarchicalIntegrityHeader.h" />
|
||||
<ClInclude Include="include\nn\hac\hierarchicalsha256.h" />
|
||||
<ClInclude Include="include\nn\hac\HierarchicalSha256Header.h" />
|
||||
<ClInclude Include="include\nn\hac\IdConverter.h" />
|
||||
<ClInclude Include="include\nn\hac\IKernelCapabilityHandler.h" />
|
||||
<ClInclude Include="include\nn\hac\InteruptEntry.h" />
|
||||
<ClInclude Include="include\nn\hac\InteruptHandler.h" />
|
||||
|
@ -67,6 +68,7 @@
|
|||
<ClInclude Include="include\nn\hac\NsoHeader.h" />
|
||||
<ClInclude Include="include\nn\hac\pfs.h" />
|
||||
<ClInclude Include="include\nn\hac\PfsHeader.h" />
|
||||
<ClInclude Include="include\nn\hac\Result.h" />
|
||||
<ClInclude Include="include\nn\hac\romfs.h" />
|
||||
<ClInclude Include="include\nn\hac\ServiceAccessControlBinary.h" />
|
||||
<ClInclude Include="include\nn\hac\ServiceAccessControlEntry.h" />
|
||||
|
@ -90,6 +92,7 @@
|
|||
<ClCompile Include="source\HandleTableSizeHandler.cpp" />
|
||||
<ClCompile Include="source\HierarchicalIntegrityHeader.cpp" />
|
||||
<ClCompile Include="source\HierarchicalSha256Header.cpp" />
|
||||
<ClCompile Include="source\IdConverter.cpp" />
|
||||
<ClCompile Include="source\InteruptEntry.cpp" />
|
||||
<ClCompile Include="source\InteruptHandler.cpp" />
|
||||
<ClCompile Include="source\KernelCapabilityBinary.cpp" />
|
||||
|
@ -108,6 +111,7 @@
|
|||
<ClCompile Include="source\NroHeader.cpp" />
|
||||
<ClCompile Include="source\NsoHeader.cpp" />
|
||||
<ClCompile Include="source\PfsHeader.cpp" />
|
||||
<ClCompile Include="source\Result.cpp" />
|
||||
<ClCompile Include="source\ServiceAccessControlBinary.cpp" />
|
||||
<ClCompile Include="source\ServiceAccessControlEntry.cpp" />
|
||||
<ClCompile Include="source\SystemCallEntry.cpp" />
|
||||
|
@ -121,7 +125,7 @@
|
|||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{91BA9E79-8242-4F7D-B997-0DFEC95EA22B}</ProjectGuid>
|
||||
<RootNamespace>hac</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>libhac</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
|
|
|
@ -183,6 +183,12 @@
|
|||
<ClInclude Include="include\nn\hac\XciUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\nn\hac\IdConverter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\nn\hac\Result.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="source\AccessControlInfoBinary.cpp">
|
||||
|
@ -296,5 +302,11 @@
|
|||
<ClCompile Include="source\XciUtils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\IdConverter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\Result.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
|
|
16
lib/libhac/source/IdConverter.cpp
Normal file
16
lib/libhac/source/IdConverter.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include <nn/hac/IdConverter.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
62
lib/libhac/source/Result.cpp
Normal file
62
lib/libhac/source/Result.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
#include <nn/hac/Result.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -54,7 +54,7 @@ void nn::hac::SystemCallHandler::exportKernelCapabilityList(fnd::List<KernelCapa
|
|||
if (isSet() == false)
|
||||
return;
|
||||
|
||||
fnd::List<SystemCallEntry> 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<KernelCapa
|
|||
entries[mSystemCalls[i] / 24].setSystemCallLowerBits(entries[mSystemCalls[i] / 24].getSystemCallLowerBits() | BIT(mSystemCalls[i] % 24));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < entries.size(); i++)
|
||||
for (size_t i = 0; i < kSyscallTotalEntryNum; i++)
|
||||
{
|
||||
if (entries[i].getSystemCallLowerBits() != 0)
|
||||
{
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="source\lz4.h">
|
||||
<Filter>Source Files</Filter>
|
||||
<ClInclude Include="include\lz4.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -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
|
||||
|
|
234
lib/libpolarssl/include/polarssl/ctr_drbg.h
Normal file
234
lib/libpolarssl/include/polarssl/ctr_drbg.h
Normal file
|
@ -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 <string.h>
|
||||
|
||||
#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 */
|
180
lib/libpolarssl/include/polarssl/entropy.h
Normal file
180
lib/libpolarssl/include/polarssl/entropy.h
Normal file
|
@ -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 <string.h>
|
||||
|
||||
#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 */
|
72
lib/libpolarssl/include/polarssl/entropy_poll.h
Normal file
72
lib/libpolarssl/include/polarssl/entropy_poll.h
Normal file
|
@ -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 <string.h>
|
||||
|
||||
#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 */
|
183
lib/libpolarssl/include/polarssl/sha4.h
Normal file
183
lib/libpolarssl/include/polarssl/sha4.h
Normal file
|
@ -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 <string.h>
|
||||
|
||||
#if defined(_MSC_VER) || defined(__WATCOMC__)
|
||||
#define UL64(x) x##ui64
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
#include <inttypes.h>
|
||||
#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 */
|
|
@ -21,7 +21,7 @@
|
|||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{394EFC16-BD3A-4538-B33D-7BA1EDB8DAC1}</ProjectGuid>
|
||||
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
|
@ -117,30 +117,38 @@
|
|||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<None Include="makefile" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\polarssl\aes.h" />
|
||||
<ClInclude Include="include\polarssl\base64.h" />
|
||||
<ClInclude Include="include\polarssl\bignum.h" />
|
||||
<ClInclude Include="include\polarssl\bn_mul.h" />
|
||||
<ClInclude Include="include\polarssl\config.h" />
|
||||
<ClInclude Include="include\polarssl\ctr_drbg.h" />
|
||||
<ClInclude Include="include\polarssl\entropy.h" />
|
||||
<ClInclude Include="include\polarssl\entropy_poll.h" />
|
||||
<ClInclude Include="include\polarssl\md.h" />
|
||||
<ClInclude Include="include\polarssl\md_wrap.h" />
|
||||
<ClInclude Include="include\polarssl\rsa.h" />
|
||||
<ClInclude Include="include\polarssl\sha1.h" />
|
||||
<ClInclude Include="include\polarssl\sha2.h" />
|
||||
<ClInclude Include="include\polarssl\sha4.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="source\aes.c" />
|
||||
<ClCompile Include="source\base64.c" />
|
||||
<ClCompile Include="source\bignum.c" />
|
||||
<ClCompile Include="source\ctr_drbg.c" />
|
||||
<ClCompile Include="source\entropy.c" />
|
||||
<ClCompile Include="source\entropy_poll.c" />
|
||||
<ClCompile Include="source\md.c" />
|
||||
<ClCompile Include="source\md_wrap.c" />
|
||||
<ClCompile Include="source\rsa.c" />
|
||||
<ClCompile Include="source\sha1.c" />
|
||||
<ClCompile Include="source\sha2.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="makefile" />
|
||||
<ClCompile Include="source\sha4.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="makefile" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\polarssl\aes.h">
|
||||
<Filter>Header Files</Filter>
|
||||
|
@ -30,6 +33,21 @@
|
|||
<ClInclude Include="include\polarssl\config.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\polarssl\ctr_drbg.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\polarssl\entropy.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\polarssl\entropy_poll.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\polarssl\md.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\polarssl\md_wrap.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\polarssl\rsa.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -39,10 +57,7 @@
|
|||
<ClInclude Include="include\polarssl\sha2.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\polarssl\md.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\polarssl\md_wrap.h">
|
||||
<ClInclude Include="include\polarssl\sha4.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
@ -56,6 +71,15 @@
|
|||
<ClCompile Include="source\bignum.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\ctr_drbg.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\entropy.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\entropy_poll.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\md.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -71,8 +95,8 @@
|
|||
<ClCompile Include="source\sha2.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="makefile" />
|
||||
<ClCompile Include="source\sha4.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
582
lib/libpolarssl/source/ctr_drbg.c
Normal file
582
lib/libpolarssl/source/ctr_drbg.c
Normal file
|
@ -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 <stdio.h>
|
||||
#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 <stdio.h>
|
||||
|
||||
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
|
261
lib/libpolarssl/source/entropy.c
Normal file
261
lib/libpolarssl/source/entropy.c
Normal file
|
@ -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 <stdio.h>
|
||||
#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
|
133
lib/libpolarssl/source/entropy_poll.c
Normal file
133
lib/libpolarssl/source/entropy_poll.c
Normal file
|
@ -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 <windows.h>
|
||||
#include <wincrypt.h>
|
||||
|
||||
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 <stdio.h>
|
||||
|
||||
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 */
|
762
lib/libpolarssl/source/sha4.c
Normal file
762
lib/libpolarssl/source/sha4.c
Normal file
|
@ -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 <stdio.h>
|
||||
#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
|
|
@ -181,16 +181,17 @@
|
|||
<ClInclude Include="source\AesCtrWrappedIFile.h" />
|
||||
<ClInclude Include="source\AssetProcess.h" />
|
||||
<ClInclude Include="source\CnmtProcess.h" />
|
||||
<ClInclude Include="source\common.h" />
|
||||
<ClInclude Include="source\ElfSymbolParser.h" />
|
||||
<ClInclude Include="source\EsTikProcess.h" />
|
||||
<ClInclude Include="source\HashTreeMeta.h" />
|
||||
<ClInclude Include="source\HashTreeWrappedIFile.h" />
|
||||
<ClInclude Include="source\KeyConfiguration.h" />
|
||||
<ClInclude Include="source\NacpProcess.h" />
|
||||
<ClInclude Include="source\NcaProcess.h" />
|
||||
<ClInclude Include="source\NpdmProcess.h" />
|
||||
<ClInclude Include="source\NroProcess.h" />
|
||||
<ClInclude Include="source\NsoProcess.h" />
|
||||
<ClInclude Include="source\nstool.h" />
|
||||
<ClInclude Include="source\OffsetAdjustedIFile.h" />
|
||||
<ClInclude Include="source\PfsProcess.h" />
|
||||
<ClInclude Include="source\PkiCertProcess.h" />
|
||||
|
@ -210,6 +211,7 @@
|
|||
<ClCompile Include="source\EsTikProcess.cpp" />
|
||||
<ClCompile Include="source\HashTreeMeta.cpp" />
|
||||
<ClCompile Include="source\HashTreeWrappedIFile.cpp" />
|
||||
<ClCompile Include="source\KeyConfiguration.cpp" />
|
||||
<ClCompile Include="source\main.cpp" />
|
||||
<ClCompile Include="source\NacpProcess.cpp" />
|
||||
<ClCompile Include="source\NcaProcess.cpp" />
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
<ClInclude Include="source\HashTreeWrappedIFile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\KeyConfiguration.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\NacpProcess.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -55,9 +58,6 @@
|
|||
<ClInclude Include="source\NsoProcess.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\nstool.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\OffsetAdjustedIFile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -88,6 +88,9 @@
|
|||
<ClInclude Include="source\XciProcess.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="source\common.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="source\AesCtrWrappedIFile.cpp">
|
||||
|
@ -111,6 +114,9 @@
|
|||
<ClCompile Include="source\HashTreeWrappedIFile.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\KeyConfiguration.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="source\main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
|
|
@ -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<fnd::IFile>& 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);
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <fnd/Vec.h>
|
||||
#include <fnd/aes.h>
|
||||
|
||||
class AesCtrWrappedIFile : public fnd::IFile
|
||||
{
|
||||
public:
|
||||
AesCtrWrappedIFile(fnd::IFile* file, bool ownIfile, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr);
|
||||
~AesCtrWrappedIFile();
|
||||
AesCtrWrappedIFile(const fnd::SharedPtr<fnd::IFile>& file, const fnd::aes::sAes128Key& key, const fnd::aes::sAesIvCtr& ctr);
|
||||
|
||||
size_t size();
|
||||
void seek(size_t offset);
|
||||
|
@ -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<fnd::IFile> mFile;
|
||||
fnd::aes::sAes128Key mKey;
|
||||
fnd::aes::sAesIvCtr mBaseCtr, mCurrentCtr;
|
||||
size_t mFileOffset;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fnd/SimpleFile.h>
|
||||
#include <fnd/Vec.h>
|
||||
#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<fnd::IFile>& 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<byte_t> 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<byte_t> 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<byte_t> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,21 +2,21 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <nn/hac/AssetHeader.h>
|
||||
#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<fnd::IFile>& 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<fnd::IFile> mFile;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
||||
|
|
|
@ -1,184 +1,27 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
#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<byte_t> 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<fnd::IFile>& 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<byte_t> 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;
|
||||
}
|
||||
|
|
|
@ -2,19 +2,19 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <nn/hac/ContentMetaBinary.h>
|
||||
|
||||
#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<fnd::IFile>& 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<fnd::IFile> 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;
|
||||
};
|
|
@ -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::sElfSymbol>& ElfSymbolParser::getSymbolList() const
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <fnd/List.h>
|
||||
#include <nn/hac/elf.h>
|
||||
#include <fnd/elf.h>
|
||||
|
||||
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<sElfSymbol>& getSymbolList() const;
|
||||
private:
|
||||
const std::string kModuleName = "ElfSymbolParser";
|
||||
|
||||
// data
|
||||
fnd::List<sElfSymbol> mSymbolList;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
#include <nn/pki/SignUtils.h>
|
||||
#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<fnd::IFile>& 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<nn::pki::SignedData<nn::pki::CertificateBody>>& certs)
|
||||
|
@ -64,14 +53,16 @@ void EsTikProcess::setVerifyMode(bool verify)
|
|||
|
||||
void EsTikProcess::importTicket()
|
||||
{
|
||||
if (mFile == nullptr)
|
||||
fnd::Vec<byte_t> scratch;
|
||||
|
||||
|
||||
if (*mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
fnd::Vec<byte_t> 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: <cannot display>" << 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
|
||||
}
|
||||
|
||||
|
|
|
@ -2,22 +2,23 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <fnd/Vec.h>
|
||||
#include <nn/pki/SignedData.h>
|
||||
#include <nn/pki/CertificateBody.h>
|
||||
#include <nn/es/TicketBody_V2.h>
|
||||
#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<fnd::IFile>& file);
|
||||
void setKeyCfg(const KeyConfiguration& keycfg);
|
||||
void setCertificateChain(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& 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<fnd::IFile> mFile;
|
||||
KeyConfiguration mKeyCfg;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
||||
|
|
|
@ -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<fnd::IFile>& 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)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <sstream>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <fnd/Vec.h>
|
||||
#include <fnd/sha.h>
|
||||
#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<fnd::IFile>& 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<fnd::IFile> mFile;
|
||||
|
||||
// data file
|
||||
fnd::IFile* mData;
|
||||
fnd::SharedPtr<fnd::IFile> mData;
|
||||
size_t mDataOffset;
|
||||
size_t mDataBlockSize;
|
||||
fnd::List<fnd::sha::sSha256Hash> mDataHashLayer;
|
||||
|
|
376
programs/nstool/source/KeyConfiguration.cpp
Normal file
376
programs/nstool/source/KeyConfiguration.cpp
Normal file
|
@ -0,0 +1,376 @@
|
|||
#include "KeyConfiguration.h"
|
||||
#include <fnd/ResourceFileReader.h>
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
#include <nn/hac/AesKeygen.h>
|
||||
#include <nn/hac/NcaUtils.h>
|
||||
|
||||
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<byte_t> 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;
|
||||
}
|
209
programs/nstool/source/KeyConfiguration.h
Normal file
209
programs/nstool/source/KeyConfiguration.h
Normal file
|
@ -0,0 +1,209 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/aes.h>
|
||||
#include <fnd/rsa.h>
|
||||
#include <fnd/ecdsa.h>
|
||||
#include <nn/hac/nca.h>
|
||||
#include <nn/pki/SignedData.h>
|
||||
#include <nn/es/TicketBody_V2.h>
|
||||
|
||||
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<sPkiRootKey> mPkiRootKeyList;
|
||||
|
||||
/* Nca External Keys */
|
||||
fnd::List<sNcaExternalContentKey> mNcaExternalContentKeyList;
|
||||
|
||||
template <class T>
|
||||
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;
|
||||
}
|
||||
};
|
|
@ -1,11 +1,185 @@
|
|||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
#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<fnd::IFile>& 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<byte_t> 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<byte_t> 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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,19 +2,19 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <nn/hac/ApplicationControlPropertyBinary.h>
|
||||
|
||||
#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<fnd::IFile>& 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<fnd::IFile> 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;
|
||||
};
|
File diff suppressed because it is too large
Load diff
|
@ -1,24 +1,25 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/SimpleFile.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <nn/hac/NcaHeader.h>
|
||||
#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<fnd::IFile>& 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<fnd::IFile> mFile;
|
||||
KeyConfiguration mKeyCfg;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
||||
|
@ -84,15 +84,14 @@ private:
|
|||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
fnd::List<sKeyAreaKey> keak_list;
|
||||
fnd::List<sKeyAreaKey> kak_list;
|
||||
|
||||
sOptional<fnd::aes::sAes128Key> aes_ctr;
|
||||
sOptional<fnd::aes::sAesXts128Key> aes_xts;
|
||||
} mBodyKeys;
|
||||
} mContentKey;
|
||||
|
||||
struct sPartitionInfo
|
||||
{
|
||||
fnd::IFile* reader;
|
||||
fnd::SharedPtr<fnd::IFile> 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;
|
||||
};
|
File diff suppressed because it is too large
Load diff
|
@ -2,20 +2,21 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <nn/hac/NpdmBinary.h>
|
||||
#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<fnd::IFile>& 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<fnd::IFile> 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;
|
||||
};
|
|
@ -1,3 +1,5 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
#include <fnd/Vec.h>
|
||||
#include <fnd/lz4.h>
|
||||
|
@ -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<fnd::IFile>& file)
|
||||
{
|
||||
mFile = file;
|
||||
mOwnIFile = ownIFile;
|
||||
}
|
||||
|
||||
void NroProcess::setCliOutputMode(CliOutputMode type)
|
||||
|
@ -99,22 +86,28 @@ const RoMetadataProcess& NroProcess::getRoMetadataProcess() const
|
|||
void NroProcess::importHeader()
|
||||
{
|
||||
fnd::Vec<byte_t> 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()
|
||||
|
|
|
@ -3,22 +3,22 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <nn/hac/npdm.h>
|
||||
#include <nn/hac/NroHeader.h>
|
||||
#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<fnd::IFile>& 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<fnd::IFile> mFile;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
#include <fnd/Vec.h>
|
||||
#include <fnd/lz4.h>
|
||||
|
@ -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<fnd::IFile>& file)
|
||||
{
|
||||
mFile = file;
|
||||
mOwnIFile = ownIFile;
|
||||
}
|
||||
|
||||
void NsoProcess::setCliOutputMode(CliOutputMode type)
|
||||
|
@ -74,13 +61,19 @@ const RoMetadataProcess& NsoProcess::getRoMetadataProcess() const
|
|||
void NsoProcess::importHeader()
|
||||
{
|
||||
fnd::Vec<byte_t> 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()
|
||||
|
|
|
@ -3,21 +3,21 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <nn/hac/npdm.h>
|
||||
#include <nn/hac/NsoHeader.h>
|
||||
|
||||
#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<fnd::IFile>& 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<fnd::IFile> mFile;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
nn::hac::npdm::InstructionType mInstructionType;
|
||||
|
|
|
@ -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<fnd::IFile>& 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
|
||||
class OffsetAdjustedIFile : public fnd::IFile
|
||||
{
|
||||
public:
|
||||
OffsetAdjustedIFile(fnd::IFile* file, bool ownIFile, size_t offset, size_t size);
|
||||
~OffsetAdjustedIFile();
|
||||
OffsetAdjustedIFile(const fnd::SharedPtr<fnd::IFile>& 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<fnd::IFile> mFile;
|
||||
size_t mBaseOffset, mCurrentOffset;
|
||||
size_t mSize;
|
||||
};
|
|
@ -1,10 +1,11 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fnd/SimpleFile.h>
|
||||
#include <fnd/io.h>
|
||||
#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<byte_t> 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<fnd::IFile>& 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<byte_t> 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;
|
||||
}
|
|
@ -2,20 +2,20 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <nn/hac/PfsHeader.h>
|
||||
|
||||
#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<fnd::IFile>& 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<fnd::IFile> 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;
|
||||
};
|
|
@ -1,6 +1,5 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
#include <nn/pki/SignUtils.h>
|
||||
#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<fnd::IFile>& 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<byte_t> 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<nn::pki::CertificateBody> 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<nn::pki::CertificateBody>& 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<nn::pki::CertificateB
|
|||
else if (cert.getBody().getPublicKeyType() == nn::pki::cert::RSA2048)
|
||||
{
|
||||
std::cout << " PublicKey:" << std::endl;
|
||||
std::cout << " Public Exponent:" << std::endl;
|
||||
fnd::SimpleTextOutput::hexDump(cert.getBody().getRsa2048PublicKey().modulus, getHexDumpLen(fnd::rsa::kRsa2048Size), 0x10, 6);
|
||||
std::cout << " Modulus:" << std::endl;
|
||||
fnd::SimpleTextOutput::hexDump(cert.getBody().getRsa2048PublicKey().modulus, getHexDumpLen(fnd::rsa::kRsa2048Size), 0x10, 6);
|
||||
std::cout << " Public Exponent:" << std::endl;
|
||||
fnd::SimpleTextOutput::hexDump(cert.getBody().getRsa2048PublicKey().public_exponent, fnd::rsa::kRsaPublicExponentSize, 0x10, 6);
|
||||
}
|
||||
else if (cert.getBody().getPublicKeyType() == nn::pki::cert::ECDSA240)
|
||||
|
@ -143,12 +129,6 @@ void PkiCertProcess::displayCert(const nn::pki::SignedData<nn::pki::CertificateB
|
|||
std::cout << " S:" << std::endl;
|
||||
fnd::SimpleTextOutput::hexDump(cert.getBody().getEcdsa240PublicKey().s, getHexDumpLen(fnd::ecdsa::kEcdsa240Size), 0x10, 6);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#undef _HEXDUMP_L
|
||||
#undef _HEXDUMP_U
|
||||
#undef _SPLIT_VER
|
||||
}
|
||||
|
||||
size_t PkiCertProcess::getHexDumpLen(size_t max_size) const
|
||||
|
|
|
@ -2,22 +2,23 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <fnd/List.h>
|
||||
#include <fnd/Vec.h>
|
||||
#include <nn/pki/SignedData.h>
|
||||
#include <nn/pki/CertificateBody.h>
|
||||
#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<fnd::IFile>& 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<fnd::IFile> mFile;
|
||||
KeyConfiguration mKeyCfg;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
#include "PkiValidator.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <nn/pki/SignUtils.h>
|
||||
#include "PkiValidator.h"
|
||||
|
||||
PkiValidator::PkiValidator()
|
||||
{
|
||||
clearCertificates();
|
||||
}
|
||||
|
||||
void PkiValidator::setRootKey(const fnd::rsa::sRsa4096Key& root_key)
|
||||
void PkiValidator::setKeyCfg(const KeyConfiguration& keycfg)
|
||||
{
|
||||
// save a copy of the certificate bank
|
||||
fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> old_certs = mCertificateBank;
|
||||
|
@ -18,7 +18,7 @@ void PkiValidator::setRootKey(const fnd::rsa::sRsa4096Key& root_key)
|
|||
mCertificateBank.clear();
|
||||
|
||||
// overwrite the root key
|
||||
mRootKey = root_key;
|
||||
mKeyCfg = keycfg;
|
||||
|
||||
// if there were certificates before, reimport them (so they are checked against the new root key)
|
||||
if (old_certs.size() > 0)
|
||||
|
@ -96,13 +96,28 @@ void PkiValidator::validateSignature(const std::string& issuer, nn::pki::sign::S
|
|||
int sig_validate_res = -1;
|
||||
|
||||
// special case if signed by Root
|
||||
if (issuer == nn::pki::sign::kRootIssuerStr)
|
||||
if (issuer.find('-', 0) == std::string::npos)
|
||||
{
|
||||
if (sign_algo != nn::pki::sign::SIGN_ALGO_RSA4096)
|
||||
fnd::rsa::sRsa4096Key rsa4096_pub;
|
||||
fnd::rsa::sRsa2048Key rsa2048_pub;
|
||||
fnd::ecdsa::sEcdsa240Key ecdsa_pub;
|
||||
|
||||
if (mKeyCfg.getPkiRootSignKey(issuer, rsa4096_pub) == true && sign_algo == nn::pki::sign::SIGN_ALGO_RSA4096)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Issued by Root, but does not have a RSA4096 signature");
|
||||
sig_validate_res = fnd::rsa::pkcs::rsaVerify(rsa4096_pub, getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data());
|
||||
}
|
||||
else if (mKeyCfg.getPkiRootSignKey(issuer, rsa2048_pub) == true && sign_algo == nn::pki::sign::SIGN_ALGO_RSA2048)
|
||||
{
|
||||
sig_validate_res = fnd::rsa::pkcs::rsaVerify(rsa2048_pub, getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data());
|
||||
}
|
||||
else if (mKeyCfg.getPkiRootSignKey(issuer, ecdsa_pub) == true && sign_algo == nn::pki::sign::SIGN_ALGO_ECDSA240)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "ECDSA signatures are not supported");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Public key for issuer \"" + issuer + "\" does not exist.");
|
||||
}
|
||||
sig_validate_res = fnd::rsa::pkcs::rsaVerify(mRootKey, getCryptoHashAlgoFromEsSignHashAlgo(hash_algo), hash.data(), signature.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
#include <nn/pki/SignedData.h>
|
||||
#include <nn/pki/CertificateBody.h>
|
||||
#include <string>
|
||||
#include "KeyConfiguration.h"
|
||||
|
||||
class PkiValidator
|
||||
{
|
||||
public:
|
||||
PkiValidator();
|
||||
|
||||
void setRootKey(const fnd::rsa::sRsa4096Key& root_key);
|
||||
void setKeyCfg(const KeyConfiguration& keycfg);
|
||||
void addCertificates(const fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>>& certs);
|
||||
void addCertificate(const nn::pki::SignedData<nn::pki::CertificateBody>& cert);
|
||||
void clearCertificates();
|
||||
|
@ -22,8 +23,7 @@ public:
|
|||
private:
|
||||
const std::string kModuleName = "NNPkiValidator";
|
||||
|
||||
|
||||
fnd::rsa::sRsa4096Key mRootKey;
|
||||
KeyConfiguration mKeyCfg;
|
||||
fnd::List<nn::pki::SignedData<nn::pki::CertificateBody>> mCertificateBank;
|
||||
|
||||
void makeCertIdent(const nn::pki::SignedData<nn::pki::CertificateBody>& cert, std::string& ident) const;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fnd/types.h>
|
||||
|
||||
#include "RoMetadataProcess.h"
|
||||
|
@ -23,12 +25,8 @@ RoMetadataProcess::RoMetadataProcess() :
|
|||
|
||||
void RoMetadataProcess::process()
|
||||
{
|
||||
if (mRoBlob.size() == 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No ro binary set.");
|
||||
}
|
||||
|
||||
importApiList();
|
||||
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||
displayRoMetaData();
|
||||
}
|
||||
|
@ -101,6 +99,11 @@ const fnd::List<ElfSymbolParser::sElfSymbol>& RoMetadataProcess::getSymbolList()
|
|||
|
||||
void RoMetadataProcess::importApiList()
|
||||
{
|
||||
if (mRoBlob.size() == 0)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No ro binary set.");
|
||||
}
|
||||
|
||||
if (mApiInfo.size > 0)
|
||||
{
|
||||
std::stringstream list_stream(std::string((char*)mRoBlob.data() + mApiInfo.offset, mApiInfo.size));
|
||||
|
@ -133,71 +136,71 @@ void RoMetadataProcess::displayRoMetaData()
|
|||
|
||||
if (api_num > 0 && (mListApi || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
|
||||
{
|
||||
printf("[SDK API List]\n");
|
||||
std::cout << "[SDK API List]" << std::endl;
|
||||
if (mSdkVerApiList.size() > 0)
|
||||
{
|
||||
printf(" Sdk Revision: %s\n", mSdkVerApiList[0].getModuleName().c_str());
|
||||
std::cout << " Sdk Revision: " << mSdkVerApiList[0].getModuleName() << std::endl;
|
||||
}
|
||||
if (mPublicApiList.size() > 0)
|
||||
{
|
||||
printf(" Public APIs:\n");
|
||||
std::cout << " Public APIs:" << std::endl;
|
||||
for (size_t i = 0; i < mPublicApiList.size(); i++)
|
||||
{
|
||||
printf(" %s (vender: %s)\n", mPublicApiList[i].getModuleName().c_str(), mPublicApiList[i].getVenderName().c_str());
|
||||
std::cout << " " << mPublicApiList[i].getModuleName() << " (vender: " << mPublicApiList[i].getVenderName() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
if (mDebugApiList.size() > 0)
|
||||
{
|
||||
printf(" Debug APIs:\n");
|
||||
std::cout << " Debug APIs:" << std::endl;
|
||||
for (size_t i = 0; i < mDebugApiList.size(); i++)
|
||||
{
|
||||
printf(" %s (vender: %s)\n", mDebugApiList[i].getModuleName().c_str(), mDebugApiList[i].getVenderName().c_str());
|
||||
std::cout << " " << mDebugApiList[i].getModuleName() << " (vender: " << mDebugApiList[i].getVenderName() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
if (mPrivateApiList.size() > 0)
|
||||
{
|
||||
printf(" Private APIs:\n");
|
||||
std::cout << " Private APIs:" << std::endl;
|
||||
for (size_t i = 0; i < mPrivateApiList.size(); i++)
|
||||
{
|
||||
printf(" %s (vender: %s)\n", mPrivateApiList[i].getModuleName().c_str(), mPrivateApiList[i].getVenderName().c_str());
|
||||
std::cout << " " << mPrivateApiList[i].getModuleName() << " (vender: " << mPrivateApiList[i].getVenderName() << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mSymbolList.getSymbolList().size() > 0 && (mListSymbols || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED)))
|
||||
{
|
||||
printf("[Symbol List]\n");
|
||||
std::cout << "[Symbol List]" << std::endl;
|
||||
for (size_t i = 0; i < mSymbolList.getSymbolList().size(); i++)
|
||||
{
|
||||
const ElfSymbolParser::sElfSymbol& symbol = mSymbolList.getSymbolList()[i];
|
||||
printf(" %s [SHN=%s (%04x)][STT=%s][STB=%s]\n", symbol.name.c_str(), getSectionIndexStr(symbol.shn_index), symbol.shn_index, getSymbolTypeStr(symbol.symbol_type), getSymbolBindingStr(symbol.symbol_binding));
|
||||
std::cout << " " << symbol.name << " [SHN=" << getSectionIndexStr(symbol.shn_index) << " (" << std::hex << std::setw(4) << std::setfill('0') << symbol.shn_index << ")][STT=" << getSymbolTypeStr(symbol.symbol_type) << "][STB=" << getSymbolBindingStr(symbol.symbol_binding) << "]" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* RoMetadataProcess::getSectionIndexStr(nn::hac::elf::SpecialSectionIndex shn_index) const
|
||||
const char* RoMetadataProcess::getSectionIndexStr(uint16_t shn_index) const
|
||||
{
|
||||
const char* str;
|
||||
switch (shn_index)
|
||||
{
|
||||
case (nn::hac::elf::SHN_UNDEF):
|
||||
case (fnd::elf::SHN_UNDEF):
|
||||
str = "UNDEF";
|
||||
break;
|
||||
case (nn::hac::elf::SHN_LOPROC):
|
||||
case (fnd::elf::SHN_LOPROC):
|
||||
str = "LOPROC";
|
||||
break;
|
||||
case (nn::hac::elf::SHN_HIPROC):
|
||||
case (fnd::elf::SHN_HIPROC):
|
||||
str = "HIPROC";
|
||||
break;
|
||||
case (nn::hac::elf::SHN_LOOS):
|
||||
case (fnd::elf::SHN_LOOS):
|
||||
str = "LOOS";
|
||||
break;
|
||||
case (nn::hac::elf::SHN_HIOS):
|
||||
case (fnd::elf::SHN_HIOS):
|
||||
str = "HIOS";
|
||||
break;
|
||||
case (nn::hac::elf::SHN_ABS):
|
||||
case (fnd::elf::SHN_ABS):
|
||||
str = "ABS";
|
||||
break;
|
||||
case (nn::hac::elf::SHN_COMMON):
|
||||
case (fnd::elf::SHN_COMMON):
|
||||
str = "COMMON";
|
||||
break;
|
||||
default:
|
||||
|
@ -207,36 +210,36 @@ const char* RoMetadataProcess::getSectionIndexStr(nn::hac::elf::SpecialSectionIn
|
|||
return str;
|
||||
}
|
||||
|
||||
const char* RoMetadataProcess::getSymbolTypeStr(nn::hac::elf::SymbolType symbol_type) const
|
||||
const char* RoMetadataProcess::getSymbolTypeStr(byte_t symbol_type) const
|
||||
{
|
||||
const char* str;
|
||||
switch (symbol_type)
|
||||
{
|
||||
case (nn::hac::elf::STT_NOTYPE):
|
||||
case (fnd::elf::STT_NOTYPE):
|
||||
str = "NOTYPE";
|
||||
break;
|
||||
case (nn::hac::elf::STT_OBJECT):
|
||||
case (fnd::elf::STT_OBJECT):
|
||||
str = "OBJECT";
|
||||
break;
|
||||
case (nn::hac::elf::STT_FUNC):
|
||||
case (fnd::elf::STT_FUNC):
|
||||
str = "FUNC";
|
||||
break;
|
||||
case (nn::hac::elf::STT_SECTION):
|
||||
case (fnd::elf::STT_SECTION):
|
||||
str = "SECTION";
|
||||
break;
|
||||
case (nn::hac::elf::STT_FILE):
|
||||
case (fnd::elf::STT_FILE):
|
||||
str = "FILE";
|
||||
break;
|
||||
case (nn::hac::elf::STT_LOOS):
|
||||
case (fnd::elf::STT_LOOS):
|
||||
str = "LOOS";
|
||||
break;
|
||||
case (nn::hac::elf::STT_HIOS):
|
||||
case (fnd::elf::STT_HIOS):
|
||||
str = "HIOS";
|
||||
break;
|
||||
case (nn::hac::elf::STT_LOPROC):
|
||||
case (fnd::elf::STT_LOPROC):
|
||||
str = "LOPROC";
|
||||
break;
|
||||
case (nn::hac::elf::STT_HIPROC):
|
||||
case (fnd::elf::STT_HIPROC):
|
||||
str = "HIPROC";
|
||||
break;
|
||||
default:
|
||||
|
@ -246,30 +249,30 @@ const char* RoMetadataProcess::getSymbolTypeStr(nn::hac::elf::SymbolType symbol_
|
|||
return str;
|
||||
}
|
||||
|
||||
const char* RoMetadataProcess::getSymbolBindingStr(nn::hac::elf::SymbolBinding symbol_binding) const
|
||||
const char* RoMetadataProcess::getSymbolBindingStr(byte_t symbol_binding) const
|
||||
{
|
||||
const char* str;
|
||||
switch (symbol_binding)
|
||||
{
|
||||
case (nn::hac::elf::STB_LOCAL):
|
||||
case (fnd::elf::STB_LOCAL):
|
||||
str = "LOCAL";
|
||||
break;
|
||||
case (nn::hac::elf::STB_GLOBAL):
|
||||
case (fnd::elf::STB_GLOBAL):
|
||||
str = "GLOBAL";
|
||||
break;
|
||||
case (nn::hac::elf::STB_WEAK):
|
||||
case (fnd::elf::STB_WEAK):
|
||||
str = "WEAK";
|
||||
break;
|
||||
case (nn::hac::elf::STB_LOOS):
|
||||
case (fnd::elf::STB_LOOS):
|
||||
str = "LOOS";
|
||||
break;
|
||||
case (nn::hac::elf::STB_HIOS):
|
||||
case (fnd::elf::STB_HIOS):
|
||||
str = "HIOS";
|
||||
break;
|
||||
case (nn::hac::elf::STB_LOPROC):
|
||||
case (fnd::elf::STB_LOPROC):
|
||||
str = "LOPROC";
|
||||
break;
|
||||
case (nn::hac::elf::STB_HIPROC):
|
||||
case (fnd::elf::STB_HIPROC):
|
||||
str = "HIPROC";
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include <nn/hac/npdm.h>
|
||||
|
||||
#include "nstool.h"
|
||||
#include "common.h"
|
||||
#include "SdkApiString.h"
|
||||
#include "ElfSymbolParser.h"
|
||||
|
||||
|
@ -62,7 +62,7 @@ private:
|
|||
void importApiList();
|
||||
void displayRoMetaData();
|
||||
|
||||
const char* getSectionIndexStr(nn::hac::elf::SpecialSectionIndex shn_index) const;
|
||||
const char* getSymbolTypeStr(nn::hac::elf::SymbolType symbol_type) const;
|
||||
const char* getSymbolBindingStr(nn::hac::elf::SymbolBinding symbol_binding) const;
|
||||
const char* getSectionIndexStr(uint16_t shn_index) const;
|
||||
const char* getSymbolTypeStr(byte_t symbol_type) const;
|
||||
const char* getSymbolBindingStr(byte_t symbol_binding) const;
|
||||
};
|
|
@ -1,11 +1,12 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
#include <fnd/SimpleFile.h>
|
||||
#include <fnd/io.h>
|
||||
#include "RomfsProcess.h"
|
||||
|
||||
RomfsProcess::RomfsProcess() :
|
||||
mFile(nullptr),
|
||||
mOwnIFile(false),
|
||||
mFile(),
|
||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||
mVerify(false),
|
||||
mExtractPath(),
|
||||
|
@ -20,36 +21,24 @@ RomfsProcess::RomfsProcess() :
|
|||
mRootDir.file_list.clear();
|
||||
}
|
||||
|
||||
RomfsProcess::~RomfsProcess()
|
||||
{
|
||||
if (mOwnIFile)
|
||||
{
|
||||
delete mFile;
|
||||
}
|
||||
}
|
||||
|
||||
void RomfsProcess::process()
|
||||
{
|
||||
if (mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
resolveRomfs();
|
||||
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||
{
|
||||
displayHeader();
|
||||
if (mListFs || _HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||
displayFs();
|
||||
}
|
||||
|
||||
if (mExtract)
|
||||
extractFs();
|
||||
}
|
||||
|
||||
void RomfsProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||
void RomfsProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||
{
|
||||
mFile = file;
|
||||
mOwnIFile = ownIFile;
|
||||
}
|
||||
|
||||
void RomfsProcess::setCliOutputMode(CliOutputMode type)
|
||||
|
@ -87,19 +76,19 @@ void RomfsProcess::printTab(size_t tab) const
|
|||
{
|
||||
for (size_t i = 0; i < tab; i++)
|
||||
{
|
||||
printf(" ");
|
||||
std::cout << " ";
|
||||
}
|
||||
}
|
||||
|
||||
void RomfsProcess::displayFile(const sFile& file, size_t tab) const
|
||||
{
|
||||
printTab(tab);
|
||||
printf("%s", file.name.c_str());
|
||||
std::cout << file.name;
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
||||
{
|
||||
printf(" (offset=0x%" PRIx64 ", size=0x%" PRIx64 ")", file.offset, file.size);
|
||||
std::cout << std::hex << " (offset=0x" << file.offset << ", size=0x" << file.size << ")";
|
||||
}
|
||||
putchar('\n');
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const
|
||||
|
@ -107,7 +96,7 @@ void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const
|
|||
if (dir.name.empty() == false)
|
||||
{
|
||||
printTab(tab);
|
||||
printf("%s\n", dir.name.c_str());
|
||||
std::cout << dir.name << std::endl;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < dir.dir_list.size(); i++)
|
||||
|
@ -122,11 +111,16 @@ void RomfsProcess::displayDir(const sDirectory& dir, size_t tab) const
|
|||
|
||||
void RomfsProcess::displayHeader()
|
||||
{
|
||||
printf("[RomFS]\n");
|
||||
printf(" DirNum: %" PRId64 "\n", (uint64_t)mDirNum);
|
||||
printf(" FileNum: %" PRId64 "\n", (uint64_t)mFileNum);
|
||||
if (mMountName.empty() == false)
|
||||
printf(" MountPoint: %s%s\n", mMountName.c_str(), mMountName.at(mMountName.length()-1) != '/' ? "/" : "");
|
||||
std::cout << "[RomFS]" << std::endl;
|
||||
std::cout << " DirNum: " << std::dec << mDirNum << std::endl;
|
||||
std::cout << " FileNum: " << std::dec << mFileNum << std::endl;
|
||||
if (mMountName.empty() == false)
|
||||
{
|
||||
std::cout << " MountPoint: " << mMountName;
|
||||
if (mMountName.at(mMountName.length()-1) != '/')
|
||||
std::cout << "/";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void RomfsProcess::displayFs()
|
||||
|
@ -156,13 +150,13 @@ void RomfsProcess::extractDir(const std::string& path, const sDirectory& dir)
|
|||
fnd::io::appendToPath(file_path, dir.file_list[i].name);
|
||||
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||
printf("extract=[%s]\n", file_path.c_str());
|
||||
std::cout << "extract=[" << file_path << "]" << std::endl;
|
||||
|
||||
outFile.open(file_path, outFile.Create);
|
||||
mFile->seek(dir.file_list[i].offset);
|
||||
(*mFile)->seek(dir.file_list[i].offset);
|
||||
for (size_t j = 0; j < ((dir.file_list[i].size / kCacheSize) + ((dir.file_list[i].size % kCacheSize) != 0)); j++)
|
||||
{
|
||||
mFile->read(mCache.data(), _MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize));
|
||||
(*mFile)->read(mCache.data(), _MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize));
|
||||
outFile.write(mCache.data(), _MIN(dir.file_list[i].size - (kCacheSize * j),kCacheSize));
|
||||
}
|
||||
outFile.close();
|
||||
|
@ -254,8 +248,13 @@ void RomfsProcess::importDirectory(uint32_t dir_offset, sDirectory& dir)
|
|||
|
||||
void RomfsProcess::resolveRomfs()
|
||||
{
|
||||
if (*mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
// read header
|
||||
mFile->read((byte_t*)&mHdr, 0, sizeof(nn::hac::sRomfsHeader));
|
||||
(*mFile)->read((byte_t*)&mHdr, 0, sizeof(nn::hac::sRomfsHeader));
|
||||
|
||||
// logic check on the header layout
|
||||
if (validateHeaderLayout(&mHdr) == false)
|
||||
|
@ -265,13 +264,13 @@ void RomfsProcess::resolveRomfs()
|
|||
|
||||
// read directory nodes
|
||||
mDirNodes.alloc(mHdr.sections[nn::hac::romfs::DIR_NODE_TABLE].size.get());
|
||||
mFile->read(mDirNodes.data(), mHdr.sections[nn::hac::romfs::DIR_NODE_TABLE].offset.get(), mDirNodes.size());
|
||||
(*mFile)->read(mDirNodes.data(), mHdr.sections[nn::hac::romfs::DIR_NODE_TABLE].offset.get(), mDirNodes.size());
|
||||
//printf("[RAW DIR NODES]\n");
|
||||
//fnd::SimpleTextOutput::hxdStyleDump(mDirNodes.data(), mDirNodes.size());
|
||||
|
||||
// read file nodes
|
||||
mFileNodes.alloc(mHdr.sections[nn::hac::romfs::FILE_NODE_TABLE].size.get());
|
||||
mFile->read(mFileNodes.data(), mHdr.sections[nn::hac::romfs::FILE_NODE_TABLE].offset.get(), mFileNodes.size());
|
||||
(*mFile)->read(mFileNodes.data(), mHdr.sections[nn::hac::romfs::FILE_NODE_TABLE].offset.get(), mFileNodes.size());
|
||||
//printf("[RAW FILE NODES]\n");
|
||||
//fnd::SimpleTextOutput::hxdStyleDump(mFileNodes.data(), mFileNodes.size());
|
||||
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <fnd/Vec.h>
|
||||
#include <fnd/List.h>
|
||||
#include <nn/hac/romfs.h>
|
||||
|
||||
#include "nstool.h"
|
||||
#include "common.h"
|
||||
|
||||
class RomfsProcess
|
||||
{
|
||||
|
@ -77,12 +78,11 @@ public:
|
|||
};
|
||||
|
||||
RomfsProcess();
|
||||
~RomfsProcess();
|
||||
|
||||
void process();
|
||||
|
||||
// generic
|
||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
||||
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||
void setCliOutputMode(CliOutputMode type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
||||
|
@ -96,8 +96,7 @@ private:
|
|||
const std::string kModuleName = "RomfsProcess";
|
||||
static const size_t kCacheSize = 0x10000;
|
||||
|
||||
fnd::IFile* mFile;
|
||||
bool mOwnIFile;
|
||||
fnd::SharedPtr<fnd::IFile> mFile;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#include "UserSettings.h"
|
||||
#include "version.h"
|
||||
#include "PkiValidator.h"
|
||||
#include "KeyConfiguration.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
#include <fnd/io.h>
|
||||
#include <fnd/SimpleFile.h>
|
||||
|
@ -37,14 +39,16 @@ void UserSettings::parseCmdArgs(const std::vector<std::string>& arg_list)
|
|||
populateCmdArgs(arg_list, args);
|
||||
populateKeyset(args);
|
||||
populateUserSettings(args);
|
||||
if (_HAS_BIT(mOutputMode, OUTPUT_KEY_DATA))
|
||||
dumpKeyConfig();
|
||||
}
|
||||
|
||||
void UserSettings::showHelp()
|
||||
{
|
||||
printf("NSTool v%d.%d.%d (C) %s\n", VER_MAJOR, VER_MINOR, VER_PATCH, AUTHORS);
|
||||
printf("%s v%d.%d.%d (C) %s\n", APP_NAME, VER_MAJOR, VER_MINOR, VER_PATCH, AUTHORS);
|
||||
printf("Built: %s %s\n\n", __TIME__, __DATE__);
|
||||
|
||||
printf("Usage: nstool [options... ] <file>\n");
|
||||
printf("Usage: %s [options... ] <file>\n", BIN_NAME);
|
||||
printf("\n General Options:\n");
|
||||
printf(" -d, --dev Use devkit keyset.\n");
|
||||
printf(" -k, --keyset Specify keyset file.\n");
|
||||
|
@ -55,18 +59,18 @@ void UserSettings::showHelp()
|
|||
printf(" --showlayout Show layout metadata.\n");
|
||||
printf(" -v, --verbose Verbose output.\n");
|
||||
printf("\n XCI (GameCard Image)\n");
|
||||
printf(" nstool [--listfs] [--update <dir> --logo <dir> --normal <dir> --secure <dir>] <.xci file>\n");
|
||||
printf(" %s [--listfs] [--update <dir> --logo <dir> --normal <dir> --secure <dir>] <.xci file>\n", BIN_NAME);
|
||||
printf(" --listfs Print file system in embedded partitions.\n");
|
||||
printf(" --update Extract \"update\" partition to directory.\n");
|
||||
printf(" --logo Extract \"logo\" partition to directory.\n");
|
||||
printf(" --normal Extract \"normal\" partition to directory.\n");
|
||||
printf(" --secure Extract \"secure\" partition to directory.\n");
|
||||
printf("\n PFS0/HFS0 (PartitionFs), RomFs, NSP (Ninendo Submission Package)\n");
|
||||
printf(" nstool [--listfs] [--fsdir <dir>] <file>\n");
|
||||
printf(" %s [--listfs] [--fsdir <dir>] <file>\n", BIN_NAME);
|
||||
printf(" --listfs Print file system.\n");
|
||||
printf(" --fsdir Extract file system to directory.\n");
|
||||
printf("\n NCA (Nintendo Content Archive)\n");
|
||||
printf(" nstool [--listfs] [--bodykey <key> --titlekey <key>] [--part0 <dir> ...] <.nca file>\n");
|
||||
printf(" %s [--listfs] [--bodykey <key> --titlekey <key>] [--part0 <dir> ...] <.nca file>\n", BIN_NAME);
|
||||
printf(" --listfs Print file system in embedded partitions.\n");
|
||||
printf(" --titlekey Specify title key extracted from ticket.\n");
|
||||
printf(" --bodykey Specify body encryption key.\n");
|
||||
|
@ -77,12 +81,12 @@ void UserSettings::showHelp()
|
|||
printf(" --part2 Extract \"partition 2\" to directory.\n");
|
||||
printf(" --part3 Extract \"partition 3\" to directory.\n");
|
||||
printf("\n NSO (Nintendo Software Object), NRO (Nintendo Relocatable Object)\n");
|
||||
printf(" nstool [--listapi --listsym] [--insttype <inst. type>] <file>\n");
|
||||
printf(" %s [--listapi --listsym] [--insttype <inst. type>] <file>\n", BIN_NAME);
|
||||
printf(" --listapi Print SDK API List.\n");
|
||||
printf(" --listsym Print Code Symbols.\n");
|
||||
printf(" --insttype Specify instruction type [64bit|32bit] (64bit is assumed).\n");
|
||||
printf("\n ASET (Homebrew Asset Blob)\n");
|
||||
printf(" nstool [--listfs] [--icon <file> --nacp <file> --fsdir <dir>] <file>\n");
|
||||
printf(" %s [--listfs] [--icon <file> --nacp <file> --fsdir <dir>] <file>\n", BIN_NAME);
|
||||
printf(" --listfs Print filesystem in embedded RomFS partition.\n");
|
||||
printf(" --icon Extract icon partition to file.\n");
|
||||
printf(" --nacp Extract NACP partition to file.\n");
|
||||
|
@ -95,9 +99,9 @@ const std::string UserSettings::getInputPath() const
|
|||
return mInputPath;
|
||||
}
|
||||
|
||||
const sKeyset& UserSettings::getKeyset() const
|
||||
const KeyConfiguration& UserSettings::getKeyCfg() const
|
||||
{
|
||||
return mKeyset;
|
||||
return mKeyCfg;
|
||||
}
|
||||
|
||||
FileType UserSettings::getFileType() const
|
||||
|
@ -385,36 +389,23 @@ void UserSettings::populateCmdArgs(const std::vector<std::string>& arg_list, sCm
|
|||
|
||||
void UserSettings::populateKeyset(sCmdArgs& args)
|
||||
{
|
||||
fnd::aes::sAes128Key zeros_aes_key;
|
||||
fnd::aes::sAesXts128Key zeros_aes_xts_key;
|
||||
memset((void*)&zeros_aes_key, 0, sizeof(fnd::aes::sAes128Key));
|
||||
memset((void*)&zeros_aes_xts_key, 0, sizeof(fnd::aes::sAesXts128Key));
|
||||
memset((void*)&mKeyset, 0, sizeof(sKeyset));
|
||||
|
||||
fnd::ResourceFileReader res;
|
||||
if (args.keyset_path.isSet)
|
||||
{
|
||||
res.processFile(*args.keyset_path);
|
||||
mKeyCfg.importHactoolGenericKeyfile(*args.keyset_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
// open other resource files in $HOME/.switch/prod.keys (or $HOME/.switch/dev.keys if -d/--dev is set).
|
||||
std::string home;
|
||||
if (home.empty()) fnd::io::getEnvironVar(home, "HOME");
|
||||
if (home.empty()) fnd::io::getEnvironVar(home, "USERPROFILE");
|
||||
if (home.empty()) return;
|
||||
|
||||
const std::string kKeysetNameStr[2] = {"prod.keys", "dev.keys"};
|
||||
const std::string kHomeSwitchDirStr = ".switch";
|
||||
|
||||
std::string keyset_path;
|
||||
fnd::io::appendToPath(keyset_path, home);
|
||||
fnd::io::appendToPath(keyset_path, kHomeSwitchDirStr);
|
||||
fnd::io::appendToPath(keyset_path, kKeysetNameStr[args.devkit_keys.isSet ? *args.devkit_keys : 0]);
|
||||
getSwitchPath(keyset_path);
|
||||
if (keyset_path.empty())
|
||||
return;
|
||||
|
||||
fnd::io::appendToPath(keyset_path, kGeneralKeyfileName[args.devkit_keys.isSet]);
|
||||
|
||||
try
|
||||
{
|
||||
res.processFile(keyset_path);
|
||||
mKeyCfg.importHactoolGenericKeyfile(keyset_path);
|
||||
}
|
||||
catch (const fnd::Exception&)
|
||||
{
|
||||
|
@ -422,132 +413,29 @@ void UserSettings::populateKeyset(sCmdArgs& args)
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// suffix
|
||||
const std::string kKeyStr = "key";
|
||||
const std::string kKekStr = "kek";
|
||||
const std::string kSourceStr = "source";
|
||||
const std::string kRsaKeySuffix[2] = {"sign_key_private", "sign_key_modulus"};
|
||||
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"};
|
||||
|
||||
// keyname bases
|
||||
const std::string kMasterBase = "master";
|
||||
const std::string kPackage1Base = "package1";
|
||||
const std::string kPackage2Base = "package2";
|
||||
const std::string kXciHeaderBase = "xci_header";
|
||||
const std::string kNcaHeaderBase[2] = {"header", "nca_header"};
|
||||
const std::string kKekGenSource = "aes_kek_generation";
|
||||
const std::string kKeyGenSource = "aes_key_generation";
|
||||
const std::string kAcidBase = "acid";
|
||||
const std::string kPkiRootBase = "pki_root";
|
||||
const std::string kTicketCommonKeyBase[2] = { "titlekek", "ticket_commonkey" };
|
||||
const std::string kNcaBodyBase[2] = {"key_area_key", "nca_body_keak"};
|
||||
const std::string kNcaBodyKeakIndexName[3] = {"application", "ocean", "system"};
|
||||
|
||||
|
||||
// sources
|
||||
fnd::aes::sAes128Key master_key[kMasterKeyNum] = { zeros_aes_key };
|
||||
fnd::aes::sAes128Key package2_key_source = zeros_aes_key;
|
||||
fnd::aes::sAes128Key ticket_titlekek_source = zeros_aes_key;
|
||||
fnd::aes::sAes128Key key_area_key_source[3] = { zeros_aes_key, zeros_aes_key, zeros_aes_key };
|
||||
fnd::aes::sAes128Key aes_kek_generation_source = zeros_aes_key;
|
||||
fnd::aes::sAes128Key aes_key_generation_source = zeros_aes_key;
|
||||
fnd::aes::sAes128Key nca_header_kek_source = zeros_aes_key;
|
||||
fnd::aes::sAesXts128Key nca_header_key_source = zeros_aes_xts_key;
|
||||
|
||||
|
||||
#define _CONCAT_2_STRINGS(str1, str2) ((str1) + "_" + (str2))
|
||||
#define _CONCAT_3_STRINGS(str1, str2, str3) ((str1) + "_"+ (str2) + "_" + (str3))
|
||||
|
||||
std::string key,val;
|
||||
|
||||
#define _SAVE_KEYDATA(key_name, array, len) \
|
||||
key = (key_name); \
|
||||
val = res[key]; \
|
||||
if (val.empty() == false) { \
|
||||
decodeHexStringToBytes(key, val, (byte_t*)array, len); \
|
||||
}
|
||||
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kPackage2Base, kKeyStr, kSourceStr), package2_key_source.key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[0], kSourceStr), ticket_titlekek_source.key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[1], kSourceStr), ticket_titlekek_source.key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[0], kSourceStr), key_area_key_source[0].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[1], kSourceStr), key_area_key_source[1].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[2], kSourceStr), key_area_key_source[2].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[0], kSourceStr), key_area_key_source[0].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[1], kSourceStr), key_area_key_source[1].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[2], kSourceStr), key_area_key_source[2].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kKekGenSource, kSourceStr), aes_kek_generation_source.key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kKeyGenSource, kSourceStr), aes_key_generation_source.key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaHeaderBase[0], kKekStr, kSourceStr), nca_header_kek_source.key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaHeaderBase[0], kKeyStr, kSourceStr), nca_header_key_source.key, 0x20);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaHeaderBase[1], kKekStr, kSourceStr), nca_header_kek_source.key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaHeaderBase[1], kKeyStr, kSourceStr), nca_header_key_source.key, 0x20);
|
||||
|
||||
// Store Key Variants/Derivatives
|
||||
for (size_t i = 0; i < kMasterKeyNum; i++)
|
||||
{
|
||||
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kMasterBase, kKeyStr, kKeyIndex[i]), master_key[i].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kPackage1Base, kKeyStr, kKeyIndex[i]), mKeyset.package1_key[i].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kPackage2Base, kKeyStr, kKeyIndex[i]), mKeyset.package2_key[i].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[0], kKeyIndex[i]), mKeyset.ticket.titlekey_kek[i].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kTicketCommonKeyBase[1], kKeyIndex[i]), mKeyset.ticket.titlekey_kek[i].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[0], kKeyIndex[i]), mKeyset.nca.key_area_key[0][i].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[1], kKeyIndex[i]), mKeyset.nca.key_area_key[1][i].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[0], kNcaBodyKeakIndexName[2], kKeyIndex[i]), mKeyset.nca.key_area_key[2][i].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[0], kKeyIndex[i]), mKeyset.nca.key_area_key[0][i].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[1], kKeyIndex[i]), mKeyset.nca.key_area_key[1][i].key, 0x10);
|
||||
_SAVE_KEYDATA(_CONCAT_3_STRINGS(kNcaBodyBase[1], kNcaBodyKeakIndexName[2], kKeyIndex[i]), mKeyset.nca.key_area_key[2][i].key, 0x10);
|
||||
}
|
||||
|
||||
// store nca header key
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[0], kKeyStr), mKeyset.nca.header_key.key[0], 0x20);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[1], kKeyStr), mKeyset.nca.header_key.key[0], 0x20);
|
||||
|
||||
// store xci header key
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kKeyStr), mKeyset.xci.header_key.key, 0x10);
|
||||
|
||||
// store rsa keys
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[1], kRsaKeySuffix[0]), mKeyset.nca.header_sign_key.priv_exponent, fnd::rsa::kRsa2048Size);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kNcaHeaderBase[1], kRsaKeySuffix[1]), mKeyset.nca.header_sign_key.modulus, fnd::rsa::kRsa2048Size);
|
||||
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kRsaKeySuffix[0]), mKeyset.xci.header_sign_key.priv_exponent, fnd::rsa::kRsa2048Size);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kXciHeaderBase, kRsaKeySuffix[1]), mKeyset.xci.header_sign_key.modulus, fnd::rsa::kRsa2048Size);
|
||||
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase, kRsaKeySuffix[0]), mKeyset.acid_sign_key.priv_exponent, fnd::rsa::kRsa2048Size);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kAcidBase, kRsaKeySuffix[1]), mKeyset.acid_sign_key.modulus, fnd::rsa::kRsa2048Size);
|
||||
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPackage2Base, kRsaKeySuffix[0]), mKeyset.package2_sign_key.priv_exponent, fnd::rsa::kRsa2048Size);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPackage2Base, kRsaKeySuffix[1]), mKeyset.package2_sign_key.modulus, fnd::rsa::kRsa2048Size);
|
||||
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase, kRsaKeySuffix[0]), mKeyset.pki.root_sign_key.priv_exponent, fnd::rsa::kRsa4096Size);
|
||||
_SAVE_KEYDATA(_CONCAT_2_STRINGS(kPkiRootBase, kRsaKeySuffix[1]), mKeyset.pki.root_sign_key.modulus, fnd::rsa::kRsa4096Size);
|
||||
|
||||
|
||||
// save keydata from input args
|
||||
if (args.nca_bodykey.isSet)
|
||||
{
|
||||
if (args.nca_bodykey.var.length() == (sizeof(fnd::aes::sAes128Key)*2))
|
||||
{
|
||||
decodeHexStringToBytes("--bodykey", args.nca_bodykey.var, mKeyset.nca.manual_body_key_aesctr.key, sizeof(fnd::aes::sAes128Key));
|
||||
}
|
||||
else
|
||||
{
|
||||
decodeHexStringToBytes("--bodykey", args.nca_bodykey.var, mKeyset.nca.manual_body_key_aesxts.key[0], sizeof(fnd::aes::sAesXts128Key));
|
||||
}
|
||||
fnd::aes::sAes128Key tmp_key;
|
||||
fnd::Vec<byte_t> tmp_raw;
|
||||
fnd::SimpleTextOutput::stringToArray(args.nca_bodykey.var, tmp_raw);
|
||||
if (tmp_raw.size() != sizeof(fnd::aes::sAes128Key))
|
||||
throw fnd::Exception(kModuleName, "Key: \"--bodykey\" has incorrect length");
|
||||
memcpy(tmp_key.key, tmp_raw.data(), 16);
|
||||
mKeyCfg.addNcaExternalContentKey(kDummyRightsIdForUserBodyKey, tmp_key);
|
||||
}
|
||||
|
||||
if (args.nca_titlekey.isSet)
|
||||
{
|
||||
if (args.nca_titlekey.var.length() == (sizeof(fnd::aes::sAes128Key)*2))
|
||||
{
|
||||
decodeHexStringToBytes("--titlekey", args.nca_titlekey.var, mKeyset.nca.manual_title_key_aesctr.key, sizeof(fnd::aes::sAes128Key));
|
||||
}
|
||||
else
|
||||
{
|
||||
decodeHexStringToBytes("--titlekey", args.nca_titlekey.var, mKeyset.nca.manual_title_key_aesxts.key[0], sizeof(fnd::aes::sAesXts128Key));
|
||||
}
|
||||
fnd::aes::sAes128Key tmp_key;
|
||||
fnd::Vec<byte_t> tmp_raw;
|
||||
fnd::SimpleTextOutput::stringToArray(args.nca_titlekey.var, tmp_raw);
|
||||
if (tmp_raw.size() != sizeof(fnd::aes::sAes128Key))
|
||||
throw fnd::Exception(kModuleName, "Key: \"--titlekey\" has incorrect length");
|
||||
memcpy(tmp_key.key, tmp_raw.data(), 16);
|
||||
mKeyCfg.addNcaExternalContentKey(kDummyRightsIdForUserTitleKey, tmp_key);
|
||||
}
|
||||
|
||||
// import certificate chain
|
||||
|
@ -601,7 +489,7 @@ void UserSettings::populateKeyset(sCmdArgs& args)
|
|||
|
||||
try
|
||||
{
|
||||
pki_validator.setRootKey(mKeyset.pki.root_sign_key);
|
||||
pki_validator.setKeyCfg(mKeyCfg);
|
||||
pki_validator.addCertificates(mCertChain);
|
||||
pki_validator.validateSignature(tik.getBody().getIssuer(), tik.getSignature().getSignType(), tik.getSignature().getSignature(), tik_hash);
|
||||
}
|
||||
|
@ -615,75 +503,24 @@ void UserSettings::populateKeyset(sCmdArgs& args)
|
|||
// extract title key
|
||||
if (tik.getBody().getTitleKeyEncType() == nn::es::ticket::AES128_CBC)
|
||||
{
|
||||
memcpy(mKeyset.nca.manual_title_key_aesctr.key, tik.getBody().getEncTitleKey(), fnd::aes::kAes128KeySize);
|
||||
fnd::aes::sAes128Key enc_title_key;
|
||||
memcpy(enc_title_key.key, tik.getBody().getEncTitleKey(), 16);
|
||||
fnd::aes::sAes128Key common_key, external_content_key;
|
||||
if (mKeyCfg.getETicketCommonKey(nn::hac::NcaUtils::getMasterKeyRevisionFromKeyGeneration(tik.getBody().getCommonKeyId()), common_key) == true)
|
||||
{
|
||||
nn::hac::AesKeygen::generateKey(external_content_key.key, tik.getBody().getEncTitleKey(), common_key.key);
|
||||
mKeyCfg.addNcaExternalContentKey(tik.getBody().getRightsId(), external_content_key);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "[WARNING] Titlekey not imported from ticket because commonkey was not available" << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "[WARNING] Titlekey not imported from ticket because it is personalised" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#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] != zeros_aes_key)
|
||||
{
|
||||
if (aes_kek_generation_source != zeros_aes_key && aes_key_generation_source != zeros_aes_key)
|
||||
{
|
||||
if (i == 0 && nca_header_kek_source != zeros_aes_key && nca_header_key_source != zeros_aes_xts_key)
|
||||
{
|
||||
if (mKeyset.nca.header_key == zeros_aes_xts_key)
|
||||
{
|
||||
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(mKeyset.nca.header_key.key[0], nca_header_key_source.key[0], nca_header_kek.key);
|
||||
nn::hac::AesKeygen::generateKey(mKeyset.nca.header_key.key[1], nca_header_key_source.key[1], nca_header_kek.key);
|
||||
//printf("nca header key[0] ");
|
||||
//fnd::SimpleTextOutput::hexDump(mKeyset.nca.header_key.key[0], 0x10);
|
||||
//printf("nca header key[1] ");
|
||||
//fnd::SimpleTextOutput::hexDump(mKeyset.nca.header_key.key[1], 0x10);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < nn::hac::nca::kKeyAreaEncryptionKeyNum; j++)
|
||||
{
|
||||
if (key_area_key_source[j] != zeros_aes_key && mKeyset.nca.key_area_key[j][i] == zeros_aes_key)
|
||||
{
|
||||
nn::hac::AesKeygen::generateKey(mKeyset.nca.key_area_key[j][i].key, aes_kek_generation_source.key, key_area_key_source[j].key, aes_key_generation_source.key, master_key[i].key);
|
||||
//printf("nca keak %d/%02d ", j, i);
|
||||
//fnd::SimpleTextOutput::hexDump(mKeyset.nca.key_area_key[j][i].key, 0x10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ticket_titlekek_source != zeros_aes_key && mKeyset.ticket.titlekey_kek[i] == zeros_aes_key)
|
||||
{
|
||||
nn::hac::AesKeygen::generateKey(mKeyset.ticket.titlekey_kek[i].key, ticket_titlekek_source.key, master_key[i].key);
|
||||
//printf("ticket titlekek %02d ", i);
|
||||
//fnd::SimpleTextOutput::hexDump(mKeyset.ticket.titlekey_kek[i].key, 0x10);
|
||||
}
|
||||
if (package2_key_source != zeros_aes_key && mKeyset.package2_key[i] == zeros_aes_key)
|
||||
{
|
||||
nn::hac::AesKeygen::generateKey(mKeyset.package2_key[i].key, package2_key_source.key, master_key[i].key);
|
||||
//printf("package2 key %02d ", i);
|
||||
//fnd::SimpleTextOutput::hexDump(mKeyset.package2_key[i].key, 0x10);
|
||||
}
|
||||
}
|
||||
/*
|
||||
for (size_t j = 0; j < nn::hac::nca::kKeyAreaEncryptionKeyNum; j++)
|
||||
{
|
||||
if (mKeyset.nca.key_area_key[j][i] != zeros_aes_key)
|
||||
{
|
||||
printf("nca body keak %d/%02d ", j, i);
|
||||
fnd::SimpleTextOutput::hexDump(mKeyset.nca.key_area_key[j][i].key, 0x10);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void UserSettings::populateUserSettings(sCmdArgs& args)
|
||||
|
@ -747,21 +584,6 @@ void UserSettings::populateUserSettings(sCmdArgs& args)
|
|||
throw fnd::Exception(kModuleName, "Unknown file type.");
|
||||
}
|
||||
|
||||
|
||||
void UserSettings::decodeHexStringToBytes(const std::string& name, const std::string& str, byte_t* out, size_t out_len)
|
||||
{
|
||||
size_t size = str.size();
|
||||
if ((size % 2) || ((size / 2) != out_len))
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "Key: \"" + name + "\" has incorrect length");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < out_len; i++)
|
||||
{
|
||||
out[i] = (charToByte(str[i * 2]) << 4) | charToByte(str[(i * 2) + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
FileType UserSettings::getFileTypeFromString(const std::string& type_str)
|
||||
{
|
||||
std::string str = type_str;
|
||||
|
@ -804,7 +626,7 @@ FileType UserSettings::getFileTypeFromString(const std::string& type_str)
|
|||
|
||||
FileType UserSettings::determineFileTypeFromFile(const std::string& path)
|
||||
{
|
||||
static const size_t kMaxReadSize = 0x4000;
|
||||
static const size_t kMaxReadSize = 0x5000;
|
||||
FileType file_type = FILE_INVALID;
|
||||
fnd::SimpleFile file;
|
||||
fnd::Vec<byte_t> scratch;
|
||||
|
@ -840,12 +662,6 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path)
|
|||
// test nca
|
||||
else if (determineValidNcaFromSample(scratch))
|
||||
file_type = FILE_NCA;
|
||||
// test cnmt
|
||||
else if (determineValidCnmtFromSample(scratch))
|
||||
file_type = FILE_CNMT;
|
||||
// test nacp
|
||||
else if (determineValidNacpFromSample(scratch))
|
||||
file_type = FILE_NACP;
|
||||
// test nso
|
||||
else if (_ASSERT_SIZE(sizeof(nn::hac::sNsoHeader)) && _TYPE_PTR(nn::hac::sNsoHeader)->st_magic.get() == nn::hac::nso::kNsoStructMagic)
|
||||
file_type = FILE_NSO;
|
||||
|
@ -861,6 +677,16 @@ FileType UserSettings::determineFileTypeFromFile(const std::string& path)
|
|||
// test hb asset
|
||||
else if (_ASSERT_SIZE(sizeof(nn::hac::sAssetHeader)) && _TYPE_PTR(nn::hac::sAssetHeader)->st_magic.get() == nn::hac::aset::kAssetStructMagic)
|
||||
file_type = FILE_HB_ASSET;
|
||||
|
||||
// do heuristics
|
||||
// test cnmt
|
||||
else if (determineValidCnmtFromSample(scratch))
|
||||
file_type = FILE_CNMT;
|
||||
// test nacp
|
||||
else if (determineValidNacpFromSample(scratch))
|
||||
file_type = FILE_NACP;
|
||||
|
||||
|
||||
// else unrecognised
|
||||
else
|
||||
file_type = FILE_INVALID;
|
||||
|
@ -880,7 +706,9 @@ bool UserSettings::determineValidNcaFromSample(const fnd::Vec<byte_t>& sample) c
|
|||
if (sample.size() < nn::hac::nca::kHeaderSize)
|
||||
return false;
|
||||
|
||||
nn::hac::NcaUtils::decryptNcaHeader(sample.data(), nca_raw, mKeyset.nca.header_key);
|
||||
fnd::aes::sAesXts128Key header_key;
|
||||
mKeyCfg.getNcaHeaderKey(header_key);
|
||||
nn::hac::NcaUtils::decryptNcaHeader(sample.data(), nca_raw, header_key);
|
||||
|
||||
if (nca_header->st_magic.get() != nn::hac::nca::kNca2StructMagic && nca_header->st_magic.get() != nn::hac::nca::kNca3StructMagic)
|
||||
return false;
|
||||
|
@ -1019,3 +847,186 @@ nn::hac::npdm::InstructionType UserSettings::getInstructionTypeFromString(const
|
|||
|
||||
return type;
|
||||
}
|
||||
|
||||
void UserSettings::getHomePath(std::string& path) const
|
||||
{
|
||||
// open other resource files in $HOME/.switch/prod.keys (or $HOME/.switch/dev.keys if -d/--dev is set).
|
||||
path.clear();
|
||||
if (path.empty()) fnd::io::getEnvironVar(path, "HOME");
|
||||
if (path.empty()) fnd::io::getEnvironVar(path, "USERPROFILE");
|
||||
if (path.empty()) return;
|
||||
}
|
||||
|
||||
void UserSettings::getSwitchPath(std::string& path) const
|
||||
{
|
||||
std::string home;
|
||||
home.clear();
|
||||
getHomePath(home);
|
||||
if (home.empty())
|
||||
return;
|
||||
|
||||
path.clear();
|
||||
fnd::io::appendToPath(path, home);
|
||||
fnd::io::appendToPath(path, kHomeSwitchDirStr);
|
||||
}
|
||||
|
||||
void UserSettings::dumpKeyConfig() const
|
||||
{
|
||||
fnd::aes::sAes128Key aes_key;
|
||||
fnd::aes::sAesXts128Key aesxts_key;
|
||||
fnd::rsa::sRsa2048Key rsa2048_key;
|
||||
fnd::rsa::sRsa4096Key rsa4096_key;
|
||||
|
||||
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"};
|
||||
|
||||
|
||||
std::cout << "[KeyConfiguration]" << std::endl;
|
||||
std::cout << " NCA Keys:" << std::endl;
|
||||
if (mKeyCfg.getNcaHeader0SignKey(rsa2048_key) == true)
|
||||
dumpRsa2048Key(rsa2048_key, "Header Signature[0] Key", 2);
|
||||
if (mKeyCfg.getNcaHeaderKey(aesxts_key) == true)
|
||||
dumpAesXtsKey(aesxts_key, "Header Encryption Key", 2);
|
||||
|
||||
for (size_t i = 0; i < kMasterKeyNum; i++)
|
||||
{
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKey(i,0, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKey-Application-" + kKeyIndex[i], 2);
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKey(i,1, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKey-Ocean-" + kKeyIndex[i], 2);
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKey(i,2, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKey-System-" + kKeyIndex[i], 2);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < kMasterKeyNum; i++)
|
||||
{
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(i,0, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-Application-" + kKeyIndex[i], 2);
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(i,1, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-Ocean-" + kKeyIndex[i], 2);
|
||||
if (mKeyCfg.getNcaKeyAreaEncryptionKeyHw(i,2, aes_key) == true)
|
||||
dumpAesKey(aes_key, "KeyAreaEncryptionKeyHw-System-" + kKeyIndex[i], 2);
|
||||
}
|
||||
|
||||
std::cout << " XCI Keys:" << std::endl;
|
||||
if (mKeyCfg.getXciHeaderSignKey(rsa2048_key) == true)
|
||||
dumpRsa2048Key(rsa2048_key, "Header Signature Key", 2);
|
||||
if (mKeyCfg.getXciHeaderKey(aes_key) == true)
|
||||
dumpAesKey(aes_key, "Extended Header Encryption Key", 2);
|
||||
|
||||
|
||||
if (mKeyCfg.getAcidSignKey(rsa2048_key) == true)
|
||||
dumpRsa2048Key(rsa2048_key, "ACID Signer Key", 1);
|
||||
|
||||
|
||||
std::cout << " Package1 Keys:" << std::endl;
|
||||
for (size_t i = 0; i < kMasterKeyNum; i++)
|
||||
{
|
||||
if (mKeyCfg.getPkg1Key(i, aes_key) == true)
|
||||
dumpAesKey(aes_key, "EncryptionKey-" + kKeyIndex[i], 2);
|
||||
}
|
||||
|
||||
std::cout << " Package2 Keys:" << std::endl;
|
||||
if (mKeyCfg.getPkg2SignKey(rsa2048_key) == true)
|
||||
dumpRsa2048Key(rsa2048_key, "Signature Key", 2);
|
||||
for (size_t i = 0; i < kMasterKeyNum; i++)
|
||||
{
|
||||
if (mKeyCfg.getPkg2Key(i, aes_key) == true)
|
||||
dumpAesKey(aes_key, "EncryptionKey-" + kKeyIndex[i], 2);
|
||||
}
|
||||
|
||||
std::cout << " ETicket Keys:" << std::endl;
|
||||
for (size_t i = 0; i < kMasterKeyNum; i++)
|
||||
{
|
||||
if (mKeyCfg.getETicketCommonKey(i, aes_key) == true)
|
||||
dumpAesKey(aes_key, "CommonKey-" + kKeyIndex[i], 2);
|
||||
}
|
||||
|
||||
if (mKeyCfg.getPkiRootSignKey("Root", rsa4096_key) == true)
|
||||
dumpRsa4096Key(rsa4096_key, "NNPKI Root Key", 1);
|
||||
}
|
||||
|
||||
void UserSettings::dumpRsa2048Key(const fnd::rsa::sRsa2048Key& key, const std::string& name, size_t indent) const
|
||||
{
|
||||
std::string indent_str;
|
||||
|
||||
indent_str.clear();
|
||||
for (size_t i = 0; i < indent; i++)
|
||||
{
|
||||
indent_str += " ";
|
||||
}
|
||||
|
||||
std::cout << indent_str << name << ":" << std::endl;
|
||||
if (key.modulus[0] != 0x00 && key.modulus[1] != 0x00)
|
||||
{
|
||||
std::cout << indent_str << " Modulus:" << std::endl;
|
||||
for (size_t i = 0; i < 0x10; i++)
|
||||
{
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.modulus + i * 0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
if (key.priv_exponent[0] != 0x00 && key.priv_exponent[1] != 0x00)
|
||||
{
|
||||
std::cout << indent_str << " Private Exponent:" << std::endl;
|
||||
for (size_t i = 0; i < 0x10; i++)
|
||||
{
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.priv_exponent + i * 0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UserSettings::dumpRsa4096Key(const fnd::rsa::sRsa4096Key& key, const std::string& name, size_t indent) const
|
||||
{
|
||||
std::string indent_str;
|
||||
|
||||
indent_str.clear();
|
||||
for (size_t i = 0; i < indent; i++)
|
||||
{
|
||||
indent_str += " ";
|
||||
}
|
||||
|
||||
std::cout << indent_str << name << ":" << std::endl;
|
||||
if (key.modulus[0] != 0x00 && key.modulus[1] != 0x00)
|
||||
{
|
||||
std::cout << indent_str << " Modulus:" << std::endl;
|
||||
for (size_t i = 0; i < 0x20; i++)
|
||||
{
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.modulus + i * 0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
if (key.priv_exponent[0] != 0x00 && key.priv_exponent[1] != 0x00)
|
||||
{
|
||||
std::cout << indent_str << " Private Exponent:" << std::endl;
|
||||
for (size_t i = 0; i < 0x20; i++)
|
||||
{
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.priv_exponent + i * 0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UserSettings::dumpAesKey(const fnd::aes::sAes128Key& key, const std::string& name, size_t indent) const
|
||||
{
|
||||
std::string indent_str;
|
||||
|
||||
indent_str.clear();
|
||||
for (size_t i = 0; i < indent; i++)
|
||||
{
|
||||
indent_str += " ";
|
||||
}
|
||||
|
||||
std::cout << indent_str << name << ":" << std::endl;
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.key, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
|
||||
void UserSettings::dumpAesXtsKey(const fnd::aes::sAesXts128Key& key, const std::string& name, size_t indent) const
|
||||
{
|
||||
std::string indent_str;
|
||||
|
||||
indent_str.clear();
|
||||
for (size_t i = 0; i < indent; i++)
|
||||
{
|
||||
indent_str += " ";
|
||||
}
|
||||
|
||||
std::cout << indent_str << name << ":" << std::endl;
|
||||
std::cout << indent_str << " " << fnd::SimpleTextOutput::arrayToString(key.key[0], 0x20, true, ":") << std::endl;
|
||||
}
|
|
@ -7,7 +7,8 @@
|
|||
#include <nn/pki/SignedData.h>
|
||||
#include <nn/pki/CertificateBody.h>
|
||||
#include <nn/hac/npdm.h>
|
||||
#include "nstool.h"
|
||||
#include "common.h"
|
||||
#include "KeyConfiguration.h"
|
||||
|
||||
class UserSettings
|
||||
{
|
||||
|
@ -19,7 +20,7 @@ public:
|
|||
|
||||
// generic options
|
||||
const std::string getInputPath() const;
|
||||
const sKeyset& getKeyset() const;
|
||||
const KeyConfiguration& getKeyCfg() const;
|
||||
FileType getFileType() const;
|
||||
bool isVerifyFile() const;
|
||||
CliOutputMode getCliOutputMode() const;
|
||||
|
@ -46,6 +47,11 @@ public:
|
|||
|
||||
private:
|
||||
const std::string kModuleName = "UserSettings";
|
||||
|
||||
const std::string kHomeSwitchDirStr = ".switch";
|
||||
const std::string kGeneralKeyfileName[2] = { "prod.keys", "dev.keys" };
|
||||
const std::string kTitleKeyfileName = "title.keys";
|
||||
|
||||
|
||||
struct sCmdArgs
|
||||
{
|
||||
|
@ -81,7 +87,7 @@ private:
|
|||
|
||||
std::string mInputPath;
|
||||
FileType mFileType;
|
||||
sKeyset mKeyset;
|
||||
KeyConfiguration mKeyCfg;
|
||||
bool mVerifyFile;
|
||||
CliOutputMode mOutputMode;
|
||||
|
||||
|
@ -109,7 +115,6 @@ private:
|
|||
void populateCmdArgs(const std::vector<std::string>& arg_list, sCmdArgs& cmd_args);
|
||||
void populateKeyset(sCmdArgs& args);
|
||||
void populateUserSettings(sCmdArgs& args);
|
||||
void decodeHexStringToBytes(const std::string& name, const std::string& str, byte_t* out, size_t out_len);
|
||||
FileType getFileTypeFromString(const std::string& type_str);
|
||||
FileType determineFileTypeFromFile(const std::string& path);
|
||||
bool determineValidNcaFromSample(const fnd::Vec<byte_t>& sample) const;
|
||||
|
@ -118,4 +123,12 @@ private:
|
|||
bool determineValidEsCertFromSample(const fnd::Vec<byte_t>& sample) const;
|
||||
bool determineValidEsTikFromSample(const fnd::Vec<byte_t>& sample) const;
|
||||
nn::hac::npdm::InstructionType getInstructionTypeFromString(const std::string& type_str);
|
||||
void getHomePath(std::string& path) const;
|
||||
void getSwitchPath(std::string& path) const;
|
||||
|
||||
void dumpKeyConfig() const;
|
||||
void dumpRsa2048Key(const fnd::rsa::sRsa2048Key& key, const std::string& name, size_t indent) const;
|
||||
void dumpRsa4096Key(const fnd::rsa::sRsa4096Key& key, const std::string& name, size_t indent) const;
|
||||
void dumpAesKey(const fnd::aes::sAes128Key& key, const std::string& name, size_t indent) const;
|
||||
void dumpAesXtsKey(const fnd::aes::sAesXts128Key& key, const std::string& name, size_t indent) const;
|
||||
};
|
|
@ -1,12 +1,12 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fnd/SimpleTextOutput.h>
|
||||
#include <nn/hac/XciUtils.h>
|
||||
#include "OffsetAdjustedIFile.h"
|
||||
#include "XciProcess.h"
|
||||
|
||||
XciProcess::XciProcess() :
|
||||
mFile(nullptr),
|
||||
mOwnIFile(false),
|
||||
mKeyset(nullptr),
|
||||
mFile(),
|
||||
mCliOutputMode(_BIT(OUTPUT_BASIC)),
|
||||
mVerify(false),
|
||||
mListFs(false),
|
||||
|
@ -15,38 +15,13 @@ XciProcess::XciProcess() :
|
|||
{
|
||||
}
|
||||
|
||||
XciProcess::~XciProcess()
|
||||
{
|
||||
if (mOwnIFile)
|
||||
{
|
||||
delete mFile;
|
||||
}
|
||||
}
|
||||
|
||||
void XciProcess::process()
|
||||
{
|
||||
fnd::Vec<byte_t> scratch;
|
||||
|
||||
if (mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
// read header page
|
||||
mFile->read((byte_t*)&mHdrPage, 0, sizeof(nn::hac::sXciHeaderPage));
|
||||
|
||||
// allocate memory for and decrypt sXciHeader
|
||||
scratch.alloc(sizeof(nn::hac::sXciHeader));
|
||||
nn::hac::XciUtils::decryptXciHeader((const byte_t*)&mHdrPage.header, scratch.data(), mKeyset->xci.header_key.key);
|
||||
importHeader();
|
||||
|
||||
// validate header signature
|
||||
if (mVerify)
|
||||
{
|
||||
validateXciSignature();
|
||||
}
|
||||
|
||||
// deserialise header
|
||||
mHdr.fromBytes(scratch.data(), scratch.size());
|
||||
|
||||
// display header
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_BASIC))
|
||||
|
@ -59,15 +34,14 @@ void XciProcess::process()
|
|||
processPartitionPfs();
|
||||
}
|
||||
|
||||
void XciProcess::setInputFile(fnd::IFile* file, bool ownIFile)
|
||||
void XciProcess::setInputFile(const fnd::SharedPtr<fnd::IFile>& file)
|
||||
{
|
||||
mFile = file;
|
||||
mOwnIFile = ownIFile;
|
||||
}
|
||||
|
||||
void XciProcess::setKeyset(const sKeyset* keyset)
|
||||
void XciProcess::setKeyCfg(const KeyConfiguration& keycfg)
|
||||
{
|
||||
mKeyset = keyset;
|
||||
mKeyCfg = keycfg;
|
||||
}
|
||||
|
||||
void XciProcess::setCliOutputMode(CliOutputMode type)
|
||||
|
@ -90,94 +64,118 @@ void XciProcess::setListFs(bool list_fs)
|
|||
mListFs = list_fs;
|
||||
}
|
||||
|
||||
void XciProcess::importHeader()
|
||||
{
|
||||
fnd::Vec<byte_t> scratch;
|
||||
|
||||
if (*mFile == nullptr)
|
||||
{
|
||||
throw fnd::Exception(kModuleName, "No file reader set.");
|
||||
}
|
||||
|
||||
// read header page
|
||||
(*mFile)->read((byte_t*)&mHdrPage, 0, sizeof(nn::hac::sXciHeaderPage));
|
||||
|
||||
// allocate memory for and decrypt sXciHeader
|
||||
scratch.alloc(sizeof(nn::hac::sXciHeader));
|
||||
|
||||
fnd::aes::sAes128Key header_key;
|
||||
mKeyCfg.getXciHeaderKey(header_key);
|
||||
nn::hac::XciUtils::decryptXciHeader((const byte_t*)&mHdrPage.header, scratch.data(), header_key.key);
|
||||
|
||||
// deserialise header
|
||||
mHdr.fromBytes(scratch.data(), scratch.size());
|
||||
}
|
||||
|
||||
void XciProcess::displayHeader()
|
||||
{
|
||||
printf("[XCI Header]\n");
|
||||
printf(" CardHeaderVersion: %d\n", mHdr.getCardHeaderVersion());
|
||||
printf(" RomSize: %s", getRomSizeStr(mHdr.getRomSizeType()));
|
||||
std::cout << "[XCI Header]" << std::endl;
|
||||
std::cout << " CardHeaderVersion: " << std::dec << (uint32_t)mHdr.getCardHeaderVersion() << std::endl;
|
||||
std::cout << " RomSize: " << getRomSizeStr(mHdr.getRomSizeType());
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||
printf(" (0x%x)", mHdr.getRomSizeType());
|
||||
printf("\n");
|
||||
printf(" PackageId: 0x%" PRIx64 "\n", mHdr.getPackageId());
|
||||
printf(" Flags: 0x%x\n", mHdr.getFlags());
|
||||
std::cout << " (0x" << std::hex << (uint32_t)mHdr.getRomSizeType() << ")";
|
||||
std::cout << std::endl;
|
||||
std::cout << " PackageId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getPackageId() << std::endl;
|
||||
std::cout << " Flags: 0x" << std::dec << (uint32_t)mHdr.getFlags() << std::endl;
|
||||
if (mHdr.getFlags() != 0)
|
||||
{
|
||||
for (uint32_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (_HAS_BIT(mHdr.getFlags(), i))
|
||||
{
|
||||
printf(" %s\n", getHeaderFlagStr(i));
|
||||
std::cout << " " << getHeaderFlagStr(i) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||
{
|
||||
printf(" InitialData:\n");
|
||||
printf(" KekIndex: %d\n", mHdr.getKekIndex());
|
||||
printf(" TitleKeyDecIndex: %d\n", mHdr.getTitleKeyDecIndex());
|
||||
printf(" Hash:\n");
|
||||
fnd::SimpleTextOutput::hexDump(mHdr.getInitialDataHash().bytes, sizeof(mHdr.getInitialDataHash().bytes), 0x10, 6);
|
||||
std::cout << " InitialData:" << std::endl;
|
||||
std::cout << " KekIndex: " << std::dec << (uint32_t)mHdr.getKekIndex() << std::endl;
|
||||
std::cout << " TitleKeyDecIndex: " << std::dec << (uint32_t)mHdr.getTitleKeyDecIndex() << std::endl;
|
||||
std::cout << " Hash:" << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes, 0x10, true, ":") << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getInitialDataHash().bytes+0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||
{
|
||||
printf(" Enc Header AES-IV:\n");
|
||||
fnd::SimpleTextOutput::hexDump(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), 0x10, 4);
|
||||
std::cout << " Extended Header AesCbc IV:" << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getAesCbcIv().iv, sizeof(mHdr.getAesCbcIv().iv), true, ":") << std::endl;
|
||||
}
|
||||
printf(" SelSec: 0x%x\n", mHdr.getSelSec());
|
||||
printf(" SelT1Key: 0x%x\n", mHdr.getSelT1Key());
|
||||
printf(" SelKey: 0x%x\n", mHdr.getSelKey());
|
||||
std::cout << " SelSec: 0x" << std::hex << mHdr.getSelSec() << std::endl;
|
||||
std::cout << " SelT1Key: 0x" << std::hex << mHdr.getSelT1Key() << std::endl;
|
||||
std::cout << " SelKey: 0x" << std::hex << mHdr.getSelKey() << std::endl;
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_LAYOUT))
|
||||
{
|
||||
printf(" RomAreaStartPage: 0x%0x", mHdr.getRomAreaStartPage());
|
||||
std::cout << " RomAreaStartPage: 0x" << std::hex << mHdr.getRomAreaStartPage();
|
||||
if (mHdr.getRomAreaStartPage() != (uint32_t)(-1))
|
||||
printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getRomAreaStartPage()));
|
||||
printf("\n");
|
||||
std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getRomAreaStartPage()) << ")";
|
||||
std::cout << std::endl;
|
||||
|
||||
printf(" BackupAreaStartPage: 0x%0x", mHdr.getBackupAreaStartPage());
|
||||
std::cout << " BackupAreaStartPage: 0x" << std::hex << mHdr.getBackupAreaStartPage();
|
||||
if (mHdr.getBackupAreaStartPage() != (uint32_t)(-1))
|
||||
printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage()));
|
||||
printf("\n");
|
||||
std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getBackupAreaStartPage()) << ")";
|
||||
std::cout << std::endl;
|
||||
|
||||
printf(" ValidDataEndPage: 0x%x", mHdr.getValidDataEndPage());
|
||||
std::cout << " ValidDataEndPage: 0x" << std::hex << mHdr.getValidDataEndPage();
|
||||
if (mHdr.getValidDataEndPage() != (uint32_t)(-1))
|
||||
printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getValidDataEndPage()));
|
||||
printf("\n");
|
||||
std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getValidDataEndPage()) << ")";
|
||||
std::cout << std::endl;
|
||||
|
||||
printf(" LimArea: 0x%x", mHdr.getLimAreaPage());
|
||||
std::cout << " LimArea: 0x" << std::hex << mHdr.getLimAreaPage();
|
||||
if (mHdr.getLimAreaPage() != (uint32_t)(-1))
|
||||
printf(" (0x%" PRIx64 ")", nn::hac::XciUtils::blockToAddr(mHdr.getLimAreaPage()));
|
||||
printf("\n");
|
||||
std::cout << " (0x" << std::hex << nn::hac::XciUtils::blockToAddr(mHdr.getLimAreaPage()) << ")";
|
||||
std::cout << std::endl;
|
||||
|
||||
printf(" PartitionFs Header:\n");
|
||||
printf(" Offset: 0x%" PRIx64 "\n", mHdr.getPartitionFsAddress());
|
||||
printf(" Size: 0x%" PRIx64 "\n", mHdr.getPartitionFsSize());
|
||||
std::cout << " PartitionFs Header:" << std::endl;
|
||||
std::cout << " Offset: 0x" << std::hex << mHdr.getPartitionFsAddress() << std::endl;
|
||||
std::cout << " Size: 0x" << std::hex << mHdr.getPartitionFsSize() << std::endl;
|
||||
if (_HAS_BIT(mCliOutputMode, OUTPUT_EXTENDED))
|
||||
{
|
||||
printf(" Hash:\n");
|
||||
fnd::SimpleTextOutput::hexDump(mHdr.getPartitionFsHash().bytes, sizeof(mHdr.getPartitionFsHash().bytes), 0x10, 6);
|
||||
std::cout << " Hash:" << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes, 0x10, true, ":") << std::endl;
|
||||
std::cout << " " << fnd::SimpleTextOutput::arrayToString(mHdr.getPartitionFsHash().bytes+0x10, 0x10, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (mHdr.getFwVerMinor() != 0)
|
||||
{
|
||||
printf("[XCI Extended Header]\n");
|
||||
printf(" FwVersion: v%d.%d\n", mHdr.getFwVerMajor(), mHdr.getFwVerMinor());
|
||||
printf(" AccCtrl1: 0x%x\n", mHdr.getAccCtrl1());
|
||||
printf(" CardClockRate: %s\n", getCardClockRate(mHdr.getAccCtrl1()));
|
||||
printf(" Wait1TimeRead: 0x%x\n", mHdr.getWait1TimeRead());
|
||||
printf(" Wait2TimeRead: 0x%x\n", mHdr.getWait2TimeRead());
|
||||
printf(" Wait1TimeWrite: 0x%x\n", mHdr.getWait1TimeWrite());
|
||||
printf(" Wait2TimeWrite: 0x%x\n", mHdr.getWait2TimeWrite());
|
||||
printf(" FwMode: 0x%x\n", mHdr.getFwMode());
|
||||
printf(" Update Partition Info:\n");
|
||||
#define _SPLIT_VER(ver) ( (ver>>26) & 0x3f), ( (ver>>20) & 0x3f), ( (ver>>16) & 0xf), (ver & 0xffff)
|
||||
printf(" CUP Version: v%" PRId32 " (%d.%d.%d.%d)\n", mHdr.getUppVersion(), _SPLIT_VER(mHdr.getUppVersion()));
|
||||
std::cout << "[XCI Extended Header]" << std::endl;
|
||||
std::cout << " FwVersion: v" << std::dec << mHdr.getFwVerMajor() << "." << mHdr.getFwVerMinor() << std::endl;
|
||||
std::cout << " AccCtrl1: 0x" << std::hex << mHdr.getAccCtrl1() << std::endl;
|
||||
std::cout << " CardClockRate: " << getCardClockRate(mHdr.getAccCtrl1()) << std::endl;
|
||||
std::cout << " Wait1TimeRead: 0x" << std::hex << mHdr.getWait1TimeRead() << std::endl;
|
||||
std::cout << " Wait2TimeRead: 0x" << std::hex << mHdr.getWait2TimeRead() << std::endl;
|
||||
std::cout << " Wait1TimeWrite: 0x" << std::hex << mHdr.getWait1TimeWrite() << std::endl;
|
||||
std::cout << " Wait2TimeWrite: 0x" << std::hex << mHdr.getWait2TimeWrite() << std::endl;
|
||||
std::cout << " FwMode: 0x" << std::hex << mHdr.getFwMode() << std::endl;
|
||||
std::cout << " Update Partition Info:" << std::endl;
|
||||
#define _SPLIT_VER(ver) std::dec << ((ver>>26) & 0x3f) << "." << ((ver>>20) & 0x3f) << "." << ((ver>>16) & 0xf) << "." << (ver & 0xffff)
|
||||
std::cout << " CUP Version: v" << std::dec << mHdr.getUppVersion() << " (" << _SPLIT_VER(mHdr.getUppVersion()) << ")" << std::endl;
|
||||
#undef _SPLIT_VER
|
||||
printf(" CUP TitleId: %016" PRIx64 "\n", mHdr.getUppId());
|
||||
printf(" Partition Hash: ");
|
||||
fnd::SimpleTextOutput::hexDump(mHdr.getUppHash(), 8);
|
||||
}
|
||||
std::cout << " CUP TitleId: 0x" << std::hex << std::setw(16) << std::setfill('0') << mHdr.getUppId() << std::endl;
|
||||
std::cout << " Partition Hash: " << fnd::SimpleTextOutput::arrayToString(mHdr.getUppHash(), 8, true, ":") << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash)
|
||||
|
@ -185,18 +183,20 @@ bool XciProcess::validateRegionOfFile(size_t offset, size_t len, const byte_t* t
|
|||
fnd::Vec<byte_t> scratch;
|
||||
fnd::sha::sSha256Hash calc_hash;
|
||||
scratch.alloc(len);
|
||||
mFile->read(scratch.data(), offset, scratch.size());
|
||||
(*mFile)->read(scratch.data(), offset, scratch.size());
|
||||
fnd::sha::Sha256(scratch.data(), scratch.size(), calc_hash.bytes);
|
||||
return calc_hash.compare(test_hash);
|
||||
}
|
||||
|
||||
void XciProcess::validateXciSignature()
|
||||
{
|
||||
fnd::rsa::sRsa2048Key header_sign_key;
|
||||
fnd::sha::sSha256Hash calc_hash;
|
||||
fnd::sha::Sha256((byte_t*)&mHdrPage.header, sizeof(nn::hac::sXciHeader), calc_hash.bytes);
|
||||
if (fnd::rsa::pkcs::rsaVerify(mKeyset->xci.header_sign_key, fnd::sha::HASH_SHA256, calc_hash.bytes, mHdrPage.signature) != 0)
|
||||
mKeyCfg.getXciHeaderSignKey(header_sign_key);
|
||||
if (fnd::rsa::pkcs::rsaVerify(header_sign_key, fnd::sha::HASH_SHA256, calc_hash.bytes, mHdrPage.signature) != 0)
|
||||
{
|
||||
printf("[WARNING] XCI Header Signature: FAIL \n");
|
||||
std::cout << "[WARNING] XCI Header Signature: FAIL" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,9 +204,9 @@ void XciProcess::processRootPfs()
|
|||
{
|
||||
if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize(), mHdr.getPartitionFsHash().bytes) == false)
|
||||
{
|
||||
printf("[WARNING] XCI Root HFS0: FAIL (bad hash)\n");
|
||||
std::cout << "[WARNING] XCI Root HFS0: FAIL (bad hash)" << std::endl;
|
||||
}
|
||||
mRootPfs.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()), OWN_IFILE);
|
||||
mRootPfs.setInputFile(new OffsetAdjustedIFile(mFile, mHdr.getPartitionFsAddress(), mHdr.getPartitionFsSize()));
|
||||
mRootPfs.setListFs(mListFs);
|
||||
mRootPfs.setVerifyMode(false);
|
||||
mRootPfs.setCliOutputMode(mCliOutputMode);
|
||||
|
@ -222,11 +222,11 @@ void XciProcess::processPartitionPfs()
|
|||
// this must be validated here because only the size of the root partiton header is known at verification time
|
||||
if (mVerify && validateRegionOfFile(mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].hash_protected_size, rootPartitions[i].hash.bytes) == false)
|
||||
{
|
||||
printf("[WARNING] XCI %s Partition HFS0: FAIL (bad hash)\n", rootPartitions[i].name.c_str());
|
||||
std::cout << "[WARNING] XCI " << rootPartitions[i].name << " Partition HFS0: FAIL (bad hash)" << std::endl;
|
||||
}
|
||||
|
||||
PfsProcess tmp;
|
||||
tmp.setInputFile(new OffsetAdjustedIFile(mFile, SHARED_IFILE, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size), OWN_IFILE);
|
||||
tmp.setInputFile(new OffsetAdjustedIFile(mFile, mHdr.getPartitionFsAddress() + rootPartitions[i].offset, rootPartitions[i].size));
|
||||
tmp.setListFs(mListFs);
|
||||
tmp.setVerifyMode(mVerify);
|
||||
tmp.setCliOutputMode(mCliOutputMode);
|
||||
|
@ -240,7 +240,8 @@ void XciProcess::processPartitionPfs()
|
|||
|
||||
const char* XciProcess::getRomSizeStr(byte_t rom_size) const
|
||||
{
|
||||
const char* str = "unknown";
|
||||
const char* str = nullptr;
|
||||
|
||||
switch (rom_size)
|
||||
{
|
||||
case (nn::hac::xci::ROM_SIZE_1GB):
|
||||
|
@ -261,13 +262,18 @@ const char* XciProcess::getRomSizeStr(byte_t rom_size) const
|
|||
case (nn::hac::xci::ROM_SIZE_32GB):
|
||||
str = "32GB";
|
||||
break;
|
||||
default:
|
||||
str = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
const char* XciProcess::getHeaderFlagStr(byte_t flag) const
|
||||
{
|
||||
const char* str = "unknown";
|
||||
const char* str = nullptr;
|
||||
|
||||
switch (flag)
|
||||
{
|
||||
case (nn::hac::xci::FLAG_AUTOBOOT):
|
||||
|
@ -279,14 +285,19 @@ const char* XciProcess::getHeaderFlagStr(byte_t flag) const
|
|||
case (nn::hac::xci::FLAG_REPAIR_TOOL):
|
||||
str = "RepairTool";
|
||||
break;
|
||||
default:
|
||||
str = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
const char* XciProcess::getCardClockRate(uint32_t acc_ctrl_1) const
|
||||
{
|
||||
const char* str = "unknown";
|
||||
const char* str = nullptr;
|
||||
|
||||
switch (acc_ctrl_1)
|
||||
{
|
||||
case (nn::hac::xci::CLOCK_RATE_25):
|
||||
|
@ -295,7 +306,10 @@ const char* XciProcess::getCardClockRate(uint32_t acc_ctrl_1) const
|
|||
case (nn::hac::xci::CLOCK_RATE_50):
|
||||
str = "50 MHz";
|
||||
break;
|
||||
|
||||
default:
|
||||
str = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
|
|
@ -2,25 +2,24 @@
|
|||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/IFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <fnd/List.h>
|
||||
#include <nn/hac/XciHeader.h>
|
||||
|
||||
#include "nstool.h"
|
||||
|
||||
#include "KeyConfiguration.h"
|
||||
#include "PfsProcess.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
class XciProcess
|
||||
{
|
||||
public:
|
||||
XciProcess();
|
||||
~XciProcess();
|
||||
|
||||
void process();
|
||||
|
||||
// generic
|
||||
void setInputFile(fnd::IFile* file, bool ownIFile);
|
||||
void setKeyset(const sKeyset* keyset);
|
||||
void setInputFile(const fnd::SharedPtr<fnd::IFile>& file);
|
||||
void setKeyCfg(const KeyConfiguration& keycfg);
|
||||
void setCliOutputMode(CliOutputMode type);
|
||||
void setVerifyMode(bool verify);
|
||||
|
||||
|
@ -32,9 +31,8 @@ private:
|
|||
const std::string kModuleName = "XciProcess";
|
||||
const std::string kXciMountPointName = "gamecard:/";
|
||||
|
||||
fnd::IFile* mFile;
|
||||
bool mOwnIFile;
|
||||
const sKeyset* mKeyset;
|
||||
fnd::SharedPtr<fnd::IFile> mFile;
|
||||
KeyConfiguration mKeyCfg;
|
||||
CliOutputMode mCliOutputMode;
|
||||
bool mVerify;
|
||||
|
||||
|
@ -62,6 +60,7 @@ private:
|
|||
PfsProcess mRootPfs;
|
||||
fnd::List<sExtractInfo> mExtractInfo;
|
||||
|
||||
void importHeader();
|
||||
void displayHeader();
|
||||
bool validateRegionOfFile(size_t offset, size_t len, const byte_t* test_hash);
|
||||
void validateXciSignature();
|
||||
|
|
60
programs/nstool/source/common.h
Normal file
60
programs/nstool/source/common.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/aes.h>
|
||||
#include <fnd/rsa.h>
|
||||
#include <nn/hac/nca.h>
|
||||
|
||||
static const size_t kMasterKeyNum = 0x20;
|
||||
static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum;
|
||||
|
||||
enum FileType
|
||||
{
|
||||
FILE_XCI,
|
||||
FILE_NSP,
|
||||
FILE_PARTITIONFS,
|
||||
FILE_ROMFS,
|
||||
FILE_NCA,
|
||||
FILE_NPDM,
|
||||
FILE_CNMT,
|
||||
FILE_NSO,
|
||||
FILE_NRO,
|
||||
FILE_NACP,
|
||||
FILE_PKI_CERT,
|
||||
FILE_ES_TIK,
|
||||
FILE_HB_ASSET,
|
||||
FILE_INVALID = -1,
|
||||
};
|
||||
|
||||
enum CliOutputModeFlag
|
||||
{
|
||||
OUTPUT_BASIC,
|
||||
OUTPUT_LAYOUT,
|
||||
OUTPUT_KEY_DATA,
|
||||
OUTPUT_EXTENDED
|
||||
};
|
||||
|
||||
typedef byte_t CliOutputMode;
|
||||
|
||||
template <typename T>
|
||||
struct sOptional
|
||||
{
|
||||
bool isSet;
|
||||
T var;
|
||||
inline sOptional() : isSet(false) {}
|
||||
inline sOptional(const T& other) : isSet(true), var(other) {}
|
||||
inline sOptional(const sOptional& other) : isSet(other.isSet), var(other.var) {}
|
||||
inline const T& operator=(const T& other) { isSet = true; var = other; return var; }
|
||||
inline const sOptional<T>& operator=(const sOptional<T>& other)
|
||||
{
|
||||
isSet = other.isSet;
|
||||
if (isSet) {
|
||||
var = other.var;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline T& operator*() { return var; }
|
||||
};
|
||||
|
||||
const byte_t kDummyRightsIdForUserTitleKey[nn::hac::nca::kRightsIdLen] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
const byte_t kDummyRightsIdForUserBodyKey[nn::hac::nca::kRightsIdLen] = {0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe};
|
|
@ -1,5 +1,6 @@
|
|||
#include <cstdio>
|
||||
#include <fnd/SimpleFile.h>
|
||||
#include <fnd/SharedPtr.h>
|
||||
#include <fnd/StringConv.h>
|
||||
#include "UserSettings.h"
|
||||
#include "XciProcess.h"
|
||||
|
@ -35,13 +36,15 @@ int main(int argc, char** argv)
|
|||
try {
|
||||
user_set.parseCmdArgs(args);
|
||||
|
||||
fnd::SharedPtr<fnd::IFile> inputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read));
|
||||
|
||||
if (user_set.getFileType() == FILE_XCI)
|
||||
{
|
||||
XciProcess xci;
|
||||
|
||||
xci.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
xci.setInputFile(inputFile);
|
||||
|
||||
xci.setKeyset(&user_set.getKeyset());
|
||||
xci.setKeyCfg(user_set.getKeyCfg());
|
||||
xci.setCliOutputMode(user_set.getCliOutputMode());
|
||||
xci.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -61,7 +64,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
PfsProcess pfs;
|
||||
|
||||
pfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
pfs.setInputFile(inputFile);
|
||||
pfs.setCliOutputMode(user_set.getCliOutputMode());
|
||||
pfs.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -75,7 +78,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
RomfsProcess romfs;
|
||||
|
||||
romfs.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
romfs.setInputFile(inputFile);
|
||||
romfs.setCliOutputMode(user_set.getCliOutputMode());
|
||||
romfs.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -89,8 +92,8 @@ int main(int argc, char** argv)
|
|||
{
|
||||
NcaProcess nca;
|
||||
|
||||
nca.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
nca.setKeyset(&user_set.getKeyset());
|
||||
nca.setInputFile(inputFile);
|
||||
nca.setKeyCfg(user_set.getKeyCfg());
|
||||
nca.setCliOutputMode(user_set.getCliOutputMode());
|
||||
nca.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -111,8 +114,8 @@ int main(int argc, char** argv)
|
|||
{
|
||||
NpdmProcess npdm;
|
||||
|
||||
npdm.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
npdm.setKeyset(&user_set.getKeyset());
|
||||
npdm.setInputFile(inputFile);
|
||||
npdm.setKeyCfg(user_set.getKeyCfg());
|
||||
npdm.setCliOutputMode(user_set.getCliOutputMode());
|
||||
npdm.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -122,7 +125,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
CnmtProcess cnmt;
|
||||
|
||||
cnmt.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
cnmt.setInputFile(inputFile);
|
||||
cnmt.setCliOutputMode(user_set.getCliOutputMode());
|
||||
cnmt.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -132,7 +135,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
NsoProcess obj;
|
||||
|
||||
obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
obj.setInputFile(inputFile);
|
||||
obj.setCliOutputMode(user_set.getCliOutputMode());
|
||||
obj.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -146,7 +149,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
NroProcess obj;
|
||||
|
||||
obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
obj.setInputFile(inputFile);
|
||||
obj.setCliOutputMode(user_set.getCliOutputMode());
|
||||
obj.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -169,7 +172,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
NacpProcess nacp;
|
||||
|
||||
nacp.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
nacp.setInputFile(inputFile);
|
||||
nacp.setCliOutputMode(user_set.getCliOutputMode());
|
||||
nacp.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -179,8 +182,8 @@ int main(int argc, char** argv)
|
|||
{
|
||||
PkiCertProcess cert;
|
||||
|
||||
cert.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
cert.setKeyset(&user_set.getKeyset());
|
||||
cert.setInputFile(inputFile);
|
||||
cert.setKeyCfg(user_set.getKeyCfg());
|
||||
cert.setCliOutputMode(user_set.getCliOutputMode());
|
||||
cert.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
@ -190,8 +193,8 @@ int main(int argc, char** argv)
|
|||
{
|
||||
EsTikProcess tik;
|
||||
|
||||
tik.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
tik.setKeyset(&user_set.getKeyset());
|
||||
tik.setInputFile(inputFile);
|
||||
tik.setKeyCfg(user_set.getKeyCfg());
|
||||
tik.setCertificateChain(user_set.getCertificateChain());
|
||||
tik.setCliOutputMode(user_set.getCliOutputMode());
|
||||
tik.setVerifyMode(user_set.isVerifyFile());
|
||||
|
@ -202,7 +205,7 @@ int main(int argc, char** argv)
|
|||
{
|
||||
AssetProcess obj;
|
||||
|
||||
obj.setInputFile(new fnd::SimpleFile(user_set.getInputPath(), fnd::SimpleFile::Read), OWN_IFILE);
|
||||
obj.setInputFile(inputFile);
|
||||
obj.setCliOutputMode(user_set.getCliOutputMode());
|
||||
obj.setVerifyMode(user_set.isVerifyFile());
|
||||
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
#pragma once
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <fnd/types.h>
|
||||
#include <fnd/aes.h>
|
||||
#include <fnd/rsa.h>
|
||||
#include <nn/hac/nca.h>
|
||||
|
||||
static const size_t kMasterKeyNum = 0x20;
|
||||
static const size_t kNcaKeakNum = nn::hac::nca::kKeyAreaEncryptionKeyNum;
|
||||
|
||||
enum IFileOwnershipMode
|
||||
{
|
||||
SHARED_IFILE = false,
|
||||
OWN_IFILE = true
|
||||
};
|
||||
|
||||
enum FileType
|
||||
{
|
||||
FILE_XCI,
|
||||
FILE_NSP,
|
||||
FILE_PARTITIONFS,
|
||||
FILE_ROMFS,
|
||||
FILE_NCA,
|
||||
FILE_NPDM,
|
||||
FILE_CNMT,
|
||||
FILE_NSO,
|
||||
FILE_NRO,
|
||||
FILE_NACP,
|
||||
FILE_PKI_CERT,
|
||||
FILE_ES_TIK,
|
||||
FILE_HB_ASSET,
|
||||
FILE_INVALID = -1,
|
||||
};
|
||||
|
||||
enum CliOutputModeFlag
|
||||
{
|
||||
OUTPUT_BASIC,
|
||||
OUTPUT_LAYOUT,
|
||||
OUTPUT_KEY_DATA,
|
||||
OUTPUT_EXTENDED
|
||||
};
|
||||
|
||||
typedef byte_t CliOutputMode;
|
||||
|
||||
template <typename T>
|
||||
struct sOptional
|
||||
{
|
||||
bool isSet;
|
||||
T var;
|
||||
inline sOptional() : isSet(false) {}
|
||||
inline const T& operator=(const T& other) { isSet = true; var = other; return var; }
|
||||
inline const sOptional<T>& operator=(const sOptional<T>& other)
|
||||
{
|
||||
isSet = other.isSet;
|
||||
if (isSet) {
|
||||
var = other.var;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
inline T& operator*() { return var; }
|
||||
};
|
||||
|
||||
struct sKeyset
|
||||
{
|
||||
fnd::rsa::sRsa2048Key acid_sign_key;
|
||||
fnd::aes::sAes128Key package1_key[kMasterKeyNum];
|
||||
fnd::rsa::sRsa2048Key package2_sign_key;
|
||||
fnd::aes::sAes128Key package2_key[kMasterKeyNum];
|
||||
|
||||
struct sNcaData
|
||||
{
|
||||
fnd::rsa::sRsa2048Key header_sign_key;
|
||||
fnd::aes::sAesXts128Key header_key;
|
||||
fnd::aes::sAes128Key key_area_key[kNcaKeakNum][kMasterKeyNum];
|
||||
|
||||
fnd::aes::sAes128Key manual_title_key_aesctr;
|
||||
fnd::aes::sAesXts128Key manual_title_key_aesxts;
|
||||
fnd::aes::sAes128Key manual_body_key_aesctr;
|
||||
fnd::aes::sAesXts128Key manual_body_key_aesxts;
|
||||
} nca;
|
||||
|
||||
struct sXciData
|
||||
{
|
||||
fnd::rsa::sRsa2048Key header_sign_key;
|
||||
fnd::aes::sAes128Key header_key;
|
||||
} xci;
|
||||
|
||||
struct sTicketData
|
||||
{
|
||||
fnd::rsa::sRsa2048Key sign_key;
|
||||
fnd::aes::sAes128Key titlekey_kek[kMasterKeyNum];
|
||||
} ticket;
|
||||
|
||||
struct sPkiData
|
||||
{
|
||||
fnd::rsa::sRsa4096Key root_sign_key;
|
||||
} pki;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
#define APP_NAME "NSTool"
|
||||
#define BIN_NAME "nstool"
|
||||
#define VER_MAJOR 1
|
||||
#define VER_MINOR 0
|
||||
#define VER_PATCH 0
|
||||
#define VER_PATCH 4
|
||||
#define AUTHORS "jakcron"
|
Loading…
Reference in a new issue