From 8e36cbd4e2b864a34e764bd1cc101d64b0e5f467 Mon Sep 17 00:00:00 2001 From: euss <7unicorn@live.nl> Date: Wed, 28 Sep 2011 20:51:51 +0200 Subject: [PATCH] importing --- AUTHORS | 0 COPYING | 339 ++++++++++++ ChangeLog | 0 INSTALL | 365 +++++++++++++ Makefile.am | 136 +++++ NEWS | 0 aes.c | 1314 ++++++++++++++++++++++++++++++++++++++++++++++ aes.h | 30 ++ autogen.sh | 22 + bn.c | 200 +++++++ common.h | 50 ++ configure.ac | 46 ++ cospkg.c | 150 ++++++ cosunpack.c | 64 +++ cosunpkg.c | 69 +++ dat.c | 64 +++ ec.c | 346 ++++++++++++ eidsplitr.c | 72 +++ makeself.c | 595 +++++++++++++++++++++ mingw_mmap.c | 61 +++ mingw_mmap.h | 29 + norunpack.c | 78 +++ pkg.c | 253 +++++++++ pupexplode | 62 +++ puppack.c | 148 ++++++ pupunpack.c | 154 ++++++ readself.c | 587 +++++++++++++++++++++ readself2.c | 1210 ++++++++++++++++++++++++++++++++++++++++++ scekrit.c | 243 +++++++++ sceverify.c | 225 ++++++++ self.c | 446 ++++++++++++++++ self.h | 197 +++++++ self_rebuilder.c | 693 ++++++++++++++++++++++++ sha1.c | 380 ++++++++++++++ sha1.h | 72 +++ spp.c | 189 +++++++ tools.c | 860 ++++++++++++++++++++++++++++++ tools.h | 73 +++ types.h | 147 ++++++ undat.c | 60 +++ ungpkg.c | 142 +++++ unpkg.c | 138 +++++ unself.c | 374 +++++++++++++ unself2.c | 74 +++ unspp.c | 62 +++ 45 files changed, 10819 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 aes.c create mode 100644 aes.h create mode 100644 autogen.sh create mode 100644 bn.c create mode 100644 common.h create mode 100644 configure.ac create mode 100644 cospkg.c create mode 100644 cosunpack.c create mode 100644 cosunpkg.c create mode 100644 dat.c create mode 100644 ec.c create mode 100644 eidsplitr.c create mode 100644 makeself.c create mode 100644 mingw_mmap.c create mode 100644 mingw_mmap.h create mode 100644 norunpack.c create mode 100644 pkg.c create mode 100644 pupexplode create mode 100644 puppack.c create mode 100644 pupunpack.c create mode 100644 readself.c create mode 100644 readself2.c create mode 100644 scekrit.c create mode 100644 sceverify.c create mode 100644 self.c create mode 100644 self.h create mode 100644 self_rebuilder.c create mode 100644 sha1.c create mode 100644 sha1.h create mode 100644 spp.c create mode 100644 tools.c create mode 100644 tools.h create mode 100644 types.h create mode 100644 undat.c create mode 100644 ungpkg.c create mode 100644 unpkg.c create mode 100644 unself.c create mode 100644 unself2.c create mode 100644 unspp.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..e69de29 diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/COPYING @@ -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. + + + Copyright (C) + + 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. + + , 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. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..7d1c323 --- /dev/null +++ b/INSTALL @@ -0,0 +1,365 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007, 2008, 2009 Free Software Foundation, Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..16dc5d0 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,136 @@ +# Makefile.am for ps3tools +# +# (C) Youness Alaoui (KaKaRoTo) +# +# Licensed under LGPL 2.1. See file COPYING. + +ERROR_CFLAGS = \ + $(PS3TOOLS_CFLAGS) \ + -fno-strict-aliasing \ + -Wextra \ + -Wundef \ + -Wnested-externs \ + -Wwrite-strings \ + -Wpointer-arith \ + -Wbad-function-cast \ + -Wmissing-declarations \ + -Wmissing-prototypes \ + -Wstrict-prototypes \ + -Wredundant-decls \ + -Wno-unused-parameter \ + -Wno-missing-field-initializers + +AM_CFLAGS = \ + $(ERROR_CFLAGS) \ + $(ZLIB_CFLAGS) + +bin_PROGRAMS = sceverify \ + readself \ + readself2 \ + unself \ + unself2 \ + makeself \ + self_rebuilder \ + ungpkg \ + norunpack \ + pupunpack \ + puppack \ + unpkg \ + pkg \ + cosunpkg \ + cospkg \ + cosunpack \ + undat \ + dat \ + unspp \ + eidsplitr \ + spp + +if HAVE_LIBGMP + bin_PROGRAMS += scekrit +endif + +SELF_DEPS = self.c \ + self.h \ + common.h + +COMMON_DEPS = types.h \ + tools.c \ + tools.h \ + aes.c \ + aes.h \ + sha1.c \ + sha1.h \ + ec.c \ + bn.c \ + mingw_mmap.c \ + mingw_mmap.h + +sceverify_SOURCES = $(COMMON_DEPS) \ + sceverify.c + +readself_SOURCES = $(COMMON_DEPS) \ + readself.c + +readself2_SOURCES = $(COMMON_DEPS) \ + readself2.c + +unself_SOURCES = $(COMMON_DEPS) \ + unself.c + +unself2_SOURCES = $(COMMON_DEPS) \ + $(SELF_DEPS) \ + unself2.c + +makeself_SOURCES = $(COMMON_DEPS) \ + makeself.c + +self_rebuilder_SOURCES = $(COMMON_DEPS) \ + self_rebuilder.c + +ungpkg_SOURCES = $(COMMON_DEPS) \ + ungpkg.c + +norunpack_SOURCES = $(COMMON_DEPS) \ + norunpack.c + +pupunpack_SOURCES = $(COMMON_DEPS) \ + pupunpack.c + +puppack_SOURCES = $(COMMON_DEPS) \ + puppack.c + +unpkg_SOURCES = $(COMMON_DEPS) \ + unpkg.c + +pkg_SOURCES = $(COMMON_DEPS) \ + pkg.c + +cosunpkg_SOURCES = $(COMMON_DEPS) \ + cosunpkg.c + +cospkg_SOURCES = $(COMMON_DEPS) \ + cospkg.c + +cosunpack_SOURCES = $(COMMON_DEPS) \ + cosunpack.c + +undat_SOURCES = $(COMMON_DEPS) \ + undat.c + +dat_SOURCES = $(COMMON_DEPS) \ + dat.c + +unspp_SOURCES = $(COMMON_DEPS) \ + unspp.c + +eidsplitr_SOURCES = $(COMMON_DEPS) \ + eidsplitr.c + +scekrit_SOURCES = $(COMMON_DEPS) \ + scekrit.c +scekrit_LDADD = $(GMP_LIBS) + +spp_SOURCES = $(COMMON_DEPS) \ + spp.c + unspp.c diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/aes.c b/aes.c new file mode 100644 index 0000000..7528a94 --- /dev/null +++ b/aes.c @@ -0,0 +1,1314 @@ +/** + * + * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project. + */ +/* + * rijndael-alg-fst.c + * + * @version 3.0 (December 2000) + * + * Optimised ANSI C code for the Rijndael cipher (now AES) + * + * @author Vincent Rijmen + * @author Antoon Bosselaers + * @author Paulo Barreto + * + * This code is hereby placed in the public domain. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "tools.h" +#include "aes.h" + +#define MAXKC (256/32) +#define MAXKB (256/8) +#define MAXNR 14 + +/* This controls loop-unrolling in aes_core.c */ +#undef FULL_UNROLL +# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3])) +# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } + +/* +Te0[x] = S [x].[02, 01, 01, 03]; +Te1[x] = S [x].[03, 02, 01, 01]; +Te2[x] = S [x].[01, 03, 02, 01]; +Te3[x] = S [x].[01, 01, 03, 02]; +Te4[x] = S [x].[01, 01, 01, 01]; + +Td0[x] = Si[x].[0e, 09, 0d, 0b]; +Td1[x] = Si[x].[0b, 0e, 09, 0d]; +Td2[x] = Si[x].[0d, 0b, 0e, 09]; +Td3[x] = Si[x].[09, 0d, 0b, 0e]; +Td4[x] = Si[x].[01, 01, 01, 01]; +*/ + +static const u32 Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, + 0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, + 0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU, + 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU, + 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, + 0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, + 0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU, + 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU, + 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, + 0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU, + 0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU, + 0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U, + 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, + 0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, + 0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU, + 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU, + 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, + 0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, + 0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU, + 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU, + 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, + 0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, + 0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U, + 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU, + 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, + 0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, + 0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU, + 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U, + 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, + 0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, + 0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U, + 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU, + 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, + 0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, + 0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U, + 0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU, + 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, + 0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, + 0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U, + 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U, + 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, + 0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, + 0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU, + 0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U, + 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, + 0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U, + 0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U, + 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U, + 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, + 0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, + 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, + 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, +}; +static const u32 Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, + 0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, + 0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU, + 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U, + 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, + 0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, + 0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U, + 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U, + 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, + 0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, + 0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U, + 0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU, + 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, + 0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, + 0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U, + 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U, + 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, + 0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, + 0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U, + 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU, + 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, + 0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, + 0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U, + 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU, + 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, + 0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, + 0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU, + 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U, + 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, + 0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, + 0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U, + 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U, + 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, + 0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, + 0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U, + 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U, + 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, + 0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, + 0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U, + 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU, + 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, + 0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, + 0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U, + 0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU, + 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, + 0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, + 0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U, + 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U, + 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, + 0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, + 0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU, + 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U, +}; +static const u32 Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, + 0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, + 0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU, + 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U, + 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, + 0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, + 0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U, + 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U, + 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, + 0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U, + 0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U, + 0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU, + 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, + 0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, + 0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U, + 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U, + 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, + 0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, + 0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U, + 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU, + 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, + 0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, + 0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U, + 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU, + 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, + 0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, + 0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU, + 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U, + 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, + 0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, + 0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U, + 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U, + 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, + 0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, + 0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U, + 0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U, + 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, + 0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, + 0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U, + 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU, + 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, + 0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, + 0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U, + 0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU, + 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, + 0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U, + 0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U, + 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U, + 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, + 0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, + 0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU, + 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U, +}; +static const u32 Te3[256] = { + + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, + 0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, + 0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U, + 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU, + 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, + 0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, + 0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU, + 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU, + 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, + 0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU, + 0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU, + 0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU, + 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, + 0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, + 0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU, + 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU, + 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, + 0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, + 0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U, + 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U, + 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, + 0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, + 0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU, + 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U, + 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, + 0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, + 0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U, + 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU, + 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, + 0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, + 0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU, + 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U, + 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, + 0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, + 0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U, + 0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U, + 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, + 0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, + 0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U, + 0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU, + 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, + 0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, + 0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU, + 0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU, + 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, + 0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U, + 0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U, + 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U, + 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, + 0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, + 0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU, + 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU, +}; +static const u32 Te4[256] = { + 0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU, + 0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U, + 0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU, + 0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U, + 0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU, + 0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U, + 0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU, + 0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U, + 0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U, + 0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU, + 0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U, + 0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U, + 0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U, + 0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU, + 0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U, + 0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U, + 0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU, + 0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U, + 0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U, + 0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U, + 0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU, + 0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU, + 0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U, + 0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU, + 0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU, + 0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U, + 0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU, + 0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U, + 0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU, + 0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U, + 0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U, + 0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U, + 0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU, + 0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U, + 0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU, + 0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U, + 0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU, + 0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U, + 0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U, + 0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU, + 0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU, + 0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU, + 0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U, + 0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U, + 0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU, + 0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U, + 0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU, + 0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U, + 0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU, + 0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U, + 0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU, + 0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU, + 0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U, + 0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU, + 0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U, + 0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU, + 0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U, + 0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U, + 0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U, + 0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU, + 0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU, + 0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U, + 0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU, + 0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U, +}; +static const u32 Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, + 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, + 0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U, + 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU, + 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, + 0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU, + 0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U, + 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU, + 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, + 0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, + 0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U, + 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU, + 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, + 0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, + 0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU, + 0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U, + 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, + 0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU, + 0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U, + 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU, + 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, + 0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U, + 0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU, + 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU, + 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, + 0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, + 0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU, + 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U, + 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, + 0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, + 0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U, + 0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U, + 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, + 0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, + 0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U, + 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U, + 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, + 0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, + 0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U, + 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U, + 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, + 0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, + 0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU, + 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU, + 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, + 0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, + 0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU, + 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU, + 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, + 0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U, + 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, + 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, +}; +static const u32 Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, + 0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U, + 0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU, + 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U, + 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, + 0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U, + 0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U, + 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U, + 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, + 0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, + 0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U, + 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU, + 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, + 0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, + 0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU, + 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU, + 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, + 0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U, + 0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU, + 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU, + 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, + 0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U, + 0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU, + 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U, + 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, + 0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, + 0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U, + 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU, + 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, + 0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, + 0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U, + 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U, + 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, + 0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, + 0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U, + 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU, + 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, + 0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, + 0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U, + 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU, + 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, + 0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, + 0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U, + 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U, + 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, + 0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, + 0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U, + 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U, + 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, + 0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, + 0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U, + 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U, +}; +static const u32 Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, + 0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, + 0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U, + 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U, + 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, + 0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, + 0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U, + 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U, + 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, + 0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, + 0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU, + 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U, + 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, + 0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, + 0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U, + 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U, + 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, + 0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, + 0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U, + 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U, + 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, + 0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU, + 0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U, + 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU, + 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, + 0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, + 0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU, + 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU, + 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, + 0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, + 0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U, + 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U, + 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, + 0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, + 0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU, + 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U, + 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, + 0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, + 0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U, + 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U, + 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, + 0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, + 0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U, + 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U, + 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, + 0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, + 0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U, + 0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U, + 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, + 0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, + 0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U, + 0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U, +}; +static const u32 Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, + 0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, + 0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U, + 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U, + 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, + 0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, + 0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU, + 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U, + 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, + 0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, + 0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U, + 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U, + 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, + 0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, + 0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U, + 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U, + 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, + 0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, + 0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U, + 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U, + 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, + 0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U, + 0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U, + 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU, + 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, + 0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, + 0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U, + 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU, + 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, + 0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, + 0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U, + 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U, + 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, + 0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, + 0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U, + 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U, + 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, + 0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, + 0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU, + 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U, + 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, + 0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, + 0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U, + 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U, + 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, + 0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, + 0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU, + 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U, + 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, + 0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, + 0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U, + 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U, +}; +static const u32 Td4[256] = { + 0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U, + 0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U, + 0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU, + 0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU, + 0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U, + 0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U, + 0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U, + 0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU, + 0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U, + 0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU, + 0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU, + 0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU, + 0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U, + 0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U, + 0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U, + 0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U, + 0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U, + 0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U, + 0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU, + 0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U, + 0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U, + 0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU, + 0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U, + 0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U, + 0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U, + 0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU, + 0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U, + 0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U, + 0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU, + 0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U, + 0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U, + 0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU, + 0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U, + 0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU, + 0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU, + 0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U, + 0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U, + 0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U, + 0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U, + 0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU, + 0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U, + 0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U, + 0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU, + 0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU, + 0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU, + 0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U, + 0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU, + 0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U, + 0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U, + 0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U, + 0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U, + 0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU, + 0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U, + 0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU, + 0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU, + 0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU, + 0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU, + 0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U, + 0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU, + 0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U, + 0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU, + 0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U, + 0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U, + 0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU, +}; +static const u32 rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, + 0x10000000, 0x20000000, 0x40000000, 0x80000000, + 0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +/** + * Expand the cipher key into the encryption key schedule. + */ +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key) { + + u32 *rk; + int i = 0; + u32 temp; + + if (!userKey || !key) + return -1; + if (bits != 128 && bits != 192 && bits != 256) + return -2; + + rk = key->rd_key; + + if (bits==128) + key->rounds = 10; + else if (bits==192) + key->rounds = 12; + else + key->rounds = 14; + + rk[0] = GETU32(userKey ); + rk[1] = GETU32(userKey + 4); + rk[2] = GETU32(userKey + 8); + rk[3] = GETU32(userKey + 12); + if (bits == 128) { + while (1) { + temp = rk[3]; + rk[4] = rk[0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + return 0; + } + rk += 4; + } + } + rk[4] = GETU32(userKey + 16); + rk[5] = GETU32(userKey + 20); + if (bits == 192) { + while (1) { + temp = rk[ 5]; + rk[ 6] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 7] = rk[ 1] ^ rk[ 6]; + rk[ 8] = rk[ 2] ^ rk[ 7]; + rk[ 9] = rk[ 3] ^ rk[ 8]; + if (++i == 8) { + return 0; + } + rk[10] = rk[ 4] ^ rk[ 9]; + rk[11] = rk[ 5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(userKey + 24); + rk[7] = GETU32(userKey + 28); + if (bits == 256) { + while (1) { + temp = rk[ 7]; + rk[ 8] = rk[ 0] ^ + (Te4[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te4[(temp ) & 0xff] & 0x0000ff00) ^ + (Te4[(temp >> 24) ] & 0x000000ff) ^ + rcon[i]; + rk[ 9] = rk[ 1] ^ rk[ 8]; + rk[10] = rk[ 2] ^ rk[ 9]; + rk[11] = rk[ 3] ^ rk[10]; + if (++i == 7) { + return 0; + } + temp = rk[11]; + rk[12] = rk[ 4] ^ + (Te4[(temp >> 24) ] & 0xff000000) ^ + (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(temp ) & 0xff] & 0x000000ff); + rk[13] = rk[ 5] ^ rk[12]; + rk[14] = rk[ 6] ^ rk[13]; + rk[15] = rk[ 7] ^ rk[14]; + + rk += 8; + } + } + return 0; +} + +/** + * Expand the cipher key into the decryption key schedule. + */ +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key) { + + u32 *rk; + int i, j, status; + u32 temp; + + /* first, start with an encryption schedule */ + status = AES_set_encrypt_key(userKey, bits, key); + if (status < 0) + return status; + + rk = key->rd_key; + + /* invert the order of the round keys: */ + for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) { + temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp; + temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp; + temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp; + temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and the last: */ + for (i = 1; i < (key->rounds); i++) { + rk += 4; + rk[0] = + Td0[Te4[(rk[0] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[0] ) & 0xff] & 0xff]; + rk[1] = + Td0[Te4[(rk[1] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[1] ) & 0xff] & 0xff]; + rk[2] = + Td0[Te4[(rk[2] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[2] ) & 0xff] & 0xff]; + rk[3] = + Td0[Te4[(rk[3] >> 24) ] & 0xff] ^ + Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^ + Td3[Te4[(rk[3] ) & 0xff] & 0xff]; + } + return 0; +} + +#ifndef AES_ASM +/* + * Encrypt a single block + * in and out can overlap + */ +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key) { + + const u32 *rk; + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + +// assert(in && out && key); + rk = key->rd_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(in ) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = + Te0[(s0 >> 24) ] ^ + Te1[(s1 >> 16) & 0xff] ^ + Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3 ) & 0xff] ^ + rk[4]; + t1 = + Te0[(s1 >> 24) ] ^ + Te1[(s2 >> 16) & 0xff] ^ + Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0 ) & 0xff] ^ + rk[5]; + t2 = + Te0[(s2 >> 24) ] ^ + Te1[(s3 >> 16) & 0xff] ^ + Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1 ) & 0xff] ^ + rk[6]; + t3 = + Te0[(s3 >> 24) ] ^ + Te1[(s0 >> 16) & 0xff] ^ + Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Te0[(t0 >> 24) ] ^ + Te1[(t1 >> 16) & 0xff] ^ + Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3 ) & 0xff] ^ + rk[0]; + s1 = + Te0[(t1 >> 24) ] ^ + Te1[(t2 >> 16) & 0xff] ^ + Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0 ) & 0xff] ^ + rk[1]; + s2 = + Te0[(t2 >> 24) ] ^ + Te1[(t3 >> 16) & 0xff] ^ + Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1 ) & 0xff] ^ + rk[2]; + s3 = + Te0[(t3 >> 24) ] ^ + Te1[(t0 >> 16) & 0xff] ^ + Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Te4[(t0 >> 24) ] & 0xff000000) ^ + (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(out , s0); + s1 = + (Te4[(t1 >> 24) ] & 0xff000000) ^ + (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = + (Te4[(t2 >> 24) ] & 0xff000000) ^ + (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = + (Te4[(t3 >> 24) ] & 0xff000000) ^ + (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Te4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(out + 12, s3); +} + +/* + * Decrypt a single block + * in and out can overlap + */ +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key) { + + const u32 *rk; + u32 s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + +// assert(in && out && key); + rk = key->rd_key; + + /* + * map byte array block to cipher state + * and add initial round key: + */ + s0 = GETU32(in ) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = + Td0[(s0 >> 24) ] ^ + Td1[(s3 >> 16) & 0xff] ^ + Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1 ) & 0xff] ^ + rk[4]; + t1 = + Td0[(s1 >> 24) ] ^ + Td1[(s0 >> 16) & 0xff] ^ + Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2 ) & 0xff] ^ + rk[5]; + t2 = + Td0[(s2 >> 24) ] ^ + Td1[(s1 >> 16) & 0xff] ^ + Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3 ) & 0xff] ^ + rk[6]; + t3 = + Td0[(s3 >> 24) ] ^ + Td1[(s2 >> 16) & 0xff] ^ + Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0 ) & 0xff] ^ + rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = + Td0[(t0 >> 24) ] ^ + Td1[(t3 >> 16) & 0xff] ^ + Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1 ) & 0xff] ^ + rk[0]; + s1 = + Td0[(t1 >> 24) ] ^ + Td1[(t0 >> 16) & 0xff] ^ + Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2 ) & 0xff] ^ + rk[1]; + s2 = + Td0[(t2 >> 24) ] ^ + Td1[(t1 >> 16) & 0xff] ^ + Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3 ) & 0xff] ^ + rk[2]; + s3 = + Td0[(t3 >> 24) ] ^ + Td1[(t2 >> 16) & 0xff] ^ + Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0 ) & 0xff] ^ + rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* + * apply last round and + * map cipher state to byte array block: + */ + s0 = + (Td4[(t0 >> 24) ] & 0xff000000) ^ + (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t1 ) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(out , s0); + s1 = + (Td4[(t1 >> 24) ] & 0xff000000) ^ + (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t2 ) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = + (Td4[(t2 >> 24) ] & 0xff000000) ^ + (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t3 ) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = + (Td4[(t3 >> 24) ] & 0xff000000) ^ + (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^ + (Td4[(t0 ) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(out + 12, s3); +} + +#endif /* AES_ASM */ + +#if 0 +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, const int enc) +{ + + unsigned long n; + unsigned long len = length; + unsigned char tmp[AES_BLOCK_SIZE]; + + assert(in && out && key && ivec); + + if (enc) { + while (len >= AES_BLOCK_SIZE) { + for(n=0; n < AES_BLOCK_SIZE; ++n) + tmp[n] = in[n] ^ ivec[n]; + AES_encrypt(tmp, out, key); + memcpy(ivec, out, AES_BLOCK_SIZE); + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (len) { + for(n=0; n < len; ++n) + tmp[n] = in[n] ^ ivec[n]; + for(n=len; n < AES_BLOCK_SIZE; ++n) + tmp[n] = ivec[n]; + AES_encrypt(tmp, tmp, key); + memcpy(out, tmp, AES_BLOCK_SIZE); + memcpy(ivec, tmp, AES_BLOCK_SIZE); + } + } else { + while (len >= AES_BLOCK_SIZE) { + memcpy(tmp, in, AES_BLOCK_SIZE); + AES_decrypt(in, out, key); + for(n=0; n < AES_BLOCK_SIZE; ++n) + out[n] ^= ivec[n]; + memcpy(ivec, tmp, AES_BLOCK_SIZE); + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + if (len) { + memcpy(tmp, in, AES_BLOCK_SIZE); + AES_decrypt(tmp, tmp, key); + for(n=0; n < len; ++n) + out[n] = tmp[n] ^ ivec[n]; + memcpy(ivec, tmp, AES_BLOCK_SIZE); + } + } +} +#endif diff --git a/aes.h b/aes.h new file mode 100644 index 0000000..ce646f1 --- /dev/null +++ b/aes.h @@ -0,0 +1,30 @@ +#ifndef QEMU_AES_H +#define QEMU_AES_H + +#include "tools.h" + +#define AES_MAXNR 14 +#define AES_BLOCK_SIZE 16 + +struct aes_key_st { + uint32_t rd_key[4 *(AES_MAXNR + 1)]; + int rounds; +}; +typedef struct aes_key_st AES_KEY; + +int AES_set_encrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); +int AES_set_decrypt_key(const unsigned char *userKey, const int bits, + AES_KEY *key); + +void AES_encrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); +void AES_decrypt(const unsigned char *in, unsigned char *out, + const AES_KEY *key); + +#if 0 +void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, + const unsigned long length, const AES_KEY *key, + unsigned char *ivec, const int enc); +#endif +#endif diff --git a/autogen.sh b/autogen.sh new file mode 100644 index 0000000..a9dddce --- /dev/null +++ b/autogen.sh @@ -0,0 +1,22 @@ +#!/bin/sh +set -e + +test -d m4 || mkdir m4 + +autoreconf -fi + +run_configure=true +for arg in $*; do + case $arg in + --no-configure) + run_configure=false + ;; + *) + ;; + esac +done + +if test $run_configure = true; then + ./configure "$@" +fi + diff --git a/bn.c b/bn.c new file mode 100644 index 0000000..2bcebb6 --- /dev/null +++ b/bn.c @@ -0,0 +1,200 @@ +// Copyright 2007,2008,2010 Segher Boessenkool +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include +#include + +#include "tools.h" + +static void bn_print(char *name, u8 *a, u32 n) +{ + u32 i; + + printf("%s = ", name); + + for (i = 0; i < n; i++) + printf("%02x", a[i]); + + printf("\n"); +} + +static void bn_zero(u8 *d, u32 n) +{ + memset(d, 0, n); +} + +void bn_copy(u8 *d, u8 *a, u32 n) +{ + memcpy(d, a, n); +} + +int bn_compare(u8 *a, u8 *b, u32 n) +{ + u32 i; + + for (i = 0; i < n; i++) { + if (a[i] < b[i]) + return -1; + if (a[i] > b[i]) + return 1; + } + + return 0; +} + +static u8 bn_add_1(u8 *d, u8 *a, u8 *b, u32 n) +{ + u32 i; + u32 dig; + u8 c; + + c = 0; + for (i = n - 1; i < n; i--) { + dig = a[i] + b[i] + c; + c = dig >> 8; + d[i] = dig; + } + + return c; +} + +static u8 bn_sub_1(u8 *d, u8 *a, u8 *b, u32 n) +{ + u32 i; + u32 dig; + u8 c; + + c = 1; + for (i = n - 1; i < n; i--) { + dig = a[i] + 255 - b[i] + c; + c = dig >> 8; + d[i] = dig; + } + + return 1 - c; +} + +void bn_reduce(u8 *d, u8 *N, u32 n) +{ + if (bn_compare(d, N, n) >= 0) + bn_sub_1(d, d, N, n); +} + +void bn_add(u8 *d, u8 *a, u8 *b, u8 *N, u32 n) +{ + if (bn_add_1(d, a, b, n)) + bn_sub_1(d, d, N, n); + + bn_reduce(d, N, n); +} + +void bn_sub(u8 *d, u8 *a, u8 *b, u8 *N, u32 n) +{ + if (bn_sub_1(d, a, b, n)) + bn_add_1(d, d, N, n); +} + +static const u8 inv256[0x80] = { + 0x01, 0xab, 0xcd, 0xb7, 0x39, 0xa3, 0xc5, 0xef, + 0xf1, 0x1b, 0x3d, 0xa7, 0x29, 0x13, 0x35, 0xdf, + 0xe1, 0x8b, 0xad, 0x97, 0x19, 0x83, 0xa5, 0xcf, + 0xd1, 0xfb, 0x1d, 0x87, 0x09, 0xf3, 0x15, 0xbf, + 0xc1, 0x6b, 0x8d, 0x77, 0xf9, 0x63, 0x85, 0xaf, + 0xb1, 0xdb, 0xfd, 0x67, 0xe9, 0xd3, 0xf5, 0x9f, + 0xa1, 0x4b, 0x6d, 0x57, 0xd9, 0x43, 0x65, 0x8f, + 0x91, 0xbb, 0xdd, 0x47, 0xc9, 0xb3, 0xd5, 0x7f, + 0x81, 0x2b, 0x4d, 0x37, 0xb9, 0x23, 0x45, 0x6f, + 0x71, 0x9b, 0xbd, 0x27, 0xa9, 0x93, 0xb5, 0x5f, + 0x61, 0x0b, 0x2d, 0x17, 0x99, 0x03, 0x25, 0x4f, + 0x51, 0x7b, 0x9d, 0x07, 0x89, 0x73, 0x95, 0x3f, + 0x41, 0xeb, 0x0d, 0xf7, 0x79, 0xe3, 0x05, 0x2f, + 0x31, 0x5b, 0x7d, 0xe7, 0x69, 0x53, 0x75, 0x1f, + 0x21, 0xcb, 0xed, 0xd7, 0x59, 0xc3, 0xe5, 0x0f, + 0x11, 0x3b, 0x5d, 0xc7, 0x49, 0x33, 0x55, 0xff, +}; + +static void bn_mon_muladd_dig(u8 *d, u8 *a, u8 b, u8 *N, u32 n) +{ + u32 dig; + u32 i; + + u8 z = -(d[n-1] + a[n-1]*b) * inv256[N[n-1]/2]; + + dig = d[n-1] + a[n-1]*b + N[n-1]*z; + dig >>= 8; + + for (i = n - 2; i < n; i--) { + dig += d[i] + a[i]*b + N[i]*z; + d[i+1] = dig; + dig >>= 8; + } + + d[0] = dig; + dig >>= 8; + + if (dig) + bn_sub_1(d, d, N, n); + + bn_reduce(d, N, n); +} + +void bn_mon_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n) +{ + u8 t[512]; + u32 i; + + bn_zero(t, n); + + for (i = n - 1; i < n; i--) + bn_mon_muladd_dig(t, a, b[i], N, n); + + bn_copy(d, t, n); +} + +void bn_to_mon(u8 *d, u8 *N, u32 n) +{ + u32 i; + + for (i = 0; i < 8*n; i++) + bn_add(d, d, d, N, n); +} + +void bn_from_mon(u8 *d, u8 *N, u32 n) +{ + u8 t[512]; + + bn_zero(t, n); + t[n-1] = 1; + bn_mon_mul(d, d, t, N, n); +} + +static void bn_mon_exp(u8 *d, u8 *a, u8 *N, u32 n, u8 *e, u32 en) +{ + u8 t[512]; + u32 i; + u8 mask; + + bn_zero(d, n); + d[n-1] = 1; + bn_to_mon(d, N, n); + + for (i = 0; i < en; i++) + for (mask = 0x80; mask != 0; mask >>= 1) { + bn_mon_mul(t, d, d, N, n); + if ((e[i] & mask) != 0) + bn_mon_mul(d, t, a, N, n); + else + bn_copy(d, t, n); + } +} + +void bn_mon_inv(u8 *d, u8 *a, u8 *N, u32 n) +{ + u8 t[512], s[512]; + + bn_zero(s, n); + s[n-1] = 2; + bn_sub_1(t, N, s, n); + bn_mon_exp(d, a, N, n, t, n); +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..af856e2 --- /dev/null +++ b/common.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) Youness Alaoui (KaKaRoTo) + * + * This software is distributed under the terms of the GNU General Public + * License ("GPL") version 3, as published by the Free Software Foundation. + * + */ + +#ifndef __COMMON_H__ +#define __COMMON_H__ + + +#include + +#ifdef WIN32 +#define MKDIR(x,y) mkdir(x) +#else +#define MKDIR(x,y) mkdir(x,y) +#endif + +#ifdef __BIG_ENDIAN__ +#define swap16(x) (x) +#define swap32(x) (x) +#define swap64(x) (x) +#else +#define swap16(x) ((((uint16_t)(x) & 0xff00) >> 8) | \ + (((uint16_t)(x) & 0x00ff) << 8)) +#define swap32(x) ((((uint32_t)(x) & 0xff000000) >> 24) | \ + (((uint32_t)(x) & 0x00ff0000) >> 8) | \ + (((uint32_t)(x) & 0x0000ff00) << 8) | \ + (((uint32_t)(x) & 0x000000ff) << 24)) +#define swap64(x) \ + ((((uint64_t)(x) & 0xff00000000000000ull) >> 56) | \ + ((uint64_t)((x) & 0x00ff000000000000ull) >> 40) | \ + ((uint64_t)((x) & 0x0000ff0000000000ull) >> 24) | \ + ((uint64_t)((x) & 0x000000ff00000000ull) >> 8) | \ + ((uint64_t)((x) & 0x00000000ff000000ull) << 8) | \ + ((uint64_t)((x) & 0x0000000000ff0000ull) << 24) | \ + ((uint64_t)((x) & 0x000000000000ff00ull) << 40) | \ + ((uint64_t)((x) & 0x00000000000000ffull) << 56)) +#endif + + +#define ERROR(err, msg) do { \ + perror (msg); \ + exit (err); \ + } while(0); + + +#endif /* __COMMON_H__ */ diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..0143966 --- /dev/null +++ b/configure.ac @@ -0,0 +1,46 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.66]) +AC_INIT([ps3tools], [0.1], []) +AC_CONFIG_SRCDIR([tools.c]) +AC_CONFIG_HEADERS([config.h]) +AM_INIT_AUTOMAKE([-Wall]) + +# Checks for programs. +AC_PROG_CC + +# Checks for libraries. +AC_CHECK_LIB([gmp], [__gmpz_init], [GMP_LIBS="-lgmp"], [GMP_LIBS=""]) +AC_CHECK_LIB([z], [inflate]) + +AC_SUBST(GMP_LIBS) +AM_CONDITIONAL(HAVE_LIBGMP, test "$GMP_LIBS" != "") + + +dnl use pretty build output with automake >= 1.11 +m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])], + [AM_DEFAULT_VERBOSITY=1 + AC_SUBST(AM_DEFAULT_VERBOSITY)]) + + +# Checks for header files. +AC_CHECK_HEADERS([arpa/inet.h fcntl.h inttypes.h limits.h stdint.h stdlib.h string.h unistd.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_INLINE +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_MMAP +AC_FUNC_REALLOC +AC_CHECK_FUNCS([getpagesize memset strrchr strstr strtoul strtoull]) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/cospkg.c b/cospkg.c new file mode 100644 index 0000000..9f7c3a6 --- /dev/null +++ b/cospkg.c @@ -0,0 +1,150 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include +#define MAX_FILES 255 + +#define COS_FILE_SIZE 7340000 + + +struct pkg_file { + char name[0x20]; + u8 *ptr; + u64 size; + u64 offset; +}; + +static u8 *hdr = NULL; +static u32 hdr_size = 0; + +static u32 n_files = 0; +static struct pkg_file files[MAX_FILES]; + +static void get_files(const char *d) +{ + DIR *dir; + struct dirent *de; + struct stat st; + char path[256]; + u32 i; + u64 offset; + + dir = opendir(d); + if (dir == NULL) + fail("opendir"); + + offset = 0; + i = 0; + while ((de = readdir(dir))) { + if (n_files == MAX_FILES) + fail("file overflow. increase MAX_FILES"); + + if (strcmp(de->d_name, ".") == 0) + continue; + + if (strcmp(de->d_name, "..") == 0) + continue; + + if (strlen(de->d_name) > 0x20) + fail("name too long: %s", de->d_name); + + snprintf(path, sizeof path, "%s/%s", d, de->d_name); + + memset(&files[i], 0, sizeof(*files)); + strncpy(files[i].name, de->d_name, 0x19); + + if (stat(path, &st) < 0) + fail("cannot stat %s", path); + + if (!S_ISREG(st.st_mode)) + fail("not a file: %s", de->d_name); + + files[i].size = st.st_size; + + files[i].ptr = mmap_file(path); + if (files[i].ptr == NULL) + fail("unable to mmap %s", path); + + files[i].offset = offset; + offset = round_up(offset + files[i].size, 0x20); + + i++; + n_files++; + } +} + +static void build_hdr(void) +{ + u8 *p; + u32 i; + u64 file_size; + + file_size = files[n_files - 1].offset + files[n_files - 1].size; + hdr_size = 0x10 + n_files * 0x30; + + if ((hdr_size + file_size) > COS_FILE_SIZE) + fail ("Too many files, size must be under %d but it is %d", + COS_FILE_SIZE, hdr_size + file_size); + + hdr = malloc(hdr_size); + + if (hdr == NULL) + fail("out of memory"); + + memset(hdr, 0, hdr_size); + p = hdr; + + wbe32(p + 0x00, 1); // magic + wbe32(p + 0x04, n_files); + wbe64(p + 0x08, COS_FILE_SIZE); + p += 0x10; + + for (i = 0; i < n_files; i++) { + wbe64(p + 0x00, files[i].offset + hdr_size); + wbe64(p + 0x08, files[i].size); + strncpy((char *)(p + 0x10), files[i].name, 0x20); + p += 0x30; + } +} + +static void write_pkg(const char *n) +{ + FILE *fp; + u32 i; + + fp = fopen(n, "wb"); + if (fp == NULL) + fail("fopen(%s) failed", n); + + fwrite(hdr, hdr_size, 1, fp); + + for (i = 0; i < n_files; i++) { + fseek(fp, files[i].offset + hdr_size, SEEK_SET); + fwrite(files[i].ptr, files[i].size, 1, fp); + } + + fseek (fp, COS_FILE_SIZE-1, SEEK_SET); + fwrite("", 1, 1, fp); + + fclose(fp); +} + +int main(int argc, char *argv[]) +{ + if (argc != 3) + fail("usage: cospkg cos.pkg dir"); + + get_files(argv[2]); + build_hdr(); + write_pkg(argv[1]); + + return 0; +} diff --git a/cosunpack.c b/cosunpack.c new file mode 100644 index 0000000..a7e5a59 --- /dev/null +++ b/cosunpack.c @@ -0,0 +1,64 @@ +// Copyright 2010 Sven Peter +// Copyright 2011 glevand +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include +#include +#include +#include +#include +#include "tools.h" + +#ifdef WIN32 +#define MKDIR(x,y) mkdir(x); +#else +#define MKDIR(x,y) mkdir(x,y) +#endif + +static u8 *cos = NULL; + +static void new_dir(const char *n) +{ + MKDIR(n, 0777); + if (chdir(n) < 0) + fail("chdir"); +} + +static void do_toc(u8 *ptr) +{ + u32 n_entries; + u32 i; + u8 *p; + u8 *tmp; + u64 size; + char name[0x20]; + + n_entries = be32(ptr + 0x04); + p = ptr + 0x10; + + for(i = 0; i < n_entries; i++) { + memcpy(name, p + 16, 0x20); + + tmp = ptr + be64(p); + size = be64(p + 0x08); + + memcpy_to_file(name, tmp, size); + + p += 0x30; + } +} + +int main(int argc, char *argv[]) +{ + if (argc != 3) + fail("usage: cosunpack dump.b directory"); + + cos = mmap_file(argv[1]); + + new_dir(argv[2]); + + do_toc(cos); + + return 0; +} diff --git a/cosunpkg.c b/cosunpkg.c new file mode 100644 index 0000000..40b233e --- /dev/null +++ b/cosunpkg.c @@ -0,0 +1,69 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include + +#ifdef WIN32 +#define MKDIR(x,y) mkdir(x) +#else +#define MKDIR(x,y) mkdir(x,y) +#endif + +u8 *pkg = NULL; + +static void unpack_file(u32 i) +{ + u8 *ptr; + u8 name[33]; + u64 offset; + u64 size; + + ptr = pkg + 0x10 + 0x30 * i; + + offset = be64(ptr + 0x00); + size = be64(ptr + 0x08); + + memset(name, 0, sizeof name); + strncpy((char *)name, (char *)(ptr + 0x10), 0x20); + + printf("unpacking %s...\n", name); + memcpy_to_file((char *)name, pkg + offset, size); +} + +static void unpack_pkg(void) +{ + u32 n_files; + u64 size; + u32 i; + + n_files = be32(pkg + 4); + size = be64(pkg + 8); + + for (i = 0; i < n_files; i++) + unpack_file(i); +} + +int main(int argc, char *argv[]) +{ + if (argc != 3) + fail("usage: cosunpkg filename.pkg target"); + + pkg = mmap_file(argv[1]); + + MKDIR(argv[2], 0777); + + if (chdir(argv[2]) != 0) + fail("chdir"); + + unpack_pkg(); + + return 0; +} diff --git a/dat.c b/dat.c new file mode 100644 index 0000000..c54f807 --- /dev/null +++ b/dat.c @@ -0,0 +1,64 @@ +// Copyright 2011 Ninjas +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + FILE *in = NULL; + + size_t len; + + size_t new_len; + + u8 *data; + u8 dat_key[0x10], dat_iv[0x10]; + u8 *out; + + if (argc != 3) + fail ("usage: dat version.txt index.dat"); + + in = fopen (argv[1], "rb"); + if (in == NULL) + fail ("Unable to open %s", argv[1]); + fseek (in, 0, SEEK_END); + len = ftell (in); + fseek (in, 0, SEEK_SET); + + data = malloc (len); + + if (fread (data, 1, len, in) != len) + fail ("Unable to read index.dat file"); + + fclose (in); + + new_len = len + 32; + if (new_len % 16 != 0) + new_len += 16 - (new_len % 16); + out = malloc (new_len); + memset (out, '\n', new_len); + memset (out, '0', 32); + memcpy (out + 32, data, len); + sha1 (out + 32, new_len - 32, out); + + if(key_get_simple("dat-key", dat_key, 0x10) < 0) + fail ("unable to load dat-key."); + if(key_get_simple("dat-iv", dat_iv, 0x10) < 0) + fail ("unable to load dat-iv."); + + aes128cbc_enc (dat_key, dat_iv, out, new_len, out); + + memcpy_to_file (argv[2], out, new_len); + + return 0; +} diff --git a/ec.c b/ec.c new file mode 100644 index 0000000..511e756 --- /dev/null +++ b/ec.c @@ -0,0 +1,346 @@ +// Copyright 2007,2008,2010 Segher Boessenkool +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include +#include + +#include "tools.h" + +struct point { + u8 x[20]; + u8 y[20]; +}; + +static u8 ec_p[20]; +static u8 ec_a[20]; // mon +static u8 ec_b[20]; // mon +static u8 ec_N[21]; +static struct point ec_G; // mon +static struct point ec_Q; // mon +static u8 ec_k[21]; + +static void elt_copy(u8 *d, u8 *a) +{ + memcpy(d, a, 20); +} + +static void elt_zero(u8 *d) +{ + memset(d, 0, 20); +} + +static int elt_is_zero(u8 *d) +{ + u32 i; + + for (i = 0; i < 20; i++) + if (d[i] != 0) + return 0; + + return 1; +} + +static void elt_add(u8 *d, u8 *a, u8 *b) +{ + bn_add(d, a, b, ec_p, 20); +} + +static void elt_sub(u8 *d, u8 *a, u8 *b) +{ + bn_sub(d, a, b, ec_p, 20); +} + +static void elt_mul(u8 *d, u8 *a, u8 *b) +{ + bn_mon_mul(d, a, b, ec_p, 20); +} + +static void elt_square(u8 *d, u8 *a) +{ + elt_mul(d, a, a); +} + +static void elt_inv(u8 *d, u8 *a) +{ + u8 s[20]; + elt_copy(s, a); + bn_mon_inv(d, s, ec_p, 20); +} + +static void point_to_mon(struct point *p) +{ + bn_to_mon(p->x, ec_p, 20); + bn_to_mon(p->y, ec_p, 20); +} + +static void point_from_mon(struct point *p) +{ + bn_from_mon(p->x, ec_p, 20); + bn_from_mon(p->y, ec_p, 20); +} + +#if 0 +static int point_is_on_curve(u8 *p) +{ + u8 s[20], t[20]; + u8 *x, *y; + + x = p; + y = p + 20; + + elt_square(t, x); + elt_mul(s, t, x); + + elt_mul(t, x, ec_a); + elt_add(s, s, t); + + elt_add(s, s, ec_b); + + elt_square(t, y); + elt_sub(s, s, t); + + return elt_is_zero(s); +} +#endif + +static void point_zero(struct point *p) +{ + elt_zero(p->x); + elt_zero(p->y); +} + +static int point_is_zero(struct point *p) +{ + return elt_is_zero(p->x) && elt_is_zero(p->y); +} + +static void point_double(struct point *r, struct point *p) +{ + u8 s[20], t[20]; + struct point pp; + u8 *px, *py, *rx, *ry; + + pp = *p; + + px = pp.x; + py = pp.y; + rx = r->x; + ry = r->y; + + if (elt_is_zero(py)) { + point_zero(r); + return; + } + + elt_square(t, px); // t = px*px + elt_add(s, t, t); // s = 2*px*px + elt_add(s, s, t); // s = 3*px*px + elt_add(s, s, ec_a); // s = 3*px*px + a + elt_add(t, py, py); // t = 2*py + elt_inv(t, t); // t = 1/(2*py) + elt_mul(s, s, t); // s = (3*px*px+a)/(2*py) + + elt_square(rx, s); // rx = s*s + elt_add(t, px, px); // t = 2*px + elt_sub(rx, rx, t); // rx = s*s - 2*px + + elt_sub(t, px, rx); // t = -(rx-px) + elt_mul(ry, s, t); // ry = -s*(rx-px) + elt_sub(ry, ry, py); // ry = -s*(rx-px) - py +} + +static void point_add(struct point *r, struct point *p, struct point *q) +{ + u8 s[20], t[20], u[20]; + u8 *px, *py, *qx, *qy, *rx, *ry; + struct point pp, qq; + + pp = *p; + qq = *q; + + px = pp.x; + py = pp.y; + qx = qq.x; + qy = qq.y; + rx = r->x; + ry = r->y; + + if (point_is_zero(&pp)) { + elt_copy(rx, qx); + elt_copy(ry, qy); + return; + } + + if (point_is_zero(&qq)) { + elt_copy(rx, px); + elt_copy(ry, py); + return; + } + + elt_sub(u, qx, px); + + if (elt_is_zero(u)) { + elt_sub(u, qy, py); + if (elt_is_zero(u)) + point_double(r, &pp); + else + point_zero(r); + + return; + } + + elt_inv(t, u); // t = 1/(qx-px) + elt_sub(u, qy, py); // u = qy-py + elt_mul(s, t, u); // s = (qy-py)/(qx-px) + + elt_square(rx, s); // rx = s*s + elt_add(t, px, qx); // t = px+qx + elt_sub(rx, rx, t); // rx = s*s - (px+qx) + + elt_sub(t, px, rx); // t = -(rx-px) + elt_mul(ry, s, t); // ry = -s*(rx-px) + elt_sub(ry, ry, py); // ry = -s*(rx-px) - py +} + +static void point_mul(struct point *d, u8 *a, struct point *b) // a is bignum +{ + u32 i; + u8 mask; + + point_zero(d); + + for (i = 0; i < 21; i++) + for (mask = 0x80; mask != 0; mask >>= 1) { + point_double(d, d); + if ((a[i] & mask) != 0) + point_add(d, d, b); + } +} + +static void generate_ecdsa(u8 *R, u8 *S, u8 *k, u8 *hash) +{ + u8 e[21]; + u8 kk[21]; + u8 m[21]; + u8 minv[21]; + struct point mG; + + e[0] = 0; + memcpy(e + 1, hash, 20); + bn_reduce(e, ec_N, 21); + +try_again: + + get_rand(m, sizeof m); + m[0] = 0; + if (bn_compare(m, ec_N, 21) >= 0) + goto try_again; + + // R = (mG).x + + point_mul(&mG, m, &ec_G); + point_from_mon(&mG); + R[0] = 0; + elt_copy(R+1, mG.x); + + // S = m**-1*(e + Rk) (mod N) + + bn_copy(kk, k, 21); + bn_reduce(kk, ec_N, 21); + bn_to_mon(m, ec_N, 21); + bn_to_mon(e, ec_N, 21); + bn_to_mon(R, ec_N, 21); + bn_to_mon(kk, ec_N, 21); + + bn_mon_mul(S, R, kk, ec_N, 21); + bn_add(kk, S, e, ec_N, 21); + bn_mon_inv(minv, m, ec_N, 21); + bn_mon_mul(S, minv, kk, ec_N, 21); + + bn_from_mon(R, ec_N, 21); + bn_from_mon(S, ec_N, 21); +} + +static int check_ecdsa(struct point *Q, u8 *R, u8 *S, u8 *hash) +{ + u8 Sinv[21]; + u8 e[21]; + u8 w1[21], w2[21]; + struct point r1, r2; + u8 rr[21]; + + e[0] = 0; + memcpy(e + 1, hash, 20); + bn_reduce(e, ec_N, 21); + + bn_to_mon(R, ec_N, 21); + bn_to_mon(S, ec_N, 21); + bn_to_mon(e, ec_N, 21); + + bn_mon_inv(Sinv, S, ec_N, 21); + + bn_mon_mul(w1, e, Sinv, ec_N, 21); + bn_mon_mul(w2, R, Sinv, ec_N, 21); + + bn_from_mon(w1, ec_N, 21); + bn_from_mon(w2, ec_N, 21); + + point_mul(&r1, w1, &ec_G); + point_mul(&r2, w2, Q); + + point_add(&r1, &r1, &r2); + + point_from_mon(&r1); + + rr[0] = 0; + memcpy(rr + 1, r1.x, 20); + bn_reduce(rr, ec_N, 21); + + bn_from_mon(R, ec_N, 21); + bn_from_mon(S, ec_N, 21); + + return (bn_compare(rr, R, 21) == 0); +} + +#if 0 +static void ec_priv_to_pub(u8 *k, u8 *Q) +{ + point_mul(Q, k, ec_G); +} +#endif + +int ecdsa_set_curve(u32 type) +{ + if (ecdsa_get_params(type, ec_p, ec_a, ec_b, ec_N, ec_G.x, ec_G.y) < 0) + return -1; + + bn_to_mon(ec_a, ec_p, 20); + bn_to_mon(ec_b, ec_p, 20); + + point_to_mon(&ec_G); + + return 0; +} + +void ecdsa_set_pub(u8 *Q) +{ + memcpy(ec_Q.x, Q, 20); + memcpy(ec_Q.y, Q+20, 20); + point_to_mon(&ec_Q); +} + +void ecdsa_set_priv(u8 *k) +{ + memcpy(ec_k, k, sizeof ec_k); +} + +int ecdsa_verify(u8 *hash, u8 *R, u8 *S) +{ + return check_ecdsa(&ec_Q, R, S, hash); +} + +void ecdsa_sign(u8 *hash, u8 *R, u8 *S) +{ + generate_ecdsa(R, S, ec_k, hash); +} diff --git a/eidsplitr.c b/eidsplitr.c new file mode 100644 index 0000000..7ef1bf8 --- /dev/null +++ b/eidsplitr.c @@ -0,0 +1,72 @@ +#include +#include +#include + +void +DumpEidData (FILE * pFile, int iInputSize, int iEidCount, + char *pFilenamePrefix) +{ + FILE *pOutput; + char *szFilename; + char *szBuf; + int iRes, iSize; + + printf ("dumping EID%d from eEID at %p, size %d (%x)..\n", + iEidCount, pFile, iInputSize, iInputSize); + + szBuf = (char *) malloc (iInputSize + 1); + szFilename = (char *) malloc (strlen (pFilenamePrefix) + 2); + + if (szBuf == NULL) + { + perror ("malloc"); + exit (1); + }; + + iSize = fread (szBuf, iInputSize, 1, pFile); + sprintf (szFilename, "%s%d", pFilenamePrefix, iEidCount); + pOutput = fopen (szFilename, "wb"); + iRes = fwrite (szBuf, iInputSize, 1, pOutput); + + if (iRes != iSize) + { + perror ("fwrite"); + exit (1); + }; + + free (szBuf); +} + +int +main (int argc, char **argv) +{ + FILE *pFile; + char *pPrefix; + + pFile = fopen (argv[1], "rb"); + if (pFile == NULL) + { + usage: + printf ("usage: %s \n", argv[0]); + exit (1); + } + + if (argc == 2 && argv[2] != NULL) + { + pPrefix = argv[2]; + goto usage; + } + + fseek (pFile, 0x70, SEEK_SET); + + if (pPrefix != NULL) + { + DumpEidData (pFile, 2144, 0, pPrefix); + DumpEidData (pFile, 672, 1, pPrefix); + DumpEidData (pFile, 1840, 2, pPrefix); + DumpEidData (pFile, 256, 3, pPrefix); + DumpEidData (pFile, 48, 4, pPrefix); + DumpEidData (pFile, 2560, 5, pPrefix); + } + return 0; +} diff --git a/makeself.c b/makeself.c new file mode 100644 index 0000000..487cd93 --- /dev/null +++ b/makeself.c @@ -0,0 +1,595 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include + +#define ALIGNMENT 0x20 +#define MAX_PHDR 255 + +static u8 *elf = NULL; +static u8 *self = NULL; + +static enum sce_key type; + +struct elf_hdr ehdr; +struct elf_phdr phdr[MAX_PHDR]; +static int arch64; + +static u8 sce_header[0x70]; +static u8 info_header[0x20]; +static u8 ctrl_header[0x70]; +static u8 version_header[0x10]; + +static u8 *sec_header; +static u32 sec_header_size; + +static u8 *meta_header; +static u32 meta_header_size; + +static u64 header_size; +static u32 meta_offset; +static u64 elf_size; +static u64 compressed_size; +static u64 info_offset; +static u64 version_offset; +static u64 elf_offset; +static u64 phdr_offset; +static u64 shdr_offset; +static u64 sec_offset; +static u64 ctrl_offset; +static u64 version; +static u64 auth_id; +static u64 vendor_id; +static u16 sdk_type; + +struct key ks; + +static const char *elf_name = NULL; +static const char *self_name = NULL; +static int compression = 0; + +static struct { + u64 offset; + u64 size; + u8 *ptr; + int compressed; +} phdr_map[MAX_PHDR]; + +static void get_type(const char *p) +{ + if (strncmp(p, "lv0", 4) == 0) + type = KEY_LV0; + else if (strncmp(p, "lv1", 4) == 0) + type = KEY_LV1; + else if (strncmp(p, "lv2", 4) == 0) + type = KEY_LV2; + else if (strncmp(p, "iso", 4) == 0) + type = KEY_ISO; + else if (strncmp(p, "app", 4) == 0) + type = KEY_APP; + else if (strncmp(p, "ldr", 4) == 0) + type = KEY_LDR; + else + fail("invalid type: %s", p); +} + +static void get_keys(const char *suffix) +{ + if (key_get(type, suffix, &ks) < 0) + fail("key_get failed"); + + if (ks.pub_avail < 0) + fail("no public key available"); + + if (ks.priv_avail < 0) + fail("no private key available"); + + if (ecdsa_set_curve(ks.ctype) < 0) + fail("ecdsa_set_curve failed"); + + ecdsa_set_pub(ks.pub); + ecdsa_set_priv(ks.priv); +} + +static void parse_elf(void) +{ + u32 i; + + arch64 = elf_read_hdr(elf, &ehdr); + + for (i = 0; i < ehdr.e_phnum; i++) + elf_read_phdr(arch64, elf + ehdr.e_phoff + i * ehdr.e_phentsize, &phdr[i]); +} + +static void build_sce_hdr(void) +{ + memset(sce_header, 0, sizeof sce_header); + + wbe32(sce_header + 0x00, 0x53434500); // magic + wbe32(sce_header + 0x04, 2); // version + wbe16(sce_header + 0x08, sdk_type); // dunno, sdk type? + wbe16(sce_header + 0x0a, 1); // SCE header type; self + wbe32(sce_header + 0x0c, meta_offset); + wbe64(sce_header + 0x10, header_size); + wbe64(sce_header + 0x18, round_up(elf_size, ALIGNMENT)); + wbe64(sce_header + 0x20, 3); // dunno, has to be 3 + wbe64(sce_header + 0x28, info_offset); + wbe64(sce_header + 0x30, elf_offset); + wbe64(sce_header + 0x38, phdr_offset); + wbe64(sce_header + 0x40, shdr_offset); + wbe64(sce_header + 0x48, sec_offset); + wbe64(sce_header + 0x50, version_offset); + wbe64(sce_header + 0x58, ctrl_offset); + wbe64(sce_header + 0x60, 0x70); // ctrl size +} + +static void build_version_hdr(void) +{ + memset(version_header, 0, sizeof version_header); + wbe32(version_header, 1); + wbe32(version_header + 0x08, 0x10); +} + +static void build_info_hdr(void) +{ + u32 app_type; + + memset(info_header, 0, sizeof info_header); + + switch (type) { + case KEY_LV0: + app_type = 1; + break; + case KEY_LV1: + app_type = 2; + break; + case KEY_LV2: + app_type = 3; + break; + case KEY_APP: + app_type = 4; + break; + case KEY_ISO: + app_type = 5; + break; + case KEY_LDR: + app_type = 6; + break; + default: + fail("something that should never fail failed."); + } + + wbe64(info_header + 0x00, auth_id); + wbe32(info_header + 0x08, vendor_id); + wbe32(info_header + 0x0c, app_type); + wbe64(info_header + 0x10, version); // version 1.0.0 +} + +static void build_ctrl_hdr(void) +{ + memset(ctrl_header, 0, sizeof ctrl_header); + + wbe32(ctrl_header + 0x00, 1); // type: control flags + wbe32(ctrl_header + 0x04, 0x30); // length + // flags are all zero here + + wbe32(ctrl_header + 0x30, 2); // type: digest + wbe32(ctrl_header + 0x34, 0x40); // length +} + +static void build_sec_hdr(void) +{ + u32 i; + u8 *ptr; + + sec_header_size = ehdr.e_phnum * 0x20; + sec_header = malloc(sec_header_size); + + memset(sec_header, 0, sec_header_size); + + for (i = 0; i < ehdr.e_phnum; i++) { + ptr = sec_header + i * 0x20; + + wbe64(ptr + 0x00, phdr_map[i].offset); + wbe64(ptr + 0x08, phdr_map[i].size); + + if (phdr_map[i].compressed == 1) + wbe32(ptr + 0x10, 2); + else + wbe32(ptr + 0x10, 1); + + wbe32(ptr + 0x14, 0); // unknown + wbe32(ptr + 0x18, 0); // unknown + + if (phdr[i].p_type == 1) + wbe32(ptr + 0x1c, 1); // encrypted LOAD phdr + else + wbe32(ptr + 0x1c, 0); // no loadable phdr + } +} + +static void meta_add_phdr(u8 *ptr, u32 i) +{ + wbe64(ptr + 0x00, phdr_map[i].offset); + wbe64(ptr + 0x08, phdr_map[i].size); + + // unknown + wbe32(ptr + 0x10, 2); + wbe32(ptr + 0x14, i); // phdr index maybe? + wbe32(ptr + 0x18, 2); + + wbe32(ptr + 0x1c, i*8); // sha index + wbe32(ptr + 0x20, 1); // not encpryted + wbe32(ptr + 0x24, 0xffffffff); // no key + wbe32(ptr + 0x28, 0xffffffff); // no iv + wbe32(ptr + 0x2c, 1); // not compressed +} + +static void meta_add_load(u8 *ptr, u32 i) +{ + wbe64(ptr + 0x00, phdr_map[i].offset); + wbe64(ptr + 0x08, phdr_map[i].size); + + // unknown + wbe32(ptr + 0x10, 2); + wbe32(ptr + 0x14, i); // phdr index maybe? + wbe32(ptr + 0x18, 2); + + wbe32(ptr + 0x1c, i*8); // sha index + wbe32(ptr + 0x20, 3); // phdr is encrypted + wbe32(ptr + 0x24, (i*8) + 6); // key index + wbe32(ptr + 0x28, (i*8) + 7); // iv index + + if (phdr_map[i].compressed == 1) + wbe32(ptr + 0x2c, 2); + else + wbe32(ptr + 0x2c, 1); +} + +static void build_meta_hdr(void) +{ + u32 i; + u8 *ptr; + + meta_header_size = 0x80 + ehdr.e_phnum * (0x30 + 0x20 + 0x60) + 0x30; + meta_header = malloc(meta_header_size); + memset(meta_header, 0, meta_header_size); + + ptr = meta_header + 0x20; + + // aes keys for meta encryption + get_rand(ptr, 0x10); + get_rand(ptr + 0x20, 0x10); + ptr += 0x40; + + // area covered by the signature + wbe64(ptr + 0x00, meta_offset + meta_header_size - 0x30); + + wbe32(ptr + 0x08, 1); + wbe32(ptr + 0x0c, ehdr.e_phnum); // number of encrypted headers + wbe32(ptr + 0x10, ehdr.e_phnum * 8); // number of keys/hashes required + wbe32(ptr + 0x14, meta_header_size / 0x10); + ptr += 0x20; + + // add encrypted phdr information + for (i = 0; i < ehdr.e_phnum; i++) { + if (phdr[i].p_type == 1) + meta_add_load(ptr, i); + else + meta_add_phdr(ptr, i); + + ptr += 0x30; + } + + // add keys/ivs and hmac keys + get_rand(ptr, ehdr.e_phnum * 8 * 0x10); +} + +static void calculate_hashes(void) +{ + u32 i; + u8 *keys; + + keys = self + meta_offset + 0x80 + (0x30 * ehdr.e_phnum); + + for (i = 0; i < ehdr.e_phnum; i++) { + memset(keys + (i * 8 * 0x10), 0, 0x20); + sha1_hmac(keys + ((i * 8) + 2) * 0x10, + self + phdr_map[i].offset, + phdr_map[i].size, + keys + (i * 8) * 0x10 + ); + } +} + +static void build_hdr(void) +{ + memcpy(self, sce_header, sizeof sce_header); + memcpy(self + info_offset, info_header, sizeof info_header); + memcpy(self + version_offset, version_header, sizeof version_header); + memcpy(self + ctrl_offset, ctrl_header, sizeof ctrl_header); + memcpy(self + sec_offset, sec_header, sec_header_size); + memcpy(self + phdr_offset, elf + ehdr.e_phoff, ehdr.e_phnum * ehdr.e_phentsize); +// memcpy(self + shdr_offset, elf + ehdr.e_shoff, ehdr.e_shnum * ehdr.e_shentsize); + memcpy(self + meta_offset, meta_header, meta_header_size); + memcpy(self + elf_offset, elf, ehdr.e_ehsize); +} + +static void write_elf(void) +{ + u32 i; + + if (compression) { + for (i = 0; i < ehdr.e_phnum; i++) { + memcpy(self + phdr_map[i].offset, + phdr_map[i].ptr, + phdr_map[i].size); + } + memcpy(self + shdr_offset, elf + ehdr.e_shoff, ehdr.e_shnum * ehdr.e_shentsize); + } else { + memcpy(self + header_size, elf, elf_size); + } +} + +static void compress_elf(void) +{ + u32 i; + u64 offset; + uLongf size_zlib; + int res; + u64 size_compressed; + + offset = header_size; + + for (i = 0; i < ehdr.e_phnum; i++) { + phdr_map[i].offset = offset; + + if (phdr[i].p_type != 1) { + phdr_map[i].ptr = elf + phdr[i].p_off; + phdr_map[i].size = phdr[i].p_filesz; + phdr_map[i].compressed = 0; + offset = round_up(offset + phdr[i].p_filesz, 0x20); + continue; + } + + size_compressed = compressBound(phdr[i].p_filesz); + size_zlib = size_compressed; + + phdr_map[i].ptr = malloc(size_compressed); + if (!phdr_map[i].ptr) + fail("out of memory"); + + res = compress(phdr_map[i].ptr, &size_zlib, + elf + phdr[i].p_off, phdr[i].p_filesz); + + if (size_zlib >= phdr[i].p_filesz) { + free(phdr_map[i].ptr); + phdr_map[i].ptr = elf + phdr[i].p_off; + phdr_map[i].size = phdr[i].p_filesz; + phdr_map[i].compressed = 0; + offset = round_up(offset + phdr[i].p_filesz, ALIGNMENT); + } else { + phdr_map[i].ptr = realloc(phdr_map[i].ptr, size_zlib); + if (phdr_map[i].ptr == NULL) + fail("out of memory"); + + phdr_map[i].size = size_zlib; + phdr_map[i].compressed = 1; + offset = round_up(offset + phdr_map[i].size, ALIGNMENT); + } + } + + compressed_size = phdr_map[i - 1].offset + phdr_map[i - 1].size; + shdr_offset = compressed_size; + compressed_size += ehdr.e_shentsize * ehdr.e_shnum; +} + +static void fill_phdr_map(void) +{ + u32 i; + + memset(phdr_map, 0, sizeof phdr_map); + + for (i = 0; i < ehdr.e_phnum; i++) { + phdr_map[i].offset = phdr[i].p_off + header_size; + phdr_map[i].size = phdr[i].p_filesz; + phdr_map[i].compressed = 0; + phdr[i].ptr = NULL; + } + + compressed_size = elf_size; + shdr_offset = ehdr.e_shoff + header_size; +} + +static void sign_hdr(void) +{ + u8 *r, *s; + u8 hash[20]; + u64 sig_len; + + sig_len = be64(self + meta_offset + 0x60); + r = self + sig_len; + s = r + 21; + + sha1(self, sig_len, hash); + + ecdsa_sign(hash, r, s); +} + +static u64 get_filesize(const char *path) +{ + struct stat st; + + stat(path, &st); + + return st.st_size; +} + +static void get_version(const char *v) +{ + u8 *ptr; + u32 i; + u32 maj, min, rev; + u32 tmp; + + i = 0; + maj = min = rev = tmp = 0; + ptr = (u8 *)v; + while (*ptr) { + if (i > 2) { + fprintf(stderr, "WARNING: invalid sdk_version, using 1.0.0\n"); + version = 1ULL << 48; + return; + } + + if (*ptr == '.') { + if (i == 0) + maj = tmp; + else if (i == 1) + min = tmp; + else if (i == 2) + rev = tmp; + i++; + ptr++; + tmp = 0; + continue; + } + + if (*ptr >= '0' && *ptr <= '9') { + tmp <<= 4; + tmp += *ptr - '0'; + ptr++; + continue; + } + + fprintf(stderr, "WARNING: invalid sdk_version, using 1.0.0\n"); + version = 1ULL << 48; + return; + } + + if (i == 2) + rev = tmp; + + version = ((u64)maj & 0xffff) << 48; + version |= ((u64)min & 0xffff) << 32; + version |= rev; +} + +static void get_vendor(char *v) +{ + vendor_id = strtoull(v, NULL, 16); +} + +static void get_auth(char *a) +{ + auth_id = strtoull(a, NULL, 16); +} + +static void get_sdktype(char * t) +{ + sdk_type = strtoul(t, NULL, 10); +} + +static void get_args(int argc, char *argv[]) +{ + u32 i; + + if (argc != 9 && argc != 10) + fail("usage: makeself [-c] [type] [version suffix] [version] [vendor id] [auth id] [sdk type] [elf] [self]"); + + i = 1; + + if (argc == 10) { + if (strcmp(argv[1], "-c") != 0) + fail("invalid option: %s", argv[1]); + compression = 1; + i++; + } + + get_type(argv[i++]); + get_keys(argv[i++]); + get_version(argv[i++]); + get_vendor(argv[i++]); + get_auth(argv[i++]); + get_sdktype(argv[i++]); + + elf_name = argv[i++]; + self_name = argv[i++]; + + if (compression) { + if (type == KEY_ISO) + fail("no compression support for isolated modules"); + if (type == KEY_LDR) + fail("no compression support for secure loaders"); + } +} + + +int main(int argc, char *argv[]) +{ + FILE *fp; + u8 bfr[ALIGNMENT]; + + get_args(argc, argv); + + elf_size = get_filesize(elf_name); + elf = mmap_file(elf_name); + + parse_elf(); + + meta_header_size = 0x80 + ehdr.e_phnum * (0x30 + 0x20 + 0x60) + 0x30; + info_offset = 0x70; + elf_offset = 0x90; + phdr_offset = elf_offset + ehdr.e_ehsize; + sec_offset = round_up(phdr_offset + ehdr.e_phentsize * ehdr.e_phnum, ALIGNMENT); + version_offset = round_up(sec_offset + ehdr.e_phnum * 0x20, ALIGNMENT); + ctrl_offset = round_up(version_offset + 0x10, ALIGNMENT); + meta_offset = round_up(ctrl_offset + 0x70, ALIGNMENT); + header_size = round_up(meta_offset + meta_header_size, 0x80); + + if (compression) + compress_elf(); + else + fill_phdr_map(); + + build_sce_hdr(); + build_info_hdr(); + build_ctrl_hdr(); + build_sec_hdr(); + build_version_hdr(); + build_meta_hdr(); + + self = malloc(header_size + elf_size); + memset(self, 0, header_size + elf_size); + + build_hdr(); + write_elf(); + calculate_hashes(); + sign_hdr(); + + sce_encrypt_data(self); + sce_encrypt_header(self, &ks); + + fp = fopen(self_name, "wb"); + if (fp == NULL) + fail("fopen(%s) failed", self_name); + + if (fwrite(self, header_size + compressed_size, 1, fp) != 1) + fail("unable to write self"); + + memset(bfr, 0, sizeof bfr); + fwrite(bfr, round_up(compressed_size, ALIGNMENT) - compressed_size, 1, fp); + + fclose(fp); + + return 0; +} diff --git a/mingw_mmap.c b/mingw_mmap.c new file mode 100644 index 0000000..96915ef --- /dev/null +++ b/mingw_mmap.c @@ -0,0 +1,61 @@ +/** This code is adapted from: + * https://kerneltrap.org/mailarchive/git/2008/11/21/4186494 + * Original code by Vasyl Vavrychuk. + * + * This file is part of Rockstars. + * Coded in Hungarian Notation so it looks stupid. :D + * + * If you haven't seen the header file, call mmap() and munmap() not the + * function names below! + */ + +#ifdef __MINGW32__ + +#include +#include "mingw_mmap.h" + +extern int getpagesize(void); + +/** + * Use CreateFileMapping and MapViewOfFile to simulate POSIX mmap(). + * Why Microsoft won't just implement these is beyond everyone's comprehension. + * @return pointer or NULL + */ +void *mingw_mmap(void *pStart, size_t sLength, int nProt, int nFlags, int nFd, off_t oOffset) { + (void)nProt; + HANDLE hHandle; + + if (pStart != NULL || !(nFlags & MAP_PRIVATE)) { + printf("Invalid usage of mingw_mmap"); + return NULL; + } + + if (oOffset % getpagesize() != 0) { + printf("Offset does not match the memory allocation granularity"); + return NULL; + } + + hHandle = CreateFileMapping((HANDLE)_get_osfhandle(nFd), NULL, PAGE_WRITECOPY, 0, 0, NULL); + if (hHandle != NULL) { + pStart = MapViewOfFile(hHandle, FILE_MAP_COPY, 0, oOffset, sLength); + } + + return pStart; +} + +/** + * Use UnmapViewOfFile to undo mmap() above. + * @param pStart + * @param length - Not used, kept for compatibility. + * @return boolean; no checks are performed. + */ +int mingw_munmap(void *pStart, size_t sLength) { + (void)sLength; + + if (UnmapViewOfFile(pStart) != 0) + return FALSE; + + return TRUE; +} + +#endif diff --git a/mingw_mmap.h b/mingw_mmap.h new file mode 100644 index 0000000..54ee9c9 --- /dev/null +++ b/mingw_mmap.h @@ -0,0 +1,29 @@ +/** This code is adapted from: + * https://kerneltrap.org/mailarchive/git/2008/11/21/4186494 + * Original code by Vasyl Vavrychuk. + * + * This file is part of Rockstars. + * Coded in Hungarian Notation so it looks stupid. :D + * + * If you read nothing from this file, know NOT to call the function names + * below but the original mmap() and munmap() functions. + */ + +#ifndef _MINGW_MMAP_H +#define _MINGW_MMAP_H + +#include +#include + +#define PROT_READ 1 +#define PROT_WRITE 2 +#define MAP_SHARED 2 +#define MAP_PRIVATE 3 + +void *mingw_mmap(void *pStart, size_t sLength, int nProt, int nFlags, int nFd, off_t oOffset); +#define mmap mingw_mmap + +int mingw_munmap(void *pStart, size_t sLength); +#define munmap mingw_munmap + +#endif /* _MINGW_MMAP_H */ diff --git a/norunpack.c b/norunpack.c new file mode 100644 index 0000000..4d74f56 --- /dev/null +++ b/norunpack.c @@ -0,0 +1,78 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include +#include +#include +#include +#include +#include "tools.h" + +#ifdef WIN32 +#define MKDIR(x,y) mkdir(x); +#else +#define MKDIR(x,y) mkdir(x,y) +#endif + +static u8 *nor = NULL; + +static void new_dir(const char *n) +{ + MKDIR(n, 0777); + if (chdir(n) < 0) + fail("chdir"); +} + +static void do_toc(u8 *ptr) +{ + u32 n_entries; + u32 i; + u8 *p; + u8 *tmp; + u64 size; + char name[0x20]; + + n_entries = be32(ptr + 0x04); + p = ptr + 0x10; + + for(i = 0; i < n_entries; i++) { + memcpy(name, p + 16, 0x20); + + if (strncmp(name, "asecure_loader", 0x20) == 0) { + new_dir("asecure_loader"); + do_toc(ptr + be64(p)); + if (chdir("..") < 0) + fail("chdir(..)"); + } else if (strncmp(name, "ros", 3) == 0) { + new_dir(name); + do_toc(ptr + be64(p) + 0x10); + if (chdir("..") < 0) + fail("chdir(..)"); + } else { + tmp = ptr + be64(p); + size = be64(p + 0x08); + if (be32(tmp + 0x10) == 0x53434500) { + tmp += 0x10; + size -= 0x10; + } + + memcpy_to_file(name, tmp, size); + } + p += 0x30; + } +} + +int main(int argc, char *argv[]) +{ + if (argc != 3) + fail("usage: norunpack dump.b directory"); + + nor = mmap_file(argv[1]); + + new_dir(argv[2]); + + do_toc(nor + 0x400); + + return 0; +} diff --git a/pkg.c b/pkg.c new file mode 100644 index 0000000..636ef3f --- /dev/null +++ b/pkg.c @@ -0,0 +1,253 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include +#include + +static struct key k; +static FILE *fp; + +static u8 info0[0x40]; +static u8 info1[0x40]; + +static u8 *content; +static u64 content_size_real; +static u64 content_size_compressed; + +static u8 sce_hdr[0x20]; +static u8 meta_hdr[0x2a0]; + +static u8 *pkg; +static u64 pkg_size; + +static void get_file(u8 *bfr, const char *name, u64 size) +{ + FILE *fp; + + fp = fopen(name, "rb"); + if (fp == NULL) + fail("fopen(%s) failed", name); + + fread(bfr, size, 1, fp); + fclose(fp); +} + +static void get_content(void) +{ + u8 *base; + uLongf size_zlib; + int res; + struct stat st; + + base = mmap_file("content"); + + if (stat("content", &st) < 0) + fail("stat(content) failed"); + + content_size_real = st.st_size; + content_size_compressed = compressBound(content_size_real); + size_zlib = content_size_compressed; + + content = malloc(content_size_compressed); + if (!content) + fail("out of memory"); + + res = compress(content, &size_zlib, base, content_size_real); + if (res != Z_OK) + fail("compress returned %d", res); + + content_size_compressed = size_zlib; + content = realloc(content, content_size_compressed); + if (!content) + fail("out of memory"); +} + +static void get_key(const char *suffix) +{ + if (key_get(KEY_PKG, suffix, &k) < 0) + fail("key_get() failed"); + + if (k.pub_avail < 0) + fail("no public key available"); + + if (k.priv_avail < 0) + fail("no private key available"); + + if (ecdsa_set_curve(k.ctype) < 0) + fail("ecdsa_set_curve failed"); + + ecdsa_set_pub(k.pub); + ecdsa_set_priv(k.priv); +} + +static void build_sce_hdr(void) +{ + memset(sce_hdr, 0, sizeof sce_hdr); + + wbe32(sce_hdr + 0x00, 0x53434500); // magic + wbe32(sce_hdr + 0x04, 2); // version + wbe16(sce_hdr + 0x08, 0); // dunno, sdk type? + wbe16(sce_hdr + 0x0a, 3); // SCE header type; pkg + wbe32(sce_hdr + 0x0c, 0); // meta offset + wbe64(sce_hdr + 0x10, sizeof sce_hdr + sizeof meta_hdr); + wbe64(sce_hdr + 0x18, 0x80 + content_size_real); +} + +static void build_meta_hdr(void) +{ + u8 *ptr; + + memset(meta_hdr, 0, sizeof meta_hdr); + ptr = meta_hdr; + + // keys for metadata encryptiomn + get_rand(ptr, 0x10); + get_rand(ptr + 0x20, 0x10); + ptr += 0x40; + + // area covered by the signature + wbe64(ptr + 0x00, sizeof sce_hdr + sizeof meta_hdr - 0x30); + wbe32(ptr + 0x0c, 3); // number of encrypted headers + wbe32(ptr + 0x10, 3 * 8); // number of keys/hashes required + ptr += 0x20; + + // first info header + wbe64(ptr + 0x00, 0x2c0); // offset + wbe64(ptr + 0x08, 0x40); // size + wbe32(ptr + 0x10, 1); // unknown + wbe32(ptr + 0x14, 1); // index + wbe32(ptr + 0x18, 2); // unknown again + wbe32(ptr + 0x1c, 0); // sha index + wbe32(ptr + 0x20, 1); // no encryption + wbe32(ptr + 0x24, 0xffffffff); // key index + wbe32(ptr + 0x28, 0xffffffff); // iv index + wbe32(ptr + 0x2c, 0x1); // no compression + ptr += 0x30; + + // second info header + wbe64(ptr + 0x00, 0x300); // offset + wbe64(ptr + 0x08, 0x40); // size + wbe32(ptr + 0x10, 2); // unknown + wbe32(ptr + 0x14, 2); // index + wbe32(ptr + 0x18, 2); // unknown again + wbe32(ptr + 0x1c, 8); // sha index + wbe32(ptr + 0x20, 1); // no encryption + wbe32(ptr + 0x24, 0xffffffff); // key index + wbe32(ptr + 0x28, 0xffffffff); // iv index + wbe32(ptr + 0x2c, 0x1); // no compression + ptr += 0x30; + + // package files + wbe64(ptr + 0x00, 0x340); // offset + wbe64(ptr + 0x08, content_size_compressed); + wbe32(ptr + 0x10, 3); // unknown + wbe32(ptr + 0x14, 3); // index + wbe32(ptr + 0x18, 2); // unknown again + wbe32(ptr + 0x1c, 16); // sha index + wbe32(ptr + 0x20, 3); // encrypted + wbe32(ptr + 0x24, 22); // key index + wbe32(ptr + 0x28, 23); // iv index + wbe32(ptr + 0x2c, 2); // compressed + ptr += 0x30; + + // add keys/ivs and hmac keys + get_rand(ptr, 3 * 8 * 0x10); +} + +static void fix_info_hdr(void) +{ + wbe64(info0 + 0x18, content_size_real); + wbe64(info0 + 0x20, content_size_compressed); + wbe64(info1 + 0x18, content_size_real); + wbe64(info1 + 0x20, content_size_compressed); +} + +static void build_pkg(void) +{ + pkg_size = sizeof sce_hdr + sizeof meta_hdr + 0x80; + pkg_size += content_size_compressed; + pkg_size = round_up(pkg_size, 0x100); + + pkg = malloc(pkg_size); + if (!pkg) + fail("out of memory"); + + memset(pkg, 0xaa, pkg_size); + memcpy(pkg, sce_hdr, 0x20); + memcpy(pkg + 0x20, meta_hdr, 0x2a0); + memcpy(pkg + 0x2c0, info0, 0x40); + memcpy(pkg + 0x300, info1, 0x40); + memcpy(pkg + 0x340, content, content_size_compressed); +} + +static void calculate_hash(u8 *data, u64 len, u8 *digest) +{ + memset(digest, 0, 0x20); + sha1_hmac(digest + 0x20, data, len, digest); +} + +static void hash_pkg(void) +{ + calculate_hash(pkg + 0x2c0, 0x40, pkg + 0x80 + 3*0x30); + calculate_hash(pkg + 0x300, 0x40, pkg + 0x80 + 3*0x30 + 8*0x10); + calculate_hash(pkg + 0x340, content_size_compressed, + pkg + 0x80 + 3*0x30 + 16*0x10); +} + +static void sign_pkg(void) +{ + u8 *r, *s; + u8 hash[20]; + u64 sig_len; + + sig_len = be64(pkg + 0x60); + r = pkg + sig_len; + s = r + 21; + + sha1(pkg, sig_len, hash); + + ecdsa_sign(hash, r, s); +} + +int main(int argc, char *argv[]) +{ + if (argc != 4) + fail("usage: pkg [key suffix] [contents] [filename.pkg]"); + + fp = fopen(argv[3], "wb"); + if (fp == NULL) + fail("fopen(%s) failed", argv[3]); + + if (chdir(argv[2]) < 0) + fail("chdir"); + + get_key(argv[1]); + get_file(info0, "info0", 0x40); + get_file(info1, "info1", 0x40); + get_content(); + + build_sce_hdr(); + build_meta_hdr(); + fix_info_hdr(); + + build_pkg(); + hash_pkg(); + sign_pkg(); + + sce_encrypt_data(pkg); + sce_encrypt_header(pkg, &k); + + fwrite(pkg, pkg_size, 1, fp); + fclose(fp); + + return 0; +} diff --git a/pupexplode b/pupexplode new file mode 100644 index 0000000..bc184a5 --- /dev/null +++ b/pupexplode @@ -0,0 +1,62 @@ +#!/bin/sh + +if [ $# -ne 2 ] ; then + echo "Usage: pupexplode " + echo "pupexplode expands all important files in a PUP and tries to decrypt every file as a self" + exit 1 +fi + +pup=$1 +outdir=$2 + +pupunpack $pup $outdir || exit + +cd $outdir || exit + +mkdir update_files +cd update_files +tar xvf ../update_files.tar || exit + +for f in dev_flash*; do + unpkg $f ${f}_unpkg || exit + tar xvf ${f}_unpkg/content || exit +done + +for f in *.pkg; do + unpkg $f ${f%.pkg} + if [ $f = "CORE_OS_PACKAGE.pkg" ]; then + cosunpkg CORE_OS_PACKAGE/content CORE_OS_PACKAGE/ + fi +done + +report_result() +{ + local r + + printf "$1" + shift + eval $@ >/dev/null 2>&1 + r=$? + if [ $r -ne 0 ] ; then + printf 'ko\n' + else + printf 'ok\n' + fi + return $r +} + +cd .. +for f in $(find . -type f); do + if readself $f >/dev/null 2>&1; then + report_result "unselfing $f... " unself $f ${f}.elf + if [ $? -eq 0 ] ; then + cpu=$(readelf -h ${f}.elf | awk '/Machine:/ {print $2}') + if [ "$cpu" = "SPU" ] ; then + report_result "disassembling ${f} for SPU..." "spu-objdump -d ${f}.elf > ${f}.asm 2>/dev/null" + elif [ "$cpu" = "PowerPC64" ] ; then + report_result "disassembling ${f} for PPC..." "ppu-objdump -d -m powerpc:common64 -EB ${f}.elf > ${f}.asm 2>/dev/null" + fi + fi + fi +done + diff --git a/puppack.c b/puppack.c new file mode 100644 index 0000000..14510d2 --- /dev/null +++ b/puppack.c @@ -0,0 +1,148 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include +#include +#include +#include +#include + +#include "tools.h" + +#define MAX_FILES 10 + +static FILE *fp; +static u8 pup_hmac[0x40]; +static u8 hdr[0x30 + 0x40 * MAX_FILES + 0x20]; +static u64 n_files; +static u64 data_size; +static u64 build = 0xfa11; + +static struct { + u8 *ptr; + u64 id; + u64 len; + u64 offset; +} files[MAX_FILES]; + +static struct id2name_tbl t_names[] = { + {0x100, "version.txt"}, + {0x101, "license.xml"}, + {0x102, "promo_flags.txt"}, + {0x103, "update_flags.txt"}, + {0x104, "patch_build.txt"}, + {0x200, "ps3swu.self"}, + {0x201, "vsh.tar"}, + {0x202, "dots.txt"}, + {0x203, "patch_data.pkg"}, + {0x300, "update_files.tar"}, + {0x501, "spkg_hdr.tar"}, + {0x601, "ps3swu2.self"}, + {0, NULL} +}; + + +static void find_files(void) +{ + struct id2name_tbl *t; + struct stat st; + u64 offset; + u32 i; + + n_files = 0; + data_size = 0; + + t = t_names; + while(t->name != NULL) { + if (stat(t->name, &st) >= 0) { + files[n_files].id = t->id; + files[n_files].ptr = mmap_file(t->name); + files[n_files].len = st.st_size; + data_size += files[n_files].len; + n_files++; + } + t++; + } + + offset = 0x50 + 0x40 * n_files; + for (i = 0; i < n_files; i++) { + files[i].offset = offset; + offset += files[i].len; + } +} + +static void calc_hmac(u8 *ptr, u64 len, u8 *hmac) +{ + memset(hmac, 0, 0x20); + sha1_hmac(pup_hmac, ptr, len, hmac); +} + +static void build_header(void) +{ + u32 i; + + memset(hdr, 0, sizeof hdr); + memcpy(hdr, "SCEUF\0\0\0", 8); + + wbe64(hdr + 0x08, 1); + wbe64(hdr + 0x10, build); + wbe64(hdr + 0x18, n_files); + wbe64(hdr + 0x20, 0x50 + n_files * 0x40); + wbe64(hdr + 0x28, data_size); + + for (i = 0; i < n_files; i++) { + wbe64(hdr + 0x30 + 0x20 * i + 0x00, files[i].id); + wbe64(hdr + 0x30 + 0x20 * i + 0x08, files[i].offset); + wbe64(hdr + 0x30 + 0x20 * i + 0x10, files[i].len); + wbe64(hdr + 0x30 + 0x20 * i + 0x18, 0); + + wbe64(hdr + 0x30 + 0x20 * n_files + 0x20 * i, i); + calc_hmac(files[i].ptr, files[i].len, + hdr + 0x30 + 0x20 * n_files + 0x20 * i + 0x08); + } + + calc_hmac(hdr, 0x30 + 0x40 * n_files, + hdr + 0x30 + 0x40 * n_files); +} + +static void write_pup(void) +{ + u32 i; + + fseek(fp, 0, SEEK_SET); + fwrite(hdr, 0x50 + 0x40 * n_files, 1, fp); + + for (i = 0; i < n_files; i++) { + fseek(fp, files[i].offset, SEEK_SET); + fwrite(files[i].ptr, files[i].len, 1, fp); + } +} + +int main(int argc, char *argv[]) +{ + if (argc < 3) + fail("usage: puppack filename.pup directory [build number]"); + + if (argc == 4) + build = atoi(argv[3]); + + if (key_get_simple("pup-hmac", pup_hmac, sizeof pup_hmac) < 0) + fail("pup hmac key not available"); + + fp = fopen(argv[1], "wb"); + if (fp == NULL) + fail("fopen(%s)", argv[1]); + + if (chdir(argv[2]) < 0) + fail("chdir(%s)", argv[1]); + + find_files(); + build_header(); + write_pup(); + + fclose(fp); + + return 0; +} + diff --git a/pupunpack.c b/pupunpack.c new file mode 100644 index 0000000..2aee52a --- /dev/null +++ b/pupunpack.c @@ -0,0 +1,154 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +#include +#include +#include +#include +#include + +#include "tools.h" + +#ifdef WIN32 +#define MKDIR(x,y) mkdir(x) +#else +#define MKDIR(x,y) mkdir(x,y) +#endif + +static u8 *pup = NULL; +static u8 pup_hmac[0x40]; +static int got_hmac = -1; +static u64 n_sections; +static u64 hdr_size; + +static struct id2name_tbl t_names[] = { + {0x100, "version.txt"}, + {0x101, "license.xml"}, + {0x102, "promo_flags.txt"}, + {0x103, "update_flags.txt"}, + {0x104, "patch_build.txt"}, + {0x200, "ps3swu.self"}, + {0x201, "vsh.tar"}, + {0x202, "dots.txt"}, + {0x203, "patch_data.pkg"}, + {0x300, "update_files.tar"}, + {0x501, "spkg_hdr.tar"}, + {0x601, "ps3swu2.self"}, + {0, NULL} +}; + +static int check_hmac(u8 *hmac, u8 *bfr, u64 len) +{ + u8 calc[0x14]; + + if (hmac == NULL) + return 1; + + if (got_hmac < 0) + return 1; + + sha1_hmac(pup_hmac, bfr, len, calc); + + if (memcmp(calc, hmac, sizeof calc) == 0) + return 0; + else + return -1; +} + +static u8 *find_hmac(u32 entry) +{ + u8 *ptr; + u32 i; + + ptr = pup + 0x30 + 0x20 * n_sections; + + for(i = 0; i < n_sections; i++) { + if (be64(ptr) == entry) + return ptr + 8; + ptr += 0x20; + } + + fail("not found: %d", entry); + return NULL; +} + +static void do_section(u64 i) +{ + u8 *ptr; + u64 entry; + u64 offset; + u64 size; + int hmac_res; + const char *fname; + const char *hmac_status; + + ptr = pup + 0x30 + 0x20 * i; + entry = be64(ptr); + offset = be64(ptr + 0x08); + size = be64(ptr + 0x10); + + fname = id2name(entry, t_names, NULL); + if (fname == NULL) + fail("unknown entry id: %08x_%08x", (u32)(entry >> 32), (u32)entry); + + hmac_res = check_hmac(find_hmac(i), pup + offset, size); + if (hmac_res < 0) + hmac_status = "FAIL"; + else if (hmac_res == 0) + hmac_status = "OK"; + else + hmac_status = "???"; + + printf("unpacking %s (%08x_%08x bytes; hmac: %s)...\n", fname, (u32)(size >> 32), (u32)size, hmac_status); + memcpy_to_file(fname, pup + offset, size); +} + +static void do_pup(void) +{ + u64 data_size; + u64 i; + int res; + + n_sections = be64(pup + 0x18); + hdr_size = be64(pup + 0x20); + data_size = be64(pup + 0x28); + + printf("sections: %" PRIu64 "\n", n_sections); + printf("hdr size: %08x_%08x\n", (u32)(hdr_size >> 32), (u32)hdr_size); + printf("data size: %08x_%08x\n", (u32)(data_size >> 32), (u32)data_size); + printf("header hmac: "); + + res = check_hmac(pup + 0x30 + 0x40 * n_sections, pup, 0x30 + 0x40 * n_sections); + + if (res < 0) + printf("FAIL\n"); + else if (res == 0) + printf("OK\n"); + else + printf("???\n"); + + for (i = 0; i < n_sections; i++) + do_section(i); +} + +int main(int argc, char *argv[]) +{ + (void)argc; + + if (argc < 3) + fail("usage: pupunpack filename.pup directory"); + + got_hmac = key_get_simple("pup-hmac", pup_hmac, sizeof pup_hmac); + pup = mmap_file(argv[1]); + + if(pup != NULL) + { + if (MKDIR(argv[2], 0777) < 0) + fail("mkdir(%s)", argv[2]); + if (chdir(argv[2]) < 0) + fail("chdir(%s)", argv[2]); + do_pup(); + } + + return 0; +} diff --git a/readself.c b/readself.c new file mode 100644 index 0000000..faa4ede --- /dev/null +++ b/readself.c @@ -0,0 +1,587 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +// +// Thanks to xorloser for his selftool! +// (see xorloser.com) +// + + +#include +#include +#include +#include "tools.h" + +static u8 *self; +static u8 *elf; + +static struct elf_hdr ehdr; + +static int arch64; +static u32 meta_offset; +static u64 elf_offset; +static u64 header_len; +static u64 phdr_offset; +static u64 shdr_offset; +static u64 filesize; +static u32 vendorid; +static u64 authid; +static u64 app_version; +static u32 app_type; +static u16 sdk_type; +static u64 info_offset; +static u64 sec_offset; +static u64 ver_info; +static u64 ctrl_offset; +static u64 ctrl_size; + +static int decrypted = -1; + +struct id2name_tbl t_sdk_type[] = { + {0, "Retail (Type 0)"}, + {1, "Retail"}, + {2, "Retail (Type 1)"}, + {0x8000, "Devkit"}, + {0, NULL} +}; + +struct id2name_tbl t_app_type[] = { + {1, "level 0"}, + {2, "level 1"}, + {3, "level 2"}, + {4, "application"}, + {5, "isolated SPU module"}, + {6, "secure loader"}, + {8, "NP-DRM application"}, + {0, NULL} +}; + +static struct id2name_tbl t_shdr_type[] = { + {0, "NULL"}, + {1, "PROGBITS"}, + {2, "SYMTAB"}, + {3, "STRTAB"}, + {4, "RELA"}, + {5, "HASH"}, + {6, "DYNAMIC"}, + {7, "NOTE"}, + {8, "NOBITS"}, + {9, "REL"}, + {10, "SHLIB"}, + {11, "DYNSYM"}, + {12, NULL}, +}; + +static struct id2name_tbl t_elf_type[] = { + {ET_NONE, "None"}, + {ET_REL, "Relocatable file"}, + {ET_EXEC, "Executable file"}, + {ET_DYN, "Shared object file"}, + {ET_CORE, "Core file"}, + {0, NULL} +}; + +static struct id2name_tbl t_elf_machine[] = { + {20, "PowerPC"}, + {21, "PowerPC64"}, + {23, "SPE"}, + {0, NULL} +}; + + +static struct id2name_tbl t_phdr_type[] = { + {0, "NULL"}, + {1, "LOAD"}, + {2, "DYN"}, + {3, "INTPR"}, + {4, "NOTE"}, + {5, "SHLIB"}, + {6, "PHDR"}, + {0, NULL} +}; + +static struct id2name_tbl t_compressed[] = { + {1, "[NO ]"}, + {2, "[YES]"}, + {0, NULL} +}; + +static struct id2name_tbl t_encrypted[] = { + {0, "[N/A]"}, + {1, "[YES]"}, + {2, "[NO ]"}, + {0, NULL} +}; + +static void parse_self(void) +{ + sdk_type = be16(self + 0x08); + meta_offset = be32(self + 0x0c); + header_len = be64(self + 0x10); + filesize = be64(self + 0x18); + info_offset = be64(self + 0x28); + elf_offset = be64(self + 0x30); + phdr_offset = be64(self + 0x38) - elf_offset; + shdr_offset = be64(self + 0x40) - elf_offset; + sec_offset = be64(self + 0x48); + ver_info = be64(self + 0x50); + ctrl_offset = be64(self + 0x58); + ctrl_size = be64(self + 0x60); + + vendorid = be32(self + info_offset + 0x08); + authid = be64(self + info_offset + 0x00); + app_type = be32(self + info_offset + 0x0c); + app_version = be64(self + info_offset + 0x10); + + elf = self + elf_offset; + arch64 = elf_read_hdr(elf, &ehdr); +} + + +static struct keylist *self_load_keys(void) +{ + enum sce_key id; + + switch (app_type) { + case 1: + id = KEY_LV0; + break; + case 2: + id = KEY_LV1; + break; + case 3: + id = KEY_LV2; + break; + case 4: + id = KEY_APP; + break; + case 5: + id = KEY_ISO; + break; + case 6: + id = KEY_LDR; + break; + case 8: + return NULL; + break; + default: + fail("invalid type: %08x", app_type); + } + + return keys_get(id); +} + +static void decrypt_header(void) +{ + struct keylist *klist; + + klist = self_load_keys(); + if (klist == NULL) + return; + + decrypted = sce_decrypt_header(self, klist); + free(klist->keys); + free(klist); +} + + +static const char *get_auth_type(void) +{ + return "Unknown"; +} + +static void show_self_header(void) +{ + printf("SELF header\n"); + printf(" elf #1 offset: %08x_%08x\n", (u32)(elf_offset>>32), (u32)elf_offset); + printf(" header len: %08x_%08x\n", (u32)(header_len>>32), (u32)header_len); + printf(" meta offset: %08x_%08x\n", 0, meta_offset); + printf(" phdr offset: %08x_%08x\n", (u32)(phdr_offset>>32), (u32)phdr_offset); + printf(" shdr offset: %08x_%08x\n", (u32)(shdr_offset>>32), (u32)shdr_offset); + printf(" file size: %08x_%08x\n", (u32)(filesize>>32), (u32)filesize); + printf(" auth id: %08x_%08x (%s)\n", (u32)(authid>>32), (u32)authid, get_auth_type()); + printf(" vendor id: %08x\n", vendorid); + printf(" info offset: %08x_%08x\n", (u32)(info_offset >> 32), (u32)info_offset); + printf(" sinfo offset: %08x_%08x\n", (u32)(sec_offset >> 32), (u32)sec_offset); + printf(" version offset: %08x_%08x\n", (u32)(ver_info >> 32), (u32)ver_info); + printf(" control info: %08x_%08x (%08x_%08x bytes)\n", + (u32)(ctrl_offset >> 32), (u32)ctrl_offset, + (u32)(ctrl_size >> 32), (u32)ctrl_size); + + printf(" app version: %x.%x.%x\n", (u16)(app_version >> 48), (u16)(app_version >> 32), (u32)app_version); + printf(" SDK type: %s\n", id2name(sdk_type, t_sdk_type, "unknown")); + printf(" app type: %s\n", id2name(app_type, t_app_type, "unknown")); + + + printf("\n"); +} + +static void print_hash(u8 *ptr, u32 len) +{ + while(len--) + printf(" %02x", *ptr++); +} + + +static void show_ctrl(void) +{ + u32 i, j; + u32 type, length; + + printf("Control info\n"); + + for (i = 0; i < ctrl_size; ) { + type = be32(self + ctrl_offset + i); + length = be32(self + ctrl_offset + i + 0x04); + switch (type) { + case 1: + if (length == 0x30) { + printf(" control flags:\n "); + print_hash(self + ctrl_offset + i + 0x10, 0x10); + printf("\n"); + break; + } + case 2: + if (length == 0x40) { + printf(" file digest:\n "); + print_hash(self + ctrl_offset + i + 0x10, 0x14); + printf("\n "); + print_hash(self + ctrl_offset + i + 0x24, 0x14); + printf("\n"); + break; + } + if (length == 0x30) { + printf(" file digest:\n "); + print_hash(self + ctrl_offset + i + 0x10, 0x14); + printf("\n"); + break; + } + case 3: + if (length == 0x90) { + + char id[0x31]; + memset(id, 0, 0x31); + memcpy(id, self + ctrl_offset + i + 0x20, 0x30); + + printf(" NPDRM info:\n"); + printf(" magic: %08x\n", be32(self + ctrl_offset + i + 0x10)); + printf(" unk0 : %08x\n", be32(self + ctrl_offset + i + 0x14)); + printf(" unk1 : %08x\n", be32(self + ctrl_offset + i + 0x18)); + printf(" unk2 : %08x\n", be32(self + ctrl_offset + i + 0x1c)); + printf(" content_id: %s\n", id); + printf(" digest: "); + print_hash(self + ctrl_offset + i + 0x50, 0x10); + printf("\n invdigest: "); + print_hash(self + ctrl_offset + i + 0x60, 0x10); + printf("\n xordigest: "); + print_hash(self + ctrl_offset + i + 0x70, 0x10); + printf("\n"); + break; + } + default: + printf(" unknown:\n"); + for(j = 0; j < length; j++) { + if ((j % 16) == 0) + printf(" "); + printf(" %02x", be8(self + ctrl_offset + i + j)); + if ((j % 16) == 15 || (j == length - 1)) + printf("\n"); + } + break; + } + i += length; + } + printf("\n"); +} + +static void show_sinfo(void) +{ + u32 i; + u64 offset, size; + u32 compressed, encrypted; + u32 unk1, unk2; + + printf("Section header\n"); + + printf(" offset size compressed unk1" + " unk2 encrypted\n"); + + for (i = 0; i < ehdr.e_phnum; i++) { + offset = be64(self + sec_offset + i*0x20 + 0x00); + size = be64(self + sec_offset + i*0x20 + 0x08); + compressed = be32(self + sec_offset + i*0x20 + 0x10); + unk1 = be32(self + sec_offset + i*0x20 + 0x14); + unk2 = be32(self + sec_offset + i*0x20 + 0x18); + encrypted = be32(self + sec_offset + i*0x20 + 0x1c); + printf(" %08x_%08x %08x_%08x %s %08x %08x %s\n", + (u32)(offset >> 32), (u32)offset, + (u32)(size >> 32), (u32)size, + id2name(compressed, t_compressed, "[???]"), + unk1, unk2, + id2name(encrypted, t_encrypted, "[???]") + ); + } + + printf("\n"); +} + +static void show_meta(void) +{ + u32 meta_len; + u32 meta_n_hdr; + u32 meta_n_keys; + u32 i; + u64 offset, size; + u8 *tmp; + + printf("Encrypted Metadata\n"); + + if (sdk_type == 0x8000) { + printf(" no encrypted metadata in fselfs.\n\n"); + return; + } + + if (decrypted < 0) { + printf(" unable to decrypt metadata\n\n"); + return; + } + + meta_len = be32(self + meta_offset + 0x60 + 0x4); + meta_n_hdr = be32(self + meta_offset + 0x60 + 0xc); + meta_n_keys = be32(self + meta_offset + 0x60 + 0x10); + + printf(" Key: "); + print_hash(self + meta_offset + 0x20, 0x10); + printf("\n"); + + printf(" IV : "); + print_hash(self + meta_offset + 0x40, 0x10); + printf("\n"); + + printf(" Signature end %08x\n", meta_len); + printf(" Sections %d\n", meta_n_hdr); + printf(" Keys %d\n", meta_n_keys); + printf("\n"); + + printf(" Sections\n"); + printf(" Offset Length Key IV SHA1\n"); + for (i = 0; i < meta_n_hdr; i++) { + tmp = self + meta_offset + 0x80 + 0x30*i; + offset = be64(tmp); + size = be64(tmp + 8); + printf(" %08x_%08x %08x_%08x %03d %03d %03d\n", + (u32)(offset >> 32), (u32)offset, (u32)(size >> 32), (u32)size, + be32(tmp + 0x24), be32(tmp + 0x28), be32(tmp + 0x1c)); + } + printf("\n"); + + printf(" Keys\n"); + printf(" Idx Data\n"); + tmp = self + meta_offset + 0x80 + 0x30*meta_n_hdr; + for (i = 0; i < meta_n_keys; i++) { + printf(" %03d ", i); + print_hash(tmp + i*0x10, 0x10); + printf("\n"); + } + printf("\n"); + + printf("\n"); + +} + +static void show_elf_header(void) +{ + printf("ELF header\n"); + + printf(" type: %s\n", id2name(ehdr.e_type, t_elf_type, "unknown")); + printf(" machine: %s\n", id2name(ehdr.e_machine, t_elf_machine, "unknown")); + printf(" version: %d\n", ehdr.e_version); + + if (arch64) { + printf(" phdr offset: %08x_%08x\n", + (u32)(ehdr.e_phoff>>32), (u32)ehdr.e_phoff); + printf(" shdr offset: %08x_%08x\n", + (u32)(ehdr.e_phoff>>32), (u32)ehdr.e_shoff); + printf(" entry: %08x_%08x\n", + (u32)(ehdr.e_entry>>32), (u32)ehdr.e_entry); + } else { + printf(" phdr offset: %08x\n", + (u32)ehdr.e_phoff); + printf(" shdr offset: %08x\n", + (u32)ehdr.e_shoff); + printf(" entry: %08x\n", + (u32)ehdr.e_entry); + } + + printf(" flags: %08x\n", ehdr.e_flags); + printf(" header size: %08x\n", ehdr.e_ehsize); + printf(" program header size: %08x\n", + ehdr.e_phentsize); + printf(" program headers: %d\n", ehdr.e_phnum); + printf(" section header size: %08x\n", + ehdr.e_shentsize); + printf(" section headers: %d\n", ehdr.e_shnum); + printf(" section header string table index: %d\n", ehdr.e_shtrndx); + + printf("\n"); +} + +static void get_flags(u32 flags, char *ptr) +{ + memset(ptr, '-', 3); + ptr[3] = 0; + + if (flags & 4) + ptr[0] = 'r'; + if (flags & 2) + ptr[1] = 'w'; + if (flags & 1) + ptr[2] = 'x'; +} + +static void show_phdr(unsigned int idx) +{ + struct elf_phdr p; + char ppc[4], spe[4], rsx[4]; + + elf_read_phdr(arch64, elf + phdr_offset + (ehdr.e_phentsize * idx), &p); + + get_flags(p.p_flags, ppc); + get_flags(p.p_flags >> 20, spe); + get_flags(p.p_flags >> 24, rsx); + + if (arch64) { + printf(" %5s %08x_%08x %08x_%08x %08x_%08x\n" + " %08x_%08x %08x_%08x" + " %s %s %s %08x_%08x\n", + id2name(p.p_type, t_phdr_type, "?????"), + (u32)(p.p_off >> 32) , (u32)p.p_off, + (u32)(p.p_vaddr >> 32) , (u32)p.p_vaddr, + (u32)(p.p_paddr >> 32) , (u32)p.p_paddr, + (u32)(p.p_memsz >> 32) , (u32)p.p_memsz, + (u32)(p.p_filesz >> 32) , (u32)p.p_filesz, + ppc, spe, rsx, + (u32)(p.p_align >> 32) , (u32)p.p_align + ); + } else { + printf(" %5s %08x %08x %08x " + "%08x %08x %s %s %s %08x\n", + id2name(p.p_type, t_phdr_type, "?????"), + (u32)p.p_off, (u32)p.p_vaddr, + (u32)p.p_paddr, (u32)p.p_memsz, (u32)p.p_filesz, + ppc, spe, rsx, (u32)p.p_align); + } +} + +static void get_shdr_flags(u32 flags, char *ptr) +{ + memset(ptr, ' ', 3); + ptr[3] = 0; + + if (flags & 4) + ptr[0] = 'w'; + if (flags & 2) + ptr[1] = 'a'; + if (flags & 1) + ptr[2] = 'e'; +} + +static void show_shdr(unsigned int idx) +{ + struct elf_shdr s; + char flags[4]; + + elf_read_shdr(arch64, elf + shdr_offset + (ehdr.e_shentsize * idx), &s); + get_shdr_flags(s.sh_flags, flags); + + if (arch64) { + printf(" [%02d] %-15s %-9s %08x_%08x" + " %02d %-3s %02d %03d %02d\n" + " %08x_%08x %08x_%08x\n", + idx, "", + id2name(s.sh_type, t_shdr_type, "????"), + (u32)(s.sh_addr >> 32), (u32)s.sh_addr, + s.sh_entsize, flags, s.sh_link, s.sh_info, + s.sh_addralign, + (u32)(s.sh_offset >> 32), (u32)s.sh_offset, + 0, (u32)s.sh_size + ); + } else { + printf(" [%02d] %-15s %-9s %08x" + " %08x %08x %02d %-3s %02d %02d %02d\n", + idx, "", + id2name(s.sh_type, t_shdr_type, "????"), + (u32)s.sh_addr, (u32)s.sh_offset, + s.sh_size, s.sh_entsize, + flags, s.sh_link, s.sh_info, s.sh_addralign); + + } +} + +static void show_phdrs(void) +{ + unsigned int i; + + printf("Program headers\n"); + + if (ehdr.e_phnum == 0) { + printf("No program headers in this file.\n"); + } else { + if (arch64) + printf(" type offset vaddr " + "paddr\n memsize filesize" + " PPU SPE RSX align\n"); + else + printf(" type offset vaddr paddr " + "memsize filesize PPU SPE RSX align\n"); + for (i = 0; i < ehdr.e_phnum; i++) + show_phdr(i); + } + + printf("\n"); +} + +static void show_shdrs(void) +{ + unsigned int i; + + printf("Section headers\n"); + + if (ehdr.e_shnum == 0) { + printf("No section headers in this file.\n"); + } else { + if (arch64) + printf(" [Nr] Name Type Addr" + " ES Flg Lk Inf Al\n" + " Off Size\n"); + else + printf(" [Nr] Name Type Addr" + " Off Size ES Flg Lk Inf Al\n"); + for (i = 0; i < ehdr.e_shnum; i++) + show_shdr(i); + } + + printf("\n"); +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) + fail("usage: readself file.self"); + + self = mmap_file(argv[1]); + + parse_self(); + decrypt_header(); + + show_self_header(); + show_ctrl(); + show_sinfo(); + show_meta(); + show_elf_header(); + show_phdrs(); + show_shdrs(); + + return 0; +} diff --git a/readself2.c b/readself2.c new file mode 100644 index 0000000..a3bbb6e --- /dev/null +++ b/readself2.c @@ -0,0 +1,1210 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +// +// Thanks to xorloser for his selftool! +// (see xorloser.com) +// + +#include +#include +#include +#include +#include "tools.h" + +static u8 *self; +static u8 *elf; + +static struct elf_hdr ehdr; + +static int arch64; + +static u32 magic; +static u32 hdr_version; +static u16 sdk_type; +static u16 hdr_type; +static u32 meta_offset; +static u64 header_len; +static u64 filesize; +static u64 unknown1; +static u64 info_offset; +static u64 elf_offset; +static u64 phdr_offset; +static u64 shdr_offset; +static u64 sec_offset; +static u64 ver_info; +static u64 ctrl_offset; +static u64 ctrl_size; +static u64 unknown2; + +static u64 authid; +static u32 vendorid; +static u32 app_type; +static u64 app_version; +static u64 unknown3; + +static u64 elf_ident; +static u64 elf_ident2; + +static int decrypted = -1; + +struct id2name_tbl t_sdk_type[] = +{ + {0, "Retail (Type 0)"}, + {1, "Retail"}, + {2, "Retail (Type 1)"}, + {3, "Unknown SDK3"}, + {4, "UNKNOWN >=3.42"}, + {5, "Unknown SDK5"}, + {6, "Unknown SDK6"}, + {7, "UNKNOWN >=3.50"}, + {8, "Unknown SDK8"}, + {9, "Unknown SDK9"}, + {0x8000, "Devkit"}, + {0, NULL} +}; + +struct id2name_tbl t_hdr_type[] = +{ + {1, "SELF"}, + {2, "UNK "}, + {3, "PKG "}, + {0, NULL} +}; + +struct id2name_tbl t_app_type[] = +{ + {1, "level 0"}, + {2, "level 1"}, + {3, "level 2"}, + {4, "application"}, + {5, "isolated SPU module"}, + {6, "secure loader"}, + {7, "unknown app type"}, + {8, "NP-DRM application"}, + {0, NULL} +}; + +static struct id2name_tbl t_shdr_type[] = +{ + {0, "NULL"}, + {1, "PROGBITS"}, + {2, "SYMTAB"}, + {3, "STRTAB"}, + {4, "RELA"}, + {5, "HASH"}, + {6, "DYNAMIC"}, + {7, "NOTE"}, + {8, "NOBITS"}, + {9, "REL"}, + {10, "SHLIB"}, + {11, "DYNSYM"}, + {12, NULL}, +}; + +static struct id2name_tbl t_elf_type[] = +{ + {ET_NONE, "None"}, + {ET_REL, "Relocatable file"}, + {ET_EXEC, "Executable file"}, + {ET_DYN, "Shared object file"}, + {ET_CORE, "Core file"}, + {0, NULL} +}; + +static struct id2name_tbl t_elf_machine[] = +{ + {20, "PowerPC"}, + {21, "PowerPC64"}, + {22, "UnknownArch"}, + {23, "SPE"}, + {0, NULL} +}; + + +static struct id2name_tbl t_phdr_type[] = +{ + {0, "NULL"}, + {1, "LOAD"}, + {2, "DYN"}, + {3, "INTPR"}, + {4, "NOTE"}, + {5, "SHLIB"}, + {6, "PHDR"}, + {7, "TLS"}, + {8, "UNK8"}, + {9, "UNK9"}, + {0x60000001, "LOOS1"}, + {0x60000002, "LOOS2"}, + {0, NULL} +}; + +static struct id2name_tbl t_compressed[] = +{ + {1, "[NO ]"}, + {2, "[YES]"}, + {0, NULL} +}; + +static struct id2name_tbl t_encrypted[] = +{ + {0, "[N/A]"}, + {1, "[YES]"}, + {2, "[NO ]"}, + {0, NULL} +}; + +static struct keylist *self_load_keys(void) +{ + enum sce_key id; + + switch (app_type) { + case 1: + id = KEY_LV0; + break; + case 2: + id = KEY_LV1; + break; + case 3: + id = KEY_LV2; + break; + case 4: + id = KEY_APP; + break; + case 5: + id = KEY_ISO; + break; + case 6: + id = KEY_LDR; + break; + case 7: + return NULL; + break; + case 8: + return NULL; + break; + default: + fail("invalid type: %08x", app_type); + } + + return keys_get(id); +} + +static const char *get_auth_type(void) +{ + return "UnknownAuthIdType"; +} + +static void print_hash(u8 *ptr, u32 len) +{ + while(len--) + printf(" %02x", *ptr++); +} + +static void get_flags(u32 flags, char *ptr) +{ + memset(ptr, '-', 3); + ptr[3] = 0; + + if (flags & 4) + ptr[0] = 'r'; + if (flags & 2) + ptr[1] = 'w'; + if (flags & 1) + ptr[2] = 'x'; +} + +static void get_shdr_flags(u32 flags, char *ptr) +{ + memset(ptr, ' ', 3); + ptr[3] = 0; + + if (flags & 4) + ptr[0] = 'w'; + if (flags & 2) + ptr[1] = 'a'; + if (flags & 1) + ptr[2] = 'e'; +} + +static void parse_self(void) +{ + magic = be32(self + 0x00); + hdr_version = be32(self + 0x04); + sdk_type = be16(self + 0x08); + hdr_type = be16(self + 0x0a); + meta_offset = be32(self + 0x0c); + header_len = be64(self + 0x10); + filesize = be64(self + 0x18); + unknown1 = be64(self + 0x20); + info_offset = be64(self + 0x28); + elf_offset = be64(self + 0x30); + phdr_offset = be64(self + 0x38) - elf_offset; + shdr_offset = be64(self + 0x40) - elf_offset; + sec_offset = be64(self + 0x48); + ver_info = be64(self + 0x50); + ctrl_offset = be64(self + 0x58); + ctrl_size = be64(self + 0x60); + unknown2 = be64(self + 0x68); + + authid = be64(self + info_offset + 0x00); + vendorid = be32(self + info_offset + 0x08); + app_type = be32(self + info_offset + 0x0c); + app_version = be64(self + info_offset + 0x10); + unknown3 = be64(self + info_offset + 0x18); + + elf_ident = be64(self + elf_offset + 0x00); + elf_ident2 = be64(self + elf_offset + 0x08); + elf = self + elf_offset; + arch64 = elf_read_hdr(elf, &ehdr); +} + +static void decrypt_header(void) +{ + struct keylist *klist; + + klist = self_load_keys(); + if (klist == NULL) + return; + + decrypted = sce_decrypt_header(self, klist); + free(klist->keys); + free(klist); +} + +static void show_self_header(void) +{ + printf("%s Info\n\n", + id2name(hdr_type, t_hdr_type, "unknown") + ); + printf(" header type: %s\n", + id2name(hdr_type, t_hdr_type, "unknown") + ); + printf(" SDK type: %s\n", + id2name(sdk_type, t_sdk_type, "unknown") + ); + printf(" app type: %s\n", + id2name(app_type, t_app_type, "unknown") + ); + printf(" arch type: %s\n", + id2name(ehdr.e_machine, t_elf_machine, "unknown") + ); + printf(" ELF type: %s\n", + id2name(ehdr.e_type, t_elf_type, "unknown") + ); + printf(" app version: %x.%x.%x\n", + (u16)(app_version >> 48), + (u16)(app_version >> 32), + (u32)app_version + ); + printf(" auth id type: %s\n\n", + get_auth_type() + ); + + printf("%s Header file\n", + id2name(hdr_type, t_hdr_type, "unknown") + ); + printf(" offset data\n"); + printf(" magic: %04x = %08x\n", + (u16)(0x0), (u32)magic + ); + printf(" header version: %04x = %08x\n", + (u16)(0x4), (u32)hdr_version + ); + printf(" sdk type: %04x = %04x\n", + (u16)(0x8), (u16)sdk_type + ); + printf(" header type: %04x = %04x\n", + (u16)(0xa), (u16)hdr_type + ); + printf(" meta offset: %04x = %08x\n", + (u16)(0x0c), (u32)meta_offset + ); + printf(" header length %04x = %08x_%08x bytes\n", + (u16)(0x10), + (u32)(header_len>>32), + (u32)header_len + ); + printf(" file length: %04x = %08x_%08x bytes\n", + (u16)(0x18), + (u32)(filesize>>32 + ), + (u32)filesize); + printf(" unknown: %04x = %08x_%08x\n", + (u16)(0x20), (u32)(unknown1>>32), + (u32)unknown1 + ); + printf(" info offset: %04x = %08x_%08x\n", + (u16)(0x28), (u32)(info_offset >> 32), + (u32)info_offset + ); + printf(" elf #1 offset: %04x = %08x_%08x\n", + (u16)(0x30), + (u32)(elf_offset>>32), + (u32)elf_offset + ); + printf(" phdr offset: %04x = %08x_%08x\n", + (u16)(0x38), + (u32)((phdr_offset + elf_offset) >>32), + (u32)(phdr_offset + elf_offset) + ); + printf(" shdr offset: %04x = %08x_%08x\n", + (u16)(0x40), + (u32)((shdr_offset + elf_offset) >>32), + (u32)(shdr_offset + elf_offset) + ); + printf(" sinfo offset: %04x = %08x_%08x\n", + (u16)(0x48), + (u32)(sec_offset >> 32), + (u32)sec_offset + ); + printf(" version offset: %04x = %08x_%08x\n", + (u16)(0x50), + (u32)(ver_info >> 32), + (u32)ver_info + ); + printf(" control offset: %04x = %08x_%08x\n", + (u16)(0x58), + (u32)(ctrl_offset >> 32), + (u32)ctrl_offset + ); + printf(" control length: %04x = %08x_%08x bytes\n", + (u16)(0x60), + (u32)(ctrl_size >> 32), + (u32)ctrl_size + ); + printf(" unknown: %04x = %08x_%08x\n\n", + (u16)(0x68), + (u32)(unknown2 >> 32), + (u32)unknown2 + ); + + printf("App Info Header file\n"); + printf(" offset data\n"); + printf(" auth id: %04x = %08x_%08x (%s)\n", + (u16)(info_offset + 0x00), + (u32)(authid>>32), + (u32)authid, get_auth_type() + ); + printf(" vendor id: %04x = %08x\n", + (u16)(info_offset + 0x08), + (u32)vendorid + ); + printf(" app type: %04x = %08x\n", + (u16)(info_offset + 0x0c), + (u32)app_type + ); + printf(" app version: %04x = %08x_%08x\n", + (u16)(info_offset + 0x10), + (u32)(app_version >> 32), + (u32)(app_version) + ); + printf(" unknown: %04x = %08x_%08x\n", + (u16)(info_offset + 0x18), + (u32)(unknown3 >> 32), + (u32)unknown3 + ); + printf("\n\n"); +} + +/* +e_type :0x%04x +e_machine :0x%04x +e_version :0x%08x +e_entry :0x%lx +e_phoff :0x%lx +e_shoff :0x%lx +e_flags :0x%08x +e_ehsize :0x%04x +e_phentsize:0x%04x +e_phnum :0x%04x +e_shentsize:0x%04x +e_shnum :0x%04x +e_shstrndx :0x%04x +*/ +static void show_elf_header(void) +{ + int counter = 0; + + printf("ELF Header file\n"); + printf(" Offset data\n"); + + printf(" ident: %04x = %08x_%08x %08x_%08x\n", + (u16)(elf_offset + counter), + (u32)(elf_ident >> 32), + (u32)(elf_ident), + (u32)(elf_ident2 >> 32), + (u32)(elf_ident2) + //ehdr.e_ident + ); + counter += 16; + printf(" type: %04x = %04x (%s)\n", + (u16)(elf_offset + counter), + (u32)(ehdr.e_type), + id2name(ehdr.e_type, t_elf_type, "unknown") + ); + counter += 2; + printf(" machine: %04x = %04x (%s)\n", + (u16)(elf_offset + counter), + (u16)(ehdr.e_machine), + id2name(ehdr.e_machine, t_elf_machine, "unknown") + ); + counter += 2; + printf(" version: %04x = %08x\n", + (u16)(elf_offset + counter), + ehdr.e_version + ); + counter += 4; + + if (arch64) { + printf(" entry: %04x = %08x_%08x\n", + (u16)(elf_offset + counter), + (u32)(ehdr.e_entry>>32), + (u32)ehdr.e_entry + ); + printf(" phdr offset: %04x = %08x_%08x\n", + (u16)(elf_offset + counter + 8), + (u32)(ehdr.e_phoff>>32), + (u32)ehdr.e_phoff + ); + printf(" shdr offset: %04x = %08x_%08x\n", + (u16)(elf_offset + counter + 16), + (u32)(ehdr.e_phoff>>32), + (u32)ehdr.e_shoff + ); + counter += 24; + } + else + { + printf(" entry: %04x = %08x\n", + (u16)(elf_offset + counter), + (u32)ehdr.e_entry + ); + printf(" phdr offset: %04x = %08x\n", + (u16)(elf_offset + counter + 4), + (u32)ehdr.e_phoff + ); + printf(" shdr offset: %04x = %08x\n", + (u16)(elf_offset + counter + 8), + (u32)ehdr.e_shoff + ); + counter += 12; + } + + printf(" flags: %04x = %08x\n", + (u16)(elf_offset + counter), + ehdr.e_flags + ); + counter += 4; + printf(" header size: %04x = %04x bytes\n", + (u16)(elf_offset + counter), + ehdr.e_ehsize + ); + counter += 2; + printf(" pheader size: %04x = %04x bytes\n", + (u16)(elf_offset + counter), + ehdr.e_phentsize + ); + counter += 2; + printf(" pheaders num: %04x = %04x\n", + (u16)(elf_offset + counter), + ehdr.e_phnum + ); + counter += 2; + printf(" sheader size: %04x = %04x bytes\n", + (u16)(elf_offset + counter), + ehdr.e_shentsize + ); + counter += 2; + printf(" sheaders num: %04x = %04x\n", + (u16)(elf_offset + counter), + ehdr.e_shnum + ); + counter += 2; + printf(" sheader str idx: %04x = %04x\n", + (u16)(elf_offset + counter), + ehdr.e_shtrndx + ); + + printf("\n\n"); +} + +static void show_phdr(unsigned int idx) +{ + struct elf_phdr p; + char ppc[4], spe[4], rsx[4]; + + elf_read_phdr(arch64, elf + phdr_offset + (ehdr.e_phentsize * idx), &p); + + get_flags(p.p_flags, ppc); + get_flags(p.p_flags >> 20, spe); + get_flags(p.p_flags >> 24, rsx); + + printf(" pheader %02x:\n", + idx + ); +/* +p_type :0x%08x +p_flags :0x%08x +p_offset :0x%lx +p_vaddr :0x%lx +p_paddr :0x%lx +p_filesz :0x%lx +p_memsz :0x%lx +p_align :0x%lx +*/ + if (arch64) + { + printf(" type: %04x = %08x (%s)\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x00), + (u32)p.p_type, + id2name(p.p_type, t_phdr_type, "?????") + ); + printf(" flags: %04x = %08x PPU:%s SPE:%s RSX:%s\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x04), + (u32)p.p_flags, + ppc, spe, rsx + ); + printf(" offset: %04x = %08x_%08x\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x08), + (u32)(p.p_off >> 32) , (u32)p.p_off + ); + printf(" vaddr: %04x = %08x_%08x\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x10), + (u32)(p.p_vaddr >> 32) , (u32)p.p_vaddr + ); + printf(" paddr: %04x = %08x_%08x\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x18), + (u32)(p.p_paddr >> 32) , (u32)p.p_paddr + ); + printf(" filesize: %04x = %08x_%08x bytes\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x20), + (u32)(p.p_filesz >> 32) , (u32)p.p_filesz + ); + printf(" memsize: %04x = %08x_%08x bytes\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x28), + (u32)(p.p_memsz >> 32) , (u32)p.p_memsz + ); + printf(" align: %04x = %08x_%08x\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x30), + (u32)(p.p_align >> 32) , (u32)p.p_align + ); + } +// TODO: fix offsets below for 32-bit + else + { + printf(" type: %04x = %s\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x00), + id2name(p.p_type, t_phdr_type, "?????") + ); + printf(" flags: %04x = %08x PPU:%s SPE:%s RSX:%s\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x04), + (u32)p.p_flags, + ppc, spe, rsx + ); + printf(" offset: %04x = %08x\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x04), + (u32)p.p_off + ); + printf(" vaddr: %04x = %08x\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x08), + (u32)p.p_vaddr + ); + printf(" paddr: %04x = %08x\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x0c), + (u32)p.p_paddr + ); + printf(" filesize: %04x = %08x bytes\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x10), + (u32)p.p_filesz + ); + printf(" memsize: %04x = %08x bytes\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x14), + (u32)p.p_memsz + ); + printf(" align: %04x = %08x\n", + (u16)(phdr_offset + elf_offset + (ehdr.e_phentsize * idx) + 0x18), + (u32)p.p_align + ); + } +} + +static void show_phdrs(void) +{ + unsigned int i; + + printf("ELF PHDR file\n"); + + if (ehdr.e_phnum == 0) + { + printf("No program headers in this file.\n"); + } + else + { + printf(" offset data\n"); + for (i = 0; i < ehdr.e_phnum; i++) + { + show_phdr(i); + } + } + + printf("\n\n"); +} + +static void show_sinfo(void) +{ + u32 i; + u64 offset, size; + u32 compressed, encrypted; + u32 unk1, unk2; + + printf("Section Info file\n"); + printf(" offset data\n"); + + for (i = 0; i < ehdr.e_phnum; i++) + { + offset = be64(self + sec_offset + i*0x20 + 0x00); + size = be64(self + sec_offset + i*0x20 + 0x08); + compressed = be32(self + sec_offset + i*0x20 + 0x10); + unk1 = be32(self + sec_offset + i*0x20 + 0x14); + unk2 = be32(self + sec_offset + i*0x20 + 0x18); + encrypted = be32(self + sec_offset + i*0x20 + 0x1c); + + printf(" section %02d:\n", + i + ); + printf(" start offset: %04x = %08x_%08x\n", + (u16)(sec_offset + i*0x20 + 0x00), + (u32)(offset >> 32), (u32)offset + ); + printf(" section size: %04x = %08x_%08x bytes\n", + (u16)(sec_offset + i*0x20 + 0x08), + (u32)(size >> 32), (u32)size + ); + printf(" compression: %04x = %s\n", + (u16)(sec_offset + i*0x20 + 0x10), + id2name(compressed, t_compressed, "[???]") + ); + printf(" unknown: %04x = %08x\n", + (u16)(sec_offset + i*0x20 + 0x14), + unk1 + ); + printf(" unknown: %04x = %08x\n", + (u16)(sec_offset + i*0x20 + 0x18), + unk2 + ); + printf(" encryption: %04x = %s\n", + (u16)(sec_offset + i*0x20 + 0x1c), + id2name(encrypted, t_encrypted, "[???]") + ); + } + + printf("\n\n"); +} + +static void show_sce_vinfo(void) +{ + u32 unk1, unk2, unk3, unk4; + + unk1 = be32(self + ver_info + 0x00); + unk2 = be32(self + ver_info + 0x04); + unk3 = be32(self + ver_info + 0x08); + unk4 = be32(self + ver_info + 0x0c); + + printf("SCE Version Info file\n"); + printf(" offset data\n"); + printf(" unknown: %04x = %08x\n", + (u16)(ver_info + 0x00), + (u32)unk1 + ); + printf(" unknown: %04x = %08x\n", + (u16)(ver_info + 0x04), + unk2 + ); + printf(" unknown: %04x = %08x\n", + (u16)(ver_info + 0x08), + unk3 + ); + printf(" unknown: %04x = %08x\n", + (u16)(ver_info + 0x0c), + unk4 + ); + printf("\n\n"); +} + +static void show_ctrl(void) +{ + u32 i, j; + u32 type, length; + + printf("Control Info file\n"); + printf(" offset data\n"); + + for (i = 0; i < ctrl_size; ) + { + type = be32(self + ctrl_offset + i); + length = be32(self + ctrl_offset + i + 0x04); + switch (type) + { + case 1: + if (length == 0x30) + { + printf(" control type: %04x = %04x\n", + (u16)(ctrl_offset + i), + (u32)type + ); + printf(" control length: %04x = %04x\n", + (u16)(ctrl_offset + i + 0x04), + (u32)length + ); + printf(" unknown: %04x = %08x_%08x\n", + (u16)(ctrl_offset + i + 0x08), + be32(self + ctrl_offset + i + 0x08), + be32(self + ctrl_offset + i + 0x0c) + ); + printf(" control flags: %04x =", + (u16)(ctrl_offset + i + 0x10) + ); + print_hash(self + ctrl_offset + i + 0x10, 0x10); + printf("\n"); + printf(" unknown: %04x = %08x_%08x\n", + (u16)(ctrl_offset + i + 0x20), + be32(self + ctrl_offset + i + 0x20), + be32(self + ctrl_offset + i + 0x24) + ); + printf(" unknown: %04x = %08x_%08x\n", + (u16)(ctrl_offset + i + 0x28), + be32(self + ctrl_offset + i + 0x28), + be32(self + ctrl_offset + i + 0x2c) + ); + printf("\n"); + break; + } + case 2: + if (length == 0x40) + { + printf(" control type: %04x = %04x\n", + (u16)(ctrl_offset + i), + (u32)type + ); + printf(" control length: %04x = %04x\n", + (u16)(ctrl_offset + i + 0x04), + (u32)length + ); + printf(" unknown: %04x = %08x_%08x\n", + (u16)(ctrl_offset + i + 0x08), + be32(self + ctrl_offset + i + 0x08), + be32(self + ctrl_offset + i + 0x0c) + ); + printf(" file digest: %04x =", + (u16)(ctrl_offset + i + 0x10) + ); + print_hash(self + ctrl_offset + i + 0x10, 0x14); + printf("\n"); + printf(" file digest: %04x =", + (u16)(ctrl_offset + i + 0x24) + ); + print_hash(self + ctrl_offset + i + 0x24, 0x14); + printf("\n"); + printf(" unknown: %04x = %08x_%08x\n", + (u16)(ctrl_offset + i + 0x38), + be32(self + ctrl_offset + i + 0x38), + be32(self + ctrl_offset + i + 0x3c) + ); + break; + } + if (length == 0x30) + { + printf(" control type: %04x = %04x\n", + (u16)(ctrl_offset + i), + (u32)type + ); + printf(" control length: %04x = %04x\n", + (u16)(ctrl_offset + i + 0x04), + (u32)length + ); + printf(" file digest: %04x =", + (u16)(ctrl_offset + i + 0x10) + ); + print_hash(self + ctrl_offset + i + 0x10, 0x14); + printf("\n"); + printf(" unknown: %04x = %08x_%08x\n", + (u16)(ctrl_offset + i + 0x24), + be32(self + ctrl_offset + i + 0x24), + be32(self + ctrl_offset + i + 0x28) + ); +// printf(" unknown: %04x = %08x_%08x\n", (u16)(ctrl_offset + i + 0x2c), be32(self + ctrl_offset + i + 0x2c), be32(self + ctrl_offset + i + 0x30)); + break; + } + case 3: + if (length == 0x90) + { + + char id[0x31]; + memset(id, 0, 0x31); + memcpy(id, self + ctrl_offset + i + 0x20, 0x30); + + printf(" NPDRM Info:\n"); + printf(" magic: %04x = %08x\n", + (u16)(ctrl_offset + i + 0x10), + be32(self + ctrl_offset + i + 0x10) + ); + printf(" unk0 : %04x = %08x\n", + (u16)(ctrl_offset + i + 0x14), + be32(self + ctrl_offset + i + 0x14) + ); + printf(" unk1 : %04x = %08x\n", + (u16)(ctrl_offset + i + 0x18), + be32(self + ctrl_offset + i + 0x18) + ); + printf(" unk2 : %04x = %08x\n", + (u16)(ctrl_offset + i + 0x1c), + be32(self + ctrl_offset + i + 0x1c) + ); + printf(" content_id: %04x = %s\n", + (u16)(ctrl_offset + i + 0x20), + id); + printf(" digest: %04x =", + (u16)(ctrl_offset + i + 0x50) + ); + print_hash(self + ctrl_offset + i + 0x50, 0x10); + printf("\n"); + printf(" invdigest: %04x =", + (u16)(ctrl_offset + i + 0x60) + ); + print_hash(self + ctrl_offset + i + 0x60, 0x10); + printf("\n"); + printf(" xordigest: %04x =", + (u16)(ctrl_offset + i + 0x70) + ); + print_hash(self + ctrl_offset + i + 0x70, 0x10); + printf("\n"); + printf(" unknown: %04x = %08x_%08x\n", + (u16)(ctrl_offset + i + 0x80), + be32(self + ctrl_offset + i + 0x80), + be32(self + ctrl_offset + i + 0x88) + ); + break; + } + default: + printf(" unknown:\n"); + for(j = 0; j < length; j++) + { + if ((j % 16) == 0) + printf(" "); + printf(" %02x", be8(self + ctrl_offset + i + j)); + if ((j % 16) == 15 || (j == length - 1)) + printf("\n"); + } + break; + } + i += length; + } + printf("\n\n"); +} + +static void show_meta(void) +{ + u32 meta_len; + u32 meta_n_hdr; + u32 meta_n_keys; + u32 i; + u64 offset, size; + u8 *tmp; + + printf("Metadata Info file\n"); + printf(" offset data\n"); + + if (sdk_type == 0x8000) { + printf(" no encrypted metadata in debug selfs.\n\n"); + return; + } + + if (decrypted < 0) { + printf(" unable to decrypt metadata\n\n"); + return; + } + + meta_len = be32(self + meta_offset + 0x60 + 0x4); + meta_n_hdr = be32(self + meta_offset + 0x60 + 0xc); + meta_n_keys = be32(self + meta_offset + 0x60 + 0x10); + + printf(" Key: %04x =", + (u16)(meta_offset + 0x20) + ); + print_hash(self + meta_offset + 0x20, 0x10); + printf("\n"); + printf(" IV : %04x =", + (u16)(meta_offset + 0x40) + ); + print_hash(self + meta_offset + 0x40, 0x10); + printf("\n\n"); + + printf("Metadata Header file\n"); + printf(" offset data\n"); + printf(" Signature end: %04x = %08x\n", + (u16)(meta_offset + 0x60 + 0x04), + meta_len + ); + printf(" Sections: %04x = %d\n", + (u16)(meta_offset + 0x60 + 0x0c), + meta_n_hdr + ); + printf(" Keys: %04x = %d\n", + (u16)(meta_offset + 0x60 + 0x10), + meta_n_keys + ); + printf("\n"); +/* + printf(" Sections file file file file file\n"); + printf(" offset Offset offset Length offset Key offset IV offset SHA1\n"); +*/ + printf(" Metadata Sections file\n"); + printf(" offset Data\n"); + for (i = 0; i < meta_n_hdr; i++) + { + tmp = self + meta_offset + 0x80 + 0x30*i; + offset = be64(tmp); + size = be64(tmp + 0x08); + printf(" section %02d:\n", i); + printf(" Offset: %04x = %08x_%08x\n", + (u16)(meta_offset + 0x80 + 0x30*i), + (u32)(offset >> 32), (u32)offset + ); + printf(" Length: %04x = %08x_%08x bytes\n", + (u16)((meta_offset + 0x80 + 0x30*i) + 0x08), + (u32)(size >> 32), (u32)size + ); + printf(" Key: %04x = %04x\n", + (u16)((meta_offset + 0x80 + 0x30*i) + 0x24), + be32(tmp + 0x24) + ); + printf(" IV: %04x = %04x\n", + (u16)((meta_offset + 0x80 + 0x30*i) + 0x28), + be32(tmp + 0x28) + ); + printf(" SHA1: %04x = %04x\n", + (u16)((meta_offset + 0x80 + 0x30*i) + 0x1c), + be32(tmp + 0x1c) + ); + } + printf("\n"); + + printf(" Metadata Keys file\n"); + printf(" offset Data\n"); + tmp = self + meta_offset + 0x80 + 0x30*meta_n_hdr; + for (i = 0; i < meta_n_keys; i++) + { + printf(" key idx %04x: %04x =", + i, + (u16)((meta_offset + 0x80 + 0x30*meta_n_hdr) + i*0x10) + ); + print_hash(tmp + i*0x10, 0x10); + printf("\n"); + } + printf("\n\n"); +} + +static void show_shdr(unsigned int idx) +{ + struct elf_shdr s; + char flags[4]; + + elf_read_shdr(arch64, elf + shdr_offset + (ehdr.e_shentsize * idx), &s); + get_shdr_flags(s.sh_flags, flags); + + if (arch64) + { +/* + printf(" section %02d: %04x %-9s %04x %-9s %04x %-3s %04x %08x_%08x %04x %08x_%08x %04x %08x_%08x %04x %04x %04x %04x %04x %04llx %04x %04llx\n", + idx, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 0*4), + "", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 1*4), + id2name(s.sh_type, t_shdr_type, "????"), + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4), + flags, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4 + 1*8), + (u32)(s.sh_addr >> 32), (u32)s.sh_addr, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4 + 2*8), + (u32)(s.sh_offset >> 32), (u32)s.sh_offset, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4 + 3*8), + 0, (u32)s.sh_size, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4 + 4*8), + (u32)s.sh_link, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 3*4 + 4*8), + (u32)s.sh_info, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 4*4 + 4*8), + (u64)s.sh_addralign, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 4*4 + 5*8), + (u64)s.sh_entsize + ); +*/ + printf(" section %02d:\n", + idx + ); + printf(" name: %04x = %s\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 0*4), + "" + ); + printf(" type: %04x = %s\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 1*4), + id2name(s.sh_type, t_shdr_type, "????") + ); + printf(" flags: %04x = %s\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4), + flags + ); + printf(" address: %04x = %08x_%08x\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4 + 1*8), + (u32)(s.sh_addr >> 32), (u32)s.sh_addr + ); + printf(" offset: %04x = %08x_%08x\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4 + 2*8), + (u32)(s.sh_offset >> 32), (u32)s.sh_offset + ); + printf(" length: %04x = %08x_%08x bytes\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4 + 3*8), + 0, (u32)s.sh_size + ); + printf(" link: %04x = %04x\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4 + 4*8), + (u32)s.sh_link + ); + printf(" info: %04x = %04x\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 3*4 + 4*8), + (u32)s.sh_info + ); + printf(" addr align: %04x = %04" PRIx64 "\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 4*4 + 4*8), + (u64)s.sh_addralign + ); + printf(" ent size: %04x = %04" PRIx64 "\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 4*4 + 5*8), + (u64)s.sh_entsize + ); + } + else + { +/* + printf(" [%02d] %04x %-9s %04x %-9s %04x %-3s %04x %08x %04x %08x %04x %08x %04x %02x %04x %02x %04x %03x %04x %02x\n", + idx, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 0*4), + "", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 1*4), + id2name(s.sh_type, t_shdr_type, "????"), + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4), + flags, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 3*4), + (u32)s.sh_addr, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 4*4), + (u32)s.sh_offset, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 5*4), + s.sh_size, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 6*4), + s.sh_link, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 7*4), + s.sh_info, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 8*4), + s.sh_addralign, + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 9*4), + s.sh_entsize + ); +*/ + printf(" section %02d:\n", + idx + ); + printf(" name: %04x = %s\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 0*4), + "" + ); + printf(" type: %04x = %s\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 1*4), + id2name(s.sh_type, t_shdr_type, "????") + ); + printf(" flags: %04x = %s\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 2*4), + flags + ); + printf(" address: %04x = %08x\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 3*4), + (u32)s.sh_addr + ); + printf(" offset: %04x = %08x\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 4*4), + (u32)s.sh_offset + ); + printf(" length: %04x = %08x bytes\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 5*4), + (u32)s.sh_size + ); + printf(" link: %04x = %04x\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 6*4), + (u32)s.sh_link + ); + printf(" info: %04x = %04x\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 7*4), + (u32)s.sh_info + ); + printf(" addr align: %04x = %04x\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 8*4), + (u32)s.sh_addralign + ); + printf(" ent size: %04x = %04x\n", + (u16)(shdr_offset + elf_offset + (ehdr.e_shentsize * idx) + 9*4), + (u32)s.sh_entsize + ); + } +} + +static void show_shdrs(void) +{ + unsigned int i; + + printf("ELF SHDRs\n"); + + if (ehdr.e_shnum == 0) + { + printf("No ELF Section Headers in this file.\n"); + } + else + { + if (arch64) + { +/* + printf(" file file file file file file file file file file\n"); + printf(" offset Name Offset Type Offset Flags Offset Address Offset Offset Offset Size Offset Link Offset Info Offset Aln Offset ES\n"); +*/ + printf(" file\n"); + printf(" Offset data\n"); + } + else + printf(" [Nr] Name Type Flags Address Offset Size Link Info Align ES\n"); + for (i = 0; i < ehdr.e_shnum; i++) + show_shdr(i); + } + printf("\n"); +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) + fail("usage: readself file.self"); + + self = mmap_file(argv[1]); + + parse_self(); + decrypt_header(); + + show_self_header(); + show_elf_header(); + show_phdrs(); + show_sinfo(); + show_sce_vinfo(); + show_ctrl(); + show_meta(); + show_shdrs(); + + return 0; +} diff --git a/scekrit.c b/scekrit.c new file mode 100644 index 0000000..ec46c2e --- /dev/null +++ b/scekrit.c @@ -0,0 +1,243 @@ +// SCEkrit.c (v1.01): Compute Sony's Private Keys +// Based on Sven's sceverify.c +// ------------------------------------------------------------- +// Compile by copying to fail0verflow's ps3tools and add +// SCEkrit.c to TOOLS in the Makefile. +// Run with two files (selfs, pkgs) signed by the same key. +// Depends on libgmp; add -lgmp to LDFLAGS +// - Aaron Lindsay / @AerialX +// And thanks gbcft! + +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include + +static int keyid = -1; + +static u8 *ptr1 = NULL; +static u8 *ptr2 = NULL; + +static u16 type; +typedef struct { + u16 flags; + u32 meta_offset; + u64 info_offset; + u32 app_type; + u64 filesize; + u64 header_len; +} fileinfo; + +static fileinfo info1; +static fileinfo info2; + +static struct keylist *klist = NULL; + +static struct keylist *self_load_keys(fileinfo* info) +{ + enum sce_key id; + + switch (info->app_type) { + case 1: + id = KEY_LV0; + break; + case 2: + id = KEY_LV1; + break; + case 3: + id = KEY_LV2; + break; + case 4: + id = KEY_APP; + break; + case 5: + id = KEY_ISO; + break; + case 6: + id = KEY_LDR; + break; + default: + fail("invalid type: %08x", info->app_type); + } + + return keys_get(id); +} + +static void read_self_header(u8* ptr, fileinfo* info) +{ + info->flags = be16(ptr + 0x08); + info->meta_offset = be32(ptr + 0x0c); + info->header_len = be64(ptr + 0x10); + info->filesize = be64(ptr + 0x18); + info->info_offset = be64(ptr + 0x28); + + info->app_type = be32(ptr + info->info_offset + 0x0c); + + klist = self_load_keys(info); +} + +static void read_pkg_header(u8* ptr, fileinfo* info) +{ + info->flags = be16(ptr + 0x08); + info->meta_offset = be32(ptr + 0x0c); + info->header_len = be64(ptr + 0x10); + info->filesize = be64(ptr + 0x18); + + klist = keys_get(KEY_PKG); +} + +static void decrypt(u8* ptr) +{ + if (keyid < 0) + keyid = sce_decrypt_header(ptr, klist); + else if (keyid != sce_decrypt_header(ptr, klist)) + fail("Both files must have the same key id"); + + if (keyid < 0) + fail("sce_decrypt_header failed"); + + if (sce_decrypt_data(ptr) < 0) + fail("sce_decrypt_data failed"); + + if (klist->keys[keyid].pub_avail < 0) + fail("no public key available"); + + if (ecdsa_set_curve(klist->keys[keyid].ctype) < 0) + fail("ecdsa_set_curve failed"); + + ecdsa_set_pub(klist->keys[keyid].pub); +} + +static void verify_signature(u8* ptr, fileinfo* info, u8* hash, u8** s, u8** r) +{ + u64 sig_len; + + sig_len = be64(ptr + info->meta_offset + 0x60); + *r = ptr + sig_len; + *s = *r + 21; + + sha1(ptr, sig_len, hash); + + printf("Signature\n"); + if (ecdsa_verify(hash, *r, *s)) + printf(" Status: OK\n"); + else + printf(" Status: FAIL\n"); +} + +static void load_num(mpz_t n, u8* un) +{ + char buffer[0x100]; + char* ptr = buffer; + int i; + for (i = 0; i < 21; i++) { + sprintf(ptr, "%02x", un[i]); + ptr += 2; + } + mpz_set_str(n, buffer, 16); +} + +static char* calculate_private_key(u8* us1, u8* us2, u8* uz1, u8* uz2, u8* un, u8* ur) +{ + mpz_t s1, s2, z1, z2, n, r, k, dA; + mpz_init(s1); mpz_init(s2); mpz_init(z1); mpz_init(z2); mpz_init(n); mpz_init(r); mpz_init(k); mpz_init(dA); + load_num(s1, us1); load_num(s2, us2); load_num(z1, uz1); load_num(z2, uz2); load_num(n, un); load_num(r, ur); + + mpz_sub(z2, z1, z2); + mpz_sub(s2, s1, s2); + mpz_invert(s2, s2, n); + mpz_mul(k, z2, s2); + mpz_mod(k, k, n); + + mpz_mul(s2, s1, k); + mpz_sub(s2, s2, z1); + mpz_invert(r, r, n); + mpz_mul(dA, s2, r); + mpz_mod(dA, dA, n); + +// printf("k: %s\n", mpz_get_str(NULL, 16, k)); + return mpz_get_str(NULL, 16, dA); +} + +int main(int argc, char *argv[]) +{ + if (argc != 3) + fail("usage: scesekrit signedfile1 signedfile2"); + + ptr1 = mmap_file(argv[1]); + ptr2 = mmap_file(argv[2]); + + type = be16(ptr1 + 0x0a); + if (type != be16(ptr2 + 0x0a)) + fail("Files must be the same type"); + + if (type == 1) { + read_self_header(ptr1, &info1); + } else if(type == 3) { + read_pkg_header(ptr1, &info1); + } else + fail("Unknown type: %d", type); + + if ((info1.flags) & 0x8000) + fail("devkit file; nothing to verify"); + + if (klist == NULL) + fail("no key found"); + + decrypt(ptr1); + + if (type == 1) { + read_self_header(ptr2, &info2); + } else if(type == 3) { + read_pkg_header(ptr2, &info2); + } else + fail("Unknown type: %d", type); + + if ((info2.flags) & 0x8000) + fail("devkit file; nothing to verify"); + + if (klist == NULL) + fail("no key found"); + + decrypt(ptr2); + + u8* s1; + u8* s2; + u8 z1[21]; + u8 z2[21]; + u8* r1; + u8* r2; + u8 ec[21]; + u8 n[21]; + z1[0] = 0; + z2[0] = 0; + + ecdsa_get_params(klist->keys[keyid].ctype, ec, ec, ec, n, ec, ec); + + printf("%s ", argv[1]); + verify_signature(ptr1, &info1, z1 + 1, &s1, &r1); + printf("%s ", argv[2]); + verify_signature(ptr2, &info2, z2 + 1, &s2, &r2); + + if (memcmp(r1, r2, 21)) + fail("Both files must share the same r signature value."); + + const char* dA = calculate_private_key(s1, s2, z1, z2, n, r1); + + int len = strlen(dA); + int i; + printf("Private Key: "); + for (i = len / 2; i < 21; i++) + printf("00"); + printf("%s\n", dA); + + return 0; +} diff --git a/sceverify.c b/sceverify.c new file mode 100644 index 0000000..c88daea --- /dev/null +++ b/sceverify.c @@ -0,0 +1,225 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include + +static u8 *ptr = NULL; + +static u16 type; +static u16 flags; +static u32 meta_offset; +static u64 info_offset; +static u32 app_type; +static u64 filesize; +static u64 header_len; +static int did_fail = 0; + +static struct keylist *klist = NULL; + +static struct keylist *self_load_keys(void) +{ + enum sce_key id; + + switch (app_type) { + case 1: + id = KEY_LV0; + break; + case 2: + id = KEY_LV1; + break; + case 3: + id = KEY_LV2; + break; + case 4: + id = KEY_APP; + break; + case 5: + id = KEY_ISO; + break; + case 6: + id = KEY_LDR; + break; + default: + fail("invalid type: %08x", app_type); + } + + return keys_get(id); +} + +static void read_self_header(void) +{ + flags = be16(ptr + 0x08); + meta_offset = be32(ptr + 0x0c); + header_len = be64(ptr + 0x10); + filesize = be64(ptr + 0x18); + info_offset = be64(ptr + 0x28); + + app_type = be32(ptr + info_offset + 0x0c); + + klist = self_load_keys(); +} + +static void read_pkg_header(void) +{ + flags = be16(ptr + 0x08); + meta_offset = be32(ptr + 0x0c); + header_len = be64(ptr + 0x10); + filesize = be64(ptr + 0x18); + + klist = keys_get(KEY_PKG); +} + +static void read_spp_header(void) +{ + flags = be16(ptr + 0x08); + meta_offset = be32(ptr + 0x0c); + header_len = be64(ptr + 0x10); + filesize = be64(ptr + 0x18); + + klist = keys_get(KEY_SPP); +} + +static void decrypt(void) +{ + int keyid; + + keyid = sce_decrypt_header(ptr, klist); + + if (keyid < 0) + fail("sce_decrypt_header failed"); + + if (sce_decrypt_data(ptr) < 0) + fail("sce_decrypt_data failed"); + + if (klist->keys[keyid].pub_avail < 0) + fail("no public key available"); + + if (ecdsa_set_curve(klist->keys[keyid].ctype) < 0) + fail("ecdsa_set_curve failed"); + + ecdsa_set_pub(klist->keys[keyid].pub); +} + +static void verify_signature(void) +{ + u8 *r, *s; + u8 hash[20]; + u64 sig_len; + + sig_len = be64(ptr + meta_offset + 0x60); + r = ptr + sig_len; + s = r + 21; + + sha1(ptr, sig_len, hash); + + printf("Signature\n"); + if (ecdsa_verify(hash, r, s)) + printf(" Status: OK\n"); + else + printf(" Status: FAIL\n"); + + printf("\n"); +} + +static int verify_hash(u8 *p, u8 *hashes) +{ + u64 offset; + u64 size; + u64 id; + u8 *hash, *key; + u8 result[20]; + + offset = be64(p + 0x00); + size = be64(p + 0x08); + id = be32(p + 0x1c); + + if (id == 0xffffffff) + return 0; + + hash = hashes + id * 0x10; + key = hash + 0x20; + + // XXX: possible integer overflow here + if (offset > (filesize + header_len)) + return 1; + + // XXX: possible integer overflow here + if ((offset + size) > (filesize + header_len)) + return 1; + + sha1_hmac(key, ptr + offset, size, result); + + if (memcmp(result, hash, 20) == 0) + return 0; + else + return -1; +} + +static void verify_hashes(void) +{ + u32 meta_n_hdr; + u32 i; + u8 *hashes; + int res; + + meta_n_hdr = be32(ptr + meta_offset + 0x60 + 0xc); + hashes = ptr + meta_offset + 0x80 + 0x30 * meta_n_hdr; + + printf("Hashes\n"); + + for (i = 0; i < meta_n_hdr; i++) { + printf(" Section #%02d: ", i); + res = verify_hash(ptr + meta_offset + 0x80 + 0x30 * i, hashes); + if (res < 0) { + did_fail = 1; + printf("FAIL*\n"); + } else if (res > 0) { + printf("???\n"); + } else { + printf("OK\n"); + } + } + + printf("\n"); +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) + fail("usage: sceverify filename"); + + ptr = mmap_file(argv[1]); + + type = be16(ptr + 0x0a); + + if (type == 1) + read_self_header(); + else if(type == 3) + read_pkg_header(); + else if(type == 4) + read_spp_header(); + else + fail("Unknown type: %d", type); + + if (flags & 0x8000) + fail("devkit file; nothing to verify"); + + if (klist == NULL) + fail("no key found"); + + decrypt(); + verify_signature(); + verify_hashes(); + + if (did_fail) + printf(" * please not that the hash will always fail for " + "unaligned non-LOAD phdrs\n"); + return 0; +} diff --git a/self.c b/self.c new file mode 100644 index 0000000..94b7b1e --- /dev/null +++ b/self.c @@ -0,0 +1,446 @@ +/* + * This software is distributed under the terms of the GNU General Public + * License ("GPL") version 2, as published by the Free Software Foundation. + */ + +#include "tools.h" +#include "self.h" +#include "common.h" + +#include +#include + +static struct keylist *load_keys(APP_INFO *app_info); +static int decrypt_metadata(uint8_t *metadata, uint32_t metadata_size, + struct keylist *klist); + + +void +self_read_headers(FILE *in, SELF *self, APP_INFO *app_info, ELF *elf, + ELF_PHDR **phdr, ELF_SHDR **shdr, SECTION_INFO **section_info, + SCEVERSION_INFO *sceversion_info, CONTROL_INFO **control_info) +{ + + // SELF + if (fread (self, sizeof(SELF), 1, in) != 1) { + ERROR (-3, "Couldn't read SELF header"); + } + + self->magic = swap32 (self->magic); + self->version = swap32 (self->version); + self->flags = swap16 (self->flags); + self->type = swap16 (self->type); + self->metadata_offset = swap32 (self->metadata_offset); + self->header_len = swap64 (self->header_len); + self->elf_filesize = swap64 (self->elf_filesize); + self->appinfo_offset = swap64 (self->appinfo_offset); + self->elf_offset = swap64 (self->elf_offset); + self->phdr_offset = swap64 (self->phdr_offset); + self->shdr_offset = swap64 (self->shdr_offset); + self->section_info_offset = swap64 (self->section_info_offset); + self->sceversion_offset = swap64 (self->sceversion_offset); + self->controlinfo_offset = swap64 (self->controlinfo_offset); + self->controlinfo_size = swap64 (self->controlinfo_size); + + if (self->magic != SCE_MAGIC) { + ERROR (-3, "not a SELF\n"); + } + + // APP INFO + if (app_info) { + fseek (in, self->appinfo_offset, SEEK_SET); + if (fread (app_info, sizeof(APP_INFO), 1, in) != 1) { + ERROR (-3, "Couldn't read APP INFO header"); + } + app_info->authid = swap64 (app_info->authid); + app_info->vendor_id = swap32 (app_info->vendor_id); + app_info->self_type = swap32 (app_info->self_type); + app_info->version = swap32 (app_info->version); + } + + // ELF + if (elf) { + fseek (in, self->elf_offset, SEEK_SET); + if (fread (elf, sizeof(ELF), 1, in) != 1) { + ERROR (-3, "Couldn't read APP INFO header"); + } + elf->type = swap16 (elf->type); + elf->machine = swap16 (elf->machine); + elf->version = swap32 (elf->version); + elf->entry_point = swap64 (elf->entry_point); + elf->phdr_offset = swap64 (elf->phdr_offset); + elf->shdr_offset = swap64 (elf->shdr_offset); + elf->flags = swap16 (elf->flags); + elf->header_size = swap32 (elf->header_size); + elf->phent_size = swap16 (elf->phent_size); + elf->phnum = swap16 (elf->phnum); + elf->shent_size = swap16 (elf->shent_size); + elf->shnum = swap16 (elf->shnum); + elf->shstrndx = swap16 (elf->shstrndx); + } + + // PHDR and SECTION INFO + if (phdr || section_info) { + uint16_t phnum = 0; + uint16_t i; + + if (elf) { + phnum = elf->phnum; + } else { + fseek (in, self->elf_offset + 52, SEEK_SET); + fread (&phnum, sizeof(uint16_t), 1, in); + } + + if (phdr) { + ELF_PHDR *elf_phdr = NULL; + + elf_phdr = malloc (sizeof(ELF_PHDR) * phnum); + + fseek (in, self->phdr_offset, SEEK_SET); + if (fread (elf_phdr, sizeof(ELF_PHDR), phnum, in) != phnum) { + ERROR (-3, "Couldn't read ELF PHDR header"); + } + + for (i = 0; i < phnum; i++) { + elf_phdr[i].type = swap32 (elf_phdr[i].type); + elf_phdr[i].flags = swap32 (elf_phdr[i].flags); + elf_phdr[i].offset_in_file = swap64 (elf_phdr[i].offset_in_file); + elf_phdr[i].vitual_addr = swap64 (elf_phdr[i].vitual_addr); + elf_phdr[i].phys_addr = swap64 (elf_phdr[i].phys_addr); + elf_phdr[i].segment_size = swap64 (elf_phdr[i].segment_size); + elf_phdr[i].segment_mem_size = swap64 (elf_phdr[i].segment_mem_size); + elf_phdr[i].alignment = swap64 (elf_phdr[i].alignment); + } + + *phdr = elf_phdr; + } + + // SECTION INFO + if (section_info) { + SECTION_INFO *sections = NULL; + + sections = malloc (sizeof(SECTION_INFO) * phnum); + + fseek (in, self->section_info_offset, SEEK_SET); + if (fread (sections, sizeof(SECTION_INFO), phnum, in) != phnum) { + ERROR (-3, "Couldn't read SECTION INFO header"); + } + + for (i = 0; i < phnum; i++) { + sections[i].offset = swap64 (sections[i].offset); + sections[i].size = swap64 (sections[i].size); + sections[i].compressed = swap32 (sections[i].compressed); + sections[i].encrypted = swap32 (sections[i].encrypted); + } + + *section_info = sections; + } + } + + // SCE VERSION INFO + if (sceversion_info) { + fseek (in, self->sceversion_offset, SEEK_SET); + if (fread (sceversion_info, sizeof(SCEVERSION_INFO), 1, in) != 1) { + ERROR (-3, "Couldn't read SCE VERSION INFO header"); + } + } + + // CONTROL INFO + if (control_info) { + uint32_t offset = 0; + uint32_t index = 0; + CONTROL_INFO *info = NULL; + + while (offset < self->controlinfo_size) { + + info = realloc (info, sizeof(CONTROL_INFO) * (index + 1)); + + fseek (in, self->controlinfo_offset + offset, SEEK_SET); + + if (fread (info + index, sizeof(CONTROL_INFO), 1, in) != 1) { + ERROR (-3, "Couldn't read CONTROL INFO header"); + } + + info[index].type = swap32 (info[index].type); + info[index].size = swap32 (info[index].size); + if (info[index].type == 1) + info[index].control_flags.control_flags = + swap64 (info[index].control_flags.control_flags); + + offset += info[index].size; + index++; + } + *control_info = info; + } + + + // SHDR + if (shdr) { + uint16_t shnum = 0; + uint16_t i; + ELF_SHDR *elf_shdr = NULL; + + if (elf) { + shnum = elf->shnum; + } else { + fseek (in, self->elf_offset + 56, SEEK_SET); + fread (&shnum, sizeof(uint16_t), 1, in); + } + + if (shnum > 0 && self->shdr_offset != 0) { + elf_shdr = malloc (sizeof(ELF_SHDR) * shnum); + + fseek (in, self->shdr_offset, SEEK_SET); + if (fread (elf_shdr, sizeof(ELF_SHDR), shnum, in) != shnum) { + ERROR (-3, "Couldn't read ELF SHDR header"); + } + + for (i = 0; i < shnum; i++) { + elf_shdr[i].name_idx = swap32 (elf_shdr[i].name_idx); + elf_shdr[i].type = swap32 (elf_shdr[i].type); + elf_shdr[i].flags = swap64 (elf_shdr[i].flags); + elf_shdr[i].virtual_addr = swap64 (elf_shdr[i].virtual_addr); + elf_shdr[i].offset_in_file = swap64 (elf_shdr[i].offset_in_file); + elf_shdr[i].segment_size = swap64 (elf_shdr[i].segment_size); + elf_shdr[i].link = swap32 (elf_shdr[i].link); + elf_shdr[i].info = swap32 (elf_shdr[i].info); + elf_shdr[i].addr_align = swap64 (elf_shdr[i].addr_align); + elf_shdr[i].entry_size = swap64 (elf_shdr[i].entry_size); + } + + *shdr = elf_shdr; + } + } + +} + + +void +self_read_metadata (FILE *in, SELF *self, APP_INFO *app_info, + METADATA_INFO *metadata_info, METADATA_HEADER *metadata_header, + METADATA_SECTION_HEADER **section_headers, uint8_t **keys, + SIGNATURE_INFO *signature_info, SIGNATURE *signature) +{ + uint8_t *metadata = NULL; + uint32_t metadata_size = self->header_len - self->metadata_offset - 0x20; + uint8_t *ptr = NULL; + uint32_t i; + + metadata = malloc (metadata_size); + fseek (in, self->metadata_offset + 0x20, SEEK_SET); + + if (fread (metadata, 1, metadata_size, in) != metadata_size) { + ERROR (-3, "Couldn't read METADATA"); + } + + if (self->flags != 0x800) { + struct keylist *klist; + + klist = load_keys(app_info); + if (klist == NULL) + ERROR(-5, "no key found"); + + if (decrypt_metadata (metadata, metadata_size, klist) < 0) + ERROR (-5, "Error decrypting metadata"); + } + + ptr = metadata; + *metadata_info = *((METADATA_INFO *)ptr); + ptr += sizeof(METADATA_INFO); + if (metadata_header) { + *metadata_header = *((METADATA_HEADER *)ptr); + metadata_header->signature_input_length = + swap64 (metadata_header->signature_input_length); + metadata_header->section_count = swap32 (metadata_header->section_count); + metadata_header->key_count = swap32 (metadata_header->key_count); + metadata_header->signature_info_size = + swap32 (metadata_header->signature_info_size); + } + ptr += sizeof(METADATA_HEADER); + if (section_headers) { + *section_headers = malloc (sizeof(METADATA_SECTION_HEADER) * + metadata_header->section_count); + for (i = 0; i < metadata_header->section_count; i++) { + (*section_headers)[i] = *((METADATA_SECTION_HEADER *)ptr); + ptr += sizeof(METADATA_SECTION_HEADER); + (*section_headers)[i].data_offset = swap64 ((*section_headers)[i].data_offset); + (*section_headers)[i].data_size = swap64 ((*section_headers)[i].data_size); + (*section_headers)[i].type = swap32 ((*section_headers)[i].type); + (*section_headers)[i].program_idx = swap32 ((*section_headers)[i].program_idx); + (*section_headers)[i].sha1_idx = swap32 ((*section_headers)[i].sha1_idx); + (*section_headers)[i].encrypted = swap32 ((*section_headers)[i].encrypted); + (*section_headers)[i].key_idx = swap32 ((*section_headers)[i].key_idx); + (*section_headers)[i].iv_idx = swap32 ((*section_headers)[i].iv_idx); + (*section_headers)[i].compressed = swap32 ((*section_headers)[i].compressed); + }; + } else { + ptr += sizeof(METADATA_SECTION_HEADER) * metadata_header->section_count; + } + *keys = malloc (metadata_header->key_count * 0x10); + memcpy (*keys, ptr, metadata_header->key_count * 0x10); + ptr += metadata_header->key_count * 0x10; + if (signature_info) { + *signature_info = *((SIGNATURE_INFO *)ptr); + signature_info->signature_size = swap32 (signature_info->signature_size); + } + ptr += sizeof(SIGNATURE_INFO); + if (signature) { + *signature = *((SIGNATURE *)ptr); + } + ptr += sizeof(SIGNATURE); + free (metadata); +} + +int +self_load_sections (FILE *in, SELF *self, ELF *elf, ELF_PHDR **phdr, + METADATA_HEADER *metadata_header, METADATA_SECTION_HEADER **section_headers, + uint8_t **keys, SELF_SECTION **sections) +{ + uint32_t num_sections = 0; + uint32_t i; + + num_sections = metadata_header->section_count + 1; + + *sections = malloc (sizeof(SELF_SECTION) * num_sections); + // ELF header + for (i = 0; i < num_sections; i++) { + uint32_t size; + METADATA_SECTION_HEADER *hdr; + + if (i == 0) { + uint32_t elf_size; + + hdr = (*section_headers); + elf_size = elf->header_size + (elf->phent_size * elf->phnum); + size = hdr->data_offset - self->header_len; + if (size < elf_size) + size = elf_size; + (*sections)[i].offset = 0; + (*sections)[i].size = size; + (*sections)[i].data = malloc (size); + + fseek (in, self->header_len, SEEK_SET); + if (fread ((*sections)[0].data, 1, size, in) != size) { + ERROR (-6, "Couldn't read section"); + } + + fseek (in, self->elf_offset, SEEK_SET); + if (fread ((*sections)[0].data, 1, size, in) != size) { + ERROR (-6, "Couldn't read section"); + } + } else { + uint8_t *temp_data = NULL; + + hdr = (*section_headers) + i - 1; + if (hdr->type == 2) { + // phdr + size = (*phdr)[hdr->program_idx].segment_size; + (*sections)[i].offset = (*phdr)[hdr->program_idx].offset_in_file; + } else if (hdr->type == 1) { + // shdr + size = (*section_headers)[i-1].data_size; + (*sections)[i].offset = elf->shdr_offset; + } else { + fail ("Unknown section type"); + } + + (*sections)[i].size = size; + (*sections)[i].data = malloc (size); + + temp_data = malloc (hdr->data_size); + fseek (in, hdr->data_offset, SEEK_SET); + if (fread (temp_data, 1, hdr->data_size, in) != hdr->data_size) { + ERROR (-6, "Couldn't read section"); + } + + if (hdr->encrypted == 3) + aes128ctr(*keys + 0x10 * hdr->key_idx, *keys + 0x10 * hdr->iv_idx, + temp_data, hdr->data_size, temp_data); + + if (hdr->compressed == 2) + decompress(temp_data, hdr->data_size, (*sections)[i].data, size); + else + memcpy ((*sections)[i].data, temp_data, size); + + free (temp_data); + } + } + + return num_sections; +} + +void +self_free_sections (SELF_SECTION **sections, uint32_t num_sections) +{ + uint32_t i; + + for (i = 0; i < num_sections; i++) { + free ((*sections)[i].data); + } + free (*sections); + *sections = NULL; +} + +static struct keylist * +load_keys(APP_INFO *app_info) +{ + enum sce_key id; + + switch (app_info->self_type) { + case 1: + id = KEY_LV0; + break; + case 2: + id = KEY_LV1; + break; + case 3: + id = KEY_LV2; + break; + case 4: + id = KEY_APP; + break; + case 5: + id = KEY_ISO; + break; + case 6: + id = KEY_LDR; + break; + default: + fprintf (stderr, "SELF type is invalid : 0x%08X\n", app_info->self_type); + exit (-4); + } + + return keys_get(id); +} + + +static int +decrypt_metadata(uint8_t *metadata, uint32_t metadata_size, + struct keylist *klist) +{ + uint32_t i; + METADATA_INFO metadata_info; + uint8_t zero[16] = {0}; + + memset (zero, 0, 16); + for (i = 0; i < klist->n; i++) { + aes256cbc(klist->keys[i].key, klist->keys[i].iv, + metadata, sizeof(METADATA_INFO), (uint8_t *) &metadata_info); + + if (memcmp (metadata_info.key_pad, zero, 16) == 0 && + memcmp (metadata_info.iv_pad, zero, 16) == 0) { + memcpy(metadata, &metadata_info, sizeof(METADATA_INFO)); + break; + } + } + + if (i >= klist->n) + return -1; + + aes128ctr(metadata_info.key, metadata_info.iv, + metadata + sizeof(METADATA_INFO), + metadata_size - sizeof(METADATA_INFO), + metadata + sizeof(METADATA_INFO)); + + return i; +} diff --git a/self.h b/self.h new file mode 100644 index 0000000..c62d890 --- /dev/null +++ b/self.h @@ -0,0 +1,197 @@ +/* + * This software is distributed under the terms of the GNU General Public + * License ("GPL") version 2, as published by the Free Software Foundation. + */ + +#ifndef SELF_H__ +#define SELF_H__ + +#include +#include + +#define SCE_MAGIC 0x53434500 + +typedef struct { + uint32_t magic; + uint32_t version; + uint16_t flags; + uint16_t type; + uint32_t metadata_offset; + uint64_t header_len; + uint64_t elf_filesize; + uint64_t unknown; + uint64_t appinfo_offset; + uint64_t elf_offset; + uint64_t phdr_offset; + uint64_t shdr_offset; + uint64_t section_info_offset; + uint64_t sceversion_offset; + uint64_t controlinfo_offset; + uint64_t controlinfo_size; + uint64_t padding; +} __attribute__((packed)) SELF; + +typedef struct { + uint64_t authid; + uint32_t vendor_id; + uint32_t self_type; + uint32_t version; + uint8_t padding[12]; +} __attribute__((packed)) APP_INFO; + +typedef struct { + uint8_t ident[16]; + uint16_t type; + uint16_t machine; + uint32_t version; + uint64_t entry_point; + uint64_t phdr_offset; + uint64_t shdr_offset; + uint16_t flags; + uint32_t header_size; + uint16_t phent_size; + uint16_t phnum; + uint16_t shent_size; + uint16_t shnum; + uint16_t shstrndx; +} __attribute__((packed)) ELF; + +typedef struct { + uint32_t type; + uint32_t flags; + uint64_t offset_in_file; + uint64_t vitual_addr; + uint64_t phys_addr; + uint64_t segment_size; + uint64_t segment_mem_size; + uint64_t alignment; +} __attribute__((packed)) ELF_PHDR; + +typedef struct { + uint32_t name_idx; + uint32_t type; + uint64_t flags; + uint64_t virtual_addr; + uint64_t offset_in_file; + uint64_t segment_size; + uint32_t link; + uint32_t info; + uint64_t addr_align; + uint64_t entry_size; +} __attribute__((packed)) ELF_SHDR; + +typedef struct { + uint64_t offset; + uint64_t size; + uint32_t compressed; // 2=compressed + uint32_t unknown1; + uint32_t unknown2; + uint32_t encrypted; // 1=encrypted +} __attribute__((packed)) SECTION_INFO; + +typedef struct { + uint32_t unknown1; + uint32_t unknown2; + uint32_t unknown3; + uint32_t unknown4; +} __attribute__((packed)) SCEVERSION_INFO; + +typedef struct { + uint32_t type; // 1==control flags; 2==file digest + uint32_t size; + union { + // type 1 + struct { + uint64_t control_flags; + uint8_t padding[32]; + } control_flags; + + // type 2 + struct { + uint64_t unknown; + uint8_t digest1[20]; + uint8_t digest2[20]; + uint8_t padding[8]; + } file_digest; + }; +} __attribute__((packed)) CONTROL_INFO; + + +typedef struct { + //uint8_t ignore[32]; + uint8_t key[16]; + uint8_t key_pad[16]; + uint8_t iv[16]; + uint8_t iv_pad[16]; +} __attribute__((packed)) METADATA_INFO; + +typedef struct { + uint64_t signature_input_length; + uint32_t unknown1; + uint32_t section_count; + uint32_t key_count; + uint32_t signature_info_size; + uint64_t unknown2; +} __attribute__((packed)) METADATA_HEADER; + +typedef struct { + uint64_t data_offset; + uint64_t data_size; + uint32_t type; // 1 = shdr, 2 == phdr + uint32_t program_idx; + uint32_t unknown; + uint32_t sha1_idx; + uint32_t encrypted; // 3=yes; 1=no + uint32_t key_idx; + uint32_t iv_idx; + uint32_t compressed; // 2=yes; 1=no +} __attribute__((packed)) METADATA_SECTION_HEADER; + +typedef struct { + uint8_t sha1[20]; + uint8_t padding[12]; + uint8_t hmac_key[64]; +} __attribute__((packed)) SECTION_HASH; + +typedef struct { + uint32_t unknown1; + uint32_t signature_size; + uint64_t unknown2; + uint64_t unknown3; + uint64_t unknown4; + uint64_t unknown5; + uint32_t unknown6; + uint32_t unknown7; +} __attribute__((packed)) SIGNATURE_INFO; + +typedef struct { + uint8_t r[21]; + uint8_t s[21]; + uint8_t padding[6]; +} __attribute__((packed)) SIGNATURE; + + +typedef struct { + uint8_t *data; + uint64_t size; + uint64_t offset; +} SELF_SECTION; + + + +void self_read_headers(FILE *in, SELF *self, APP_INFO *app_info, ELF *elf, + ELF_PHDR **phdr, ELF_SHDR **shdr, SECTION_INFO **section_info, + SCEVERSION_INFO *sceversion_info, CONTROL_INFO **control_info); + +void self_read_metadata (FILE *in, SELF *self, APP_INFO *app_info, + METADATA_INFO *metadata_info, METADATA_HEADER *metadata_header, + METADATA_SECTION_HEADER **section_headers, uint8_t **keys, + SIGNATURE_INFO *signature_info, SIGNATURE *signature); + +int self_load_sections (FILE *in, SELF *self, ELF *elf, ELF_PHDR **phdr, + METADATA_HEADER *metadata_header, METADATA_SECTION_HEADER **section_headers, + uint8_t **keys, SELF_SECTION **sections); + +void self_free_sections (SELF_SECTION **sections, uint32_t num_sections); + +#endif /* SELF_H__ */ diff --git a/self_rebuilder.c b/self_rebuilder.c new file mode 100644 index 0000000..ce92854 --- /dev/null +++ b/self_rebuilder.c @@ -0,0 +1,693 @@ +// based on fail0verflow reverse engineering of self executables +// Copyright 2010 Sven Peter +// 2011 Modified By Anonymous developers on EFNET +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include + +#define ALIGNMENT 0x20 +#define MAX_PHDR 255 +//#define DEBUG 1 + +// pseudo header for self_rebuilder +// All structure start here +static struct { + u32 offset ; + u32 size ; + u32 compressed ; + u32 size_uncompressed ; + u32 elf_offset ; +} self_sections[MAX_PHDR] ; + +struct self_sec { + u32 idx ; + u64 offset ; + u64 size ; + u32 compressed ; + u32 encrypted ; + u64 next ; +} ; + +static struct { + u32 count ; + u32 address ; + int size ; + u32 number ; + u32 compressed ; +} compressed_sections[MAX_PHDR] ; + +enum { + VERIFY_HASH = 0, + SIGN_HASH, +} ; + +// end + +static u8 *elf = NULL ; +static u8 *self = NULL ; + +static u32 type ; +static int packed_type ; + +struct elf_hdr ehdr ; +struct elf_shdr eshdr ; +struct elf_phdr phdr[MAX_PHDR] ; + +static int arch64 ; + +static u32 meta_offset ; +static u64 elf_size ; +static u64 info_offset ; +static u64 elf_offset ; +static u64 phdr_offset ; +static u64 shdr_offset ; +static u64 sec_offset ; +static u64 ctrl_offset ; +static u64 version ; +static u64 auth_id ; +static u64 vendor_id ; +static u16 sdk_type ; +static char versionsuffix[4] ; + +static u32 n_sections ; + +// readself +static u64 filesize ; +static int self_size ; +static u64 header_len ; +static u64 ver_info ; +static u64 ctrl_size ; +static int decrypted = -1 ; + +// +struct key ks ; + +static const char *elf_name = NULL ; +static const char *self_name = NULL ; + +struct id2name_tbl t_sdk_type[] = { + {0, "Retail (Type 0)"}, + {1, "Retail"}, + {2, "Retail (Type 1)"}, + {3, "Unknown SDK3"}, + {4, "Unknown > = 3.42"}, + {5, "Unknown SDK5"}, + {6, "Unknown SDK6"}, + {7, "Unknown > = 3.50"}, + {8, "Unknown SDK8"}, + {9, "Unknown SDK9"}, + {0x8000, "Devkit"}, + {0, NULL} +} ; + +struct id2name_tbl t_app_type[] = { + {1, "level 0"}, + {2, "level 1"}, + {3, "level 2"}, + {4, "application"}, + {5, "isolated SPU module"}, + {6, "secure loader"}, + {7, "unknown app type"}, + {8, "NP-DRM application"}, + {0, NULL} +} ; + +static void +get_keys (const char *suffix) +{ + if (key_get (packed_type, suffix, &ks) < 0) { + fail ("key_get failed") ; + } + + if (ks.pub_avail < 0) { + fail ("no public key available") ; + } + + if (ks.priv_avail < 0) { + fail ("no private key available") ; + } + + if (ecdsa_set_curve (ks.ctype) < 0) { + fail ("ecdsa_set_curve failed") ; + } + + ecdsa_set_pub (ks.pub) ; + ecdsa_set_priv (ks.priv) ; +} + +static void +parse_elf (void) +{ + u32 i ; + + arch64 = elf_read_hdr (elf, &ehdr) ; + + for (i = 0; i < ehdr.e_phnum; i++) { + elf_read_phdr (arch64, elf + ehdr.e_phoff + i * ehdr.e_phentsize, &phdr[i]) ; + } +} + +static void +parse_self (void) +{ + //here we are taking every self information needed and more + sdk_type = be16 (self + 0x08) ; + meta_offset = be32 (self + 0x0c) ; + header_len = be64 (self + 0x10) ; + filesize = be64 (self + 0x18) ; + info_offset = be64 (self + 0x28) ; + elf_offset = be64 (self + 0x30) ; + phdr_offset = be64 (self + 0x38) - elf_offset ; + shdr_offset = be64 (self + 0x40) - elf_offset ; + sec_offset = be64 (self + 0x48) ; + ver_info = be64 (self + 0x50) ; + ctrl_offset = be64 (self + 0x58) ; + ctrl_size = be64 (self + 0x60) ; + + vendor_id = be32 (self + info_offset + 0x08) ; + auth_id = be64 (self + info_offset + 0x00) ; + type = be32 (self + info_offset + 0x0c) ; + packed_type = (type - 1) ; + version = be64 (self + info_offset + 0x10) ; + + elf = self + elf_offset ; + arch64 = elf_read_hdr (elf, &ehdr) ; +} + +static int +qsort_compare (const void *a, const void *b) +{ + const struct self_sec *sa, *sb ; + + sa = a ; + sb = b ; + + if (sa->offset > sb->offset) { + return 1 ; + } else if (sa->offset < sb->offset) { + return -1 ; + } else { + return 0 ; + } +} + +static void +read_section (u32 i, struct self_sec *sec) +{ + u8 *ptr ; + + ptr = self + sec_offset + i * 0x20 ; + + sec->idx = i ; + sec->offset = be64 (ptr + 0x00) ; + sec->size = be64 (ptr + 0x08) ; + sec->compressed = be32 (ptr + 0x10) == 2 ? 1 : 0 ; + sec->encrypted = be32 (ptr + 0x1c) ; + sec->next = be64 (ptr + 0x20) ; +} + + +// Change compressed section size +static void +change_section_size (u32 i, u64 size) +{ + u8 *ptr ; + + ptr = self + sec_offset + i * 0x20 ; + + self_sections[i + 1].size = size ; + wbe64 (ptr + 0x08, size) ; + wbe64 (self + meta_offset + 0x60 + 0x20 + i * 0x30 + 0x08, size) ; +} + +// Change compressed section offset +/* +static void +change_section_offset (u32 i, int delta) +{ + u8 *ptr ; + u64 val ; + + ptr = self + sec_offset + i * 0x20 ; + val = be64 (ptr) ; + val += delta ; + wbe64 (ptr, val) ; + + self_sections[i + 1].offset = val ; + wbe64 (self + meta_offset + 0x60 + 0x20 + i * 0x30 + 0x00, val) ; + compressed_sections[i].address += delta ; + +} +*/ + +// read every original section to know the number and the position +static void +read_sections (void) +{ + struct self_sec s[MAX_PHDR] ; + struct elf_phdr p ; + u32 i ; + u32 j ; + u32 n_secs ; + u32 self_offset, elf_offset ; + + memset (s, 0, sizeof s) ; + for (i = 0, j = 0; i < ehdr.e_phnum; i++) { + read_section (i, &s[j]) ; + if (s[j].compressed) { + j++ ; + } + } + + n_secs = j ; + qsort (s, n_secs, sizeof (*s), qsort_compare) ; + + elf_offset = 0 ; + self_offset = header_len ; + j = 0 ; + i = 0 ; + while (elf_offset < filesize) { + if (i == n_secs) { + self_sections[j].offset = self_offset ; + self_sections[j].size = filesize - elf_offset ; + self_sections[j].compressed = 0 ; + self_sections[j].size_uncompressed = filesize - elf_offset ; + self_sections[j].elf_offset = elf_offset ; + elf_offset = filesize ; + } else if (self_offset == s[i].offset) { + self_sections[j].offset = self_offset ; + self_sections[j].size = s[i].size ; + compressed_sections[i].size = self_sections[j].size ; + compressed_sections[i].address = self_sections[j].offset ; + self_sections[j].compressed = 1 ; + elf_read_phdr (arch64, elf + phdr_offset + (ehdr.e_phentsize * s[i].idx), &p) ; + self_sections[j].size_uncompressed = p.p_filesz ; + self_sections[j].elf_offset = p.p_off ; + elf_offset = p.p_off + p.p_filesz ; + self_offset = s[i].next ; + compressed_sections[i].number = j ; + compressed_sections[i].compressed = 1 ; +#ifdef DEBUG + printf ("section number compressed %d size 0x%x\n", + compressed_sections[0].count, compressed_sections[i].size) ; +#endif + i++ ; + compressed_sections[0].count = i ; + } else { + elf_read_phdr (arch64, elf + phdr_offset + (ehdr.e_phentsize * s[i].idx), &p) ; + self_sections[j].offset = self_offset ; + self_sections[j].size = p.p_off - elf_offset ; + self_sections[j].compressed = 0 ; + self_sections[j].size_uncompressed = self_sections[j].size ; + self_sections[j].elf_offset = elf_offset ; + + elf_offset += self_sections[j].size ; + self_offset += s[i].offset - self_offset ; + } + j++ ; + } + n_sections = j ; +} + + +static void +write_sections (void) +{ + unsigned int i = 0 ; + unsigned int level ; + unsigned long size_compressed = 16 * 1024 * 1024 ; + u8 *compressed_buffer = NULL ; + + for (i = 0; i < compressed_sections[0].count; i++) { + level = 7 ; + if (compressed_sections[i].compressed) { + size_compressed = 16 * 1024 * 1024 ; + compressed_buffer = malloc (size_compressed) ; + if (compress2 (compressed_buffer, &size_compressed, + elf + phdr[i].p_off, phdr[i].p_filesz, 6) != Z_OK) { + perror ("couldn't compress data") ; + exit (-1) ; + } + +#if 1 + while ( (int) size_compressed > compressed_sections[i].size ) { + if (compress2 (compressed_buffer, &size_compressed, + elf + phdr[i].p_off, phdr[i].p_filesz, level) != Z_OK) { + perror ("couldn't compress data") ; + exit (-1) ; + } + if ( (int) size_compressed > compressed_sections[i].size) { + if ( level > 9 ) { + perror ("Compressed data is too big") ; + exit (-1) ; + } + } + level++; + } +#else + { + int delta, j ; + delta = size_compressed - compressed_sections[i].size ; + + if (delta % 0x10 != 0) { + delta += (0x10 - delta % 0x10) ; + } + self_size += delta ; + for (j = i + 1; j < compressed_sections[0].count; j++) { + change_section_offset (j, delta) ; + } + } +#endif + + printf (" ELF section %02x\n level: %d\n size: 0x%x\n new size: 0x%x\n", + compressed_sections[i].number, + (int) level, + compressed_sections[i].size, + (unsigned int) size_compressed) ; + change_section_size (i, size_compressed) ; + + memcpy (self + compressed_sections[i].address, compressed_buffer, + size_compressed) ; + compressed_sections[i].size = size_compressed ; + free (compressed_buffer) ; + } + } + printf ("\n") ; +} + +static void +sign_header (void) +{ + u8 *r, *s ; + u8 hash[20] ; + u64 sig_len ; + + sig_len = be64 (self + meta_offset + 0x60) ; + r = self + sig_len ; + s = r + 21 ; + + sha1 (self, sig_len, hash) ; + + ecdsa_sign (hash, r, s) ; +} + +static u64 +get_filesize (const char *path) +{ + struct stat st ; + + stat (path, &st) ; + + return st.st_size ; +} + +static struct keylist * +self_load_keys (void) +{ + enum sce_key id ; + + switch (type) { + case 1: + id = KEY_LV0 ; + break ; + case 2: + id = KEY_LV1 ; + break ; + case 3: + id = KEY_LV2 ; + break ; + case 4: + id = KEY_APP ; + break ; + case 5: + id = KEY_ISO ; + break ; + case 6: + id = KEY_LDR ; + break ; + default: + fail ("invalid type: %08x", type) ; + return NULL ; + break ; + } + return keys_get (id) ; +} + +static void +decrypt_header (void) +{ + struct keylist *klist ; + + klist = self_load_keys () ; + if (klist == NULL) + return ; + + decrypted = sce_decrypt_header (self, klist) ; + + free (klist->keys) ; + free (klist) ; +} + +static void +show_self_header (void) +{ + printf ("SELF header information\n") ; + printf (" auth id: %08x%08x \n", (u32) (auth_id >> 32), + (u32) auth_id) ; + printf (" vendor id: %08x%08x\n", (u32) (vendor_id >> 32), + (u32) vendor_id) ; + printf (" app version: %x.%x.%x\n", (u16) (version >> 48), + (u16) (version >> 32), (u32) version) ; + + /* take version suffix */ + sprintf (versionsuffix, "%x%02x", (u16) (version >> 48), (u16) (version >> 32)) ; + printf (" version suffix: %s ", versionsuffix) ; + printf ("\n") ; + + printf (" SDK type: %s\n", id2name (sdk_type, t_sdk_type, "unknown")) ; +#ifdef DEBUG + printf (" type: %d\n sdk_type: %d\n", type, sdk_type) ; +#endif + printf (" app type: %s\n", id2name (type, t_app_type, "unknown")) ; +} + +static void +verify_signature (void) +{ + u8 *r, *s ; + u8 hash[20] ; + u64 sig_len ; + + sig_len = be64 (self + meta_offset + 0x60) ; + r = self + sig_len ; + s = r + 21 ; + + sha1 (self, sig_len, hash) ; + + printf ("Signature of the SELF header\n") ; + if (ecdsa_verify (hash, r, s)) { + printf (" Status: OK\n") ; + } else { + printf (" Status: FAIL\n") ; + } + printf ("\n") ; +} + +static int +verify_sign_hash (u8 * p, u8 * hashes, u8 * result, int sign) +{ + u64 offset ; + u64 size ; + u64 id ; + u8 *hash, *key ; + + offset = be64 (p + 0x00) ; + size = be64 (p + 0x08) ; + id = be32 (p + 0x1c) ; + + if (id == 0xffffffff) { + return 0 ; + } + + hash = hashes + id * 0x10 ; + key = hash + 0x20 ; + + // XXX: possible integer overflow here + if (offset > (filesize + header_len)) { + return 1 ; + } + + // XXX: possible integer overflow here + if ( (offset + size) > (filesize + header_len)) { + return 1 ; + } + + //Fix all section sign + if (sign) { + sha1_hmac (key, self + offset, size, hash) ; + } else { + sha1_hmac (key, self + offset, size, result) ; + } + + if (memcmp (result, hash, 20) == 0) { + return 0 ; + } else { + return -1 ; + } +} + +static void +calculate_hashes (void) +{ + u32 i ; + u32 meta_n_hdr ; + u8 result[20] ; + u8 *hashes ; + + meta_n_hdr = be32 (self + meta_offset + 0x60 + 0xc) ; + hashes = self + meta_offset + 0x80 + (0x30 * meta_n_hdr) ; + + for (i = 0; i < meta_n_hdr; i++) { + verify_sign_hash (self + meta_offset + 0x80 + 0x30 * i, + hashes, result, SIGN_HASH) ; + } +} + +static void +verify_hashes (void) +{ + u32 meta_n_hdr ; + u32 i ; + u8 *hashes ; + u8 result[20] ; + int res ; + + meta_n_hdr = be32 (self + meta_offset + 0x60 + 0xc) ; + hashes = self + meta_offset + 0x80 + 0x30 * meta_n_hdr ; + + printf ("Verifying hashes\n") ; + + for (i = 0; i < meta_n_hdr; i++) { + printf (" Section %02d\n", i) ; + res = verify_sign_hash (self + meta_offset + 0x80 + 0x30 * i, + hashes, result, VERIFY_HASH) ; + if (res < 0) { + printf (" hash: FAIL\n") ; + } else if (res > 0) { + printf (" hash: wtf phony???\n") ; + } else { + printf (" hash: OK\n") ; + } + } + + printf ("\n") ; +} + +static void +decrypt (void) +{ + int keyid ; + struct keylist *klist ; + + klist = self_load_keys () ; + if (klist == NULL) + return ; + + keyid = sce_decrypt_header (self, klist) ; + + if (keyid < 0) { + fail ("sce_decrypt_header failed") ; + } + + if (sce_decrypt_data (self) < 0) { + fail ("sce_decrypt_data failed") ; + } + + if (klist->keys[keyid].pub_avail < 0) { + fail ("no public key available") ; + } + + if (ecdsa_set_curve (klist->keys[keyid].ctype) < 0) { + fail ("ecdsa_set_curve failed") ; + } + + ecdsa_set_pub (klist->keys[keyid].pub) ; +} + +int +main (int argc, char *argv[]) +{ + FILE *fp ; + + printf ("SELF Rebuilder by Anonymous developers on EFNET\n") ; + printf (" SELF and SPRX packer and signer \n") ; + printf (" Based on the fail0verflow Tools \n") ; + printf (" ! use with caution ! \n") ; + + printf ("\n") ; + if (argc != 4) { + printf ("Usage: %s \n", argv[0]) ; + printf ("\tinput.elf: The input ELF to sign \n" + "\toutput.self: The output SELF/SPRX to generate\n" + "\toriginal.self: The reference original SELF/SPRX\n") ; + return -1 ; + } + self_size = get_filesize (argv[3]) ; + self = mmap_file (argv[3]) ; + + parse_self () ; + decrypt_header () ; + + show_self_header () ; + + read_sections () ; + + get_keys (versionsuffix) ; + + elf_name = argv[1] ; + self_name = argv[2] ; + + printf ("\nStarting to build self or sprx now...\n") ; + + elf_size = get_filesize (elf_name) ; + elf = mmap_file (elf_name) ; + + parse_elf () ; + + write_sections () ; + + calculate_hashes () ; + sign_header () ; + sce_decrypt_data (self) ; + sce_encrypt_header (self, &ks) ; + fp = fopen (self_name, "wb") ; + if (fp == NULL) { + fail ("fopen (%s) failed", self_name) ; + } + + if (fwrite (self, self_size, 1, fp) != 1) { + fail ("unable to write self") ; + } + + fclose (fp) ; + + self = mmap_file (self_name) ; + + parse_self () ; + decrypt () ; + verify_signature () ; + verify_hashes () ; + + printf (" Finished\n") ; + + return 0 ; +} diff --git a/sha1.c b/sha1.c new file mode 100644 index 0000000..b9afc1d --- /dev/null +++ b/sha1.c @@ -0,0 +1,380 @@ +/* + * sha1.c + * + * Copyright (C) 1998 + * Paul E. Jones + * All Rights Reserved + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without + * a fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING + * FROM THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + * + ***************************************************************************** + * $Id: sha1.c,v 1.2 2004/03/27 18:00:33 paulej Exp $ + ***************************************************************************** + * + * Description: + * This file implements the Secure Hashing Standard as defined + * in FIPS PUB 180-1 published April 17, 1995. + * + * The Secure Hashing Standard, which uses the Secure Hashing + * Algorithm (SHA), produces a 160-bit message digest for a + * given data stream. In theory, it is highly improbable that + * two messages will produce the same message digest. Therefore, + * this algorithm can serve as a means of providing a "fingerprint" + * for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code was + * written with the expectation that the processor has at least + * a 32-bit machine word size. If the machine word size is larger, + * the code should still function properly. One caveat to that + * is that the input functions taking characters and character + * arrays assume that only 8 bits of information are stored in each + * character. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated for + * messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is a + * multiple of the size of an 8-bit character. + * + */ + +#include "sha1.h" + +/* + * Define the circular shift macro + */ +#define SHA1CircularShift(bits,word) \ + ((((word) << (bits)) & 0xFFFFFFFF) | \ + ((word) >> (32-(bits)))) + +/* Function prototypes */ +void SHA1ProcessMessageBlock(SHA1Context *); +void SHA1PadMessage(SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1Reset(SHA1Context *context) +{ + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Message_Digest[0] = 0x67452301; + context->Message_Digest[1] = 0xEFCDAB89; + context->Message_Digest[2] = 0x98BADCFE; + context->Message_Digest[3] = 0x10325476; + context->Message_Digest[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array within the SHA1Context provided + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * + * Returns: + * 1 if successful, 0 if it failed. + * + * Comments: + * + */ +int SHA1Result(SHA1Context *context) +{ + + if (context->Corrupted) + { + return 0; + } + + if (!context->Computed) + { + SHA1PadMessage(context); + context->Computed = 1; + } + + return 1; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion of + * the message. + * + * Parameters: + * context: [in/out] + * The SHA-1 context to update + * message_array: [in] + * An array of characters representing the next portion of the + * message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1Input( SHA1Context *context, + const unsigned char *message_array, + unsigned length) +{ + if (!length) + { + return; + } + + if (context->Computed || context->Corrupted) + { + context->Corrupted = 1; + return; + } + + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + context->Length_Low += 8; + /* Force it to 32 bits */ + context->Length_Low &= 0xFFFFFFFF; + if (context->Length_Low == 0) + { + context->Length_High++; + /* Force it to 32 bits */ + context->Length_High &= 0xFFFFFFFF; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in the SHAContext, especially the + * single character names, were used because those were the names + * used in the publication. + * + * + */ +void SHA1ProcessMessageBlock(SHA1Context *context) +{ + const unsigned K[] = /* Constants defined in SHA-1 */ + { + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + unsigned temp; /* Temporary word value */ + unsigned W[80]; /* Word sequence */ + unsigned A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = ((unsigned) context->Message_Block[t * 4]) << 24; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]); + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Message_Digest[0]; + B = context->Message_Digest[1]; + C = context->Message_Digest[2]; + D = context->Message_Digest[3]; + E = context->Message_Digest[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Message_Digest[0] = + (context->Message_Digest[0] + A) & 0xFFFFFFFF; + context->Message_Digest[1] = + (context->Message_Digest[1] + B) & 0xFFFFFFFF; + context->Message_Digest[2] = + (context->Message_Digest[2] + C) & 0xFFFFFFFF; + context->Message_Digest[3] = + (context->Message_Digest[3] + D) & 0xFFFFFFFF; + context->Message_Digest[4] = + (context->Message_Digest[4] + E) & 0xFFFFFFFF; + + context->Message_Block_Index = 0; +} + +/* + * SHA1PadMessage + * + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call SHA1ProcessMessageBlock() + * appropriately. When it returns, it can be assumed that the + * message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (context->Length_High >> 24) & 0xFF; + context->Message_Block[57] = (context->Length_High >> 16) & 0xFF; + context->Message_Block[58] = (context->Length_High >> 8) & 0xFF; + context->Message_Block[59] = (context->Length_High) & 0xFF; + context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF; + context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF; + context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF; + context->Message_Block[63] = (context->Length_Low) & 0xFF; + + SHA1ProcessMessageBlock(context); +} diff --git a/sha1.h b/sha1.h new file mode 100644 index 0000000..23a71b3 --- /dev/null +++ b/sha1.h @@ -0,0 +1,72 @@ +/* + * sha1.h + * + * Copyright (C) 1998 + * Paul E. Jones + * All Rights Reserved + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without + * a fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING + * FROM THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without + * a fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING + * FROM THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + * + ***************************************************************************** + * $Id: sha1.h,v 1.2 2004/03/27 18:00:33 paulej Exp $ + ***************************************************************************** + * + * Description: + * This class implements the Secure Hashing Standard as defined + * in FIPS PUB 180-1 published April 17, 1995. + * + * Many of the variable names in the SHA1Context, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +/* + * This structure will hold context information for the hashing + * operation + */ +typedef struct SHA1Context +{ + unsigned Message_Digest[5]; /* Message Digest (output) */ + + unsigned Length_Low; /* Message length in bits */ + unsigned Length_High; /* Message length in bits */ + + unsigned char Message_Block[64]; /* 512-bit message blocks */ + int Message_Block_Index; /* Index into message block array */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corruped? */ +} SHA1Context; + +/* + * Function Prototypes + */ +void SHA1Reset(SHA1Context *); +int SHA1Result(SHA1Context *); +void SHA1Input( SHA1Context *, + const unsigned char *, + unsigned); + +#endif diff --git a/spp.c b/spp.c new file mode 100644 index 0000000..f98b0d4 --- /dev/null +++ b/spp.c @@ -0,0 +1,189 @@ +// Copyright 2010 Sven Peter +// Copyright 2011 glevand +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include + +static struct key k; +static FILE *fp; + +static u8 *content; +static u64 content_size; + +static u8 sce_hdr[0x20]; +static u8 meta_hdr[0x1e0]; + +static u8 *spp; +static u64 spp_size; + +static void get_profile(const char *filename) +{ + struct stat st; + + content = mmap_file(filename); + + if (stat(filename, &st) < 0) + fail("stat(%s) failed", filename); + + content_size = st.st_size; +} + +static void get_key(const char *suffix) +{ + if (key_get(KEY_SPP, suffix, &k) < 0) + fail("key_get() failed"); + + if (k.pub_avail < 0) + fail("no public key available"); + + if (k.priv_avail < 0) + fail("no private key available"); + + if (ecdsa_set_curve(k.ctype) < 0) + fail("ecdsa_set_curve failed"); + + ecdsa_set_pub(k.pub); + ecdsa_set_priv(k.priv); +} + +static void build_sce_hdr(void) +{ + memset(sce_hdr, 0, sizeof sce_hdr); + + wbe32(sce_hdr + 0x00, 0x53434500); // magic + wbe32(sce_hdr + 0x04, 2); // version + wbe16(sce_hdr + 0x08, 0); // dunno, sdk type? + wbe16(sce_hdr + 0x0a, 4); // SCE header type; profile + wbe32(sce_hdr + 0x0c, 0); // meta offset + wbe64(sce_hdr + 0x10, sizeof sce_hdr + sizeof meta_hdr); + wbe64(sce_hdr + 0x18, content_size); +} + +static void build_meta_hdr(void) +{ + u8 *ptr; + + memset(meta_hdr, 0, sizeof meta_hdr); + ptr = meta_hdr; + + // keys for metadata encryption + get_rand(ptr, 0x10); + get_rand(ptr + 0x20, 0x10); + ptr += 0x40; + + // area covered by the signature + wbe64(ptr + 0x00, sizeof sce_hdr + sizeof meta_hdr - 0x30); + wbe32(ptr + 0x08, 1); + wbe32(ptr + 0x0c, 2); // number of encrypted headers + wbe32(ptr + 0x10, 2 * 8); // number of keys/hashes required + ptr += 0x20; + + // header + wbe64(ptr + 0x00, 0x200); // offset + wbe64(ptr + 0x08, 0x20); // size + wbe32(ptr + 0x10, 1); // unknown + wbe32(ptr + 0x14, 1); // index + wbe32(ptr + 0x18, 2); // unknown again + wbe32(ptr + 0x1c, 0); // sha index + wbe32(ptr + 0x20, 1); // no encryption + wbe32(ptr + 0x24, 0xffffffff); // key index + wbe32(ptr + 0x28, 0xffffffff); // iv index + wbe32(ptr + 0x2c, 0x1); // no compression + ptr += 0x30; + + // profile + wbe64(ptr + 0x00, 0x220); // offset + wbe64(ptr + 0x08, content_size - 0x20); + wbe32(ptr + 0x10, 2); // unknown + wbe32(ptr + 0x14, 2); // index + wbe32(ptr + 0x18, 2); // unknown again + wbe32(ptr + 0x1c, 8); // sha index + wbe32(ptr + 0x20, 3); // encrypted + wbe32(ptr + 0x24, 0); // key index + wbe32(ptr + 0x28, 1); // iv index + wbe32(ptr + 0x2c, 0x1); // no compression + ptr += 0x30; + + // add keys/ivs and hmac keys + get_rand(ptr, 2 * 8 * 0x10); +} + +static void build_spp(void) +{ + spp_size = sizeof sce_hdr + sizeof meta_hdr; + spp_size += content_size; + + spp = malloc(spp_size); + if (!spp) + fail("out of memory"); + + memset(spp, 0xaa, spp_size); + memcpy(spp, sce_hdr, 0x20); + memcpy(spp + 0x20, meta_hdr, 0x1e0); + memcpy(spp + 0x200, content, content_size); +} + +static void calculate_hash(u8 *data, u64 len, u8 *digest) +{ + memset(digest, 0, 0x20); + sha1_hmac(digest + 0x20, data, len, digest); +} + +static void hash_spp(void) +{ + calculate_hash(spp + 0x200, 0x20, spp + 0x80 + 2*0x30); + calculate_hash(spp + 0x220, content_size - 0x20, + spp + 0x80 + 2*0x30 + 8*0x10); +} + +static void sign_spp(void) +{ + u8 *r, *s; + u8 hash[20]; + u64 sig_len; + + sig_len = be64(spp + 0x60); + r = spp + sig_len; + s = r + 21; + + sha1(spp, sig_len, hash); + + ecdsa_sign(hash, r, s); +} + +int main(int argc, char *argv[]) +{ + if (argc != 4) + fail("usage: spp [key suffix] [filename.pp] [filename.spp]"); + + fp = fopen(argv[3], "wb"); + if (fp == NULL) + fail("fopen(%s) failed", argv[3]); + + get_key(argv[1]); + get_profile(argv[2]); + + build_sce_hdr(); + build_meta_hdr(); + + build_spp(); + hash_spp(); + sign_spp(); + + sce_encrypt_data(spp); + sce_encrypt_header(spp, &k); + + fwrite(spp, spp_size, 1, fp); + fclose(fp); + + return 0; +} diff --git a/tools.c b/tools.c new file mode 100644 index 0000000..2fe3c8f --- /dev/null +++ b/tools.c @@ -0,0 +1,860 @@ +// Copyright 2010 Sven Peter +// Copyright 2007,2008,2010 Segher Boessenkool +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include "mingw_mmap.h" +#include +#include +#else +#include +#endif + +#include "tools.h" +#include "aes.h" +#include "sha1.h" + +static struct id2name_tbl t_key2file[] = { + {KEY_LV0, "lv0"}, + {KEY_LV1, "lv1"}, + {KEY_LV2, "lv2"}, + {KEY_APP, "app"}, + {KEY_ISO, "iso"}, + {KEY_LDR, "ldr"}, + {KEY_PKG, "pkg"}, + {KEY_SPP, "spp"}, + {0, NULL} +}; + +// +// misc +// + +void *mmap_file(const char *path) +{ + int fd; + struct stat st; + void *ptr; + + fd = open(path, O_RDONLY); + if(fd == -1) + fail("open %s", path); + if(fstat(fd, &st) != 0) + fail("fstat %s", path); + + ptr = mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if(ptr==NULL) + fail("mmap"); + close(fd); + + return ptr; +} + +void memcpy_to_file(const char *fname, u8 *ptr, u64 size) +{ + FILE *fp; + + fp = fopen(fname, "wb"); + fwrite(ptr, size, 1, fp); + fclose(fp); +} + +void fail(const char *a, ...) +{ + char msg[1024]; + va_list va; + + va_start(va, a); + vsnprintf(msg, sizeof msg, a, va); + fprintf(stderr, "%s\n", msg); + perror("perror"); + + exit(1); +} + +void decompress(u8 *in, u64 in_len, u8 *out, u64 out_len) +{ + z_stream s; + int ret; + + memset(&s, 0, sizeof(s)); + + s.zalloc = Z_NULL; + s.zfree = Z_NULL; + s.opaque = Z_NULL; + + ret = inflateInit(&s); + if (ret != Z_OK) + fail("inflateInit returned %d", ret); + + s.avail_in = in_len; + s.next_in = in; + + s.avail_out = out_len; + s.next_out = out; + + ret = inflate(&s, Z_FINISH); + if (ret != Z_OK && ret != Z_STREAM_END) + fail("inflate returned %d", ret); + + inflateEnd(&s); +} + +const char *id2name(u32 id, struct id2name_tbl *t, const char *unk) +{ + while (t->name != NULL) { + if (id == t->id) + return t->name; + t++; + } + return unk; +} + +#ifdef WIN32 +void get_rand(u8 *bfr, u32 size) +{ + HCRYPTPROV hProv; + + if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + fail("unable to open random"); + + if (!CryptGenRandom(hProv, size, bfr)) + fail("unable to read random numbers"); + + CryptReleaseContext(hProv, 0); +} +#else +void get_rand(u8 *bfr, u32 size) +{ + FILE *fp; + + fp = fopen("/dev/urandom", "r"); + if (fp == NULL) + fail("unable to open random"); + + if (fread(bfr, size, 1, fp) != 1) + fail("unable to read random numbers"); + + fclose(fp); +} +#endif + +// +// ELF helpers +// +int elf_read_hdr(u8 *hdr, struct elf_hdr *h) +{ + int arch64; + memcpy(h->e_ident, hdr, 16); + hdr += 16; + + arch64 = h->e_ident[4] == 2; + + h->e_type = be16(hdr); + hdr += 2; + h->e_machine = be16(hdr); + hdr += 2; + h->e_version = be32(hdr); + hdr += 4; + + if (arch64) { + h->e_entry = be64(hdr); + h->e_phoff = be64(hdr + 8); + h->e_shoff = be64(hdr + 16); + hdr += 24; + } else { + h->e_entry = be32(hdr); + h->e_phoff = be32(hdr + 4); + h->e_shoff = be32(hdr + 8); + hdr += 12; + } + + h->e_flags = be32(hdr); + hdr += 4; + + h->e_ehsize = be16(hdr); + hdr += 2; + h->e_phentsize = be16(hdr); + hdr += 2; + h->e_phnum = be16(hdr); + hdr += 2; + h->e_shentsize = be16(hdr); + hdr += 2; + h->e_shnum = be16(hdr); + hdr += 2; + h->e_shtrndx = be16(hdr); + + return arch64; +} + +void elf_read_phdr(int arch64, u8 *phdr, struct elf_phdr *p) +{ + if (arch64) { + p->p_type = be32(phdr + 0); + p->p_flags = be32(phdr + 4); + p->p_off = be64(phdr + 1*8); + p->p_vaddr = be64(phdr + 2*8); + p->p_paddr = be64(phdr + 3*8); + p->p_filesz = be64(phdr + 4*8); + p->p_memsz = be64(phdr + 5*8); + p->p_align = be64(phdr + 6*8); + } else { + p->p_type = be32(phdr + 0*4); + p->p_off = be32(phdr + 1*4); + p->p_vaddr = be32(phdr + 2*4); + p->p_paddr = be32(phdr + 3*4); + p->p_filesz = be32(phdr + 4*4); + p->p_memsz = be32(phdr + 5*4); + p->p_flags = be32(phdr + 6*4); + p->p_align = be32(phdr + 7*4); + } +} + +void elf_read_shdr(int arch64, u8 *shdr, struct elf_shdr *s) +{ + if (arch64) { + s->sh_name = be32(shdr + 0*4); + s->sh_type = be32(shdr + 1*4); + s->sh_flags = be64(shdr + 2*4); + s->sh_addr = be64(shdr + 2*4 + 1*8); + s->sh_offset = be64(shdr + 2*4 + 2*8); + s->sh_size = be64(shdr + 2*4 + 3*8); + s->sh_link = be32(shdr + 2*4 + 4*8); + s->sh_info = be32(shdr + 3*4 + 4*8); + s->sh_addralign = be64(shdr + 4*4 + 4*8); + s->sh_entsize = be64(shdr + 4*4 + 5*8); + } else { + s->sh_name = be32(shdr + 0*4); + s->sh_type = be32(shdr + 1*4); + s->sh_flags = be32(shdr + 2*4); + s->sh_addr = be32(shdr + 3*4); + s->sh_offset = be32(shdr + 4*4); + s->sh_size = be32(shdr + 5*4); + s->sh_link = be32(shdr + 6*4); + s->sh_info = be32(shdr + 7*4); + s->sh_addralign = be32(shdr + 8*4); + s->sh_entsize = be32(shdr + 9*4); + } +} + +void elf_write_shdr(int arch64, u8 *shdr, struct elf_shdr *s) +{ + if (arch64) { + wbe32(shdr + 0*4, s->sh_name); + wbe32(shdr + 1*4, s->sh_type); + wbe64(shdr + 2*4, s->sh_flags); + wbe64(shdr + 2*4 + 1*8, s->sh_addr); + wbe64(shdr + 2*4 + 2*8, s->sh_offset); + wbe64(shdr + 2*4 + 3*8, s->sh_size); + wbe32(shdr + 2*4 + 4*8, s->sh_link); + wbe32(shdr + 3*4 + 4*8, s->sh_info); + wbe64(shdr + 4*4 + 4*8, s->sh_addralign); + wbe64(shdr + 4*4 + 5*8, s->sh_entsize); + } else { + wbe32(shdr + 0*4, s->sh_name); + wbe32(shdr + 1*4, s->sh_type); + wbe32(shdr + 2*4, s->sh_flags); + wbe32(shdr + 3*4, s->sh_addr); + wbe32(shdr + 4*4, s->sh_offset); + wbe32(shdr + 5*4, s->sh_size); + wbe32(shdr + 6*4, s->sh_link); + wbe32(shdr + 7*4, s->sh_info); + wbe32(shdr + 8*4, s->sh_addralign); + wbe32(shdr + 9*4, s->sh_entsize); + } +} + +// +// crypto +// +void aes256cbc(u8 *key, u8 *iv_in, u8 *in, u64 len, u8 *out) +{ + AES_KEY k; + u32 i; + u8 tmp[16]; + u8 iv[16]; + + memcpy(iv, iv_in, 16); + memset(&k, 0, sizeof k); + AES_set_decrypt_key(key, 256, &k); + + while (len > 0) { + memcpy(tmp, in, 16); + AES_decrypt(in, out, &k); + + for (i = 0; i < 16; i++) + out[i] ^= iv[i]; + + memcpy(iv, tmp, 16); + + out += 16; + in += 16; + len -= 16; + + } +} + + +void aes256cbc_enc(u8 *key, u8 *iv, u8 *in, u64 len, u8 *out) +{ + AES_KEY k; + u32 i; + u8 tmp[16]; + + memcpy(tmp, iv, 16); + memset(&k, 0, sizeof k); + AES_set_encrypt_key(key, 256, &k); + + while (len > 0) { + for (i = 0; i < 16; i++) + tmp[i] ^= *in++; + + AES_encrypt(tmp, out, &k); + memcpy(tmp, out, 16); + + out += 16; + len -= 16; + } +} + + +void aes128cbc(u8 *key, u8 *iv_in, u8 *in, u64 len, u8 *out) +{ + AES_KEY k; + u32 i; + u8 tmp[16]; + u8 iv[16]; + + memcpy(iv, iv_in, 16); + memset(&k, 0, sizeof k); + AES_set_decrypt_key(key, 128, &k); + + while (len > 0) { + memcpy(tmp, in, 16); + AES_decrypt(in, out, &k); + + for (i = 0; i < 16; i++) + out[i] ^= iv[i]; + + memcpy(iv, tmp, 16); + + out += 16; + in += 16; + len -= 16; + + } +} + +void aes128cbc_enc(u8 *key, u8 *iv, u8 *in, u64 len, u8 *out) +{ + AES_KEY k; + u32 i; + u8 tmp[16]; + + memcpy(tmp, iv, 16); + memset(&k, 0, sizeof k); + AES_set_encrypt_key(key, 128, &k); + + while (len > 0) { + for (i = 0; i < 16; i++) + tmp[i] ^= *in++; + + AES_encrypt(tmp, out, &k); + memcpy(tmp, out, 16); + + out += 16; + len -= 16; + } +} + +void aes128ctr(u8 *key, u8 *iv, u8 *in, u64 len, u8 *out) +{ + AES_KEY k; + u32 i; + u8 ctr[16]; + u64 tmp; + + memset(ctr, 0, 16); + memset(&k, 0, sizeof k); + + AES_set_encrypt_key(key, 128, &k); + + for (i = 0; i < len; i++) { + if ((i & 0xf) == 0) { + AES_encrypt(iv, ctr, &k); + + // increase nonce + tmp = be64(iv + 8) + 1; + wbe64(iv + 8, tmp); + if (tmp == 0) + wbe64(iv, be64(iv) + 1); + } + *out++ = *in++ ^ ctr[i & 0x0f]; + } +} + + +// FIXME: use a non-broken sha1.c *sigh* +static void sha1_fixup(struct SHA1Context *ctx, u8 *digest) +{ + u32 i; + + for(i = 0; i < 5; i++) { + *digest++ = ctx->Message_Digest[i] >> 24 & 0xff; + *digest++ = ctx->Message_Digest[i] >> 16 & 0xff; + *digest++ = ctx->Message_Digest[i] >> 8 & 0xff; + *digest++ = ctx->Message_Digest[i] & 0xff; + } +} + +void sha1(u8 *data, u32 len, u8 *digest) +{ + struct SHA1Context ctx; + + SHA1Reset(&ctx); + SHA1Input(&ctx, data, len); + SHA1Result(&ctx); + + sha1_fixup(&ctx, digest); +} + +void sha1_hmac(u8 *key, u8 *data, u32 len, u8 *digest) +{ + struct SHA1Context ctx; + u32 i; + u8 ipad[0x40]; + u8 tmp[0x40 + 0x14]; // opad + hash(ipad + message) + + SHA1Reset(&ctx); + + for (i = 0; i < sizeof ipad; i++) { + tmp[i] = key[i] ^ 0x5c; // opad + ipad[i] = key[i] ^ 0x36; + } + + SHA1Input(&ctx, ipad, sizeof ipad); + SHA1Input(&ctx, data, len); + SHA1Result(&ctx); + + sha1_fixup(&ctx, tmp + 0x40); + + sha1(tmp, sizeof tmp, digest); + +} + +static int key_build_path(char *ptr) +{ + char *home = NULL; + char *dir = NULL; + + memset(ptr, 0, 256); + + dir = getenv("PS3_KEYS"); + if (dir != NULL) { + strncpy(ptr, dir, 256); + return 0; + } + +#ifdef WIN32 + home = getenv("USERPROFILE"); +#else + home = getenv("HOME"); +#endif + if (home == NULL) { + snprintf (ptr, 256, "ps3keys"); + } else { +#ifdef WIN32 + snprintf(ptr, 256, "%s\\ps3keys\\", home); +#else + snprintf(ptr, 256, "%s/.ps3/", home); +#endif + } + + return 0; +} + +static int key_read(const char *path, u32 len, u8 *dst) +{ + FILE *fp = NULL; + u32 read; + int ret = -1; + + fp = fopen(path, "rb"); + if (fp == NULL) + goto fail; + + read = fread(dst, len, 1, fp); + + if (read != 1) + goto fail; + + ret = 0; + +fail: + if (fp != NULL) + fclose(fp); + + return ret; +} + +struct keylist *keys_get(enum sce_key type) +{ + const char *name = NULL; + char base[256]; + char path[256]; + void *tmp = NULL; + char *id; + DIR *dp; + struct dirent *dent; + struct keylist *klist; + u8 bfr[4]; + + klist = malloc(sizeof *klist); + if (klist == NULL) + goto fail; + + memset(klist, 0, sizeof *klist); + + name = id2name(type, t_key2file, NULL); + if (name == NULL) + goto fail; + + if (key_build_path(base) < 0) + goto fail; + + dp = opendir(base); + if (dp == NULL) + goto fail; + + while ((dent = readdir(dp)) != NULL) { + if (strncmp(dent->d_name, name, strlen(name)) == 0 && + strstr(dent->d_name, "key") != NULL) { + tmp = realloc(klist->keys, (klist->n + 1) * sizeof(struct key)); + if (tmp == NULL) + goto fail; + + id = strrchr(dent->d_name, '-'); + if (id != NULL) + id++; + + klist->keys = tmp; + memset(&klist->keys[klist->n], 0, sizeof(struct key)); + + snprintf(path, sizeof path, "%s/%s-key-%s", base, name, id); + if (key_read(path, 32, klist->keys[klist->n].key) != 0) { + printf(" key file: %s (ERROR)\n", path); + } + + snprintf(path, sizeof path, "%s/%s-iv-%s", base, name, id); + if (key_read(path, 16, klist->keys[klist->n].iv) != 0) { + printf(" iv file: %s (ERROR)\n", path); + } + + klist->keys[klist->n].pub_avail = -1; + klist->keys[klist->n].priv_avail = -1; + + snprintf(path, sizeof path, "%s/%s-pub-%s", base, name, id); + if (key_read(path, 40, klist->keys[klist->n].pub) == 0) { + snprintf(path, sizeof path, "%s/%s-ctype-%s", base, name, id); + key_read(path, 4, bfr); + + klist->keys[klist->n].pub_avail = 1; + klist->keys[klist->n].ctype = be32(bfr); + } else { + printf(" pub file: %s (ERROR)\n", path); + } + + snprintf(path, sizeof path, "%s/%s-priv-%s", base, name, id); + if (key_read(path, 21, klist->keys[klist->n].priv) == 0) { + klist->keys[klist->n].priv_avail = 1; + } else { + printf(" priv file: %s (ERROR)\n", path); + } + + + klist->n++; + } + } + + return klist; + +fail: + if (klist != NULL) { + if (klist->keys != NULL) + free(klist->keys); + free(klist); + } + klist = NULL; + + return NULL; +} + +int key_get_simple(const char *name, u8 *bfr, u32 len) +{ + char base[256]; + char path[256]; + + if (key_build_path(base) < 0) + return -1; + + snprintf(path, sizeof path, "%s/%s", base, name); + if (key_read(path, len, bfr) < 0) + return -1; + + return 0; +} + +int key_get(enum sce_key type, const char *suffix, struct key *k) +{ + const char *name = ""; + const char *rev = ""; + char base[256]; + char path[256]; + u8 tmp[4]; + + if ( strncmp( suffix, "retail", strlen( suffix ) ) == 0 ) { + rev = "retail"; + } else if ( atoi( suffix ) <= 92 ) { + suffix = "092"; + rev = "0x00"; + } else if ( atoi( suffix ) <= 331 ) { + suffix = "315"; + rev = "0x01"; + } else if ( atoi( suffix ) <= 342 ) { + suffix = "341"; + rev = "0x04"; + } else if ( atoi( suffix ) <= 350 ) { + suffix = "350"; + rev = "0x07"; + } else if ( atoi( suffix ) <= 355 ) { + suffix = "355"; + rev = "0x0a"; + } else if ( atoi( suffix ) <= 356 ) { + suffix = "356"; + rev = "0x0d"; + } + printf(" file suffix: %s (rev %s)\n", suffix, rev ); + + if (key_build_path(base) < 0) + return -1; + + name = id2name(type, t_key2file, NULL); + if (name == NULL) + return -1; + + snprintf(path, sizeof path, "%s/%s-key-%s", base, name, suffix); + if (key_read(path, 32, k->key) < 0) { + printf(" key file: %s (ERROR)\n", path); + return -1; + } + + snprintf(path, sizeof path, "%s/%s-iv-%s", base, name, suffix); + if (key_read(path, 16, k->iv) < 0) { + printf(" iv file: %s (ERROR)\n", path); + return -1; + } + + k->pub_avail = k->priv_avail = 1; + + snprintf(path, sizeof path, "%s/%s-ctype-%s", base, name, suffix); + if (key_read(path, 4, tmp) < 0) { + k->pub_avail = k->priv_avail = -1; + printf(" ctype file: %s (ERROR)\n", path); + return 0; + } + + k->ctype = be32(tmp); + + snprintf(path, sizeof path, "%s/%s-pub-%s", base, name, suffix); + if (key_read(path, 40, k->pub) < 0) { + printf(" pub file: %s (ERROR)\n", path); + k->pub_avail = -1; + } + + snprintf(path, sizeof path, "%s/%s-priv-%s", base, name, suffix); + if (key_read(path, 21, k->priv) < 0) { + printf(" priv file: %s (ERROR)\n", path); + k->priv_avail = -1; + } + + return 0; +} + +static void memcpy_inv(u8 *dst, u8 *src, u32 len) +{ + u32 j; + + for (j = 0; j < len; j++) + dst[j] = ~src[j]; +} + +int ecdsa_get_params(u32 type, u8 *p, u8 *a, u8 *b, u8 *N, u8 *Gx, u8 *Gy) +{ + static u8 tbl[64 * 121]; + char path[256]; + u32 offset; + + if (type >= 64) + return -1; + + if (key_build_path(path) < 0) + return -1; + + strncat(path, "/curves", sizeof path); + + if (key_read(path, sizeof tbl, tbl) < 0) + return -1; + + offset = type * 121; + + memcpy_inv(p, tbl + offset + 0, 20); + memcpy_inv(a, tbl + offset + 20, 20); + memcpy_inv(b, tbl + offset + 40, 20); + memcpy_inv(N, tbl + offset + 60, 21); + memcpy_inv(Gx, tbl + offset + 81, 20); + memcpy_inv(Gy, tbl + offset + 101, 20); + + return 0; +} + +int sce_decrypt_header(u8 *ptr, struct keylist *klist) +{ + u32 meta_offset; + u32 meta_len; + u64 header_len; + u32 i, j; + u8 tmp[0x40]; + int success = 0; + + + meta_offset = be32(ptr + 0x0c); + header_len = be64(ptr + 0x10); + + for (i = 0; i < klist->n; i++) { + aes256cbc(klist->keys[i].key, + klist->keys[i].iv, + ptr + meta_offset + 0x20, + 0x40, + tmp); + + success = 1; + for (j = 0x10; j < (0x10 + 0x10); j++) + if (tmp[j] != 0) + success = 0; + + for (j = 0x30; j < (0x30 + 0x10); j++) + if (tmp[j] != 0) + success = 0; + + if (success == 1) { + memcpy(ptr + meta_offset + 0x20, tmp, 0x40); + break; + } + } + + if (success != 1) + return -1; + + memcpy(tmp, ptr + meta_offset + 0x40, 0x10); + aes128ctr(ptr + meta_offset + 0x20, + tmp, + ptr + meta_offset + 0x60, + 0x20, + ptr + meta_offset + 0x60); + + meta_len = header_len - meta_offset; + + aes128ctr(ptr + meta_offset + 0x20, + tmp, + ptr + meta_offset + 0x80, + meta_len - 0x80, + ptr + meta_offset + 0x80); + + return i; +} + +int sce_encrypt_header(u8 *ptr, struct key *k) +{ + u32 meta_offset; + u32 meta_len; + u64 header_len; + u8 iv[16]; + + meta_offset = be32(ptr + 0x0c); + header_len = be64(ptr + 0x10); + meta_len = header_len - meta_offset; + + memcpy(iv, ptr + meta_offset + 0x40, 0x10); + aes128ctr(ptr + meta_offset + 0x20, + iv, + ptr + meta_offset + 0x60, + meta_len - 0x60, + ptr + meta_offset + 0x60); + + aes256cbc_enc(k->key, k->iv, + ptr + meta_offset + 0x20, + 0x40, + ptr + meta_offset + 0x20); + + + return 0; +} + +int sce_decrypt_data(u8 *ptr) +{ + u64 meta_offset; + u32 meta_len; + u32 meta_n_hdr; + u64 header_len; + u32 i; + + u64 offset; + u64 size; + u32 keyid; + u32 ivid; + u8 *tmp; + + u8 iv[16]; + + meta_offset = be32(ptr + 0x0c); + header_len = be64(ptr + 0x10); + meta_len = header_len - meta_offset; + meta_n_hdr = be32(ptr + meta_offset + 0x60 + 0xc); + + for (i = 0; i < meta_n_hdr; i++) { + tmp = ptr + meta_offset + 0x80 + 0x30*i; + offset = be64(tmp); + size = be64(tmp + 8); + keyid = be32(tmp + 0x24); + ivid = be32(tmp + 0x28); + + if (keyid == 0xffffffff || ivid == 0xffffffff) + continue; + + memcpy(iv, ptr + meta_offset + 0x80 + 0x30 * meta_n_hdr + ivid * 0x10, 0x10); + aes128ctr(ptr + meta_offset + 0x80 + 0x30 * meta_n_hdr + keyid * 0x10, + iv, + ptr + offset, + size, + ptr + offset); + } + + return 0; +} + +int sce_encrypt_data(u8 *ptr) +{ + return sce_decrypt_data(ptr); +} diff --git a/tools.h b/tools.h new file mode 100644 index 0000000..4eb6d30 --- /dev/null +++ b/tools.h @@ -0,0 +1,73 @@ +// Copyright 2010 Sven Peter +// Copyright 2007,2008,2010 Segher Boessenkool +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#ifndef TOOLS_H__ +#define TOOLS_H__ 1 +#include + +#include "types.h" + +enum sce_key { + KEY_LV0 = 0, + KEY_LV1, + KEY_LV2, + KEY_APP, + KEY_ISO, + KEY_LDR, + KEY_PKG, + KEY_SPP +}; + +void *mmap_file(const char *path); +void memcpy_to_file(const char *fname, u8 *ptr, u64 size); +const char *id2name(u32 id, struct id2name_tbl *t, const char *unk); +void fail(const char *fmt, ...) __attribute__((noreturn)); +void decompress(u8 *in, u64 in_len, u8 *out, u64 out_len); +void get_rand(u8 *bfr, u32 size); + +int elf_read_hdr(u8 *hdr, struct elf_hdr *h); +void elf_read_phdr(int arch64, u8 *phdr, struct elf_phdr *p); +void elf_read_shdr(int arch64, u8 *shdr, struct elf_shdr *s); +void elf_write_shdr(int arch64, u8 *shdr, struct elf_shdr *s); + +void aes256cbc(u8 *key, u8 *iv, u8 *in, u64 len, u8 *out); +void aes256cbc_enc(u8 *key, u8 *iv, u8 *in, u64 len, u8 *out); +void aes128ctr(u8 *key, u8 *iv, u8 *in, u64 len, u8 *out); +void aes128cbc(u8 *key, u8 *iv_in, u8 *in, u64 len, u8 *out); +void aes128cbc_enc(u8 *key, u8 *iv, u8 *in, u64 len, u8 *out); + +void sha1(u8 *data, u32 len, u8 *digest); +void sha1_hmac(u8 *key, u8 *data, u32 len, u8 *digest); + +int key_get(enum sce_key type, const char *suffix, struct key *k); +int key_get_simple(const char *name, u8 *bfr, u32 len); +struct keylist *keys_get(enum sce_key type); + +int sce_decrypt_header(u8 *ptr, struct keylist *klist); +int sce_encrypt_header(u8 *ptr, struct key *k); +int sce_decrypt_data(u8 *ptr); +int sce_encrypt_data(u8 *ptr); + +int ecdsa_get_params(u32 type, u8 *p, u8 *a, u8 *b, u8 *N, u8 *Gx, u8 *Gy); +int ecdsa_set_curve(u32 type); +void ecdsa_set_pub(u8 *Q); +void ecdsa_set_priv(u8 *k); +int ecdsa_verify(u8 *hash, u8 *R, u8 *S); +void ecdsa_sign(u8 *hash, u8 *R, u8 *S); + +void bn_copy(u8 *d, u8 *a, u32 n); +int bn_compare(u8 *a, u8 *b, u32 n); +void bn_reduce(u8 *d, u8 *N, u32 n); +void bn_add(u8 *d, u8 *a, u8 *b, u8 *N, u32 n); +void bn_sub(u8 *d, u8 *a, u8 *b, u8 *N, u32 n); +void bn_to_mon(u8 *d, u8 *N, u32 n); +void bn_from_mon(u8 *d, u8 *N, u32 n); +void bn_mon_mul(u8 *d, u8 *a, u8 *b, u8 *N, u32 n); +void bn_mon_inv(u8 *d, u8 *a, u8 *N, u32 n); + +#define round_up(x,n) (-(-(x) & -(n))) + +#define array_size(x) (sizeof(x) / sizeof(*(x))) +#endif diff --git a/types.h b/types.h new file mode 100644 index 0000000..5fbe8bf --- /dev/null +++ b/types.h @@ -0,0 +1,147 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +#ifndef TYPES_H__ +#define TYPES_H__ + +#include + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + + +struct elf_phdr { + u32 p_type; + u64 p_off; + u64 p_vaddr; + u64 p_paddr; + u64 p_filesz; + u64 p_memsz; + u32 p_flags; + u64 p_align; + + void *ptr; +}; + +struct elf_shdr { + u32 sh_name; + u32 sh_type; + u32 sh_flags; + u64 sh_addr; + u64 sh_offset; + u32 sh_size; + u32 sh_link; + u32 sh_info; + u32 sh_addralign; + u32 sh_entsize; +}; + +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOOS 0xfe00 +#define ET_HIOS 0xfeff +#define ET_LOPROC 0xff00 +#define ET_HIPROC 0xffff +struct elf_hdr { + char e_ident[16]; + u16 e_type; + u16 e_machine; + u32 e_version; + u64 e_entry; + u64 e_phoff; + u64 e_shoff; + u32 e_flags; + u16 e_ehsize; + u16 e_phentsize; + u16 e_phnum; + u16 e_shentsize; + u16 e_shnum; + u16 e_shtrndx; +}; + + +struct id2name_tbl { + u32 id; + const char *name; +}; + +struct key { + u8 key[32]; + u8 iv[16]; + + int pub_avail; + int priv_avail; + u8 pub[40]; + u8 priv[21]; + u32 ctype; +}; + +struct keylist { + u32 n; + struct key *keys; +}; + +static inline u8 be8(u8 *p) +{ + return *p; +} + +static inline u16 be16(u8 *p) +{ + u16 a; + + a = p[0] << 8; + a |= p[1]; + + return a; +} + +static inline u32 be32(u8 *p) +{ + u32 a; + + a = p[0] << 24; + a |= p[1] << 16; + a |= p[2] << 8; + a |= p[3] << 0; + + return a; +} + +static inline u64 be64(u8 *p) +{ + u32 a, b; + + a = be32(p); + b = be32(p + 4); + + return ((u64)a<<32) | b; +} + +static inline void wbe16(u8 *p, u16 v) +{ + p[0] = v >> 8; + p[1] = v; +} + +static inline void wbe32(u8 *p, u32 v) +{ + p[0] = v >> 24; + p[1] = v >> 16; + p[2] = v >> 8; + p[3] = v; +} + +static inline void wbe64(u8 *p, u64 v) +{ + wbe32(p + 4, v); + v >>= 32; + wbe32(p, v); +} + +#endif diff --git a/undat.c b/undat.c new file mode 100644 index 0000000..9d6e94c --- /dev/null +++ b/undat.c @@ -0,0 +1,60 @@ +// Copyright 2011 Ninjas +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + FILE *in = NULL; + + size_t len; + + u8 *data; + u8 dat_key[0x10], dat_iv[0x10]; + u8 digest[20]; + + if (argc != 3) + fail ("usage: undat index.dat version.txt"); + + in = fopen (argv[1], "rb"); + if (in == NULL) + fail ("Unable to open %s", argv[1]); + fseek (in, 0, SEEK_END); + len = ftell (in); + fseek (in, 0, SEEK_SET); + + if (len < 0x1f) + fail ("invalid index.dat size : 0x%X", len); + + data = malloc (len); + + if (fread (data, 1, len, in) != len) + fail ("Unable to read index.dat file"); + + fclose (in); + + if(key_get_simple("dat-key", dat_key, 0x10) < 0) + fail ("unable to load dat-key."); + if(key_get_simple("dat-iv", dat_iv, 0x10) < 0) + fail ("unable to load dat-iv."); + + aes128cbc (dat_key, dat_iv, data, len, data); + sha1 (data + 32, len - 32, digest); + + if (memcmp (data, digest, 20) != 0) + fail ("SHA1 mac mismatch"); + + memcpy_to_file (argv[2], data + 32, len - 32); + + return 0; +} diff --git a/ungpkg.c b/ungpkg.c new file mode 100644 index 0000000..1f644ae --- /dev/null +++ b/ungpkg.c @@ -0,0 +1,142 @@ +// Copyright 2010-2011 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +// Thanks to Mathieulh for his C# retail unpacker +// (http://twitter.com/#!/Mathieulh/status/23070344881381376) +// Thanks to Matt_P for his python debug unpacker +// (https://github.com/HACKERCHANNEL/PS3Py/blob/master/pkg.py) + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#define MKDIR(x,y) mkdir(x) +#else +#define MKDIR(x,y) mkdir(x,y) +#endif + + +static u8 *pkg = NULL; +static u64 size; +static u64 offset; + + +static void decrypt_retail_pkg(void) +{ + u8 key[0x10]; + u8 iv[0x10]; + + if (be16(pkg + 0x06) != 1) + fail("invalid pkg type: %x", be16(pkg + 0x06)); + + if (key_get_simple("gpkg-key", key, 0x10) < 0) + fail("failed to load the package key."); + + memcpy(iv, pkg + 0x70, 0x10); + aes128ctr(key, iv, pkg + offset, size, pkg + offset); +} + +static void decrypt_debug_pkg(void) +{ + u8 key[0x40]; + u8 bfr[0x1c]; + u64 i; + + memset(key, 0, sizeof key); + memcpy(key, pkg + 0x60, 8); + memcpy(key + 0x08, pkg + 0x60, 8); + memcpy(key + 0x10, pkg + 0x60 + 0x08, 8); + memcpy(key + 0x18, pkg + 0x60 + 0x08, 8); + + sha1(key, sizeof key, bfr); + + for (i = 0; i < size; i++) { + if (i != 0 && (i % 16) == 0) { + wbe64(key + 0x38, be64(key + 0x38) + 1); + sha1(key, sizeof key, bfr); + } + pkg[offset + i] ^= bfr[i & 0xf]; + } +} + +static void unpack_pkg(void) +{ + u64 i; + u64 n_files; + u32 fname_len; + u32 fname_off; + u64 file_offset; + u32 flags; + char fname[256]; + u8 *tmp; + + n_files = be32(pkg + 0x14); + + for (i = 0; i < n_files; i++) { + tmp = pkg + offset + i*0x20; + + fname_off = be32(tmp) + offset; + fname_len = be32(tmp + 0x04); + file_offset = be64(tmp + 0x08) + offset; + size = be64(tmp + 0x10); + flags = be32(tmp + 0x18); + + if (fname_len >= sizeof fname) + fail("filename too long: %s", pkg + fname_off); + + memset(fname, 0, sizeof fname); + strncpy(fname, (char *)(pkg + fname_off), fname_len); + + flags &= 0xff; + if (flags == 4) + MKDIR(fname, 0777); + else if (flags == 1 || flags == 3) + memcpy_to_file(fname, pkg + file_offset, size); + else + fail("unknown flags: %08x", flags); + } +} + +int main(int argc, char *argv[]) +{ + char *dir; + + if (argc != 2 && argc != 3) + fail("usage: ungpkg filename.pkg [target]"); + + pkg = mmap_file(argv[1]); + + if (argc == 2) { + dir = malloc(0x31); + memset(dir, 0, 0x31); + memset(dir, 0, 0x30); + memcpy(dir, pkg + 0x30, 0x30); + } else { + dir = argv[2]; + } + + MKDIR(dir, 0777); + + if (chdir(dir) != 0) + fail("chdir(%s)", dir); + + offset = be64(pkg + 0x20); + size = be64(pkg + 0x28); + + if (be16(pkg + 0x04) & 0x8000) + decrypt_retail_pkg(); + else + decrypt_debug_pkg(); + + unpack_pkg(); + + return 0; +} diff --git a/unpkg.c b/unpkg.c new file mode 100644 index 0000000..498f14b --- /dev/null +++ b/unpkg.c @@ -0,0 +1,138 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#define MKDIR(x,y) mkdir(x) +#else +#define MKDIR(x,y) mkdir(x,y) +#endif + +u8 *pkg = NULL; +static u64 dec_size; +static u32 meta_offset; +static u32 n_sections; + +static void unpack_content(const char *name) +{ + u8 *tmp; + u8 *decompressed; + u64 offset; + u64 size; + u64 size_real; + + tmp = pkg + meta_offset + 0x80 + 0x30 * 2; + + offset = be64(tmp); + size = be64(tmp + 8); + size_real = dec_size - 0x80; + + if (be32(tmp + 0x2c) == 0x2) { + decompressed = malloc(size_real); + memset(decompressed, 0xaa, size_real); + + decompress(pkg + offset, size, decompressed, size_real); + + memcpy_to_file(name, decompressed, size_real); + } else { + memcpy_to_file(name, pkg + offset, size); + } +} + +static void unpack_info(u32 i) +{ + u8 *tmp; + u64 offset; + u64 size; + char path[256]; + + tmp = pkg + meta_offset + 0x80 + 0x30 * i; + + snprintf(path, sizeof path, "info%d", i); + + offset = be64(tmp); + size = be64(tmp + 8); + + if (size != 0x40) + fail("weird info size: %08x", size); + + memcpy_to_file(path, pkg + offset, size); +} + +static void unpack_pkg(void) +{ + unpack_info(0); + unpack_info(1); + unpack_content("content"); +} + +static void decrypt_pkg(void) +{ + u16 flags; + u16 type; + u32 hdr_len; + struct keylist *k; + + flags = be16(pkg + 0x08); + type = be16(pkg + 0x0a); + hdr_len = be64(pkg + 0x10); + dec_size = be64(pkg + 0x18); + + if (type != 3) + fail("no .pkg file"); + + k = keys_get(KEY_PKG); + + if (k == NULL) + fail("no key found"); + + if (sce_decrypt_header(pkg, k) < 0) + fail("header decryption failed"); + + if (sce_decrypt_data(pkg) < 0) + fail("data decryption failed"); + + meta_offset = be32(pkg + 0x0c); + n_sections = be32(pkg + meta_offset + 0x60 + 0xc); + + if (n_sections != 3) + fail("invalid section count: %d", n_sections); +} + +int main(int argc, char *argv[]) +{ + if (argc == 3) { + pkg = mmap_file(argv[1]); + + MKDIR(argv[2], 0777); + + if (chdir(argv[2]) != 0) + fail("chdir"); + + decrypt_pkg(); + unpack_pkg(); + } else if (argc == 4) { + if (strcmp(argv[1], "-s") != 0) + fail("invalid option: %s", argv[1]); + + pkg = mmap_file(argv[2]); + + decrypt_pkg(); + unpack_content(argv[3]); + } else { + fail("usage: unpkg [-s] filename.pkg target"); + } + + + return 0; +} diff --git a/unself.c b/unself.c new file mode 100644 index 0000000..8172686 --- /dev/null +++ b/unself.c @@ -0,0 +1,374 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include + +#define MAX_SECTIONS 255 + +static u8 *self = NULL; +static u8 *elf = NULL; +static FILE *out = NULL; + +static u64 info_offset; +static u32 key_ver; +static u64 phdr_offset; +static u64 shdr_offset; +static u64 sec_offset; +static u64 ver_offset; +static u64 version; +static u64 elf_offset; +static u64 meta_offset; +static u64 header_len; +static u64 filesize; +static u32 arch64; +static u32 n_sections; + +static struct elf_hdr ehdr; + +static u32 app_type; + +static struct { + u32 offset; + u32 size; + u32 compressed; + u32 size_uncompressed; + u32 elf_offset; +} self_sections[MAX_SECTIONS]; + +static void read_header(void) +{ + key_ver = be16(self + 0x08); + meta_offset = be32(self + 0x0c); + header_len = be64(self + 0x10); + filesize = be64(self + 0x18); + info_offset = be64(self + 0x28); + elf_offset = be64(self + 0x30); + phdr_offset = be64(self + 0x38) - elf_offset; + shdr_offset = be64(self + 0x40) - elf_offset; + sec_offset = be64(self + 0x48); + ver_offset = be64(self + 0x50); + + version = be64(self + info_offset + 0x10); + app_type = be32(self + info_offset + 0x0c); + + elf = self + elf_offset; + arch64 = elf_read_hdr(elf, &ehdr); +} + +struct self_sec { + u32 idx; + u64 offset; + u64 size; + u32 compressed; + u32 encrypted; + u64 next; +}; + +static void read_section(u32 i, struct self_sec *sec) +{ + u8 *ptr; + + ptr = self + sec_offset + i*0x20; + + sec->idx = i; + sec->offset = be64(ptr + 0x00); + sec->size = be64(ptr + 0x08); + sec->compressed = be32(ptr + 0x10) == 2 ? 1 : 0; + sec->encrypted = be32(ptr + 0x1c); + sec->next = be64(ptr + 0x20); +} + +static int qsort_compare(const void *a, const void *b) +{ + const struct self_sec *sa, *sb; + sa = a; + sb = b; + + if (sa->offset > sb->offset) + return 1; + else if(sa->offset < sb->offset) + return -1; + else + return 0; +} + +static void read_sections(void) +{ + struct self_sec s[MAX_SECTIONS]; + struct elf_phdr p; + u32 i; + u32 j; + u32 n_secs; + u32 self_offset, elf_offset; + + memset(s, 0, sizeof s); + for (i = 0, j = 0; i < ehdr.e_phnum; i++) { + read_section(i, &s[j]); + if (s[j].compressed) + j++; + } + + n_secs = j; + qsort(s, n_secs, sizeof(*s), qsort_compare); + + elf_offset = 0; + self_offset = header_len; + j = 0; + i = 0; + while (elf_offset < filesize) { + if (i == n_secs) { + self_sections[j].offset = self_offset; + self_sections[j].size = filesize - elf_offset; + self_sections[j].compressed = 0; + self_sections[j].size_uncompressed = filesize - elf_offset; + self_sections[j].elf_offset = elf_offset; + elf_offset = filesize; + } else if (self_offset == s[i].offset) { + self_sections[j].offset = self_offset; + self_sections[j].size = s[i].size; + self_sections[j].compressed = 1; + elf_read_phdr(arch64, elf + phdr_offset + + (ehdr.e_phentsize * s[i].idx), &p); + self_sections[j].size_uncompressed = p.p_filesz; + self_sections[j].elf_offset = p.p_off; + + elf_offset = p.p_off + p.p_filesz; + self_offset = s[i].next; + i++; + } else { + elf_read_phdr(arch64, elf + phdr_offset + + (ehdr.e_phentsize * s[i].idx), &p); + self_sections[j].offset = self_offset; + self_sections[j].size = p.p_off - elf_offset; + self_sections[j].compressed = 0; + self_sections[j].size_uncompressed = self_sections[j].size; + self_sections[j].elf_offset = elf_offset; + + elf_offset += self_sections[j].size; + self_offset += s[i].offset - self_offset; + } + j++; + } + + n_sections = j; +} + +static void write_elf(void) +{ + u32 i; + u8 *bfr; + u32 size; + u32 offset = 0; + + for (i = 0; i < n_sections; i++) { + fseek(out, self_sections[i].elf_offset, SEEK_SET); + offset = self_sections[i].elf_offset; + if (self_sections[i].compressed) { + size = self_sections[i].size_uncompressed; + + bfr = malloc(size); + if (bfr == NULL) + fail("failed to allocate %d bytes", size); + + offset += size; + + printf("compressed self_sections[i].offset 0x%x self_sections[i].size 0x%x\n", + self_sections[i].offset,self_sections[i].size); + + + decompress(self + self_sections[i].offset, + self_sections[i].size, + bfr, size); + fwrite(bfr, size, 1, out); + free(bfr); + } else { + bfr = self + self_sections[i].offset; + size = self_sections[i].size; + offset += size; + + fwrite(bfr, size, 1, out); + } + } +} + +static void remove_shnames(u64 shdr_offset, u16 n_shdr, u64 shstrtab_offset, u32 strtab_size) +{ + u16 i; + u32 size; + struct elf_shdr s; + + if (arch64) + size = 0x40; + else + size = 0x28; + + for (i = 0; i < n_shdr; i++) { + elf_read_shdr(arch64, elf + shdr_offset + i * size, &s); + + s.sh_name = 0; + if (s.sh_type == 3) { + s.sh_offset = shstrtab_offset; + s.sh_size = strtab_size; + } + + elf_write_shdr(arch64, elf + shdr_offset + i * size, &s); + } +} + +static void check_elf(void) +{ + u8 bfr[0x48]; + u64 elf_offset; + u64 phdr_offset; + u64 shdr_offset; + u64 phdr_offset_new; + u64 shdr_offset_new; + u64 shstrtab_offset; + u16 n_phdr; + u16 n_shdr; + const char shstrtab[] = ".unknown\0\0"; + const char elf_magic[4] = {0x7f, 'E', 'L', 'F'}; + + fseek(out, 0, SEEK_SET); + fread(bfr, 4, 1, out); + + if (memcmp(bfr, elf_magic, sizeof elf_magic) == 0) + return; + + elf_offset = be64(self + 0x30); + phdr_offset = be64(self + 0x38) - elf_offset; + shdr_offset = be64(self + 0x40) - elf_offset; + + if (arch64) { + fseek(out, 0x48, SEEK_SET); + phdr_offset_new = 0x48; + + fseek(out, 0, SEEK_END); + shdr_offset_new = ftell(out); + + n_phdr = be16(elf + 0x38); + n_shdr = be16(elf + 0x3c); + shstrtab_offset = shdr_offset_new + n_shdr * 0x40; + + remove_shnames(shdr_offset, n_shdr, shstrtab_offset, sizeof shstrtab); + + fseek(out, phdr_offset_new, SEEK_SET); + fwrite(elf + phdr_offset, 0x38, n_phdr, out); + + fseek(out, shdr_offset_new, SEEK_SET); + fwrite(elf + shdr_offset, 0x40, n_shdr, out); + + wbe64(elf + 0x20, phdr_offset_new); + wbe64(elf + 0x28, shdr_offset_new); + + fseek(out, SEEK_SET, 0); + fwrite(elf, 0x48, 1, out); + + fseek(out, shstrtab_offset, SEEK_SET); + fwrite(shstrtab, sizeof shstrtab, 1, out); + } else { + fseek(out, 0x34, SEEK_SET); + phdr_offset_new = 0x34; + fseek(out, 0, SEEK_END); + shdr_offset_new = ftell(out); + + n_phdr = be16(elf + 0x2c); + n_shdr = be16(elf + 0x30); + shstrtab_offset = shdr_offset_new + n_shdr * 0x40; + + remove_shnames(shdr_offset, n_shdr, shstrtab_offset, sizeof shstrtab); + + fseek(out, phdr_offset_new, SEEK_SET); + fwrite(elf + phdr_offset, 0x20, n_phdr, out); + + fseek(out, shdr_offset_new, SEEK_SET); + fwrite(elf + shdr_offset, 0x28, n_shdr, out); + + wbe32(elf + 0x1c, phdr_offset_new); + wbe32(elf + 0x20, shdr_offset_new); + + fseek(out, SEEK_SET, 0); + fwrite(elf, 0x34, 1, out); + + fseek(out, shstrtab_offset, SEEK_SET); + fwrite(shstrtab, sizeof shstrtab, 1, out); + } +} + +static struct keylist *self_load_keys(void) +{ + enum sce_key id; + + switch (app_type) { + case 1: + id = KEY_LV0; + break; + case 2: + id = KEY_LV1; + break; + case 3: + id = KEY_LV2; + break; + case 4: + id = KEY_APP; + break; + case 5: + id = KEY_ISO; + break; + case 6: + id = KEY_LDR; + break; + default: + fail("invalid type: %08x", app_type); + } + + return keys_get(id); +} + +static void self_decrypt(void) +{ + struct keylist *klist; + + klist = self_load_keys(); + if (klist == NULL) + fail("no key found"); + + if (sce_decrypt_header(self, klist) < 0) + fail("self_decrypt_header failed"); + + if (sce_decrypt_data(self) < 0) + fail("self_decrypt_data failed"); +} + +int main(int argc, char *argv[]) +{ + if (argc != 3) + fail("usage: unself in.self out.elf"); + + self = mmap_file(argv[1]); + + if (be32(self) != 0x53434500) + fail("not a SELF"); + + read_header(); + read_sections(); + + if (key_ver != 0x8000) + self_decrypt(); + + out = fopen(argv[2], "wb+"); + + write_elf(); + check_elf(); + + fclose(out); + + return 0; +} diff --git a/unself2.c b/unself2.c new file mode 100644 index 0000000..6adb683 --- /dev/null +++ b/unself2.c @@ -0,0 +1,74 @@ +/* + * This software is distributed under the terms of the GNU General Public + * License ("GPL") version 2, as published by the Free Software Foundation. + */ + +#include "tools.h" +#include "self.h" +#include "common.h" + +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + FILE *in = NULL; + FILE *out = NULL; + SELF self; + APP_INFO app_info; + ELF elf; + ELF_PHDR *phdr = NULL; + ELF_SHDR *shdr = NULL; + SECTION_INFO *section_info = NULL; + SCEVERSION_INFO sceversion_info; + CONTROL_INFO *control_info = NULL; + METADATA_INFO metadata_info; + METADATA_HEADER metadata_header; + METADATA_SECTION_HEADER *section_headers = NULL; + uint8_t *keys = NULL; + SIGNATURE_INFO signature_info; + SIGNATURE signature; + SELF_SECTION *sections = NULL; + int num_sections; + int i; + + if (argc != 3) { + fprintf(stderr, "usage: %s in.self out.elf\n", argv[0]); + return -1; + } + + in = fopen (argv[1], "rb"); + if (in == NULL) { + ERROR (-2, "Can't open input file"); + } + + self_read_headers(in, &self, &app_info, &elf, &phdr, &shdr, + §ion_info, &sceversion_info, &control_info); + + self_read_metadata (in, &self, &app_info, &metadata_info, + &metadata_header, §ion_headers, &keys, + &signature_info, &signature); + + num_sections = self_load_sections (in, &self, &elf, &phdr, + &metadata_header, §ion_headers, &keys, §ions); + + fclose (in); + + out = fopen (argv[2], "wb"); + if (out == NULL) { + ERROR (-2, "Can't open output file"); + } + + for (i = 0; i < num_sections; i++) { + fseek (out, sections[i].offset, SEEK_SET); + if (fwrite (sections[i].data, 1, sections[i].size, out) != sections[i].size) { + ERROR (-7, "Error writing section"); + } + } + + self_free_sections (§ions, num_sections); + + return 0; +} diff --git a/unspp.c b/unspp.c new file mode 100644 index 0000000..ca56cf4 --- /dev/null +++ b/unspp.c @@ -0,0 +1,62 @@ +// Copyright 2010 Sven Peter +// Licensed under the terms of the GNU GPL, version 2 +// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + +#include "tools.h" +#include "types.h" + +#include +#include +#include +#include +#include +#include + +u8 *pkg = NULL; +static u64 header_size; +static u64 dec_size; + +static void decrypt_spp(void) +{ + u16 flags; + u16 type; + u32 hdr_len; + struct keylist *k; + + flags = be16(pkg + 0x08); + type = be16(pkg + 0x0a); + hdr_len = be64(pkg + 0x10); + dec_size = be64(pkg + 0x18); + + if (type != 4) + fail("no .spp file"); + + k = keys_get(KEY_SPP); + + if (k == NULL) + fail("no key found"); + + if (sce_decrypt_header(pkg, k) < 0) + fail("header decryption failed"); + + if (sce_decrypt_data(pkg) < 0) + fail("data decryption failed"); + + header_size = be64(pkg + 0x10); + dec_size = be64(pkg + 0x18); +} + +int main(int argc, char *argv[]) +{ + if (argc == 3) { + pkg = mmap_file(argv[1]); + + decrypt_spp(); + memcpy_to_file(argv[2], pkg + header_size, dec_size); + } else { + fail("usage: unspp default.spp target"); + } + + + return 0; +}