Initial commit
This commit is contained in:
commit
34b960b774
339
LICENSE
Normal file
339
LICENSE
Normal file
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
200
Makefile
Normal file
200
Makefile
Normal file
@ -0,0 +1,200 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# DATA is a list of directories containing data files
|
||||
# INCLUDES is a list of directories containing header files
|
||||
# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm".
|
||||
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
|
||||
#
|
||||
# NO_ICON: if set to anything, do not use icon.
|
||||
# NO_NACP: if set to anything, no .nacp file is generated.
|
||||
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
|
||||
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
|
||||
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
|
||||
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
|
||||
# ICON is the filename of the icon (.jpg), relative to the project folder.
|
||||
# If not set, it attempts to use one of the following (in this order):
|
||||
# - <Project name>.jpg
|
||||
# - icon.jpg
|
||||
# - <libnx folder>/default_icon.jpg
|
||||
#---------------------------------------------------------------------------------
|
||||
APP_TITLE := Lockpick
|
||||
APP_AUTHOR := shchmue
|
||||
APP_VERSION := 1.0
|
||||
|
||||
TARGET := $(subst $e ,_,$(notdir $(APP_TITLE)))
|
||||
BUILD := build
|
||||
OUTDIR := out
|
||||
SOURCES := source
|
||||
DATA := data
|
||||
INCLUDES := include
|
||||
EXEFS_SRC := exefs_src
|
||||
ICON := icon.jpg
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -O3 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__ `freetype-config --cflags`
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -std=gnu++17 -fno-rtti -fno-exceptions
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := -lnx -lmbedcrypto -lstdc++fs `freetype-config --libs`
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX) $(TOPDIR)/source/mbedtls
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(OUTDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CC)
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
#---------------------------------------------------------------------------------
|
||||
export LD := $(CXX)
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC)
|
||||
|
||||
ifeq ($(strip $(ICON)),)
|
||||
icons := $(wildcard *.jpg)
|
||||
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
|
||||
else
|
||||
ifneq (,$(findstring icon.jpg,$(icons)))
|
||||
export APP_ICON := $(TOPDIR)/icon.jpg
|
||||
endif
|
||||
endif
|
||||
else
|
||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_ICON)),)
|
||||
export NROFLAGS += --icon=$(APP_ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
export NROFLAGS += --nacp=$(CURDIR)/$(OUTDIR)/$(TARGET).nacp
|
||||
endif
|
||||
|
||||
ifneq ($(APP_TITLEID),)
|
||||
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||
endif
|
||||
|
||||
ifneq ($(ROMFS),)
|
||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir -p $@ $(BUILD) $(OUTDIR)
|
||||
$(MAKE) -C source/mbedtls/lib all
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
$(MAKE) -C source/mbedtls/lib clean
|
||||
@rm -fr $(BUILD) $(OUTDIR) $(TARGET).pfs0 $(TARGET).nso $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
all : $(OUTPUT).pfs0 $(OUTPUT).nro
|
||||
|
||||
$(OUTPUT).pfs0 : $(OUTPUT).nso
|
||||
|
||||
$(OUTPUT).nso : $(OUTPUT).elf
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
|
||||
else
|
||||
$(OUTPUT).nro : $(OUTPUT).elf
|
||||
endif
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
58
README.md
Normal file
58
README.md
Normal file
@ -0,0 +1,58 @@
|
||||
Lockpick
|
||||
=
|
||||
This is a ground-up C++17 rewrite of homebrew key derivation software, namely [kezplez-nx](https://github.com/tesnos/kezplez-nx). It also dumps titlekeys. This will dump all keys through `*_key_05` on firmwares below 6.2.0 and through `*_key_06` on 6.2.0 and above.
|
||||
|
||||
What this software does differently
|
||||
=
|
||||
* Dumps titlekeys
|
||||
* Uses the superfast `xxHash` instead of `sha256` when searching exefs for keys for a ~5x speed improvement
|
||||
* Gets all possible keys from running process memory - this means no need to decrypt `Package2` at all, let alone decompress `KIP`s
|
||||
* Gets `header_key` without `tsec`, `sbk`, `master_key_00` or `aes` sources - which may or may not be the same way `ChoiDujourNX` does it :eyes: (and I'm gonna issue a challenge to homebrew title installers to implement similar code so you don't need your users to use separate software like this :stuck_out_tongue_winking_eye: it's up to you to figure out if the same can be done for `key_area_keys` if needed)
|
||||
|
||||
Usage
|
||||
=
|
||||
1. Use [Hekate](https://github.com/CTCaer/hekate/releases) to dump TSEC and fuses:
|
||||
1. Push hekate payload bin using [TegraRCMSmash](https://github.com/rajkosto/TegraRcmSmash)/[TegraRCMGUI](https://github.com/eliboa/TegraRcmGUI)/modchip/injector
|
||||
2. Using the `VOL` and `Power` buttons to navigate, select `Console info...`
|
||||
3. Select `Print fuse info`
|
||||
4. Press `Power` to save fuses to SD card
|
||||
5. Select `Print TSEC keys`
|
||||
6. Press `Power` to save TSEC to SD card
|
||||
2. Launch CFW of choice
|
||||
3. Open `Homebrew Menu`
|
||||
4. Run `Lockpick`
|
||||
5. Use the resulting `prod.keys` file as needed and rename if required
|
||||
|
||||
Building
|
||||
=
|
||||
Release built with `libnx v1.6.0`.
|
||||
|
||||
Uses `freetype` which comes with `switch-portlibs` via `devkitPro pacman`:
|
||||
```
|
||||
pacman -S libnx switch-portlibs
|
||||
```
|
||||
then run:
|
||||
```
|
||||
make
|
||||
```
|
||||
to build.
|
||||
|
||||
Special Thanks
|
||||
=
|
||||
* tèsnos! For making [kezplez-nx](https://github.com/tesnos/kezplez-nx), being an all-around cool and helpful person and open to my contributions, not to mention patient with my *enthusiasm*. kezplez taught me an absolute TON about homebrew.
|
||||
* SciresM for [hactool](https://github.com/SciresM/hactool), containing to my knowledge the first public key derivation *software*, and for `get_titlekeys.py`
|
||||
* roblabla for the original keys [gist](https://gist.github.com/roblabla/d8358ab058bbe3b00614740dcba4f208) and for believing in our habilities
|
||||
* The folks in the [ReSwitched](https://reswitched.team/) Discord server for answering my innumerable questions while researching this (and having such a useful chat backlog!)
|
||||
* The memory reading code from jakibaki's [sys-netcheat](https://github.com/jakibaki/sys-netcheat) was super useful for getting keys out of running process memory
|
||||
* The System Save dumping methodology from Adubbz' [Compelled Disclosure](https://github.com/Adubbz/Compelled-Disclosure)
|
||||
* Shouts out to fellow key derivers: shadowninja108 for [HACGUI](https://github.com/shadowninja108/HACGUI), Thealexblarney for [Libhac](https://github.com/Thealexbarney/LibHac), and [rajkosto](https://github.com/rajkosto/) :eyes:
|
||||
* The constantly-improving docs on [Switchbrew wiki](https://switchbrew.org/wiki/) and [libnx](https://switchbrew.github.io/libnx/files.html)
|
||||
* [mission2000](https://github.com/misson20000) for help with `std::invoke` to get the function timer working
|
||||
* Literally the friends I made along the way! I came to the scene late and I've still managed to meet some wonderful people :) Thanks for all the help testing, making suggestions, and cheerleading!
|
||||
|
||||
Licenses
|
||||
=
|
||||
* `AES` functions are from [mbedtls](https://tls.mbed.org/) licensed under [GPLv2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html))
|
||||
* `creport_debug_types` and fast `sha256` implementation are from [Atmosphère](https://github.com/atmosphere-NX/Atmosphere) licensed under [GPLv2](https://github.com/Atmosphere-NX/Atmosphere/blob/master/LICENSE)
|
||||
* Simple `xxHash` implementation is from [stbrumme](https://github.com/stbrumme/xxhash) licensed under [MIT](https://github.com/stbrumme/xxhash/blob/master/LICENSE)
|
||||
* Padlock icon is from [Icons8](https://icons8.com/) licensed under [Creative Commons Attribution-NoDerivs 3.0 Unported](https://creativecommons.org/licenses/by-nd/3.0/)
|
238
source/Common.cpp
Normal file
238
source/Common.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) 2018 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
Shared font code adapted from
|
||||
https://github.com/switchbrew/switch-examples/tree/master/graphics/shared_font
|
||||
*/
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
extern "C" {
|
||||
#include <machine/endian.h>
|
||||
}
|
||||
|
||||
#include "sha256.h"
|
||||
|
||||
namespace Common {
|
||||
static u32 framebuf_width = 0;
|
||||
static u32 *framebuf;
|
||||
// FreeType vars
|
||||
static FT_Library library;
|
||||
static FT_Face face;
|
||||
|
||||
void draw_glyph(FT_Bitmap *bitmap, u32 x, u32 y, u32 color) {
|
||||
u32 framex, framey;
|
||||
u8* imageptr = bitmap->buffer;
|
||||
|
||||
for (u32 tmpy = 0; tmpy < bitmap->rows; tmpy++) {
|
||||
for (u32 tmpx = 0; tmpx < bitmap->width; tmpx++) {
|
||||
framex = x + tmpx;
|
||||
framey = y + tmpy;
|
||||
|
||||
// color calculation is extremely simplistic and only supports 0 or 0xff in each element for proper antialiasing
|
||||
framebuf[framey * framebuf_width + framex] = RGBA8_MAXALPHA(imageptr[tmpx], imageptr[tmpx], imageptr[tmpx]) & color;
|
||||
}
|
||||
|
||||
imageptr += bitmap->pitch;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_line(u32 x, u32 y, u32 length, u32 color) {
|
||||
for (u32 tmpx = x; tmpx < x + length; tmpx++)
|
||||
framebuf[y * framebuf_width + tmpx] = color;
|
||||
}
|
||||
|
||||
void draw_set_rect(u32 x, u32 y, u32 width, u32 height, u32 color) {
|
||||
for (u32 tmpy = y; tmpy < y + height; tmpy++)
|
||||
draw_line(x, tmpy, width, color);
|
||||
}
|
||||
|
||||
void draw_text(u32 x, u32 y, u32 color, const char *str) {
|
||||
u32 tmpx = x;
|
||||
FT_UInt glyph_index;
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
|
||||
for (size_t i = 0; i < strlen(str); i++) {
|
||||
if (str[i] == '\n') {
|
||||
tmpx = x;
|
||||
y += face->size->metrics.height / 64;
|
||||
continue;
|
||||
}
|
||||
|
||||
glyph_index = FT_Get_Char_Index(face, (FT_ULong)str[i]);
|
||||
|
||||
if (R_FAILED(FT_Load_Glyph(face, glyph_index, FT_LOAD_COLOR) ||
|
||||
FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL) != 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
draw_glyph(&slot->bitmap, tmpx + slot->bitmap_left, y - slot->bitmap_top, color);
|
||||
|
||||
tmpx += slot->advance.x >> 6;
|
||||
y += slot->advance.y >> 6;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_text_with_time(u32 x, u32 y, u32 color, const char *str, const float time) {
|
||||
char time_str[32];
|
||||
sprintf(time_str, "%1.6f seconds", time);
|
||||
draw_text(x, y, color, str);
|
||||
draw_text(0x190, y, color, time_str);
|
||||
}
|
||||
|
||||
void draw_text_with_time(u32 x, u32 y, u32 color, const char *str, const int64_t time) {
|
||||
draw_text_with_time(x, y, color, str, time / 1000000.0f);
|
||||
}
|
||||
|
||||
void intro() {
|
||||
appletLockExit();
|
||||
|
||||
PlFontData font;
|
||||
|
||||
consoleInit(NULL);
|
||||
|
||||
plGetSharedFontByType(&font, PlSharedFontType_Standard);
|
||||
|
||||
FT_Init_FreeType(&library);
|
||||
FT_New_Memory_Face(library, static_cast<FT_Byte *>(font.address), font.size, 0, &face);
|
||||
FT_Set_Char_Size(face, 0, 6*64, 300, 300);
|
||||
|
||||
gfxSetMode(GfxMode_LinearDouble);
|
||||
framebuf = (u32 *)gfxGetFramebuffer(&framebuf_width, NULL);
|
||||
memset(framebuf, 0, gfxGetFramebufferSize());
|
||||
|
||||
draw_text(0x10, 0x020, YELLOW, "Lockpick! by shchmue");
|
||||
|
||||
draw_set_rect(814, 452 + 42 * 0, 450, 42, RGBA8_MAXALPHA(0xe7, 0x00, 0x00));
|
||||
draw_set_rect(814, 452 + 42 * 1, 450, 42, RGBA8_MAXALPHA(0xff, 0x8c, 0x00));
|
||||
draw_set_rect(814, 452 + 42 * 2, 450, 42, RGBA8_MAXALPHA(0xff, 0xef, 0x00));
|
||||
draw_set_rect(814, 452 + 42 * 3, 450, 42, RGBA8_MAXALPHA(0x00, 0x81, 0x1f));
|
||||
draw_set_rect(814, 452 + 42 * 4, 450, 42, RGBA8_MAXALPHA(0x00, 0x44, 0xff));
|
||||
draw_set_rect(814, 452 + 42 * 5, 450, 42, RGBA8_MAXALPHA(0x76, 0x00, 0x89));
|
||||
|
||||
if ( !(envIsSyscallHinted(0x60) && // svcDebugActiveProcess
|
||||
envIsSyscallHinted(0x63) && // svcGetDebugEvent
|
||||
envIsSyscallHinted(0x65) && // svcGetProcessList
|
||||
envIsSyscallHinted(0x69) && // svcQueryDebugProcessMemory
|
||||
envIsSyscallHinted(0x6a))) { // svcReadDebugProcessMemory
|
||||
draw_text(0x190, 0x20, RED, "Error: Please run with debug svc permissions!");
|
||||
wait_to_exit(Status_fail);
|
||||
}
|
||||
|
||||
draw_text(0x10, 0x080, CYAN, "Get Tegra keys...");
|
||||
draw_text(0x10, 0x0a0, CYAN, "Get keys from memory...");
|
||||
draw_text(0x10, 0x0c0, CYAN, "Get master keys...");
|
||||
draw_text(0x10, 0x0e0, CYAN, "Derive remaining keys...");
|
||||
draw_text(0x10, 0x100, CYAN, "Saving keys to keyfile...");
|
||||
draw_text(0x10, 0x130, CYAN, "Total time elapsed:");
|
||||
|
||||
consoleUpdate(NULL);
|
||||
}
|
||||
|
||||
void get_tegra_keys(Key &sbk, Key &tsec, Key &tsec_root) {
|
||||
// support hekate dump
|
||||
if (!std::filesystem::exists("/backup"))
|
||||
return;
|
||||
for (auto &p : std::filesystem::recursive_directory_iterator("/backup")) {
|
||||
if (sbk.found() && tsec.found())
|
||||
return;
|
||||
if (p.is_regular_file()) {
|
||||
if (!sbk.found() && (p.file_size() == 0x2fc) &&
|
||||
(std::string("fuse").compare(std::string(p.path().filename()).substr(0, 4)) == 0))
|
||||
{
|
||||
std::ifstream fuse_file(p.path(), std::ios::binary);
|
||||
byte_vector temp_key(0x10);
|
||||
fuse_file.seekg(0xa4);
|
||||
fuse_file.read(reinterpret_cast<char *>(temp_key.data()), 0x10);
|
||||
sbk = Key("secure_boot_key", 0x10, temp_key);
|
||||
}
|
||||
else if (!tsec.found() && (p.file_size() == 0x30) &&
|
||||
(std::string("tsec").compare(std::string(p.path().filename()).substr(0, 4)) == 0))
|
||||
{
|
||||
std::ifstream tsec_file(p.path(), std::ios::binary);
|
||||
byte_vector temp_key(0x10);
|
||||
tsec_file.read(reinterpret_cast<char *>(temp_key.data()), 0x10);
|
||||
tsec = Key("tsec_key", 0x10, temp_key);
|
||||
tsec_file.read(reinterpret_cast<char *>(temp_key.data()), 0x10);
|
||||
tsec_root.find_key(temp_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// support biskeydump v7 dump
|
||||
if (std::filesystem::exists("/device.keys")) {
|
||||
std::ifstream key_file("/device.keys");
|
||||
for (std::string line; std::getline(key_file, line); !sbk.found() && !tsec.found()) {
|
||||
line.erase(std::remove_if(
|
||||
line.begin(), line.end(),
|
||||
[l = std::locale{}](auto ch) { return std::isspace(ch, l); }
|
||||
), line.end());
|
||||
if (line.substr(0, 15).compare("secure_boot_key") == 0)
|
||||
sbk = Key("secure_boot_key", 0x10, key_string_to_byte_vector(line));
|
||||
else if (line.substr(0, 8).compare("tsec_key") == 0)
|
||||
tsec = Key("tsec_key", 0x10, key_string_to_byte_vector(line));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wait_to_exit(int status) {
|
||||
if (status == Status_fail)
|
||||
draw_text(0x1f4, 0x080, RED, ">> Press + to exit <<");
|
||||
else if (status == Status_success_no_titlekeys)
|
||||
draw_text(0x1f4, 0x1a0, GREEN, ">> Press + to exit <<");
|
||||
else if (status == Status_success_titlekeys)
|
||||
draw_text(0x1f4, 0x1f0, GREEN, ">> Press + to exit <<");
|
||||
else if (status == Status_success_titlekeys_failed)
|
||||
draw_text(0x1f4, 0x1f0, RED, ">> Press + to exit <<");
|
||||
|
||||
while(appletMainLoop() & (status != Status_success_no_titlekeys)) {
|
||||
hidScanInput();
|
||||
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
if (kDown & KEY_PLUS) break;
|
||||
|
||||
consoleUpdate(NULL);
|
||||
}
|
||||
|
||||
FT_Done_Face(face);
|
||||
FT_Done_FreeType(library);
|
||||
|
||||
consoleExit(NULL);
|
||||
|
||||
appletUnlockExit();
|
||||
}
|
||||
|
||||
void sha256(const u8 *data, u8 *hash, size_t length) {
|
||||
struct sha256_state ctx;
|
||||
sha256_init(&ctx);
|
||||
sha256_update(&ctx, data, length);
|
||||
sha256_finalize(&ctx);
|
||||
sha256_finish(&ctx, hash);
|
||||
}
|
||||
|
||||
byte_vector key_string_to_byte_vector(std::string key_string) {
|
||||
key_string = key_string.substr(key_string.find('=') + 1);
|
||||
byte_vector temp_key(key_string.size() / 2);
|
||||
for (size_t i = 0; i < temp_key.size(); i += 8)
|
||||
*reinterpret_cast<u64 *>(temp_key.data() + i) = __bswap64(strtoul(key_string.substr(i * 2, 0x10).c_str(), NULL, 16));
|
||||
return temp_key;
|
||||
}
|
||||
}
|
63
source/Common.hpp
Normal file
63
source/Common.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2018 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Key.hpp"
|
||||
|
||||
#include <ft2build.h>
|
||||
#include <switch.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
#define GREEN RGBA8_MAXALPHA(0, 0xff, 0)
|
||||
#define RED RGBA8_MAXALPHA(0xff, 0, 0)
|
||||
#define CYAN RGBA8_MAXALPHA(0, 0xff, 0xff)
|
||||
#define YELLOW RGBA8_MAXALPHA(0xff, 0xff, 0)
|
||||
|
||||
enum {
|
||||
Status_fail = 0,
|
||||
Status_success_no_titlekeys,
|
||||
Status_success_titlekeys,
|
||||
Status_success_titlekeys_failed
|
||||
};
|
||||
|
||||
class Key;
|
||||
|
||||
namespace Common {
|
||||
// draw letter, called by draw_text
|
||||
void draw_glyph(FT_Bitmap *bitmap, u32 x, u32 y, u32 color);
|
||||
// draw horizontal line
|
||||
void draw_line(u32 x, u32 y, u32 length, u32 color);
|
||||
// draw filled rectangle
|
||||
void draw_set_rect(u32 x, u32 y, u32 width, u32 height, u32 color);
|
||||
// draw string
|
||||
void draw_text(u32 x, u32 y, u32 color, const char *str);
|
||||
// draw string and time elapsed
|
||||
void draw_text_with_time(u32 x, u32 y, u32 color, const char *str, const float time);
|
||||
// overload for microseconds
|
||||
void draw_text_with_time(u32 x, u32 y, u32 color, const char *str, const int64_t time);
|
||||
|
||||
// init font and draw interface
|
||||
void intro();
|
||||
// get tegra keys from payload dump
|
||||
void get_tegra_keys(Key &sbk, Key &tsec, Key &tsec_root);
|
||||
// print exit in color green or red (fail==true)
|
||||
void wait_to_exit(int status);
|
||||
|
||||
void sha256(const u8 *data, u8 *hash, size_t length);
|
||||
// reads "<keyname> = <hexkey>" and returns byte vector
|
||||
std::vector<u8> key_string_to_byte_vector(std::string key_string);
|
||||
}
|
166
source/Key.cpp
Normal file
166
source/Key.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2018 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Key.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
|
||||
#include <mbedtls/aes.h>
|
||||
#include <mbedtls/cmac.h>
|
||||
|
||||
#include "xxhash64.h"
|
||||
|
||||
size_t Key::saved_key_count = 0;
|
||||
|
||||
Key::Key(std::string name, u64 xx_hash, byte_vector hash, u8 length, byte_vector key) :
|
||||
key(key),
|
||||
name(name),
|
||||
xx_hash(xx_hash),
|
||||
hash(hash),
|
||||
length(length)
|
||||
{
|
||||
}
|
||||
|
||||
// init with hash only
|
||||
Key::Key(std::string name, u64 xx_hash, byte_vector hash, u8 length) :
|
||||
Key(name, xx_hash, hash, length, {})
|
||||
{
|
||||
}
|
||||
|
||||
// init with key only
|
||||
Key::Key(std::string name, u8 length, byte_vector key) :
|
||||
Key(name, {}, {}, length, key)
|
||||
{
|
||||
is_found = true;
|
||||
}
|
||||
|
||||
// nameless key
|
||||
Key::Key(byte_vector key, u8 length) :
|
||||
Key({}, {}, {}, length, key)
|
||||
{
|
||||
is_found = true;
|
||||
}
|
||||
|
||||
// key to be assigned later
|
||||
Key::Key(std::string name, u8 length) :
|
||||
Key(name, {}, {}, length, {})
|
||||
{
|
||||
}
|
||||
|
||||
// declare only
|
||||
Key::Key() :
|
||||
Key({}, {}, {}, {}, {})
|
||||
{
|
||||
}
|
||||
|
||||
void Key::save_key(std::ofstream &file) {
|
||||
if (!found())
|
||||
return;
|
||||
|
||||
// format: <keyname> = <hex key> for hactool and similar tools
|
||||
char key_chars[3] = "00";
|
||||
file.write(name.c_str(), name.size());
|
||||
file.write(" = ", 3);
|
||||
for (u8 c : key) {
|
||||
sprintf(key_chars, "%02x", c);
|
||||
file.write(key_chars, 2);
|
||||
}
|
||||
file.write("\n", 1);
|
||||
|
||||
saved_key_count++;
|
||||
}
|
||||
|
||||
byte_vector Key::aes_decrypt_ctr(const byte_vector &data, byte_vector iv) {
|
||||
byte_vector dest(data.size());
|
||||
if (!found())
|
||||
return dest;
|
||||
|
||||
// used internally
|
||||
size_t nc_off = 0;
|
||||
u8 stream_block[0x10];
|
||||
|
||||
mbedtls_aes_context dec;
|
||||
mbedtls_aes_init(&dec);
|
||||
mbedtls_aes_setkey_enc(&dec, key.data(), length * 8);
|
||||
mbedtls_aes_crypt_ctr(&dec, data.size(), &nc_off, iv.data(), stream_block, data.data(), dest.data());
|
||||
mbedtls_aes_free(&dec);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
byte_vector Key::aes_decrypt_ecb(const byte_vector &data) {
|
||||
byte_vector dest(data.size());
|
||||
if (!found())
|
||||
return dest;
|
||||
|
||||
mbedtls_aes_context dec;
|
||||
mbedtls_aes_init(&dec);
|
||||
mbedtls_aes_setkey_dec(&dec, key.data(), length * 8);
|
||||
for (size_t offset = 0; offset < data.size(); offset += 0x10)
|
||||
mbedtls_aes_crypt_ecb(&dec, MBEDTLS_AES_DECRYPT, data.data() + offset, dest.data() + offset);
|
||||
mbedtls_aes_free(&dec);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
byte_vector Key::cmac(byte_vector data) {
|
||||
byte_vector dest(data.size());
|
||||
if (!found())
|
||||
return dest;
|
||||
|
||||
mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), key.data(), length * 8, data.data(), data.size(), dest.data());
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
void Key::find_key(const byte_vector &buffer) {
|
||||
if ((buffer.size() == 0) || (found()))
|
||||
return;
|
||||
|
||||
u8 temp_hash[0x20];
|
||||
|
||||
if (buffer.size() == length) {
|
||||
Common::sha256(buffer.data(), temp_hash, length);
|
||||
if (!std::equal(hash.begin(), hash.end(), temp_hash))
|
||||
return;
|
||||
std::copy(buffer.begin(), buffer.begin() + length, std::back_inserter(key));
|
||||
is_found = true;
|
||||
}
|
||||
|
||||
// hash every length-sized byte chunk in buffer until it matches member hash
|
||||
for (size_t i = 0; i < buffer.size() - length; i++) {
|
||||
if (xx_hash == XXHash64::hash(buffer.data() + i, length, 0)) {
|
||||
// double-check sha256 since xxhash64 isn't as collision-safe
|
||||
Common::sha256(buffer.data() + i, temp_hash, length);
|
||||
if (!std::equal(hash.begin(), hash.end(), temp_hash))
|
||||
continue;
|
||||
std::copy(buffer.begin() + i, buffer.begin() + i + length, std::back_inserter(key));
|
||||
is_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte_vector Key::generate_kek(Key &master_key, const Key &kek_seed, const Key &key_seed) {
|
||||
Key kek(master_key.aes_decrypt_ecb(kek_seed.key), 0x10);
|
||||
Key srcKek(kek.aes_decrypt_ecb(key), 0x10);
|
||||
if (key_seed.found())
|
||||
return srcKek.aes_decrypt_ecb(key_seed.key);
|
||||
else
|
||||
return srcKek.key;
|
||||
}
|
72
source/Key.hpp
Normal file
72
source/Key.hpp
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2018 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
typedef std::vector<u8> byte_vector;
|
||||
|
||||
class Key {
|
||||
public:
|
||||
Key(std::string name, u64 xx_hash, byte_vector hash, u8 length, byte_vector key);
|
||||
// init with hash only
|
||||
Key(std::string name, u64 xx_hash, byte_vector hash, u8 length);
|
||||
// init with key only
|
||||
Key(std::string name, u8 length, byte_vector key);
|
||||
// temp key, no name stored
|
||||
Key(byte_vector key, u8 length);
|
||||
// key to be assigned later
|
||||
Key(std::string name, u8 length);
|
||||
// for declaration only
|
||||
Key();
|
||||
|
||||
bool found() const { return is_found; }
|
||||
void set_found() { is_found = true; }
|
||||
|
||||
// write key to file
|
||||
void save_key(std::ofstream &file);
|
||||
|
||||
static const size_t get_saved_key_count() { return saved_key_count; }
|
||||
|
||||
// return CTR-decrypted data
|
||||
byte_vector aes_decrypt_ctr(const byte_vector &data, byte_vector iv);
|
||||
// return ECB-decrypted data
|
||||
byte_vector aes_decrypt_ecb(const byte_vector &data);
|
||||
// return CMAC of data
|
||||
byte_vector cmac(byte_vector data);
|
||||
// find key in buffer by hash, optionally specify start offset
|
||||
void find_key(const byte_vector &buffer);
|
||||
// get key encryption key
|
||||
byte_vector generate_kek(Key &master_key, const Key &kek_seed, const Key &key_seed);
|
||||
|
||||
byte_vector key;
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
u64 xx_hash;
|
||||
byte_vector hash;
|
||||
u8 length;
|
||||
bool is_found = false;
|
||||
|
||||
static size_t saved_key_count;
|
||||
};
|
650
source/KeyCollection.cpp
Normal file
650
source/KeyCollection.cpp
Normal file
@ -0,0 +1,650 @@
|
||||
/*
|
||||
* Copyright (c) 2018 shchmue
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "KeyCollection.hpp"
|
||||
|
||||
#include "Common.hpp"
|
||||
#include "creport_debug_types.hpp"
|
||||
#include "Stopwatch.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
|
||||
extern "C" {
|
||||
#include "set_ext.h"
|
||||
}
|
||||
|
||||
const u8 KeyCollection::null_hash[0x20] = { // hash of empty string
|
||||
0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14, 0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24,
|
||||
0x27, 0xAE, 0x41, 0xE4, 0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55};
|
||||
|
||||
// function timer
|
||||
template<typename Duration = std::chrono::microseconds, typename FT, typename ... Args>
|
||||
typename Duration::rep profile(FT&& fun, Args&&... args) {
|
||||
const auto beg = std::chrono::high_resolution_clock::now();
|
||||
std::invoke(fun, std::forward<Args>(args)...);//std::forward<FT>(fun)(std::forward<Args>(args)...);
|
||||
const auto end = std::chrono::high_resolution_clock::now();
|
||||
return std::chrono::duration_cast<Duration>(end - beg).count();
|
||||
}
|
||||
|
||||
KeyCollection::KeyCollection() {
|
||||
// init all key hashes
|
||||
u8 index = 0;
|
||||
char keynum[] = "00";
|
||||
|
||||
for (auto key : std::vector<byte_vector>
|
||||
{
|
||||
{0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3},
|
||||
{0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC},
|
||||
{0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B},
|
||||
{0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE},
|
||||
{0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80},
|
||||
{0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0}
|
||||
})
|
||||
{
|
||||
sprintf(keynum, "%02x", index++);
|
||||
keyblob_key_source.push_back(Key {"keyblob_key_source_" + std::string(keynum), 0x10, key});
|
||||
}
|
||||
|
||||
for (auto key : std::vector<byte_vector>
|
||||
{
|
||||
{0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */
|
||||
{0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */
|
||||
{0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */
|
||||
{0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */
|
||||
{0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */
|
||||
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
|
||||
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
|
||||
})
|
||||
{
|
||||
mkey_vector.push_back(Key {key, 0x10});
|
||||
}
|
||||
|
||||
master_kek_source.resize(KNOWN_KEYBLOBS);
|
||||
master_kek_source.push_back(Key {"master_kek_source_06", 0x10, {
|
||||
0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}});
|
||||
|
||||
//======================================Keys======================================//
|
||||
// from Package1 -> TrustZone (Secure Monitor)
|
||||
aes_kek_generation_source = {"aes_kek_generation_source", 0x10, {
|
||||
0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9}};
|
||||
aes_kek_seed_01 = {"aes_kek_seed_01", 0x10, {
|
||||
0xA2, 0xAB, 0xBF, 0x9C, 0x92, 0x2F, 0xBB, 0xE3, 0x78, 0x79, 0x9B, 0xC0, 0xCC, 0xEA, 0xA5, 0x74}};
|
||||
aes_kek_seed_03 = {"aes_kek_seed_03", 0x10, {
|
||||
0xE5, 0x4D, 0x9A, 0x02, 0xF0, 0x4F, 0x5F, 0xA8, 0xAD, 0x76, 0x0A, 0xF6, 0x32, 0x95, 0x59, 0xBB}};
|
||||
package2_key_source = {"package2_key_source", 0x10, {
|
||||
0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}};
|
||||
titlekek_source = {"titlekek_source", 0x10, {
|
||||
0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B}};
|
||||
retail_specific_aes_key_source = {"retail_specific_aes_key_source", 0x10, {
|
||||
0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95}};
|
||||
|
||||
// from Package1ldr
|
||||
keyblob_mac_key_source = {"keyblob_mac_key_source", 0x10, {
|
||||
0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5}};
|
||||
master_key_source = {"master_key_source", 0x10, {
|
||||
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C}};
|
||||
per_console_key_source = {"per_console_key_source", 0x10, {
|
||||
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78}};
|
||||
|
||||
// from SPL
|
||||
aes_key_generation_source = {"aes_key_generation_source", 0x10, {
|
||||
0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8}};
|
||||
|
||||
// from FS
|
||||
bis_kek_source = {"bis_kek_source", 0x10, {
|
||||
0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F}};
|
||||
bis_key_source_00 = {"bis_key_source_00", 0x20, {
|
||||
0xF8, 0x3F, 0x38, 0x6E, 0x2C, 0xD2, 0xCA, 0x32, 0xA8, 0x9A, 0xB9, 0xAA, 0x29, 0xBF, 0xC7, 0x48,
|
||||
0x7D, 0x92, 0xB0, 0x3A, 0xA8, 0xBF, 0xDE, 0xE1, 0xA7, 0x4C, 0x3B, 0x6E, 0x35, 0xCB, 0x71, 0x06}};
|
||||
bis_key_source_01 = {"bis_key_source_01", 0x20, {
|
||||
0x41, 0x00, 0x30, 0x49, 0xDD, 0xCC, 0xC0, 0x65, 0x64, 0x7A, 0x7E, 0xB4, 0x1E, 0xED, 0x9C, 0x5F,
|
||||
0x44, 0x42, 0x4E, 0xDA, 0xB4, 0x9D, 0xFC, 0xD9, 0x87, 0x77, 0x24, 0x9A, 0xDC, 0x9F, 0x7C, 0xA4}};
|
||||
bis_key_source_02 = {"bis_key_source_02", 0x20, {
|
||||
0x52, 0xC2, 0xE9, 0xEB, 0x09, 0xE3, 0xEE, 0x29, 0x32, 0xA1, 0x0C, 0x1F, 0xB6, 0xA0, 0x92, 0x6C,
|
||||
0x4D, 0x12, 0xE1, 0x4B, 0x2A, 0x47, 0x4C, 0x1C, 0x09, 0xCB, 0x03, 0x59, 0xF0, 0x15, 0xF4, 0xE4}};
|
||||
|
||||
//=====================================Hashes=====================================//
|
||||
// from FS
|
||||
header_kek_source = {"header_kek_source", 0x9fd1b07be05b8f4d, {
|
||||
0x18, 0x88, 0xca, 0xed, 0x55, 0x51, 0xb3, 0xed, 0xe0, 0x14, 0x99, 0xe8, 0x7c, 0xe0, 0xd8, 0x68,
|
||||
0x27, 0xf8, 0x08, 0x20, 0xef, 0xb2, 0x75, 0x92, 0x10, 0x55, 0xaa, 0x4e, 0x2a, 0xbd, 0xff, 0xc2}, 0x10};
|
||||
header_key_source = {"header_key_source", 0x3e7228ec5873427b, {
|
||||
0x8f, 0x78, 0x3e, 0x46, 0x85, 0x2d, 0xf6, 0xbe, 0x0b, 0xa4, 0xe1, 0x92, 0x73, 0xc4, 0xad, 0xba,
|
||||
0xee, 0x16, 0x38, 0x00, 0x43, 0xe1, 0xb8, 0xc4, 0x18, 0xc4, 0x08, 0x9a, 0x8b, 0xd6, 0x4a, 0xa6}, 0x20};
|
||||
key_area_key_application_source = {"key_area_key_application_source", 0x0b14ccce20dbb59b, {
|
||||
0x04, 0xad, 0x66, 0x14, 0x3c, 0x72, 0x6b, 0x2a, 0x13, 0x9f, 0xb6, 0xb2, 0x11, 0x28, 0xb4, 0x6f,
|
||||
0x56, 0xc5, 0x53, 0xb2, 0xb3, 0x88, 0x71, 0x10, 0x30, 0x42, 0x98, 0xd8, 0xd0, 0x09, 0x2d, 0x9e}, 0x10};
|
||||
key_area_key_ocean_source = {"key_area_key_ocean_source", 0x055b26945075ff88, {
|
||||
0xfd, 0x43, 0x40, 0x00, 0xc8, 0xff, 0x2b, 0x26, 0xf8, 0xe9, 0xa9, 0xd2, 0xd2, 0xc1, 0x2f, 0x6b,
|
||||
0xe5, 0x77, 0x3c, 0xbb, 0x9d, 0xc8, 0x63, 0x00, 0xe1, 0xbd, 0x99, 0xf8, 0xea, 0x33, 0xa4, 0x17}, 0x10};
|
||||
key_area_key_system_source = {"key_area_key_system_source", 0xb2c28e84e1796251, {
|
||||
0x1f, 0x17, 0xb1, 0xfd, 0x51, 0xad, 0x1c, 0x23, 0x79, 0xb5, 0x8f, 0x15, 0x2c, 0xa4, 0x91, 0x2e,
|
||||
0xc2, 0x10, 0x64, 0x41, 0xe5, 0x17, 0x22, 0xf3, 0x87, 0x00, 0xd5, 0x93, 0x7a, 0x11, 0x62, 0xf7}, 0x10};
|
||||
save_mac_kek_source = {"save_mac_kek_source", 0x1e15ac1f6f21a26a, {
|
||||
0x3D, 0xCB, 0xA1, 0x00, 0xAD, 0x4D, 0xF1, 0x54, 0x7F, 0xE3, 0xC4, 0x79, 0x5C, 0x4B, 0x22, 0x8A,
|
||||
0xA9, 0x80, 0x38, 0xF0, 0x7A, 0x36, 0xF1, 0xBC, 0x14, 0x8E, 0xEA, 0xF3, 0xDC, 0xD7, 0x50, 0xF4}, 0x10};
|
||||
save_mac_key_source = {"save_mac_key_source", 0x68b9ed0d367e6dc4, {
|
||||
0xB4, 0x7B, 0x60, 0x0B, 0x1A, 0xD3, 0x14, 0xF9, 0x41, 0x14, 0x7D, 0x8B, 0x39, 0x1D, 0x4B, 0x19,
|
||||
0x87, 0xCC, 0x8C, 0x88, 0x4A, 0xC8, 0x9F, 0xFC, 0x91, 0xCA, 0xE2, 0x21, 0xC5, 0x24, 0x51, 0xF7}, 0x10};
|
||||
sd_card_kek_source = {"sd_card_kek_source", 0xc408d710a3b821eb, {
|
||||
0x6B, 0x2E, 0xD8, 0x77, 0xC2, 0xC5, 0x23, 0x34, 0xAC, 0x51, 0xE5, 0x9A, 0xBF, 0xA7, 0xEC, 0x45,
|
||||
0x7F, 0x4A, 0x7D, 0x01, 0xE4, 0x62, 0x91, 0xE9, 0xF2, 0xEA, 0xA4, 0x5F, 0x01, 0x1D, 0x24, 0xB7}, 0x10};
|
||||
sd_card_nca_key_source = {"sd_card_nca_key_source", 0xbea347c9f8472947, {
|
||||
0x2E, 0x75, 0x1C, 0xEC, 0xF7, 0xD9, 0x3A, 0x2B, 0x95, 0x7B, 0xD5, 0xFF, 0xCB, 0x08, 0x2F, 0xD0,
|
||||
0x38, 0xCC, 0x28, 0x53, 0x21, 0x9D, 0xD3, 0x09, 0x2C, 0x6D, 0xAB, 0x98, 0x38, 0xF5, 0xA7, 0xCC}, 0x20};
|
||||
sd_card_save_key_source = {"sd_card_save_key_source", 0xf87fe8c3688c3022, {
|
||||
0xD4, 0x82, 0x74, 0x35, 0x63, 0xD3, 0xEA, 0x5D, 0xCD, 0xC3, 0xB7, 0x4E, 0x97, 0xC9, 0xAC, 0x8A,
|
||||
0x34, 0x21, 0x64, 0xFA, 0x04, 0x1A, 0x1D, 0xC8, 0x0F, 0x17, 0xF6, 0xD3, 0x1E, 0x4B, 0xC0, 0x1C}, 0x20};
|
||||
|
||||
// from ES
|
||||
eticket_rsa_kek_source = {"eticket_rsa_kek_source", 0x76d15de09d439bdc, {
|
||||
0xB7, 0x1D, 0xB2, 0x71, 0xDC, 0x33, 0x8D, 0xF3, 0x80, 0xAA, 0x2C, 0x43, 0x35, 0xEF, 0x88, 0x73,
|
||||
0xB1, 0xAF, 0xD4, 0x08, 0xE8, 0x0B, 0x35, 0x82, 0xD8, 0x71, 0x9F, 0xC8, 0x1C, 0x5E, 0x51, 0x1C}, 0x10};
|
||||
eticket_rsa_kekek_source = {"eticket_rsa_kekek_source", 0x97436d4ff39703da, {
|
||||
0xE8, 0x96, 0x5A, 0x18, 0x7D, 0x30, 0xE5, 0x78, 0x69, 0xF5, 0x62, 0xD0, 0x43, 0x83, 0xC9, 0x96,
|
||||
0xDE, 0x48, 0x7B, 0xBA, 0x57, 0x61, 0x36, 0x3D, 0x2D, 0x4D, 0x32, 0x39, 0x18, 0x66, 0xA8, 0x5C}, 0x10};
|
||||
|
||||
// from SSL
|
||||
ssl_rsa_kek_source_x = {"ssl_rsa_kek_source_x", 0xa7084dadd5d9da93, {
|
||||
0x69, 0xA0, 0x8E, 0x62, 0xE0, 0xAE, 0x50, 0x7B, 0xB5, 0xDA, 0x0E, 0x65, 0x17, 0x9A, 0xE3, 0xBE,
|
||||
0x05, 0x1F, 0xED, 0x3C, 0x49, 0x94, 0x1D, 0xF4, 0xEF, 0x29, 0x56, 0xD3, 0x6D, 0x30, 0x11, 0x0C}, 0x10};
|
||||
ssl_rsa_kek_source_y = {"ssl_rsa_kek_source_y", 0xbafd95c9f258dc4a, {
|
||||
0x1C, 0x86, 0xF3, 0x63, 0x26, 0x54, 0x17, 0xD4, 0x99, 0x22, 0x9E, 0xB1, 0xC4, 0xAD, 0xC7, 0x47,
|
||||
0x9B, 0x2A, 0x15, 0xF9, 0x31, 0x26, 0x1F, 0x31, 0xEE, 0x67, 0x76, 0xAE, 0xB4, 0xC7, 0x65, 0x42}, 0x10};
|
||||
|
||||
// from TSEC
|
||||
tsec_root_key = {"tsec_root_key", 0x57b73665b0bbd424, {
|
||||
0x03, 0x2a, 0xdf, 0x0a, 0x6b, 0xe7, 0xdd, 0x7c, 0x11, 0xa4, 0xfa, 0x5c, 0xd6, 0x4a, 0x15, 0x75,
|
||||
0xe4, 0x69, 0xb9, 0xda, 0x5d, 0x8b, 0xd5, 0x6a, 0x12, 0xd0, 0xfb, 0xc0, 0xeb, 0x84, 0xe8, 0xe7}, 0x10};
|
||||
|
||||
rsa_oaep_kek_generation_source = {"rsa_oaep_kek_generation_source", 0x10};
|
||||
rsa_private_kek_generation_source = {"rsa_private_kek_generation_source", 0x10};
|
||||
|
||||
es_keys = {
|
||||
&eticket_rsa_kek_source,
|
||||
&eticket_rsa_kekek_source
|
||||
};
|
||||
|
||||
fs_rodata_keys = {
|
||||
&bis_kek_source,
|
||||
&bis_key_source_00,
|
||||
&bis_key_source_01,
|
||||
&bis_key_source_02,
|
||||
&header_kek_source,
|
||||
&key_area_key_application_source,
|
||||
&key_area_key_ocean_source,
|
||||
&key_area_key_system_source,
|
||||
&save_mac_kek_source,
|
||||
&save_mac_key_source
|
||||
};
|
||||
|
||||
// only look for sd keys if at least firm 2.0.0
|
||||
if (kernelAbove200()) {
|
||||
fs_rodata_keys.insert(fs_rodata_keys.end(), {
|
||||
&sd_card_kek_source,
|
||||
&sd_card_nca_key_source,
|
||||
&sd_card_save_key_source
|
||||
});
|
||||
}
|
||||
|
||||
package1ldr_keys = {
|
||||
&keyblob_mac_key_source,
|
||||
&master_key_source,
|
||||
&per_console_key_source
|
||||
};
|
||||
|
||||
ssl_keys = {
|
||||
&ssl_rsa_kek_source_x,
|
||||
&ssl_rsa_kek_source_y
|
||||
};
|
||||
|
||||
tz_keys = {
|
||||
&aes_kek_generation_source,
|
||||
&package2_key_source,
|
||||
&titlekek_source,
|
||||
&retail_specific_aes_key_source,
|
||||
&aes_kek_seed_01,
|
||||
&aes_kek_seed_03
|
||||
};
|
||||
};
|
||||
|
||||
int KeyCollection::get_keys() {
|
||||
Stopwatch total_time;
|
||||
total_time.start();
|
||||
|
||||
int64_t profiler_time = profile(Common::get_tegra_keys, sbk, tsec, tsec_root_key);
|
||||
if ((sbk.found() && tsec.found()) || tsec_root_key.found()) {
|
||||
Common::draw_text_with_time(0x10, 0x80, GREEN, "Get Tegra keys...", profiler_time);
|
||||
} else {
|
||||
Common::draw_text(0x010, 0x80, RED, "Get Tegra keys...");
|
||||
Common::draw_text(0x190, 0x80, RED, "Failed");
|
||||
Common::draw_text(0x190, 0x20, RED, "Warning: Saving limited keyset.");
|
||||
Common::draw_text(0x190, 0x40, RED, "Dump Tegra keys with payload and run again to get all keys.");
|
||||
}
|
||||
|
||||
profiler_time = profile(&KeyCollection::get_memory_keys, *this);
|
||||
Common::draw_text_with_time(0x10, 0x0a0, GREEN, "Get keys from memory...", profiler_time);
|
||||
|
||||
profiler_time = profile(&KeyCollection::get_master_keys, *this);
|
||||
Common::draw_text_with_time(0x10, 0x0c0, GREEN, "Get master keys...", profiler_time);
|
||||
|
||||
profiler_time = profile(&KeyCollection::derive_keys, *this);
|
||||
Common::draw_text_with_time(0x10, 0x0e0, GREEN, "Derive remaining keys...", profiler_time);
|
||||
|
||||
profiler_time = profile(&KeyCollection::save_keys, *this);
|
||||
Common::draw_text_with_time(0x10, 0x100, GREEN, "Saving keys to keyfile...", profiler_time);
|
||||
|
||||
total_time.stop();
|
||||
Common::draw_line(0x8, 0x110, 0x280, GREEN);
|
||||
Common::draw_text_with_time(0x10, 0x130, GREEN, "Total time elapsed:", total_time.get_elapsed());
|
||||
|
||||
char keys_str[32];
|
||||
sprintf(keys_str, "Total keys found: %lu", Key::get_saved_key_count());
|
||||
Common::draw_text(0x2a0, 0x130, CYAN, keys_str);
|
||||
|
||||
Common::draw_text(0x30, 0x160, YELLOW, "WARNING: dumping titlekeys may crash homebrew or games UNLESS you reboot afterwards");
|
||||
Common::draw_text(0x160, 0x180, CYAN, ">> Press A to dump titlekeys or + to exit <<");
|
||||
|
||||
for(;;) {
|
||||
hidScanInput();
|
||||
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
if (kDown & KEY_PLUS)
|
||||
return Status_success_no_titlekeys;
|
||||
else if (kDown & KEY_A)
|
||||
break;
|
||||
|
||||
consoleUpdate(NULL);
|
||||
}
|
||||
|
||||
Common::draw_text(0x10, 0x1b0, CYAN, "Dumping titlekeys...");
|
||||
consoleUpdate(NULL);
|
||||
profiler_time = profile(&KeyCollection::get_titlekeys, *this);
|
||||
if (titlekeys_dumped > 0) {
|
||||
Common::draw_text_with_time(0x10, 0x1b0, GREEN, "Dumping titlekeys...", profiler_time);
|
||||
sprintf(keys_str, "Titlekeys found: %lu", titlekeys_dumped);
|
||||
Common::draw_text(0x2a0, 0x1b0, CYAN, keys_str);
|
||||
return Status_success_titlekeys;
|
||||
} else {
|
||||
Common::draw_text(0x010, 0x1b0, RED, "Dumping titlekeys...");
|
||||